Windows2000/private/windows/media/avi/avicap/capinit.c
2020-09-30 17:12:32 +02:00

635 lines
19 KiB
C

/*
* 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 <windows.h>
#include <windowsx.h>
#include <win32.h>
#define MODULE_DEBUG_PREFIX "AVICAP32\\"
#define _INC_MMDEBUG_CODE_ TRUE
#include "MMDEBUG.H"
#if !defined CHICAGO
#include <ntverp.h>
#endif
#include <mmsystem.h>
#include <msvideo.h>
#include "ivideo32.h"
#include <drawdib.h>
#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