/**************************************************************************** * * capinit.c * * Initialization code. * * Microsoft Video for Windows Sample Capture Class * * Copyright (c) 1992 - 1995 Microsoft Corporation. All Rights Reserved. * * You have a royalty-free right to use, modify, reproduce and * distribute the Sample Files (and/or any modified version) in * any way you find useful, provided that you agree that * Microsoft has no warranty obligations or liability for any * Sample Application Files which are modified. * ***************************************************************************/ #define INC_OLE2 #pragma warning(disable:4103) #include #include #include #define MODULE_DEBUG_PREFIX "AVICAP32\\" #define _INC_MMDEBUG_CODE_ TRUE #include "MMDEBUG.H" #if !defined CHICAGO #include #endif #include #include #include "ivideo32.h" #include "avicapi.h" HINSTANCE ghInstDll; TCHAR szCaptureWindowClass[] = TEXT("ClsCapWin"); // If the following structure changes, update AVICAP and AVICAP.32 also!!! typedef struct tCapDriverInfo { TCHAR szKeyEnumName[MAX_PATH]; TCHAR szDriverName[MAX_PATH]; TCHAR szDriverDescription[MAX_PATH]; TCHAR szDriverVersion[80]; TCHAR szSoftwareKey[MAX_PATH]; DWORD dnDevNode; // Set if this is a PnP device BOOL fOnlySystemIni; // If the [path]drivername is only in system.ini BOOL fDisabled; // User has disabled driver in the control panel BOOL fActive; // Reserved } CAPDRIVERINFO, FAR *LPCAPDRIVERINFO; DWORD videoCreateDriverList (void); DWORD videoFreeDriverList (void); extern UINT wTotalVideoDevs; // total video devices extern LPCAPDRIVERINFO aCapDriverList[]; // Array of all capture drivers #if !defined CHICAGO typedef struct tagVS_VERSION { WORD wTotLen; WORD wValLen; WORD wType; TCHAR szSig[16]; WORD Padding1[1]; VS_FIXEDFILEINFO vffInfo; } VS_VERSION; typedef struct tagLANGANDCP { WORD wLanguage; WORD wCodePage; } LANGANDCP; /* typedef struct _VS_FIXEDFILEINFO { // vsffi DWORD dwSignature; DWORD dwStrucVersion; DWORD dwFileVersionMS; DWORD dwFileVersionLS; DWORD dwProductVersionMS; DWORD dwProductVersionLS; DWORD dwFileFlagsMask; DWORD dwFileFlags; DWORD dwFileOS; DWORD dwFileType; DWORD dwFileSubtype; DWORD dwFileDateMS; DWORD dwFileDateLS; } VS_FIXEDFILEINFO; VS_VERSION_INFO { WORD wLength; WORD wValueLength; WORD wType; WCHAR szKey[16]; WORD Padding1[]; VS_FIXEDFILEINFO Value; WORD Padding2[]; WORD Children[]; }; */ #endif BOOL gfIsRTL; BOOL FAR PASCAL RegisterCaptureClass (HINSTANCE hInst) { WNDCLASS cls; // If we're already registered, we're OK if (GetClassInfo(hInst, szCaptureWindowClass, &cls)) return TRUE; cls.hCursor = LoadCursor(NULL, IDC_ARROW); cls.hIcon = NULL; cls.lpszMenuName = NULL; cls.lpszClassName = szCaptureWindowClass; cls.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1); cls.hInstance = hInst; cls.style = CS_HREDRAW|CS_VREDRAW | CS_BYTEALIGNCLIENT | CS_GLOBALCLASS | CS_DBLCLKS; cls.lpfnWndProc = (WNDPROC) CapWndProc; cls.cbClsExtra = 0; // Kludge, VB Status and Error GlobalAlloc'd ptrs + room to grow... cls.cbWndExtra = sizeof (LPCAPSTREAM) + sizeof (DWORD) * 4; RegisterClass(&cls); return TRUE; } // // Internal version // Get the name and version of the video device // BOOL capInternalGetDriverDesc (UINT wDriverIndex, LPTSTR lpszName, int cbName, LPTSTR lpszVer, int cbVer) { #ifdef CHICAGO // This calls into 16-bit AVICAP via a thunk return (BOOL) capxGetDriverDescription ((WORD) wDriverIndex, lpszName, (WORD) cbName, lpszVer, (WORD) cbVer); #else LPTSTR lpVersion; UINT wVersionLen; BOOL bRetCode; TCHAR szGetName[MAX_PATH]; DWORD dwVerInfoSize; DWORD dwVerHnd; TCHAR szBuf[MAX_PATH]; BOOL fGetName; BOOL fGetVersion; fGetName = lpszName != NULL && cbName != 0; fGetVersion = lpszVer != NULL && cbVer != 0; if(fGetName) lpszName[0] = TEXT('\0'); if(fGetVersion) lpszVer [0] = TEXT('\0'); if(DV_ERR_OK != videoCreateDriverList ()) return FALSE; if(wDriverIndex >= wTotalVideoDevs) { videoFreeDriverList (); return FALSE; } // Use description and version from registry, // but can be overwritten by the file's description and product version. if(fGetName) { if(lstrlen(aCapDriverList[wDriverIndex]->szDriverDescription)) lstrcpyn(lpszName, aCapDriverList[wDriverIndex]->szDriverDescription, cbName); else // If no description, we have at least the driver name. lstrcpyn(lpszName, aCapDriverList[wDriverIndex]->szDriverName, cbName); } if(fGetVersion) lstrcpyn(lpszVer, aCapDriverList[wDriverIndex]->szDriverVersion, cbVer); lstrcpyn(szBuf, aCapDriverList[wDriverIndex]->szDriverName, MAX_PATH); videoFreeDriverList (); // You must find the size first before getting any file info dwVerInfoSize = GetFileVersionInfoSize(szBuf, &dwVerHnd); if (dwVerInfoSize) { LPTSTR lpstrVffInfo; // Pointer to block to hold info HANDLE hMem; // handle to mem alloc'ed // Get a block big enough to hold version info hMem = GlobalAlloc(GMEM_MOVEABLE, dwVerInfoSize); lpstrVffInfo = GlobalLock(hMem); // Get the File Version first if (GetFileVersionInfo(szBuf, 0L, dwVerInfoSize, lpstrVffInfo)) { VS_VERSION FAR *pVerInfo = (VS_VERSION FAR *) lpstrVffInfo; // fill in the file version wsprintf(szBuf, TEXT("Version: %d.%d.%d.%d"), HIWORD(pVerInfo->vffInfo.dwFileVersionMS), LOWORD(pVerInfo->vffInfo.dwFileVersionMS), HIWORD(pVerInfo->vffInfo.dwFileVersionLS), LOWORD(pVerInfo->vffInfo.dwFileVersionLS)); if (fGetVersion) lstrcpyn (lpszVer, szBuf, cbVer); } // Now try to get the FileDescription // First try this for the "Translation" entry, and then // try the American english translation. // Keep track of the string length for easy updating. // 040904E4 represents the language ID and the four // least significant digits represent the codepage for // which the data is formatted. The language ID is // composed of two parts: the low ten bits represent // the major language and the high six bits represent // the sub language. lstrcpy(szGetName, TEXT("\\StringFileInfo\\040904E4\\FileDescription")); wVersionLen = 0; lpVersion = NULL; // Look for the corresponding string. bRetCode = VerQueryValue((LPVOID)lpstrVffInfo, (LPTSTR)szGetName, (void FAR* FAR*)&lpVersion, (UINT FAR *) &wVersionLen); if (fGetName && bRetCode && wVersionLen && lpVersion) lstrcpyn (lpszName, lpVersion, cbName); // Let go of the memory GlobalUnlock(hMem); GlobalFree(hMem); } return TRUE; #endif } #ifdef UNICODE // ansi thunk for above (called from ansi thunk functions // for capGetDriverDescriptionA, and WM_GET_DRIVER_NAMEA etc) BOOL capInternalGetDriverDescA(UINT wDriverIndex, LPSTR lpszName, int cbName, LPSTR lpszVer, int cbVer) { LPWSTR pName = NULL, pVer = NULL; BOOL bRet; if (lpszName) { pName = LocalAlloc(LPTR, cbName * sizeof(WCHAR)); } if (lpszVer) { pVer = LocalAlloc(LPTR, cbVer * sizeof(WCHAR)); } bRet = capInternalGetDriverDesc( wDriverIndex, pName, cbName, pVer, cbVer); if (lpszName) { WideToAnsi(lpszName, pName, cbName); } if (lpszVer) { WideToAnsi(lpszVer, pVer, cbVer); } if (pVer) { LocalFree(pVer); } if (pName) { LocalFree(pName); } return bRet; } #endif // // Exported version // Get the name and version of the video device // // unicode and win-16 version - see ansi thunk below BOOL VFWAPI capGetDriverDescription (UINT wDriverIndex, LPTSTR lpszName, int cbName, LPTSTR lpszVer, int cbVer) { return (capInternalGetDriverDesc (wDriverIndex, lpszName, cbName, lpszVer, cbVer)); } #ifdef UNICODE // ansi thunk for above BOOL VFWAPI capGetDriverDescriptionA(UINT wDriverIndex, LPSTR lpszName, int cbName, LPSTR lpszVer, int cbVer) { return capInternalGetDriverDescA(wDriverIndex, lpszName, cbName, lpszVer, cbVer); } #endif // // Disconnect from hardware resources // BOOL CapWinDisconnectHardware(LPCAPSTREAM lpcs) { if( lpcs->hVideoCapture ) { videoStreamFini (lpcs->hVideoCapture); videoClose( lpcs->hVideoCapture ); } if( lpcs->hVideoDisplay ) { videoStreamFini (lpcs->hVideoDisplay); videoClose( lpcs->hVideoDisplay ); } if( lpcs->hVideoIn ) { videoClose( lpcs->hVideoIn ); } lpcs->fHardwareConnected = FALSE; lpcs->hVideoCapture = NULL; lpcs->hVideoDisplay = NULL; lpcs->hVideoIn = NULL; lpcs->sCapDrvCaps.fHasDlgVideoSource = FALSE; lpcs->sCapDrvCaps.fHasDlgVideoFormat = FALSE; lpcs->sCapDrvCaps.fHasDlgVideoDisplay = FALSE; lpcs->sCapDrvCaps.fHasDlgVideoDisplay = FALSE; lpcs->sCapDrvCaps.fHasOverlay = FALSE; lpcs->sCapDrvCaps.fDriverSuppliesPalettes = FALSE; lpcs->sCapDrvCaps.hVideoIn = NULL; lpcs->sCapDrvCaps.hVideoOut = NULL; lpcs->sCapDrvCaps.hVideoExtIn = NULL; lpcs->sCapDrvCaps.hVideoExtOut = NULL; return TRUE; } // // Connect to hardware resources // Return: TRUE if hardware connected to the stream // BOOL CapWinConnectHardware (LPCAPSTREAM lpcs, UINT wDeviceIndex) { DWORD dwError; CHANNEL_CAPS VideoCapsExternalOut; TCHAR ach1[MAX_PATH]; TCHAR ach2[MAX_PATH * 3]; CAPINFOCHUNK cic; HINSTANCE hInstT; lpcs->hVideoCapture = NULL; lpcs->hVideoDisplay = NULL; lpcs->hVideoIn = NULL; lpcs->fHardwareConnected = FALSE; lpcs->fUsingDefaultPalette = TRUE; lpcs->sCapDrvCaps.fHasDlgVideoSource = FALSE; lpcs->sCapDrvCaps.fHasDlgVideoFormat = FALSE; lpcs->sCapDrvCaps.fHasDlgVideoDisplay = FALSE; lpcs->sCapDrvCaps.wDeviceIndex = wDeviceIndex; // Clear any existing capture device name chunk cic.fccInfoID = mmioFOURCC ('I','S','F','T'); cic.lpData = NULL; cic.cbData = 0; SetInfoChunk (lpcs, &cic); // try and open the video hardware!!! if( !(dwError = videoOpen( &lpcs->hVideoIn, wDeviceIndex, VIDEO_IN ) ) ) { if( !(dwError = videoOpen( &lpcs->hVideoCapture, wDeviceIndex, VIDEO_EXTERNALIN ) ) ) { // We don't require the EXTERNALOUT channel, // but do require EXTERNALIN and IN videoOpen( &lpcs->hVideoDisplay, wDeviceIndex, VIDEO_EXTERNALOUT ); if( (!dwError) && lpcs->hVideoCapture && lpcs->hVideoIn ) { lpcs->fHardwareConnected = TRUE; capInternalGetDriverDesc (wDeviceIndex, ach1, sizeof (ach1) / sizeof(TCHAR), ach2, sizeof (ach2) / sizeof(TCHAR)); lstrcat (ach1, TEXT(", ")); lstrcat (ach1, ach2); statusUpdateStatus (lpcs, IDS_CAP_INFO, (LPTSTR) ach1); // Make a string of the current task and capture driver ach2[0] = '\0'; if (hInstT = GetWindowInstance (GetParent(lpcs->hwnd))) GetModuleFileName (hInstT, ach2, sizeof (ach2)/sizeof(TCHAR)); lstrcat (ach2, TEXT(" -AVICAP32- ")); lstrcat (ach2, ach1); // Set software chunk with name of capture device if (*ach2) { #ifdef UNICODE // INFO chunks must be ASCII data CHAR achA[MAX_PATH*3]; cic.cbData = lstrlen(ach2) + 1; // set the number of characters WideToAnsi(achA, ach2, cic.cbData); cic.lpData = achA; #else cic.lpData = ach2; cic.cbData = lstrlen(ach2) + 1; #endif SetInfoChunk (lpcs, &cic); } } } } if (dwError) errorDriverID (lpcs, dwError); if(!lpcs->fHardwareConnected) { CapWinDisconnectHardware(lpcs); } else { if (lpcs->hVideoDisplay && videoGetChannelCaps (lpcs->hVideoDisplay, &VideoCapsExternalOut, sizeof (CHANNEL_CAPS)) == DV_ERR_OK) { lpcs->sCapDrvCaps.fHasOverlay = (BOOL)(VideoCapsExternalOut.dwFlags & (DWORD)VCAPS_OVERLAY); } else lpcs->sCapDrvCaps.fHasOverlay = FALSE; // if the hardware doesn't support it, make sure we don't enable if (!lpcs->sCapDrvCaps.fHasOverlay) lpcs->fOverlayWindow = FALSE; // Start the external in channel streaming continuously videoStreamInit (lpcs->hVideoCapture, 0L, 0L, 0L, 0L); } // end if hardware is available #if 0 // if we don't have a powerful machine, disable capture if (GetWinFlags() & (DWORD) WF_CPU286) CapWinDisconnectHardware(lpcs); #endif if (!lpcs->fHardwareConnected){ lpcs->fLiveWindow = FALSE; lpcs->fOverlayWindow = FALSE; } if (lpcs->hVideoIn) lpcs->sCapDrvCaps.fHasDlgVideoFormat = !videoDialog (lpcs->hVideoIn, lpcs->hwnd, VIDEO_DLG_QUERY); if (lpcs->hVideoCapture) lpcs->sCapDrvCaps.fHasDlgVideoSource = !videoDialog (lpcs->hVideoCapture, lpcs->hwnd, VIDEO_DLG_QUERY); if (lpcs->hVideoDisplay) lpcs->sCapDrvCaps.fHasDlgVideoDisplay = !videoDialog (lpcs->hVideoDisplay, lpcs->hwnd, VIDEO_DLG_QUERY); // these handles are not supported on WIN32 for the good reason that // the videoXXX api set is not published for 32-bit // we might want to make use of the handles ourselves...??? lpcs->sCapDrvCaps.hVideoIn = NULL; lpcs->sCapDrvCaps.hVideoOut = NULL; lpcs->sCapDrvCaps.hVideoExtIn = NULL; lpcs->sCapDrvCaps.hVideoExtOut = NULL; return lpcs->fHardwareConnected; } // // Creates a child window of the capture class // Normally: // Set lpszWindowName to NULL // Set dwStyle to WS_CHILD | WS_VISIBLE // Set hmenu to a unique child id // Unicode and Win-16 version. See ansi thunk below HWND VFWAPI capCreateCaptureWindow ( LPCTSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hwndParent, int nID) { DWORD dwExStyle; dwExStyle = gfIsRTL ? WS_EX_LEFTSCROLLBAR | WS_EX_RIGHT | WS_EX_RTLREADING : 0; RegisterCaptureClass(ghInstDll); #ifdef USE_AVIFILE AVIFileInit(); #endif return CreateWindowEx(dwExStyle, szCaptureWindowClass, lpszWindowName, dwStyle, x, y, nWidth, nHeight, hwndParent, (HMENU) nID, ghInstDll, NULL); } #ifdef UNICODE // ansi thunk HWND VFWAPI capCreateCaptureWindowA ( LPCSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hwndParent, int nID) { LPWSTR pw; int chsize; HWND hwnd; if (lpszWindowName == NULL) { pw = NULL; } else { // remember the null chsize = lstrlenA(lpszWindowName) + 1; pw = LocalLock(LocalAlloc(LPTR, chsize * sizeof(WCHAR))); AnsiToWide(pw, lpszWindowName, chsize); } hwnd = capCreateCaptureWindowW(pw, dwStyle, x, y, nWidth, nHeight, hwndParent, nID); if (pw != NULL) { LocalFree(LocalHandle(pw)); } return(hwnd); } #endif #ifdef CHICAGO static char pszDll16[] = "AVICAP.DLL"; static char pszDll32[] = "AVICAP32.DLL"; BOOL PASCAL avicapf_ThunkConnect32(LPCSTR pszDll16, LPCSTR pszDll32, HINSTANCE hinst, DWORD dwReason); BOOL WINAPI DllMain( HANDLE hInstance, DWORD dwReason, LPVOID reserved) { #if defined DEBUG || defined DEBUG_RETAIL DebugSetOutputLevel (GetProfileInt ("Debug", "Avicap32", 0)); AuxDebugEx (1, DEBUGLINE "DllEntryPoint, %08x,%08x,%08x\r\n", hInstance, dwReason, reserved); #endif if (dwReason == DLL_PROCESS_ATTACH) { char ach[2]; ghInstDll = hInstance; LoadString(ghInstDll, IDS_CAP_RTL, ach, sizeof(ach)); gfIsRTL = ach[0] == TEXT('1'); // INLINE_BREAK; if (!avicapf_ThunkConnect32(pszDll16, pszDll32, hInstance, dwReason)) return FALSE; #if defined _WIN32 && defined CHICAGO // we do this so that we can Get LinPageLock & PageAllocate services // ; // OpenMMDEVLDR(); #endif } else if (dwReason == DLL_PROCESS_DETACH) { #if defined _WIN32 && defined CHICAGO ; // CloseMMDEVLDR(); #endif return avicapf_ThunkConnect32(pszDll16, pszDll32, hInstance, dwReason); } return TRUE; } #else // this is the NT dll entry point BOOL DllInstanceInit(HANDLE hInstance, DWORD dwReason, LPVOID reserved) { if (dwReason == DLL_PROCESS_ATTACH) { TCHAR ach[2]; ghInstDll = hInstance; DisableThreadLibraryCalls(hInstance); LoadString(ghInstDll, IDS_CAP_RTL, ach, NUMELMS(ach)); gfIsRTL = ach[0] == TEXT('1'); DebugSetOutputLevel (GetProfileIntA("Debug", "Avicap32", 0)); videoInitHandleList(); } else if (dwReason == DLL_PROCESS_DETACH) { videoDeleteHandleList(); } return TRUE; } #endif // CHICAGO / NT dll entry point