Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

651 lines
19 KiB

  1. /****************************************************************************
  2. *
  3. * capinit.c
  4. *
  5. * Initialization code.
  6. *
  7. * Microsoft Video for Windows Sample Capture Class
  8. *
  9. * Copyright (c) 1992 - 1995 Microsoft Corporation. All Rights Reserved.
  10. *
  11. * You have a royalty-free right to use, modify, reproduce and
  12. * distribute the Sample Files (and/or any modified version) in
  13. * any way you find useful, provided that you agree that
  14. * Microsoft has no warranty obligations or liability for any
  15. * Sample Application Files which are modified.
  16. *
  17. ***************************************************************************/
  18. #define INC_OLE2
  19. #pragma warning(disable:4103)
  20. #include <windows.h>
  21. #include <windowsx.h>
  22. #include <win32.h>
  23. #define MODULE_DEBUG_PREFIX "AVICAP32\\"
  24. #define _INC_MMDEBUG_CODE_ TRUE
  25. #include "MMDEBUG.H"
  26. #if !defined CHICAGO
  27. #include <ntverp.h>
  28. #endif
  29. #include <mmsystem.h>
  30. #include <vfw.h>
  31. #include "ivideo32.h"
  32. #include "avicapi.h"
  33. HINSTANCE ghInstDll;
  34. TCHAR szCaptureWindowClass[] = TEXT("ClsCapWin");
  35. // If the following structure changes, update AVICAP and AVICAP.32 also!!!
  36. typedef struct tCapDriverInfo {
  37. TCHAR szKeyEnumName[MAX_PATH];
  38. TCHAR szDriverName[MAX_PATH];
  39. TCHAR szDriverDescription[MAX_PATH];
  40. TCHAR szDriverVersion[80];
  41. TCHAR szSoftwareKey[MAX_PATH];
  42. DWORD dnDevNode; // Set if this is a PnP device
  43. BOOL fOnlySystemIni; // If the [path]drivername is only in system.ini
  44. BOOL fDisabled; // User has disabled driver in the control panel
  45. BOOL fActive; // Reserved
  46. } CAPDRIVERINFO, FAR *LPCAPDRIVERINFO;
  47. DWORD videoCreateDriverList (void);
  48. DWORD videoFreeDriverList (void);
  49. extern UINT wTotalVideoDevs; // total video devices
  50. extern LPCAPDRIVERINFO aCapDriverList[]; // Array of all capture drivers
  51. #if !defined CHICAGO
  52. typedef struct tagVS_VERSION
  53. {
  54. WORD wTotLen;
  55. WORD wValLen;
  56. WORD wType;
  57. TCHAR szSig[16];
  58. WORD Padding1[1];
  59. VS_FIXEDFILEINFO vffInfo;
  60. } VS_VERSION;
  61. typedef struct tagLANGANDCP
  62. {
  63. WORD wLanguage;
  64. WORD wCodePage;
  65. } LANGANDCP;
  66. /*
  67. typedef struct _VS_FIXEDFILEINFO { // vsffi
  68. DWORD dwSignature;
  69. DWORD dwStrucVersion;
  70. DWORD dwFileVersionMS;
  71. DWORD dwFileVersionLS;
  72. DWORD dwProductVersionMS;
  73. DWORD dwProductVersionLS;
  74. DWORD dwFileFlagsMask;
  75. DWORD dwFileFlags;
  76. DWORD dwFileOS;
  77. DWORD dwFileType;
  78. DWORD dwFileSubtype;
  79. DWORD dwFileDateMS;
  80. DWORD dwFileDateLS;
  81. } VS_FIXEDFILEINFO;
  82. VS_VERSION_INFO {
  83. WORD wLength;
  84. WORD wValueLength;
  85. WORD wType;
  86. WCHAR szKey[16];
  87. WORD Padding1[];
  88. VS_FIXEDFILEINFO Value;
  89. WORD Padding2[];
  90. WORD Children[];
  91. };
  92. */
  93. #endif
  94. BOOL gfIsRTL;
  95. /* Helper */
  96. void SafeAppend(LPTSTR psz1, LPCTSTR psz2, size_t nChars)
  97. {
  98. int len1inchars = lstrlen(psz1);
  99. int spaceleftinchars = nChars - len1inchars;
  100. int charstocopy = min(spaceleftinchars, lstrlen(psz2) + 1);
  101. CopyMemory(psz1 + len1inchars, psz2, charstocopy * sizeof(TCHAR));
  102. /* Null terminate */
  103. psz1[nChars - 1] = 0;
  104. }
  105. #define SAFEAPPEND(sz1, sz2) \
  106. SafeAppend(sz1, sz2, NUMELMS(sz1))
  107. BOOL FAR PASCAL RegisterCaptureClass (HINSTANCE hInst)
  108. {
  109. WNDCLASS cls;
  110. // If we're already registered, we're OK
  111. if (GetClassInfo(hInst, szCaptureWindowClass, &cls))
  112. return TRUE;
  113. cls.hCursor = LoadCursor(NULL, IDC_ARROW);
  114. cls.hIcon = NULL;
  115. cls.lpszMenuName = NULL;
  116. cls.lpszClassName = szCaptureWindowClass;
  117. cls.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
  118. cls.hInstance = hInst;
  119. cls.style = CS_HREDRAW|CS_VREDRAW | CS_BYTEALIGNCLIENT |
  120. CS_GLOBALCLASS | CS_DBLCLKS;
  121. cls.lpfnWndProc = CapWndProc;
  122. cls.cbClsExtra = 0;
  123. // Kludge, VB Status and Error GlobalAlloc'd ptrs + room to grow...
  124. cls.cbWndExtra = sizeof (LPCAPSTREAM) + sizeof (DWORD) * 4;
  125. RegisterClass(&cls);
  126. return TRUE;
  127. }
  128. //
  129. // Internal version
  130. // Get the name and version of the video device
  131. //
  132. BOOL capInternalGetDriverDesc (UINT wDriverIndex,
  133. LPTSTR lpszName, int cbName,
  134. LPTSTR lpszVer, int cbVer)
  135. {
  136. #ifdef CHICAGO
  137. // This calls into 16-bit AVICAP via a thunk
  138. return (BOOL) capxGetDriverDescription ((WORD) wDriverIndex,
  139. lpszName, (WORD) cbName,
  140. lpszVer, (WORD) cbVer);
  141. #else
  142. LPTSTR lpVersion;
  143. UINT wVersionLen;
  144. BOOL bRetCode;
  145. TCHAR szGetName[MAX_PATH];
  146. DWORD dwVerInfoSize;
  147. DWORD dwVerHnd;
  148. TCHAR szBuf[MAX_PATH];
  149. BOOL fGetName;
  150. BOOL fGetVersion;
  151. fGetName = lpszName != NULL && cbName != 0;
  152. fGetVersion = lpszVer != NULL && cbVer != 0;
  153. if(fGetName)
  154. lpszName[0] = TEXT('\0');
  155. if(fGetVersion)
  156. lpszVer [0] = TEXT('\0');
  157. if(DV_ERR_OK != videoCreateDriverList ())
  158. return FALSE;
  159. if(wDriverIndex >= wTotalVideoDevs) {
  160. videoFreeDriverList ();
  161. return FALSE;
  162. }
  163. // Use description and version from registry,
  164. // but can be overwritten by the file's description and product version.
  165. if(fGetName) {
  166. if(lstrlen(aCapDriverList[wDriverIndex]->szDriverDescription))
  167. lstrcpyn(lpszName, aCapDriverList[wDriverIndex]->szDriverDescription, cbName);
  168. else // If no description, we have at least the driver name.
  169. lstrcpyn(lpszName, aCapDriverList[wDriverIndex]->szDriverName, cbName);
  170. }
  171. if(fGetVersion)
  172. lstrcpyn(lpszVer, aCapDriverList[wDriverIndex]->szDriverVersion, cbVer);
  173. lstrcpyn(szBuf, aCapDriverList[wDriverIndex]->szDriverName, MAX_PATH);
  174. videoFreeDriverList ();
  175. // You must find the size first before getting any file info
  176. dwVerInfoSize = GetFileVersionInfoSize(szBuf, &dwVerHnd);
  177. if (dwVerInfoSize) {
  178. LPTSTR lpstrVffInfo; // Pointer to block to hold info
  179. HANDLE hMem; // handle to mem alloc'ed
  180. // Get a block big enough to hold version info
  181. hMem = GlobalAlloc(GMEM_MOVEABLE, dwVerInfoSize);
  182. lpstrVffInfo = GlobalLock(hMem);
  183. // Get the File Version first
  184. if (GetFileVersionInfo(szBuf, 0L, dwVerInfoSize, lpstrVffInfo)) {
  185. VS_VERSION FAR *pVerInfo = (VS_VERSION FAR *) lpstrVffInfo;
  186. // fill in the file version
  187. wsprintf(szBuf,
  188. TEXT("Version: %d.%d.%d.%d"),
  189. HIWORD(pVerInfo->vffInfo.dwFileVersionMS),
  190. LOWORD(pVerInfo->vffInfo.dwFileVersionMS),
  191. HIWORD(pVerInfo->vffInfo.dwFileVersionLS),
  192. LOWORD(pVerInfo->vffInfo.dwFileVersionLS));
  193. if (fGetVersion)
  194. lstrcpyn (lpszVer, szBuf, cbVer);
  195. }
  196. // Now try to get the FileDescription
  197. // First try this for the "Translation" entry, and then
  198. // try the American english translation.
  199. // Keep track of the string length for easy updating.
  200. // 040904E4 represents the language ID and the four
  201. // least significant digits represent the codepage for
  202. // which the data is formatted. The language ID is
  203. // composed of two parts: the low ten bits represent
  204. // the major language and the high six bits represent
  205. // the sub language.
  206. lstrcpy(szGetName, TEXT("\\StringFileInfo\\040904E4\\FileDescription"));
  207. wVersionLen = 0;
  208. lpVersion = NULL;
  209. // Look for the corresponding string.
  210. bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
  211. (LPTSTR)szGetName,
  212. (void FAR* FAR*)&lpVersion,
  213. (UINT FAR *) &wVersionLen);
  214. if (fGetName && bRetCode && wVersionLen && lpVersion)
  215. lstrcpyn (lpszName, lpVersion, cbName);
  216. // Let go of the memory
  217. GlobalUnlock(hMem);
  218. GlobalFree(hMem);
  219. }
  220. return TRUE;
  221. #endif
  222. }
  223. #ifdef UNICODE
  224. // ansi thunk for above (called from ansi thunk functions
  225. // for capGetDriverDescriptionA, and WM_GET_DRIVER_NAMEA etc)
  226. BOOL capInternalGetDriverDescA(UINT wDriverIndex,
  227. LPSTR lpszName, int cbName,
  228. LPSTR lpszVer, int cbVer)
  229. {
  230. LPWSTR pName = NULL, pVer = NULL;
  231. BOOL bRet;
  232. if (lpszName) {
  233. pName = LocalAlloc(LPTR, cbName * sizeof(WCHAR));
  234. }
  235. if (lpszVer) {
  236. pVer = LocalAlloc(LPTR, cbVer * sizeof(WCHAR));
  237. }
  238. bRet = capInternalGetDriverDesc(
  239. wDriverIndex,
  240. pName, cbName,
  241. pVer, cbVer);
  242. if (lpszName) {
  243. WideToAnsi(lpszName, pName, cbName);
  244. }
  245. if (lpszVer) {
  246. WideToAnsi(lpszVer, pVer, cbVer);
  247. }
  248. if (pVer) {
  249. LocalFree(pVer);
  250. }
  251. if (pName) {
  252. LocalFree(pName);
  253. }
  254. return bRet;
  255. }
  256. #endif
  257. //
  258. // Exported version
  259. // Get the name and version of the video device
  260. //
  261. // unicode and win-16 version - see ansi thunk below
  262. BOOL VFWAPI capGetDriverDescription (UINT wDriverIndex,
  263. LPTSTR lpszName, int cbName,
  264. LPTSTR lpszVer, int cbVer)
  265. {
  266. return (capInternalGetDriverDesc (wDriverIndex,
  267. lpszName, cbName,
  268. lpszVer, cbVer));
  269. }
  270. #ifdef UNICODE
  271. // ansi thunk for above
  272. BOOL VFWAPI capGetDriverDescriptionA(UINT wDriverIndex,
  273. LPSTR lpszName, int cbName,
  274. LPSTR lpszVer, int cbVer)
  275. {
  276. return capInternalGetDriverDescA(wDriverIndex,
  277. lpszName, cbName, lpszVer, cbVer);
  278. }
  279. #endif
  280. //
  281. // Disconnect from hardware resources
  282. //
  283. BOOL CapWinDisconnectHardware(LPCAPSTREAM lpcs)
  284. {
  285. if( lpcs->hVideoCapture ) {
  286. videoStreamFini (lpcs->hVideoCapture);
  287. videoClose( lpcs->hVideoCapture );
  288. }
  289. if( lpcs->hVideoDisplay ) {
  290. videoStreamFini (lpcs->hVideoDisplay);
  291. videoClose( lpcs->hVideoDisplay );
  292. }
  293. if( lpcs->hVideoIn ) {
  294. videoClose( lpcs->hVideoIn );
  295. }
  296. lpcs->fHardwareConnected = FALSE;
  297. lpcs->hVideoCapture = NULL;
  298. lpcs->hVideoDisplay = NULL;
  299. lpcs->hVideoIn = NULL;
  300. lpcs->sCapDrvCaps.fHasDlgVideoSource = FALSE;
  301. lpcs->sCapDrvCaps.fHasDlgVideoFormat = FALSE;
  302. lpcs->sCapDrvCaps.fHasDlgVideoDisplay = FALSE;
  303. lpcs->sCapDrvCaps.fHasDlgVideoDisplay = FALSE;
  304. lpcs->sCapDrvCaps.fHasOverlay = FALSE;
  305. lpcs->sCapDrvCaps.fDriverSuppliesPalettes = FALSE;
  306. lpcs->sCapDrvCaps.hVideoIn = NULL;
  307. lpcs->sCapDrvCaps.hVideoOut = NULL;
  308. lpcs->sCapDrvCaps.hVideoExtIn = NULL;
  309. lpcs->sCapDrvCaps.hVideoExtOut = NULL;
  310. return TRUE;
  311. }
  312. //
  313. // Connect to hardware resources
  314. // Return: TRUE if hardware connected to the stream
  315. //
  316. BOOL CapWinConnectHardware (LPCAPSTREAM lpcs, UINT wDeviceIndex)
  317. {
  318. DWORD dwError;
  319. CHANNEL_CAPS VideoCapsExternalOut;
  320. TCHAR ach1[MAX_PATH];
  321. TCHAR ach2[MAX_PATH * 3];
  322. CAPINFOCHUNK cic;
  323. HINSTANCE hInstT;
  324. lpcs->hVideoCapture = NULL;
  325. lpcs->hVideoDisplay = NULL;
  326. lpcs->hVideoIn = NULL;
  327. lpcs->fHardwareConnected = FALSE;
  328. lpcs->fUsingDefaultPalette = TRUE;
  329. lpcs->sCapDrvCaps.fHasDlgVideoSource = FALSE;
  330. lpcs->sCapDrvCaps.fHasDlgVideoFormat = FALSE;
  331. lpcs->sCapDrvCaps.fHasDlgVideoDisplay = FALSE;
  332. lpcs->sCapDrvCaps.wDeviceIndex = wDeviceIndex;
  333. // Clear any existing capture device name chunk
  334. cic.fccInfoID = mmioFOURCC ('I','S','F','T');
  335. cic.lpData = NULL;
  336. cic.cbData = 0;
  337. SetInfoChunk (lpcs, &cic);
  338. // try and open the video hardware!!!
  339. if( !(dwError = videoOpen( &lpcs->hVideoIn, wDeviceIndex, VIDEO_IN ) ) ) {
  340. if( !(dwError = videoOpen( &lpcs->hVideoCapture, wDeviceIndex, VIDEO_EXTERNALIN ) ) ) {
  341. // We don't require the EXTERNALOUT channel,
  342. // but do require EXTERNALIN and IN
  343. videoOpen( &lpcs->hVideoDisplay, wDeviceIndex, VIDEO_EXTERNALOUT );
  344. if( (!dwError) && lpcs->hVideoCapture && lpcs->hVideoIn ) {
  345. lpcs->fHardwareConnected = TRUE;
  346. capInternalGetDriverDesc (wDeviceIndex,
  347. ach1, sizeof (ach1) / sizeof(TCHAR),
  348. ach2, sizeof (ach2) / sizeof(TCHAR));
  349. SAFEAPPEND(ach1, TEXT(", "));
  350. SAFEAPPEND(ach1, ach2);
  351. statusUpdateStatus (lpcs, IDS_CAP_INFO, (LPTSTR) ach1);
  352. // Make a string of the current task and capture driver
  353. ach2[0] = '\0';
  354. if (hInstT = GetWindowInstance (GetParent(lpcs->hwnd)))
  355. GetModuleFileName (hInstT, ach2, sizeof (ach2)/sizeof(TCHAR));
  356. SAFEAPPEND (ach2, TEXT(" -AVICAP32- "));
  357. SAFEAPPEND (ach2, ach1);
  358. // Set software chunk with name of capture device
  359. if (*ach2) {
  360. #ifdef UNICODE
  361. // INFO chunks must be ASCII data
  362. CHAR achA[MAX_PATH*3];
  363. cic.cbData = lstrlen(ach2) + 1; // set the number of characters
  364. WideToAnsi(achA, ach2, cic.cbData);
  365. cic.lpData = achA;
  366. #else
  367. cic.lpData = ach2;
  368. cic.cbData = lstrlen(ach2) + 1;
  369. #endif
  370. SetInfoChunk (lpcs, &cic);
  371. }
  372. }
  373. }
  374. }
  375. if (dwError)
  376. errorDriverID (lpcs, dwError);
  377. if(!lpcs->fHardwareConnected) {
  378. CapWinDisconnectHardware(lpcs);
  379. }
  380. else {
  381. if (lpcs->hVideoDisplay && videoGetChannelCaps (lpcs->hVideoDisplay,
  382. &VideoCapsExternalOut,
  383. sizeof (CHANNEL_CAPS)) == DV_ERR_OK) {
  384. lpcs->sCapDrvCaps.fHasOverlay = (BOOL)(VideoCapsExternalOut.dwFlags &
  385. (DWORD)VCAPS_OVERLAY);
  386. }
  387. else
  388. lpcs->sCapDrvCaps.fHasOverlay = FALSE;
  389. // if the hardware doesn't support it, make sure we don't enable
  390. if (!lpcs->sCapDrvCaps.fHasOverlay)
  391. lpcs->fOverlayWindow = FALSE;
  392. // Start the external in channel streaming continuously
  393. videoStreamInit (lpcs->hVideoCapture, 0L, 0L, 0L, 0L);
  394. } // end if hardware is available
  395. #if 0
  396. // if we don't have a powerful machine, disable capture
  397. if (GetWinFlags() & (DWORD) WF_CPU286)
  398. CapWinDisconnectHardware(lpcs);
  399. #endif
  400. if (!lpcs->fHardwareConnected){
  401. lpcs->fLiveWindow = FALSE;
  402. lpcs->fOverlayWindow = FALSE;
  403. }
  404. if (lpcs->hVideoIn)
  405. lpcs->sCapDrvCaps.fHasDlgVideoFormat = !videoDialog (lpcs->hVideoIn,
  406. lpcs->hwnd, VIDEO_DLG_QUERY);
  407. if (lpcs->hVideoCapture)
  408. lpcs->sCapDrvCaps.fHasDlgVideoSource = !videoDialog (lpcs->hVideoCapture,
  409. lpcs->hwnd, VIDEO_DLG_QUERY);
  410. if (lpcs->hVideoDisplay)
  411. lpcs->sCapDrvCaps.fHasDlgVideoDisplay = !videoDialog (lpcs->hVideoDisplay,
  412. lpcs->hwnd, VIDEO_DLG_QUERY);
  413. // these handles are not supported on WIN32 for the good reason that
  414. // the videoXXX api set is not published for 32-bit
  415. // we might want to make use of the handles ourselves...???
  416. lpcs->sCapDrvCaps.hVideoIn = NULL;
  417. lpcs->sCapDrvCaps.hVideoOut = NULL;
  418. lpcs->sCapDrvCaps.hVideoExtIn = NULL;
  419. lpcs->sCapDrvCaps.hVideoExtOut = NULL;
  420. return lpcs->fHardwareConnected;
  421. }
  422. //
  423. // Creates a child window of the capture class
  424. // Normally:
  425. // Set lpszWindowName to NULL
  426. // Set dwStyle to WS_CHILD | WS_VISIBLE
  427. // Set hmenu to a unique child id
  428. // Unicode and Win-16 version. See ansi thunk below
  429. HWND VFWAPI capCreateCaptureWindow (
  430. LPCTSTR lpszWindowName,
  431. DWORD dwStyle,
  432. int x, int y, int nWidth, int nHeight,
  433. HWND hwndParent, int nID)
  434. {
  435. DWORD dwExStyle;
  436. dwExStyle = gfIsRTL ? WS_EX_LEFTSCROLLBAR | WS_EX_RIGHT | WS_EX_RTLREADING : 0;
  437. RegisterCaptureClass(ghInstDll);
  438. #ifdef USE_AVIFILE
  439. AVIFileInit();
  440. #endif
  441. return CreateWindowEx(dwExStyle,
  442. szCaptureWindowClass,
  443. lpszWindowName,
  444. dwStyle,
  445. x, y, nWidth, nHeight,
  446. hwndParent, (HMENU) nID,
  447. ghInstDll,
  448. NULL);
  449. }
  450. #ifdef UNICODE
  451. // ansi thunk
  452. HWND VFWAPI capCreateCaptureWindowA (
  453. LPCSTR lpszWindowName,
  454. DWORD dwStyle,
  455. int x, int y, int nWidth, int nHeight,
  456. HWND hwndParent, int nID)
  457. {
  458. LPWSTR pw;
  459. int chsize;
  460. HWND hwnd;
  461. if (lpszWindowName == NULL) {
  462. pw = NULL;
  463. } else {
  464. // remember the null
  465. chsize = lstrlenA(lpszWindowName) + 1;
  466. pw = LocalLock(LocalAlloc(LPTR, chsize * sizeof(WCHAR)));
  467. AnsiToWide(pw, lpszWindowName, chsize);
  468. }
  469. hwnd = capCreateCaptureWindowW(pw, dwStyle, x, y, nWidth, nHeight,
  470. hwndParent, nID);
  471. if (pw != NULL) {
  472. LocalFree(LocalHandle(pw));
  473. }
  474. return(hwnd);
  475. }
  476. #endif
  477. #ifdef CHICAGO
  478. static char pszDll16[] = "AVICAP.DLL";
  479. static char pszDll32[] = "AVICAP32.DLL";
  480. BOOL PASCAL avicapf_ThunkConnect32(LPCSTR pszDll16, LPCSTR pszDll32, HINSTANCE hinst, DWORD dwReason);
  481. BOOL WINAPI DllMain(
  482. HANDLE hInstance,
  483. DWORD dwReason,
  484. LPVOID reserved)
  485. {
  486. #if defined DEBUG || defined DEBUG_RETAIL
  487. DebugSetOutputLevel (GetProfileInt ("Debug", "Avicap32", 0));
  488. AuxDebugEx (1, DEBUGLINE "DllEntryPoint, %08x,%08x,%08x\r\n", hInstance, dwReason, reserved);
  489. #endif
  490. if (dwReason == DLL_PROCESS_ATTACH)
  491. {
  492. char ach[2];
  493. ghInstDll = hInstance;
  494. LoadString(ghInstDll, IDS_CAP_RTL, ach, sizeof(ach));
  495. gfIsRTL = ach[0] == TEXT('1');
  496. // INLINE_BREAK;
  497. if (!avicapf_ThunkConnect32(pszDll16, pszDll32, hInstance, dwReason))
  498. return FALSE;
  499. #if defined _WIN32 && defined CHICAGO
  500. // we do this so that we can Get LinPageLock & PageAllocate services
  501. //
  502. ;
  503. // OpenMMDEVLDR();
  504. #endif
  505. }
  506. else if (dwReason == DLL_PROCESS_DETACH)
  507. {
  508. #if defined _WIN32 && defined CHICAGO
  509. ;
  510. // CloseMMDEVLDR();
  511. #endif
  512. return avicapf_ThunkConnect32(pszDll16, pszDll32, hInstance, dwReason);
  513. }
  514. return TRUE;
  515. }
  516. #else // this is the NT dll entry point
  517. BOOL DllInstanceInit(HANDLE hInstance, DWORD dwReason, LPVOID reserved)
  518. {
  519. if (dwReason == DLL_PROCESS_ATTACH) {
  520. TCHAR ach[2];
  521. ghInstDll = hInstance;
  522. DisableThreadLibraryCalls(hInstance);
  523. LoadString(ghInstDll, IDS_CAP_RTL, ach, NUMELMS(ach));
  524. gfIsRTL = ach[0] == TEXT('1');
  525. DebugSetOutputLevel (GetProfileIntA("Debug", "Avicap32", 0));
  526. videoInitHandleList();
  527. } else if (dwReason == DLL_PROCESS_DETACH) {
  528. videoDeleteHandleList();
  529. }
  530. return TRUE;
  531. }
  532. #endif // CHICAGO / NT dll entry point