/* * 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 #include "avicap.h" #include "avicapi.h" HINSTANCE ghInstDll; TCHAR szCaptureWindowClass[] = TEXT("ClsCapWin"); #if !defined CHICAGO typedef struct tagVS_VERSION { WORD wTotLen; WORD wValLen; TCHAR szSig[16]; VS_FIXEDFILEINFO vffInfo; } VS_VERSION; typedef struct tagLANGANDCP { WORD wLanguage; WORD wCodePage; } LANGANDCP; #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; const static TCHAR szNull[] = TEXT(""); const static TCHAR szVideo[] = TEXT("msvideo"); const static TCHAR szSystemIni[] = TEXT("system.ini"); const static TCHAR szDrivers[] = TEXT("Drivers32"); static TCHAR szKey[sizeof(szVideo) / sizeof(TCHAR) + 2]; fGetName = lpszName != NULL && cbName != 0; fGetVersion = lpszVer != NULL && cbVer != 0; if (fGetName) lpszName[0] = TEXT('\0'); if (fGetVersion) lpszVer[0] = TEXT('\0'); lstrcpy(szKey, szVideo); szKey[sizeof(szVideo) / sizeof(TCHAR) - 1] = TEXT('\0'); if (wDriverIndex > 0) { szKey[sizeof(szVideo) / sizeof(TCHAR)] = TEXT('\0'); szKey[(sizeof(szVideo) / sizeof(TCHAR)) - 1] = (TCHAR)(TEXT('1') + (wDriverIndex - 1)); // driver ordinal } if (GetPrivateProfileString(szDrivers, szKey, szNull, szBuf, sizeof(szBuf) / sizeof(TCHAR), szSystemIni) < 2) return FALSE; // Copy in the driver name initially, just in case the driver // has omitted a description field. if (fGetName) lstrcpyn(lpszName, szBuf, cbName); // 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) { cic.lpData = ach2; cic.cbData = lstrlen(ach2) + 1; 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 static char szMSVIDEO[] = "MSVideo"; BOOL DllInstanceInit(HANDLE hInstance, DWORD dwReason, LPVOID reserved) { #if 0 static BOOL bFixedUp = FALSE; #endif if (dwReason == DLL_PROCESS_ATTACH) { TCHAR ach[2]; #if 0 // this hack has been superceded by correct thunking of capGetDriverDescription // in an nt-supplied 16-bit avicap.dll if (!bFixedUp) { HKEY hkey16 = NULL; HKEY hkey32 = NULL; char achValue[256]; DWORD dwType, cbValue = sizeof(achValue); // In order to get 16 bit capture applications to work, a 16 bit // application must believe that there is a capture driver // installed. Because these applications look in the 16 bit // registry (equates to INI file) then we fudge the situation. // IF there is no information on the 16 bit side, BUT we have // installed a 32 bit driver, then copy the 32 bit driver // information to the 16 bit registry. Note: this does NOT mean // that the capture will happen in 16 bit. The 32 bit code will // still get invoked to do the capture. RegCreateKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\Drivers", &hkey16); RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32", &hkey32); if (hkey16 && hkey32) { LONG result = RegQueryValueExA( hkey16, szMSVIDEO, NULL, &dwType, achValue, &cbValue); // If there is no value stored in the 16 bit section of the // registry (equates to INI file) then see if we have a // 32 bit driver installed. if ((result != ERROR_SUCCESS) && (result != ERROR_MORE_DATA)) { cbValue = sizeof(achValue); if (RegQueryValueExA( hkey32, szMSVIDEO, NULL, &dwType, achValue, &cbValue) == ERROR_SUCCESS) { // there is a 32-bit MSVideo and no 16-bit MSVideo - // write the 32-bit one into the 16-bit list so that // capGetDriverDescription will work // cbValue will be set correctly from the previous // query call RegSetValueExA( hkey16, szMSVIDEO, 0, dwType, achValue, cbValue); } } } if (hkey16) { RegCloseKey(hkey16); } if (hkey32) { RegCloseKey(hkey32); } bFixedUp = TRUE; } #endif 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