Source code of Windows XP (NT5)
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.

648 lines
18 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 <msvideo.h>
  31. #include "ivideo32.h"
  32. #include <drawdib.h>
  33. #include "avicap.h"
  34. #include "avicapi.h"
  35. HINSTANCE ghInstDll;
  36. TCHAR szCaptureWindowClass[] = TEXT("ClsCapWin");
  37. #if !defined CHICAGO
  38. typedef struct tagVS_VERSION
  39. {
  40. WORD wTotLen;
  41. WORD wValLen;
  42. TCHAR szSig[16];
  43. VS_FIXEDFILEINFO vffInfo;
  44. } VS_VERSION;
  45. typedef struct tagLANGANDCP
  46. {
  47. WORD wLanguage;
  48. WORD wCodePage;
  49. } LANGANDCP;
  50. #endif
  51. BOOL gfIsRTL;
  52. BOOL FAR PASCAL RegisterCaptureClass (HINSTANCE hInst)
  53. {
  54. WNDCLASS cls;
  55. // If we're already registered, we're OK
  56. if (GetClassInfo(hInst, szCaptureWindowClass, &cls))
  57. return TRUE;
  58. cls.hCursor = LoadCursor(NULL, IDC_ARROW);
  59. cls.hIcon = NULL;
  60. cls.lpszMenuName = NULL;
  61. cls.lpszClassName = szCaptureWindowClass;
  62. cls.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
  63. cls.hInstance = hInst;
  64. cls.style = CS_HREDRAW|CS_VREDRAW | CS_BYTEALIGNCLIENT |
  65. CS_GLOBALCLASS | CS_DBLCLKS;
  66. cls.lpfnWndProc = (WNDPROC) CapWndProc;
  67. cls.cbClsExtra = 0;
  68. // Kludge, VB Status and Error GlobalAlloc'd ptrs + room to grow...
  69. cls.cbWndExtra = sizeof (LPCAPSTREAM) + sizeof (DWORD) * 4;
  70. RegisterClass(&cls);
  71. return TRUE;
  72. }
  73. //
  74. // Internal version
  75. // Get the name and version of the video device
  76. //
  77. BOOL capInternalGetDriverDesc (UINT wDriverIndex,
  78. LPTSTR lpszName, int cbName,
  79. LPTSTR lpszVer, int cbVer)
  80. {
  81. #ifdef CHICAGO
  82. // This calls into 16-bit AVICAP via a thunk
  83. return (BOOL) capxGetDriverDescription ((WORD) wDriverIndex,
  84. lpszName, (WORD) cbName,
  85. lpszVer, (WORD) cbVer);
  86. #else
  87. LPTSTR lpVersion;
  88. UINT wVersionLen;
  89. BOOL bRetCode;
  90. TCHAR szGetName[MAX_PATH];
  91. DWORD dwVerInfoSize;
  92. DWORD dwVerHnd;
  93. TCHAR szBuf[MAX_PATH];
  94. BOOL fGetName;
  95. BOOL fGetVersion;
  96. const static TCHAR szNull[] = TEXT("");
  97. const static TCHAR szVideo[] = TEXT("msvideo");
  98. const static TCHAR szSystemIni[] = TEXT("system.ini");
  99. const static TCHAR szDrivers[] = TEXT("Drivers32");
  100. static TCHAR szKey[sizeof(szVideo)/sizeof(TCHAR) + 2];
  101. fGetName = lpszName != NULL && cbName != 0;
  102. fGetVersion = lpszVer != NULL && cbVer != 0;
  103. if (fGetName)
  104. lpszName[0] = TEXT('\0');
  105. if (fGetVersion)
  106. lpszVer [0] = TEXT('\0');
  107. lstrcpy(szKey, szVideo);
  108. szKey[sizeof(szVideo)/sizeof(TCHAR) - 1] = TEXT('\0');
  109. if( wDriverIndex > 0 ) {
  110. szKey[sizeof(szVideo)/sizeof(TCHAR)] = TEXT('\0');
  111. szKey[(sizeof(szVideo)/sizeof(TCHAR))-1] = (TCHAR)(TEXT('1') + (wDriverIndex-1) ); // driver ordinal
  112. }
  113. if (GetPrivateProfileString(szDrivers, szKey, szNull,
  114. szBuf, sizeof(szBuf)/sizeof(TCHAR), szSystemIni) < 2)
  115. return FALSE;
  116. // Copy in the driver name initially, just in case the driver
  117. // has omitted a description field.
  118. if (fGetName)
  119. lstrcpyn(lpszName, szBuf, cbName);
  120. // You must find the size first before getting any file info
  121. dwVerInfoSize = GetFileVersionInfoSize(szBuf, &dwVerHnd);
  122. if (dwVerInfoSize) {
  123. LPTSTR lpstrVffInfo; // Pointer to block to hold info
  124. HANDLE hMem; // handle to mem alloc'ed
  125. // Get a block big enough to hold version info
  126. hMem = GlobalAlloc(GMEM_MOVEABLE, dwVerInfoSize);
  127. lpstrVffInfo = GlobalLock(hMem);
  128. // Get the File Version first
  129. if (GetFileVersionInfo(szBuf, 0L, dwVerInfoSize, lpstrVffInfo)) {
  130. VS_VERSION FAR *pVerInfo = (VS_VERSION FAR *) lpstrVffInfo;
  131. // fill in the file version
  132. wsprintf(szBuf,
  133. TEXT("Version: %d.%d.%d.%d"),
  134. HIWORD(pVerInfo->vffInfo.dwFileVersionMS),
  135. LOWORD(pVerInfo->vffInfo.dwFileVersionMS),
  136. HIWORD(pVerInfo->vffInfo.dwFileVersionLS),
  137. LOWORD(pVerInfo->vffInfo.dwFileVersionLS));
  138. if (fGetVersion)
  139. lstrcpyn (lpszVer, szBuf, cbVer);
  140. }
  141. // Now try to get the FileDescription
  142. // First try this for the "Translation" entry, and then
  143. // try the American english translation.
  144. // Keep track of the string length for easy updating.
  145. // 040904E4 represents the language ID and the four
  146. // least significant digits represent the codepage for
  147. // which the data is formatted. The language ID is
  148. // composed of two parts: the low ten bits represent
  149. // the major language and the high six bits represent
  150. // the sub language.
  151. lstrcpy(szGetName, TEXT("\\StringFileInfo\\040904E4\\FileDescription"));
  152. wVersionLen = 0;
  153. lpVersion = NULL;
  154. // Look for the corresponding string.
  155. bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
  156. (LPTSTR)szGetName,
  157. (void FAR* FAR*)&lpVersion,
  158. (UINT FAR *) &wVersionLen);
  159. if (fGetName && bRetCode && wVersionLen && lpVersion)
  160. lstrcpyn (lpszName, lpVersion, cbName);
  161. // Let go of the memory
  162. GlobalUnlock(hMem);
  163. GlobalFree(hMem);
  164. }
  165. return TRUE;
  166. #endif
  167. }
  168. #ifdef UNICODE
  169. // ansi thunk for above (called from ansi thunk functions
  170. // for capGetDriverDescriptionA, and WM_GET_DRIVER_NAMEA etc)
  171. BOOL capInternalGetDriverDescA(UINT wDriverIndex,
  172. LPSTR lpszName, int cbName,
  173. LPSTR lpszVer, int cbVer)
  174. {
  175. LPWSTR pName = NULL, pVer = NULL;
  176. BOOL bRet;
  177. if (lpszName) {
  178. pName = LocalAlloc(LPTR, cbName * sizeof(WCHAR));
  179. }
  180. if (lpszVer) {
  181. pVer = LocalAlloc(LPTR, cbVer * sizeof(WCHAR));
  182. }
  183. bRet = capInternalGetDriverDesc(
  184. wDriverIndex,
  185. pName, cbName,
  186. pVer, cbVer);
  187. if (lpszName) {
  188. WideToAnsi(lpszName, pName, cbName);
  189. }
  190. if (lpszVer) {
  191. WideToAnsi(lpszVer, pVer, cbVer);
  192. }
  193. if (pVer) {
  194. LocalFree(pVer);
  195. }
  196. if (pName) {
  197. LocalFree(pName);
  198. }
  199. return bRet;
  200. }
  201. #endif
  202. //
  203. // Exported version
  204. // Get the name and version of the video device
  205. //
  206. // unicode and win-16 version - see ansi thunk below
  207. BOOL VFWAPI capGetDriverDescription (UINT wDriverIndex,
  208. LPTSTR lpszName, int cbName,
  209. LPTSTR lpszVer, int cbVer)
  210. {
  211. return (capInternalGetDriverDesc (wDriverIndex,
  212. lpszName, cbName,
  213. lpszVer, cbVer));
  214. }
  215. #ifdef UNICODE
  216. // ansi thunk for above
  217. BOOL VFWAPI capGetDriverDescriptionA(UINT wDriverIndex,
  218. LPSTR lpszName, int cbName,
  219. LPSTR lpszVer, int cbVer)
  220. {
  221. return capInternalGetDriverDescA(wDriverIndex,
  222. lpszName, cbName, lpszVer, cbVer);
  223. }
  224. #endif
  225. //
  226. // Disconnect from hardware resources
  227. //
  228. BOOL CapWinDisconnectHardware(LPCAPSTREAM lpcs)
  229. {
  230. if( lpcs->hVideoCapture ) {
  231. videoStreamFini (lpcs->hVideoCapture);
  232. videoClose( lpcs->hVideoCapture );
  233. }
  234. if( lpcs->hVideoDisplay ) {
  235. videoStreamFini (lpcs->hVideoDisplay);
  236. videoClose( lpcs->hVideoDisplay );
  237. }
  238. if( lpcs->hVideoIn ) {
  239. videoClose( lpcs->hVideoIn );
  240. }
  241. lpcs->fHardwareConnected = FALSE;
  242. lpcs->hVideoCapture = NULL;
  243. lpcs->hVideoDisplay = NULL;
  244. lpcs->hVideoIn = NULL;
  245. lpcs->sCapDrvCaps.fHasDlgVideoSource = FALSE;
  246. lpcs->sCapDrvCaps.fHasDlgVideoFormat = FALSE;
  247. lpcs->sCapDrvCaps.fHasDlgVideoDisplay = FALSE;
  248. lpcs->sCapDrvCaps.fHasDlgVideoDisplay = FALSE;
  249. lpcs->sCapDrvCaps.fHasOverlay = FALSE;
  250. lpcs->sCapDrvCaps.fDriverSuppliesPalettes = FALSE;
  251. lpcs->sCapDrvCaps.hVideoIn = NULL;
  252. lpcs->sCapDrvCaps.hVideoOut = NULL;
  253. lpcs->sCapDrvCaps.hVideoExtIn = NULL;
  254. lpcs->sCapDrvCaps.hVideoExtOut = NULL;
  255. return TRUE;
  256. }
  257. //
  258. // Connect to hardware resources
  259. // Return: TRUE if hardware connected to the stream
  260. //
  261. BOOL CapWinConnectHardware (LPCAPSTREAM lpcs, UINT wDeviceIndex)
  262. {
  263. DWORD dwError;
  264. CHANNEL_CAPS VideoCapsExternalOut;
  265. TCHAR ach1[MAX_PATH];
  266. TCHAR ach2[MAX_PATH * 3];
  267. CAPINFOCHUNK cic;
  268. HINSTANCE hInstT;
  269. lpcs->hVideoCapture = NULL;
  270. lpcs->hVideoDisplay = NULL;
  271. lpcs->hVideoIn = NULL;
  272. lpcs->fHardwareConnected = FALSE;
  273. lpcs->fUsingDefaultPalette = TRUE;
  274. lpcs->sCapDrvCaps.fHasDlgVideoSource = FALSE;
  275. lpcs->sCapDrvCaps.fHasDlgVideoFormat = FALSE;
  276. lpcs->sCapDrvCaps.fHasDlgVideoDisplay = FALSE;
  277. lpcs->sCapDrvCaps.wDeviceIndex = wDeviceIndex;
  278. // Clear any existing capture device name chunk
  279. cic.fccInfoID = mmioFOURCC ('I','S','F','T');
  280. cic.lpData = NULL;
  281. cic.cbData = 0;
  282. SetInfoChunk (lpcs, &cic);
  283. // try and open the video hardware!!!
  284. if( !(dwError = videoOpen( &lpcs->hVideoIn, wDeviceIndex, VIDEO_IN ) ) ) {
  285. if( !(dwError = videoOpen( &lpcs->hVideoCapture, wDeviceIndex, VIDEO_EXTERNALIN ) ) ) {
  286. // We don't require the EXTERNALOUT channel,
  287. // but do require EXTERNALIN and IN
  288. videoOpen( &lpcs->hVideoDisplay, wDeviceIndex, VIDEO_EXTERNALOUT );
  289. if( (!dwError) && lpcs->hVideoCapture && lpcs->hVideoIn ) {
  290. lpcs->fHardwareConnected = TRUE;
  291. capInternalGetDriverDesc (wDeviceIndex,
  292. ach1, sizeof (ach1) / sizeof(TCHAR),
  293. ach2, sizeof (ach2) / sizeof(TCHAR));
  294. lstrcat (ach1, TEXT(", "));
  295. lstrcat (ach1, ach2);
  296. statusUpdateStatus (lpcs, IDS_CAP_INFO, (LPTSTR) ach1);
  297. // Make a string of the current task and capture driver
  298. ach2[0] = '\0';
  299. if (hInstT = GetWindowInstance (GetParent(lpcs->hwnd)))
  300. GetModuleFileName (hInstT, ach2, sizeof (ach2)/sizeof(TCHAR));
  301. lstrcat (ach2, TEXT(" -AVICAP32- "));
  302. lstrcat (ach2, ach1);
  303. // Set software chunk with name of capture device
  304. if (*ach2) {
  305. cic.lpData = ach2;
  306. cic.cbData = lstrlen(ach2) + 1;
  307. SetInfoChunk (lpcs, &cic);
  308. }
  309. }
  310. }
  311. }
  312. if (dwError)
  313. errorDriverID (lpcs, dwError);
  314. if(!lpcs->fHardwareConnected) {
  315. CapWinDisconnectHardware(lpcs);
  316. }
  317. else {
  318. if (lpcs->hVideoDisplay && videoGetChannelCaps (lpcs->hVideoDisplay,
  319. &VideoCapsExternalOut,
  320. sizeof (CHANNEL_CAPS)) == DV_ERR_OK) {
  321. lpcs->sCapDrvCaps.fHasOverlay = (BOOL)(VideoCapsExternalOut.dwFlags &
  322. (DWORD)VCAPS_OVERLAY);
  323. }
  324. else
  325. lpcs->sCapDrvCaps.fHasOverlay = FALSE;
  326. // if the hardware doesn't support it, make sure we don't enable
  327. if (!lpcs->sCapDrvCaps.fHasOverlay)
  328. lpcs->fOverlayWindow = FALSE;
  329. // Start the external in channel streaming continuously
  330. videoStreamInit (lpcs->hVideoCapture, 0L, 0L, 0L, 0L);
  331. } // end if hardware is available
  332. #if 0
  333. // if we don't have a powerful machine, disable capture
  334. if (GetWinFlags() & (DWORD) WF_CPU286)
  335. CapWinDisconnectHardware(lpcs);
  336. #endif
  337. if (!lpcs->fHardwareConnected){
  338. lpcs->fLiveWindow = FALSE;
  339. lpcs->fOverlayWindow = FALSE;
  340. }
  341. if (lpcs->hVideoIn)
  342. lpcs->sCapDrvCaps.fHasDlgVideoFormat = !videoDialog (lpcs->hVideoIn,
  343. lpcs->hwnd, VIDEO_DLG_QUERY);
  344. if (lpcs->hVideoCapture)
  345. lpcs->sCapDrvCaps.fHasDlgVideoSource = !videoDialog (lpcs->hVideoCapture,
  346. lpcs->hwnd, VIDEO_DLG_QUERY);
  347. if (lpcs->hVideoDisplay)
  348. lpcs->sCapDrvCaps.fHasDlgVideoDisplay = !videoDialog (lpcs->hVideoDisplay,
  349. lpcs->hwnd, VIDEO_DLG_QUERY);
  350. // these handles are not supported on WIN32 for the good reason that
  351. // the videoXXX api set is not published for 32-bit
  352. // we might want to make use of the handles ourselves...???
  353. lpcs->sCapDrvCaps.hVideoIn = NULL;
  354. lpcs->sCapDrvCaps.hVideoOut = NULL;
  355. lpcs->sCapDrvCaps.hVideoExtIn = NULL;
  356. lpcs->sCapDrvCaps.hVideoExtOut = NULL;
  357. return lpcs->fHardwareConnected;
  358. }
  359. //
  360. // Creates a child window of the capture class
  361. // Normally:
  362. // Set lpszWindowName to NULL
  363. // Set dwStyle to WS_CHILD | WS_VISIBLE
  364. // Set hmenu to a unique child id
  365. // Unicode and Win-16 version. See ansi thunk below
  366. HWND VFWAPI capCreateCaptureWindow (
  367. LPCTSTR lpszWindowName,
  368. DWORD dwStyle,
  369. int x, int y, int nWidth, int nHeight,
  370. HWND hwndParent, int nID)
  371. {
  372. DWORD dwExStyle;
  373. dwExStyle = gfIsRTL ? WS_EX_LEFTSCROLLBAR | WS_EX_RIGHT | WS_EX_RTLREADING : 0;
  374. RegisterCaptureClass(ghInstDll);
  375. #ifdef USE_AVIFILE
  376. AVIFileInit();
  377. #endif
  378. return CreateWindowEx(dwExStyle,
  379. szCaptureWindowClass,
  380. lpszWindowName,
  381. dwStyle,
  382. x, y, nWidth, nHeight,
  383. hwndParent, (HMENU) nID,
  384. ghInstDll,
  385. NULL);
  386. }
  387. #ifdef UNICODE
  388. // ansi thunk
  389. HWND VFWAPI capCreateCaptureWindowA (
  390. LPCSTR lpszWindowName,
  391. DWORD dwStyle,
  392. int x, int y, int nWidth, int nHeight,
  393. HWND hwndParent, int nID)
  394. {
  395. LPWSTR pw;
  396. int chsize;
  397. HWND hwnd;
  398. if (lpszWindowName == NULL) {
  399. pw = NULL;
  400. } else {
  401. // remember the null
  402. chsize = lstrlenA(lpszWindowName) + 1;
  403. pw = LocalLock(LocalAlloc(LPTR, chsize * sizeof(WCHAR)));
  404. AnsiToWide(pw, lpszWindowName, chsize);
  405. }
  406. hwnd = capCreateCaptureWindowW(pw, dwStyle, x, y, nWidth, nHeight,
  407. hwndParent, nID);
  408. if (pw != NULL) {
  409. LocalFree(LocalHandle(pw));
  410. }
  411. return(hwnd);
  412. }
  413. #endif
  414. #ifdef CHICAGO
  415. static char pszDll16[] = "AVICAP.DLL";
  416. static char pszDll32[] = "AVICAP32.DLL";
  417. BOOL PASCAL avicapf_ThunkConnect32(LPCSTR pszDll16, LPCSTR pszDll32, HINSTANCE hinst, DWORD dwReason);
  418. BOOL WINAPI DllMain(
  419. HANDLE hInstance,
  420. DWORD dwReason,
  421. LPVOID reserved)
  422. {
  423. #if defined DEBUG || defined DEBUG_RETAIL
  424. DebugSetOutputLevel (GetProfileInt ("Debug", "Avicap32", 0));
  425. AuxDebugEx (1, DEBUGLINE "DllEntryPoint, %08x,%08x,%08x\r\n", hInstance, dwReason, reserved);
  426. #endif
  427. if (dwReason == DLL_PROCESS_ATTACH)
  428. {
  429. char ach[2];
  430. ghInstDll = hInstance;
  431. LoadString(ghInstDll, IDS_CAP_RTL, ach, sizeof(ach));
  432. gfIsRTL = ach[0] == TEXT('1');
  433. // INLINE_BREAK;
  434. if (!avicapf_ThunkConnect32(pszDll16, pszDll32, hInstance, dwReason))
  435. return FALSE;
  436. #if defined _WIN32 && defined CHICAGO
  437. // we do this so that we can Get LinPageLock & PageAllocate services
  438. //
  439. ;
  440. // OpenMMDEVLDR();
  441. #endif
  442. }
  443. else if (dwReason == DLL_PROCESS_DETACH)
  444. {
  445. #if defined _WIN32 && defined CHICAGO
  446. ;
  447. // CloseMMDEVLDR();
  448. #endif
  449. return avicapf_ThunkConnect32(pszDll16, pszDll32, hInstance, dwReason);
  450. }
  451. return TRUE;
  452. }
  453. #else // this is the NT dll entry point
  454. static char szMSVIDEO[] = "MSVideo";
  455. BOOL DllInstanceInit(HANDLE hInstance, DWORD dwReason, LPVOID reserved)
  456. {
  457. #if 0
  458. static BOOL bFixedUp = FALSE;
  459. #endif
  460. if (dwReason == DLL_PROCESS_ATTACH) {
  461. TCHAR ach[2];
  462. #if 0
  463. // this hack has been superceded by correct thunking of capGetDriverDescription
  464. // in an nt-supplied 16-bit avicap.dll
  465. if (!bFixedUp) {
  466. HKEY hkey16=NULL;
  467. HKEY hkey32=NULL;
  468. char achValue[256];
  469. DWORD dwType, cbValue = sizeof(achValue);
  470. // In order to get 16 bit capture applications to work, a 16 bit
  471. // application must believe that there is a capture driver
  472. // installed. Because these applications look in the 16 bit
  473. // registry (equates to INI file) then we fudge the situation.
  474. // IF there is no information on the 16 bit side, BUT we have
  475. // installed a 32 bit driver, then copy the 32 bit driver
  476. // information to the 16 bit registry. Note: this does NOT mean
  477. // that the capture will happen in 16 bit. The 32 bit code will
  478. // still get invoked to do the capture.
  479. RegCreateKeyA(HKEY_LOCAL_MACHINE,
  480. "Software\\Microsoft\\Windows NT\\CurrentVersion\\Drivers",
  481. &hkey16);
  482. RegOpenKeyA(HKEY_LOCAL_MACHINE,
  483. "Software\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32",
  484. &hkey32);
  485. if (hkey16 && hkey32) {
  486. LONG result =
  487. RegQueryValueExA(
  488. hkey16,
  489. szMSVIDEO,
  490. NULL,
  491. &dwType,
  492. achValue,
  493. &cbValue);
  494. // If there is no value stored in the 16 bit section of the
  495. // registry (equates to INI file) then see if we have a
  496. // 32 bit driver installed.
  497. if ((result != ERROR_SUCCESS) && (result != ERROR_MORE_DATA)) {
  498. cbValue = sizeof(achValue);
  499. if (RegQueryValueExA(
  500. hkey32,
  501. szMSVIDEO,
  502. NULL,
  503. &dwType,
  504. achValue,
  505. &cbValue) == ERROR_SUCCESS) {
  506. // there is a 32-bit MSVideo and no 16-bit MSVideo -
  507. // write the 32-bit one into the 16-bit list so that
  508. // capGetDriverDescription will work
  509. // cbValue will be set correctly from the previous
  510. // query call
  511. RegSetValueExA(
  512. hkey16,
  513. szMSVIDEO,
  514. 0,
  515. dwType,
  516. achValue,
  517. cbValue);
  518. }
  519. }
  520. }
  521. if (hkey16) {
  522. RegCloseKey(hkey16);
  523. }
  524. if (hkey32) {
  525. RegCloseKey(hkey32);
  526. }
  527. bFixedUp = TRUE;
  528. }
  529. #endif
  530. ghInstDll = hInstance;
  531. DisableThreadLibraryCalls(hInstance);
  532. LoadString(ghInstDll, IDS_CAP_RTL, ach, NUMELMS(ach));
  533. gfIsRTL = ach[0] == TEXT('1');
  534. DebugSetOutputLevel (GetProfileIntA("Debug", "Avicap32", 0));
  535. videoInitHandleList();
  536. } else if (dwReason == DLL_PROCESS_DETACH) {
  537. videoDeleteHandleList();
  538. }
  539. return TRUE;
  540. }
  541. #endif // CHICAGO / NT dll entry point