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.

1285 lines
42 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1994-1997 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: drvinfo.c
  6. * Content: DirectDraw driver info implementation
  7. *@@BEGIN_MSINTERNAL
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 17-jun-98 jeffno initial implementation, after michael lyons and toddla
  12. * 14-jun-99 mregen return WHQL certification level -- postponed
  13. *@@END_MSINTERNAL
  14. *
  15. ***************************************************************************/
  16. #include "ddrawpr.h"
  17. #include <tchar.h>
  18. #include <stdio.h>
  19. #include <wincrypt.h>
  20. #include <wintrust.h>
  21. #include <softpub.h>
  22. #include <mscat.h>
  23. //========================================================================
  24. //
  25. // just some handy forward declarations
  26. //
  27. DWORD GetWHQLLevel(LPTSTR lpszDriver, LPSTR lpszWin9xDriver);
  28. DWORD IsFileDigitallySigned(LPTSTR lpszDriver);
  29. BOOL FileIsSignedOld(LPTSTR lpszFile);
  30. //
  31. // These functions are defined in mscat.h. They are not available on win95,
  32. // so we have to use LoadLibrary to load mscat32.dll and wincrypt.dll
  33. //
  34. typedef HCATINFO WINAPI funcCryptCATAdminEnumCatalogFromHash(HCATADMIN hCatAdmin,
  35. BYTE *pbHash,
  36. DWORD cbHash,
  37. DWORD dwFlags,
  38. HCATINFO *phPrevCatInfo);
  39. typedef BOOL WINAPI funcCryptCATAdminCalcHashFromFileHandle(HANDLE hFile,
  40. DWORD *pcbHash,
  41. BYTE *pbHash,
  42. DWORD dwFlags);
  43. typedef HANDLE WINAPI funcCryptCATOpen( LPWSTR pwszFileName,
  44. DWORD fdwOpenFlags,
  45. HCRYPTPROV hProv,
  46. DWORD dwPublicVersion,
  47. DWORD dwEncodingType);
  48. typedef BOOL WINAPI funcCryptCATClose(IN HANDLE hCatalog);
  49. typedef CRYPTCATATTRIBUTE * WINAPI funcCryptCATGetCatAttrInfo( HANDLE hCatalog,
  50. LPWSTR pwszReferenceTag);
  51. typedef BOOL WINAPI funcCryptCATAdminAcquireContext(HCATADMIN *phCatAdmin,
  52. GUID *pgSubsystem,
  53. DWORD dwFlags);
  54. typedef BOOL WINAPI funcCryptCATAdminReleaseContext(HCATADMIN hCatAdmin,
  55. DWORD dwFlags);
  56. typedef BOOL WINAPI funcCryptCATAdminReleaseCatalogContext(HCATADMIN hCatAdmin,
  57. HCATINFO hCatInfo,
  58. DWORD dwFlags);
  59. typedef BOOL WINAPI funcCryptCATCatalogInfoFromContext(HCATINFO hCatInfo,
  60. CATALOG_INFO *psCatInfo,
  61. DWORD dwFlags);
  62. typedef CRYPTCATATTRIBUTE * WINAPI funcCryptCATEnumerateCatAttr(HCATINFO hCatalog,
  63. CRYPTCATATTRIBUTE *lpCat);
  64. //
  65. // function defined in wincrypt.dll
  66. //
  67. typedef LONG WINAPI funcWinVerifyTrust(HWND hwnd, GUID *pgActionID,
  68. LPVOID pWVTData);
  69. //
  70. // our storage for the mscat32/wincrypt dll loader
  71. //
  72. typedef struct tagCatApi {
  73. BOOL bInitialized;
  74. HINSTANCE hLibMSCat;
  75. HINSTANCE hLibWinTrust;
  76. HCATADMIN hCatAdmin;
  77. funcCryptCATClose *pCryptCATClose;
  78. funcCryptCATGetCatAttrInfo *pCryptCATGetCatAttrInfo;
  79. funcCryptCATOpen *pCryptCATOpen;
  80. funcCryptCATAdminEnumCatalogFromHash *pCryptCATAdminEnumCatalogFromHash;
  81. funcCryptCATAdminCalcHashFromFileHandle *pCryptCATAdminCalcHashFromFileHandle;
  82. funcCryptCATAdminAcquireContext *pCryptCATAdminAcquireContext;
  83. funcCryptCATAdminReleaseContext *pCryptCATAdminReleaseContext;
  84. funcCryptCATAdminReleaseCatalogContext *pCryptCATAdminReleaseCatalogContext;
  85. funcCryptCATCatalogInfoFromContext *pCryptCATCatalogInfoFromContext;
  86. funcCryptCATEnumerateCatAttr *pCryptCATEnumerateCatAttr;
  87. funcWinVerifyTrust *pWinVerifyTrust;
  88. } CATAPI,* LPCATAPI;
  89. //========================================================================
  90. //
  91. // some helper functions to open/close crypt API
  92. //
  93. BOOL InitCATAPI(LPCATAPI lpCatApi)
  94. {
  95. UINT uiOldErrorMode;
  96. HINSTANCE hLibMSCat;
  97. HINSTANCE hLibWinTrust;
  98. DDASSERT(lpCatApi!=NULL);
  99. ZeroMemory( lpCatApi, sizeof(CATAPI));
  100. // already initialized by ZeroMemory
  101. // lpCatApi->bInitialized=FALSE:
  102. uiOldErrorMode=SetErrorMode(SEM_NOOPENFILEERRORBOX);
  103. hLibMSCat=LoadLibrary("mscat32.dll");
  104. hLibWinTrust=LoadLibrary("wintrust.dll");
  105. if (hLibMSCat!=NULL &&
  106. hLibWinTrust!=NULL)
  107. {
  108. lpCatApi->pCryptCATOpen=(funcCryptCATOpen *)
  109. GetProcAddress ( hLibMSCat, "CryptCATOpen");
  110. lpCatApi->pCryptCATClose=(funcCryptCATClose *)
  111. GetProcAddress ( hLibMSCat, "CryptCATClose");
  112. lpCatApi->pCryptCATGetCatAttrInfo=(funcCryptCATGetCatAttrInfo *)
  113. GetProcAddress ( hLibMSCat, "CryptCATGetCatAttrInfo");
  114. lpCatApi->pCryptCATAdminCalcHashFromFileHandle=(funcCryptCATAdminCalcHashFromFileHandle*)
  115. GetProcAddress ( hLibMSCat, "CryptCATAdminCalcHashFromFileHandle");
  116. lpCatApi->pCryptCATAdminEnumCatalogFromHash=(funcCryptCATAdminEnumCatalogFromHash*)
  117. GetProcAddress ( hLibMSCat, "CryptCATAdminEnumCatalogFromHash");
  118. lpCatApi->pCryptCATAdminAcquireContext=(funcCryptCATAdminAcquireContext*)
  119. GetProcAddress ( hLibMSCat, "CryptCATAdminAcquireContext");
  120. lpCatApi->pCryptCATAdminReleaseContext=(funcCryptCATAdminReleaseContext*)
  121. GetProcAddress ( hLibMSCat, "CryptCATAdminReleaseContext");
  122. lpCatApi->pCryptCATAdminReleaseCatalogContext=(funcCryptCATAdminReleaseCatalogContext*)
  123. GetProcAddress ( hLibMSCat, "CryptCATAdminReleaseCatalogContext");
  124. lpCatApi->pCryptCATCatalogInfoFromContext=(funcCryptCATCatalogInfoFromContext*)
  125. GetProcAddress ( hLibMSCat, "CryptCATCatalogInfoFromContext");
  126. lpCatApi->pCryptCATEnumerateCatAttr=(funcCryptCATEnumerateCatAttr*)
  127. GetProcAddress ( hLibMSCat, "CryptCATEnumerateCatAttr");
  128. lpCatApi->pWinVerifyTrust=(funcWinVerifyTrust*)
  129. GetProcAddress ( hLibWinTrust,"WinVerifyTrust");
  130. if (lpCatApi->pCryptCATOpen!=NULL &&
  131. lpCatApi->pCryptCATClose!=NULL &&
  132. lpCatApi->pCryptCATGetCatAttrInfo!=NULL &&
  133. lpCatApi->pCryptCATAdminCalcHashFromFileHandle!=NULL &&
  134. lpCatApi->pCryptCATAdminEnumCatalogFromHash!=NULL &&
  135. lpCatApi->pCryptCATAdminAcquireContext!=NULL &&
  136. lpCatApi->pCryptCATAdminReleaseContext!=NULL &&
  137. lpCatApi->pCryptCATAdminReleaseCatalogContext!=NULL &&
  138. lpCatApi->pCryptCATCatalogInfoFromContext!=NULL &&
  139. lpCatApi->pCryptCATEnumerateCatAttr !=NULL &&
  140. lpCatApi->pWinVerifyTrust!=NULL
  141. )
  142. {
  143. if ((*lpCatApi->pCryptCATAdminAcquireContext)(&lpCatApi->hCatAdmin,NULL,0))
  144. {
  145. lpCatApi->hLibMSCat=hLibMSCat;
  146. lpCatApi->hLibWinTrust=hLibWinTrust;
  147. lpCatApi->bInitialized=TRUE;
  148. }
  149. }
  150. }
  151. if (!lpCatApi->bInitialized)
  152. {
  153. FreeLibrary(hLibMSCat);
  154. FreeLibrary(hLibWinTrust);
  155. }
  156. SetErrorMode(uiOldErrorMode);
  157. return lpCatApi->bInitialized;
  158. }
  159. BOOL ReleaseCATAPI(LPCATAPI lpCatApi)
  160. {
  161. DDASSERT(lpCatApi!=NULL);
  162. if (lpCatApi->bInitialized)
  163. {
  164. (*lpCatApi->pCryptCATAdminReleaseContext)( lpCatApi->hCatAdmin, 0);
  165. FreeLibrary(lpCatApi->hLibMSCat);
  166. FreeLibrary(lpCatApi->hLibWinTrust);
  167. ZeroMemory( lpCatApi, sizeof(CATAPI));
  168. return TRUE;
  169. }
  170. return FALSE;
  171. }
  172. //========================================================================
  173. //
  174. // _strstr
  175. //
  176. // String-in-string function, written to avoid RTL inclusion necessity.
  177. //
  178. //========================================================================
  179. char *_strstr(char *s1, char *s2)
  180. {
  181. if (s1 && s2)
  182. {
  183. while (*s1)
  184. {
  185. char *p1=s1;
  186. char *p2=s2;
  187. while (*p2 && (*p1==*p2))
  188. {
  189. p1++;
  190. p2++;
  191. }
  192. if (*p2==0)
  193. return s1;
  194. s1++;
  195. }
  196. }
  197. return NULL;
  198. }
  199. //***&&*%**!!ing c runtime
  200. DWORD _atoi(char * p)
  201. {
  202. DWORD dw=0;
  203. while ( (*p >= '0' && *p <= '9') || (*p >= 'A' && *p <= 'F') || (*p >= 'A' && *p <= 'F') )
  204. {
  205. dw = dw*16;
  206. if (*p >= 'a')
  207. dw += *p-'a' + 10;
  208. else if (*p >= 'A')
  209. dw += *p-'A' + 10;
  210. else
  211. dw += *p-'0';
  212. p++;
  213. }
  214. return dw;
  215. }
  216. char *FindLast(char * s, char c)
  217. {
  218. char * pFound=0;
  219. if (s)
  220. {
  221. while (*s)
  222. {
  223. if (*s == c)
  224. pFound = s;
  225. s++;
  226. }
  227. }
  228. return pFound;
  229. }
  230. //========================================================================
  231. // hard-coded vendor IDs
  232. //========================================================================
  233. #define VEN_3DFX "VEN_121A"
  234. #define VEN_3DFXVOODOO1 "VEN_121A&DEV_0001"
  235. #define VEN_POWERVR "VEN_1033"
  236. #ifdef WIN95
  237. void GetFileVersionData(
  238. LPDDDRIVERINFOEX pDI)
  239. {
  240. void * buffer;
  241. VS_FIXEDFILEINFO * verinfo;
  242. DWORD dwSize;
  243. DWORD dwHi,dwLo;
  244. //Failure means 0 returned
  245. pDI->di.liDriverVersion.HighPart = 0;
  246. pDI->di.liDriverVersion.LowPart = 0;
  247. dwSize=GetFileVersionInfoSize(pDI->di.szDriver, 0);
  248. if (!dwSize)
  249. return;
  250. buffer=LocalAlloc(LPTR, dwSize);
  251. if (!buffer)
  252. return;
  253. if (!GetFileVersionInfo(pDI->di.szDriver, 0, dwSize, buffer))
  254. {
  255. LocalFree(buffer);
  256. return;
  257. }
  258. if (!VerQueryValue(buffer, "\\", (void **)&verinfo, (UINT *)&dwSize))
  259. {
  260. LocalFree(buffer);
  261. return;
  262. }
  263. pDI->di.liDriverVersion.HighPart = verinfo->dwFileVersionMS;
  264. pDI->di.liDriverVersion.LowPart = verinfo->dwFileVersionLS;
  265. LocalFree(buffer);
  266. }
  267. extern HRESULT _GetDriverInfoFromRegistry(char *szClass, char *szClassNot, char *szVendor, LPDDDRIVERINFOEX pDI);
  268. /*
  269. * following are all the 9x-specific version functions
  270. */
  271. void GetHALName(
  272. LPDDRAWI_DIRECTDRAW_GBL pdrv,
  273. LPDDDRIVERINFOEX pDI)
  274. {
  275. pDI->di.szDriver[0] = 0;
  276. lstrcpyn(pDI->di.szDriver, pdrv->dd32BitDriverData.szName, sizeof(pDI->di.szDriver) );
  277. }
  278. BOOL CheckPowerVR(LPDDRAWI_DIRECTDRAW_GBL pdrv, LPDDDRIVERINFOEX pDI)
  279. {
  280. BOOL bFound=FALSE;
  281. HKEY hKey;
  282. DWORD dwSize;
  283. DWORD dwType;
  284. if (pdrv->dwFlags & DDRAWI_SECONDARYDRIVERLOADED)
  285. {
  286. /*
  287. * Any secondary driver information in the registry at all? (assert this is true)
  288. */
  289. if( ERROR_SUCCESS == RegOpenKey( HKEY_LOCAL_MACHINE,
  290. REGSTR_PATH_SECONDARY,
  291. &hKey ) )
  292. {
  293. /*
  294. * Extract the name of the secondary driver's DLL. (assert this works)
  295. */
  296. dwSize = sizeof( pDI->di.szDriver ) - 1;
  297. if( ERROR_SUCCESS == RegQueryValueEx( hKey,
  298. REGSTR_VALUE_SECONDARY_DRIVERNAME,
  299. NULL,
  300. &dwType,
  301. pDI->di.szDriver,
  302. &dwSize ) )
  303. {
  304. if( REG_SZ == dwType )
  305. {
  306. GetFileVersionData(pDI);
  307. }
  308. }
  309. RegCloseKey(hKey);
  310. }
  311. if (SUCCEEDED(_GetDriverInfoFromRegistry(NULL, "Display", VEN_POWERVR, pDI)))
  312. {
  313. //got PVR data...
  314. bFound = TRUE;
  315. }
  316. }
  317. return bFound;
  318. }
  319. HRESULT Check3Dfx(LPDDDRIVERINFOEX pDI)
  320. {
  321. HRESULT hr = DD_OK;
  322. if (FAILED(_GetDriverInfoFromRegistry(NULL, "Display", VEN_3DFX, pDI)))
  323. {
  324. DPF_ERR("Couldn't get registry data for this device");
  325. hr = DDERR_NOTFOUND;
  326. }
  327. return hr;
  328. }
  329. HRESULT GetDriverInfoFromRegistry(char *szClass, char *szClassNot, char *szVendor, LPDDDRIVERINFOEX pDI)
  330. {
  331. return _GetDriverInfoFromRegistry(szClass, szClassNot, szVendor, pDI);
  332. }
  333. /*
  334. * Given a DISPLAY_DEVICE, get driver name
  335. * NOTE::: THIS FUNCTION NUKES THE DISPLAY_DEVICE.DeviceKey STRING!!!!
  336. */
  337. void GetWin9XDriverName(DISPLAY_DEVICEA * pdd, LPSTR pDrvName)
  338. {
  339. HKEY hKey;
  340. lstrcat( pdd->DeviceKey, "\\DEFAULT" );
  341. if( ERROR_SUCCESS == RegOpenKeyEx(
  342. HKEY_LOCAL_MACHINE,
  343. pdd->DeviceKey,
  344. 0,
  345. KEY_QUERY_VALUE ,
  346. &hKey ) )
  347. {
  348. DWORD dwSize = MAX_DDDEVICEID_STRING;
  349. DWORD dwType = 0;
  350. RegQueryValueEx( hKey,
  351. TEXT("drv"),
  352. NULL,
  353. &dwType,
  354. pDrvName,
  355. &dwSize );
  356. RegCloseKey(hKey);
  357. }
  358. }
  359. #else //win95
  360. /*
  361. * following are all the NT-specific version functions
  362. */
  363. void GetFileVersionData(
  364. LPDDDRIVERINFOEX pDI)
  365. {
  366. //Failure means 0 returned
  367. pDI->di.liDriverVersion.HighPart = 0;
  368. pDI->di.liDriverVersion.LowPart = 0;
  369. }
  370. void GetHALName(
  371. LPDDRAWI_DIRECTDRAW_GBL pdrv,
  372. LPDDDRIVERINFOEX pDI)
  373. {
  374. pDI->di.szDriver[0] = 0;
  375. }
  376. BOOL CheckPowerVR(LPDDRAWI_DIRECTDRAW_GBL pdrv, LPDDDRIVERINFOEX pdi)
  377. {
  378. return FALSE;
  379. }
  380. HRESULT Check3Dfx(LPDDDRIVERINFOEX pDI)
  381. {
  382. return DDERR_GENERIC;
  383. }
  384. HRESULT GetDriverInfoFromRegistry(char *szClass, char *szClassNot, char *szVendor, LPDDDRIVERINFOEX pDI)
  385. {
  386. return DDERR_GENERIC;
  387. }
  388. /*
  389. * Given a DISPLAY_DEVICE, get driver name, assuming winnt5
  390. * NOTE::: THIS FUNCTION NUKES THE DISPLAY_DEVICE.DeviceKey STRING!!!!
  391. */
  392. void GetNTDriverNameAndVersion(DISPLAY_DEVICEA * pdd, LPDDDRIVERINFOEX pDI)
  393. {
  394. HKEY hKey;
  395. //
  396. // old style to determine display driver...returns name of miniport!
  397. //
  398. char * pTemp;
  399. // The device key has the form blah\blah\services\<devicekey>\DeviceN
  400. // So we back up one node:
  401. if ( (pTemp = FindLast(pdd->DeviceKey,'\\')) )
  402. {
  403. char * pTempX;
  404. char cOld=*pTemp;
  405. *pTemp = 0;
  406. //If we back up one node, we'll have the registry key under which the driver is stored. Let's use that!
  407. if ( (pTempX = FindLast(pdd->DeviceKey,'\\')) )
  408. {
  409. lstrcpyn(pDI->di.szDriver, pTemp+1, sizeof(pDI->di.szDriver));
  410. //ATTENTION No point getting version data without a filname:
  411. //We need a new service or something to get the used display driver name
  412. //GetFileVersionData(pDI);
  413. }
  414. *pTemp=cOld;
  415. }
  416. //
  417. // we can find the display driver in a registry key
  418. //
  419. // note: InstalledDisplayDrivers can contain several entries
  420. // to display drivers Since there is no way to find out which
  421. // one is the active one, we always return the first as being
  422. // the display driver!
  423. //
  424. if( ERROR_SUCCESS == RegOpenKeyEx(
  425. HKEY_LOCAL_MACHINE,
  426. pdd->DeviceKey+18,
  427. 0,
  428. KEY_QUERY_VALUE ,
  429. &hKey ) )
  430. {
  431. DWORD dwSize=sizeof(pDI->di.szDriver), dwType=0;
  432. if( ERROR_SUCCESS == RegQueryValueEx( hKey,
  433. TEXT("InstalledDisplayDrivers"),
  434. NULL,
  435. &dwType,
  436. pDI->di.szDriver,
  437. &dwSize ) )
  438. {
  439. lstrcat(pDI->di.szDriver, TEXT(".dll"));
  440. }
  441. RegCloseKey(hKey);
  442. }
  443. }
  444. #endif //win95
  445. void GenerateIdentifier(LPDDDRIVERINFOEX pDI)
  446. {
  447. LPDWORD pdw;
  448. CopyMemory(&pDI->di.guidDeviceIdentifier, &CLSID_DirectDraw, sizeof(pDI->di.guidDeviceIdentifier));
  449. //The device IDs get XORed into the whole GUID with the vendor and device ID in the
  450. //first two DWORDs so they don't get XORed with anything else. This makes it
  451. DDASSERT(sizeof(GUID) >= 4*sizeof(DWORD));
  452. pdw = (LPDWORD) &pDI->di.guidDeviceIdentifier;
  453. pdw[0] ^= pDI->di.dwVendorId;
  454. pdw[1] ^= pDI->di.dwDeviceId;
  455. pdw[2] ^= pDI->di.dwSubSysId;
  456. pdw[3] ^= pDI->di.dwRevision;
  457. // The driver version gets XORed into the last two DWORDs of the GUID:
  458. pdw[2] ^= pDI->di.liDriverVersion.LowPart;
  459. pdw[3] ^= pDI->di.liDriverVersion.HighPart;
  460. }
  461. void ParseDeviceId(LPDDDRIVERINFOEX pDI)
  462. {
  463. char * p;
  464. DPF(5,"Parsing %s",pDI->szDeviceID);
  465. pDI->di.dwVendorId = 0;
  466. pDI->di.dwDeviceId = 0;
  467. pDI->di.dwSubSysId = 0;
  468. pDI->di.dwRevision = 0;
  469. if(p =_strstr(pDI->szDeviceID, "VEN_"))
  470. pDI->di.dwVendorId = _atoi( p + 4);
  471. if(p = _strstr(pDI->szDeviceID, "DEV_"))
  472. pDI->di.dwDeviceId = _atoi( p + 4);
  473. if(p = _strstr(pDI->szDeviceID, "SUBSYS_"))
  474. pDI->di.dwSubSysId = _atoi( p + 7);
  475. if(p = _strstr(pDI->szDeviceID, "REV_"))
  476. pDI->di.dwRevision = _atoi( p + 4);
  477. }
  478. HRESULT DDAPI DD_GetDeviceIdentifier( LPDIRECTDRAW lpDD, LPDDDEVICEIDENTIFIER pDI, DWORD dwFlags)
  479. {
  480. DDDEVICEIDENTIFIER2 ddi2;
  481. LPDDRAWI_DIRECTDRAW_INT this_int;
  482. HRESULT hr;
  483. ZeroMemory(&ddi2, sizeof(ddi2));
  484. hr = DD_GetDeviceIdentifier7(lpDD, &ddi2, dwFlags);
  485. TRY
  486. {
  487. this_int = (LPDDRAWI_DIRECTDRAW_INT) lpDD;
  488. if( VALID_DIRECTDRAW_PTR( this_int ) )
  489. {
  490. if (VALIDEX_DDDEVICEIDENTIFIER_PTR( pDI ))
  491. {
  492. CopyMemory(pDI,&ddi2,sizeof(*pDI));
  493. }
  494. else
  495. {
  496. DPF_ERR( "Invalid version struct passed" );
  497. hr = DDERR_INVALIDPARAMS;
  498. }
  499. }
  500. else
  501. {
  502. DPF_ERR( "Invalid driver object passed" );
  503. hr = DDERR_INVALIDOBJECT;
  504. }
  505. }
  506. EXCEPT(EXCEPTION_EXECUTE_HANDLER)
  507. {
  508. DPF_ERR("Exception encountered querying device info");
  509. hr = DDERR_INVALIDPARAMS;
  510. }
  511. return hr;
  512. }
  513. HRESULT InternalGetDeviceIdentifier7( LPDIRECTDRAW lpDD, LPDDDEVICEIDENTIFIER2 pDI, DWORD dwFlags, BOOL bWHQL)
  514. {
  515. HRESULT hr=DD_OK;
  516. LPDDRAWI_DIRECTDRAW_INT this_int;
  517. LPDDRAWI_DIRECTDRAW_LCL this_lcl;
  518. LPDDRAWI_DIRECTDRAW_GBL pdrv;
  519. int n;
  520. DISPLAY_DEVICEA dd;
  521. DDDRIVERINFOEX di;
  522. BOOL bFound;
  523. #ifndef WINNT
  524. static char szWin9xName[MAX_DDDEVICEID_STRING];
  525. #endif
  526. ENTER_DDRAW();
  527. TRY
  528. {
  529. this_int = (LPDDRAWI_DIRECTDRAW_INT) lpDD;
  530. if( VALID_DIRECTDRAW_PTR( this_int ) )
  531. {
  532. this_lcl = this_int->lpLcl;
  533. pdrv = this_lcl->lpGbl;
  534. if (VALIDEX_DDDEVICEIDENTIFIER2_PTR( pDI ))
  535. {
  536. /*
  537. * Reset to something sensible
  538. */
  539. ZeroMemory(&di,sizeof(di));
  540. #ifndef WINNT
  541. szWin9xName[0] = '\0';
  542. #endif
  543. if (0 == (dwFlags & ~DDGDI_VALID) )
  544. {
  545. /*
  546. * First step: version info and name for the ddraw HAL driver (on 9x), and format it into a string
  547. */
  548. GetHALName(pdrv, &di);
  549. GetFileVersionData(&di);
  550. /*
  551. * If it's a 3dfx, it's easy
  552. */
  553. if ( 0 == (pdrv->dwFlags & DDRAWI_DISPLAYDRV) )
  554. {
  555. hr = Check3Dfx(&di);
  556. }
  557. else
  558. {
  559. /*
  560. * Not a 3dfx.
  561. */
  562. /*
  563. * Next step: Figure out which display device we really are and get description string for it
  564. */
  565. ZeroMemory(&dd, sizeof(dd));
  566. dd.cb = sizeof(dd);
  567. bFound=FALSE;
  568. for( n=0; xxxEnumDisplayDevicesA( NULL, n, &dd, 0 ); n++ )
  569. {
  570. char * pDeviceName = pdrv->cDriverName;
  571. //DDraw has this convention that the primary device is always DISPLAY.
  572. if (0 == _stricmp(dd.DeviceName, pdrv->cDriverName ) ||
  573. ((dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) &&
  574. (0 == _stricmp(pdrv->cDriverName , "DISPLAY")) ) )
  575. {
  576. /*
  577. * Found the device. Now we can get some data for it.
  578. */
  579. lstrcpyn(di.di.szDescription, dd.DeviceString, sizeof(di.di.szDescription));
  580. lstrcpyn(di.szDeviceID, dd.DeviceID, sizeof(di.szDeviceID) );
  581. bFound = TRUE;
  582. #ifdef WINNT
  583. GetNTDriverNameAndVersion(&dd,&di);
  584. #else
  585. GetWin9XDriverName(&dd, szWin9xName);
  586. if( di.di.szDriver[0] == '\0' )
  587. {
  588. lstrcpyn( di.di.szDriver, szWin9xName, sizeof(di.di.szDriver) );
  589. }
  590. #endif
  591. break;
  592. }
  593. ZeroMemory(&dd, sizeof(dd));
  594. dd.cb = sizeof(dd);
  595. }
  596. /*
  597. * Final step: Go get the pnp id of the chipset
  598. */
  599. if (!bFound)
  600. {
  601. /*
  602. * Didn't find it: xxxEnumDisplayDevices failed, i.e. we're on 9x or NT4,
  603. */
  604. if (FAILED(GetDriverInfoFromRegistry("Display", NULL, NULL, &di)))
  605. {
  606. DPF_ERR("Couldn't get registry data for display");
  607. hr = DDERR_NOTFOUND;
  608. }
  609. }
  610. }
  611. if (SUCCEEDED(hr))
  612. {
  613. ParseDeviceId(&di);
  614. /*
  615. * Finally, for the primary only, check if a PowerVR is in and functioning
  616. */
  617. if (0 == (dwFlags & DDGDI_GETHOSTIDENTIFIER) )
  618. {
  619. if (IsVGADevice(pdrv->cDriverName) && CheckPowerVR(pdrv, &di))
  620. {
  621. ParseDeviceId(&di);
  622. }
  623. }
  624. /*
  625. * Munge driver version and ID into the identifier GUID.
  626. */
  627. GenerateIdentifier(&di);
  628. }
  629. }
  630. else
  631. {
  632. DPF_ERR( "Invalid flags passed" );
  633. hr = DDERR_INVALIDPARAMS;
  634. }
  635. /*
  636. * Finally copy the struct, or 0s if failed, to the app's buffer
  637. */
  638. CopyMemory(pDI,&di.di,offsetof(DDDEVICEIDENTIFIER2,dwWHQLLevel) + sizeof(DWORD));
  639. /*
  640. * Our compiler packs structs to 8 byte boundaries, but this struct is only 4 byte aligned.
  641. * In short, sizeof(*pDI) == 1072, but the actual size is 1068, so we cannot copy the
  642. * buffer using sizeof, so we instead do the above wackiness. We need to assert, however,
  643. * so we can fix this if this structure ever grows.
  644. */
  645. DDASSERT((sizeof(*pDI) - (offsetof(DDDEVICEIDENTIFIER2,dwWHQLLevel) + sizeof(DWORD))) <= 4);
  646. if (bWHQL)
  647. {
  648. #ifdef WINNT
  649. pDI->dwWHQLLevel=GetWHQLLevel((LPTSTR)&di.di.szDriver, NULL);
  650. #else
  651. pDI->dwWHQLLevel=GetWHQLLevel((LPTSTR)&di.di.szDriver, szWin9xName);
  652. #endif
  653. }
  654. else
  655. {
  656. pDI->dwWHQLLevel = 0;
  657. }
  658. /*
  659. * lets find out here if driver is WHQL certified
  660. */
  661. }
  662. else
  663. {
  664. DPF_ERR( "Invalid version struct passed" );
  665. hr = DDERR_INVALIDPARAMS;
  666. }
  667. }
  668. else
  669. {
  670. DPF_ERR( "Invalid driver object passed" );
  671. hr = DDERR_INVALIDOBJECT;
  672. }
  673. }
  674. EXCEPT(EXCEPTION_EXECUTE_HANDLER)
  675. {
  676. DPF_ERR("Exception encountered querying device info");
  677. hr = DDERR_INVALIDPARAMS;
  678. }
  679. LEAVE_DDRAW();
  680. return hr;
  681. }
  682. HRESULT DDAPI DD_GetDeviceIdentifier7( LPDIRECTDRAW lpDD, LPDDDEVICEIDENTIFIER2 pDI, DWORD dwFlags)
  683. {
  684. return InternalGetDeviceIdentifier7 (lpDD, pDI, dwFlags, TRUE);
  685. }
  686. /*
  687. * Voodoo1GoodToGo
  688. *
  689. * The Voodoo 1 driver will succeed the CreateDC call on Voodoo 2, Voodoo 3,
  690. * or Banshee hardware, but if we use the driver beyond that it will hang
  691. * the hardware. This is a work around to not enumerate a Voodoo 1
  692. * driver if the hardware isn't there.
  693. *
  694. * To our knowledge, only two guids were ever used to enumerate Voodoo1
  695. * hardware, so we will look for those guids and assume that anything else
  696. * doesn't need to be checked.
  697. */
  698. BOOL Voodoo1GoodToGo( GUID * pGuid )
  699. {
  700. DDDRIVERINFOEX DI;
  701. if (IsEqualIID(pGuid, &guidVoodoo1A) || IsEqualIID(pGuid, &guidVoodoo1B) )
  702. {
  703. #ifdef WIN95
  704. /*
  705. * Now search the hardware enum key to see if Voodoo 1 hardware exists
  706. */
  707. if (FAILED(_GetDriverInfoFromRegistry(NULL, "Display", VEN_3DFXVOODOO1, &DI)))
  708. {
  709. return FALSE;
  710. }
  711. #else
  712. return FALSE;
  713. #endif
  714. }
  715. return TRUE;
  716. }
  717. #ifndef WINNT
  718. /****************************************************************************
  719. *
  720. * FileIsSignedOld
  721. *
  722. * find win95 style of signature
  723. *
  724. ****************************************************************************/
  725. BOOL FileIsSignedOld(LPTSTR lpszFile)
  726. {
  727. typedef struct tagIMAGE_DOS_HEADER // DOS .EXE header
  728. {
  729. WORD e_magic; // Magic number
  730. WORD e_cblp; // Bytes on last page of file
  731. WORD e_cp; // Pages in file
  732. WORD e_crlc; // Relocations
  733. WORD e_cparhdr; // Size of header in paragraphs
  734. WORD e_minalloc; // Minimum extra paragraphs needed
  735. WORD e_maxalloc; // Maximum extra paragraphs needed
  736. WORD e_ss; // Initial (relative) SS value
  737. WORD e_sp; // Initial SP value
  738. WORD e_csum; // Checksum
  739. WORD e_ip; // Initial IP value
  740. WORD e_cs; // Initial (relative) CS value
  741. WORD e_lfarlc; // File address of relocation table
  742. WORD e_ovno; // Overlay number
  743. WORD e_res[4]; // Reserved words
  744. WORD e_oemid; // OEM identifier (for e_oeminfo)
  745. WORD e_oeminfo; // OEM information; e_oemid specific
  746. WORD e_res2[10]; // Reserved words
  747. LONG e_lfanew; // File address of new exe header
  748. } IMAGE_DOS_HEADER, * PIMAGE_DOS_HEADER, FAR* LPIMAGE_DOS_HEADER;
  749. typedef struct tagIMAGE_OS2_HEADER // OS/2 .EXE header
  750. {
  751. WORD ne_magic; // Magic number
  752. CHAR ne_ver; // Version number
  753. CHAR ne_rev; // Revision number
  754. WORD ne_enttab; // Offset of Entry Table
  755. WORD ne_cbenttab; // Number of bytes in Entry Table
  756. LONG ne_crc; // Checksum of whole file
  757. WORD ne_flags; // Flag word
  758. WORD ne_autodata; // Automatic data segment number
  759. WORD ne_heap; // Initial heap allocation
  760. WORD ne_stack; // Initial stack allocation
  761. LONG ne_csip; // Initial CS:IP setting
  762. LONG ne_sssp; // Initial SS:SP setting
  763. WORD ne_cseg; // Count of file segments
  764. WORD ne_cmod; // Entries in Module Reference Table
  765. WORD ne_cbnrestab; // Size of non-resident name table
  766. WORD ne_segtab; // Offset of Segment Table
  767. WORD ne_rsrctab; // Offset of Resource Table
  768. WORD ne_restab; // Offset of resident name table
  769. WORD ne_modtab; // Offset of Module Reference Table
  770. WORD ne_imptab; // Offset of Imported Names Table
  771. LONG ne_nrestab; // Offset of Non-resident Names Table
  772. WORD ne_cmovent; // Count of movable entries
  773. WORD ne_align; // Segment alignment shift count
  774. WORD ne_cres; // Count of resource segments
  775. BYTE ne_exetyp; // Target Operating system
  776. BYTE ne_flagsothers; // Other .EXE flags
  777. WORD ne_pretthunks; // offset to return thunks
  778. WORD ne_psegrefbytes; // offset to segment ref. bytes
  779. WORD ne_swaparea; // Minimum code swap area size
  780. WORD ne_expver; // Expected Windows version number
  781. } IMAGE_OS2_HEADER, * PIMAGE_OS2_HEADER, FAR* LPIMAGE_OS2_HEADER;
  782. typedef struct tagWINSTUB
  783. {
  784. IMAGE_DOS_HEADER idh;
  785. BYTE rgb[14];
  786. } WINSTUB, * PWINSTUB, FAR* LPWINSTUB;
  787. typedef struct tagFILEINFO
  788. {
  789. BYTE cbInfo[0x120];
  790. } FILEINFO, * PFILEINFO, FAR* LPFILEINFO;
  791. FILEINFO fi;
  792. int nRC;
  793. LPIMAGE_DOS_HEADER lpmz;
  794. LPIMAGE_OS2_HEADER lpne;
  795. BYTE cbInfo[9+32+2];
  796. BOOL IsSigned = FALSE;
  797. OFSTRUCT OpenStruct;
  798. HFILE hFile;
  799. static WINSTUB winstub = {
  800. {
  801. IMAGE_DOS_SIGNATURE, /* magic */
  802. 0, /* bytes on last page - varies */
  803. 0, /* pages in file - varies */
  804. 0, /* relocations */
  805. 4, /* paragraphs in header */
  806. 1, /* min allocation */
  807. 0xFFFF, /* max allocation */
  808. 0, /* initial SS */
  809. 0xB8, /* initial SP */
  810. 0, /* checksum (ha!) */
  811. 0, /* initial IP */
  812. 0, /* initial CS */
  813. 0x40, /* lfarlc */
  814. 0, /* overlay number */
  815. { 0, 0, 0, 0}, /* reserved */
  816. 0, /* oem id */
  817. 0, /* oem info */
  818. 0, /* compiler bug */
  819. { 0}, /* reserved */
  820. 0x80, /* lfanew */
  821. },
  822. {
  823. 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD,
  824. 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21,
  825. }
  826. };
  827. OpenStruct.cBytes = sizeof( OpenStruct );
  828. lstrcpyn( OpenStruct.szPathName, lpszFile, OFS_MAXPATHNAME );
  829. hFile = OpenFile(lpszFile, &OpenStruct, OF_READ);
  830. if (hFile == HFILE_ERROR )
  831. {
  832. return FALSE;
  833. }
  834. nRC = 0;
  835. ReadFile( (HANDLE) hFile, (LPVOID)&fi, sizeof(FILEINFO), &nRC, NULL);
  836. if (nRC != sizeof(FILEINFO))
  837. {
  838. goto FileIsSigned_exit;
  839. }
  840. lpmz = (LPIMAGE_DOS_HEADER)(&fi);
  841. lpne = (LPIMAGE_OS2_HEADER)((WORD)&fi + 0x80);
  842. winstub.idh.e_cblp = lpmz->e_cblp;
  843. winstub.idh.e_cp = lpmz->e_cp;
  844. if (memcmp(&fi, &winstub, sizeof(winstub)) == 0)
  845. {
  846. goto FileIsSigned_exit;
  847. }
  848. memcpy(cbInfo, &((PWINSTUB)(&fi)->cbInfo)->rgb[14], sizeof(cbInfo));
  849. if ( (cbInfo[4] != ' ' ) || // space
  850. (cbInfo[8] != ' ' ) || // space
  851. (cbInfo[9+32] != '\n') || // return
  852. (cbInfo[9+32+1] != '$' ) ) // Dollar Sign
  853. {
  854. goto FileIsSigned_exit;
  855. }
  856. cbInfo[4] = 0;
  857. cbInfo[8] = 0;
  858. if ( (strcmp((const char*)&cbInfo[0], "Cert") != 0) ||
  859. (strcmp((const char*)&cbInfo[5], "DX2") != 0) )
  860. {
  861. goto FileIsSigned_exit;
  862. }
  863. IsSigned=TRUE;
  864. FileIsSigned_exit:
  865. _lclose( hFile );
  866. return IsSigned;
  867. }
  868. #endif
  869. /*
  870. * GetWHQLLevel - On Win95, look for old stamp only. On Win2000, use digital
  871. * signature only. On Win98, look for old stamp first, then digital signature
  872. * if no old stamp.
  873. *
  874. * return 0 -- unsigned or uncertified
  875. * return 1 -- driver certified
  876. * return 1997 -- driver certified, PC97 compliant...
  877. * return 1998...
  878. *
  879. *
  880. * arguments:
  881. *
  882. * lpszDriver----Path of driver file
  883. *
  884. */
  885. DWORD GetWHQLLevel(LPTSTR lpszDriver, LPSTR lpszWin9xDriver)
  886. {
  887. TCHAR szTmp[MAX_PATH];
  888. DWORD dwWhqlLevel = 0;
  889. // here we should rather call
  890. if (GetSystemDirectory( szTmp, MAX_PATH-lstrlen(lpszDriver)-2)==0)
  891. return 0;
  892. lstrcat( szTmp, TEXT("\\"));
  893. lstrcat( szTmp, lpszDriver);
  894. _tcslwr( szTmp);
  895. //
  896. // Look for a digital signature
  897. //
  898. dwWhqlLevel = IsFileDigitallySigned(szTmp);
  899. if( dwWhqlLevel != 0 )
  900. {
  901. return dwWhqlLevel;
  902. }
  903. #ifndef WINNT
  904. // It wasn't digitally signed, but it may still have been signed
  905. // the old way. On Win9X, however, lpszDriver actually contains the
  906. // 32 bit HAL name rather than the display driver, but we typically only
  907. // signed the display driver, so we should use lpszWin9xDriver.
  908. if( lpszWin9xDriver[0] != '\0' )
  909. {
  910. GetSystemDirectory( szTmp, MAX_PATH-lstrlen(lpszWin9xDriver)-2);
  911. lstrcat( szTmp, TEXT("\\"));
  912. lstrcat( szTmp, lpszWin9xDriver);
  913. }
  914. else
  915. {
  916. GetSystemDirectory( szTmp, MAX_PATH-lstrlen(lpszDriver)-2);
  917. lstrcat( szTmp, TEXT("\\"));
  918. lstrcat( szTmp, lpszDriver);
  919. }
  920. if (FileIsSignedOld(szTmp))
  921. {
  922. return 1;
  923. }
  924. #endif
  925. return 0;
  926. }
  927. DWORD IsFileDigitallySigned(LPTSTR lpszDriver)
  928. {
  929. DWORD dwWHQLLevel=0; // default, driver not certified
  930. CATAPI catapi;
  931. WCHAR *lpFileName;
  932. DRIVER_VER_INFO VerInfo;
  933. TCHAR szBuffer[50];
  934. LPSTR lpAttr;
  935. #ifndef UNICODE
  936. WCHAR wszDriver[MAX_PATH];
  937. MultiByteToWideChar(CP_ACP, 0, lpszDriver, -1, wszDriver, MAX_PATH);
  938. lpFileName = wcsrchr(wszDriver, TEXT('\\'));
  939. if (lpFileName==NULL)
  940. {
  941. lpFileName = wszDriver;
  942. }
  943. else
  944. {
  945. lpFileName++;
  946. }
  947. #else
  948. lpFileName = _tcsrchr(lpszDriver, TEXT('\\'));
  949. if (lpFileName==NULL) lpFileName = lpszDriver;
  950. #endif
  951. //
  952. // try to load and initialize the mscat32.dll and wintrust.dll
  953. // these dlls are not available on win95
  954. //
  955. if (InitCATAPI(&catapi))
  956. {
  957. HANDLE hFile;
  958. DWORD cbHashSize=0;
  959. BYTE *pbHash;
  960. BOOL bResult;
  961. //
  962. // create a handle to our driver, because cat api wants handle to file
  963. //
  964. hFile = CreateFile( lpszDriver,
  965. GENERIC_READ,
  966. FILE_SHARE_READ | FILE_SHARE_WRITE,
  967. 0,
  968. OPEN_EXISTING,
  969. FILE_ATTRIBUTE_NORMAL,
  970. 0
  971. );
  972. if (hFile!=INVALID_HANDLE_VALUE)
  973. {
  974. // first query hash size...
  975. bResult=(*catapi.pCryptCATAdminCalcHashFromFileHandle)(hFile,
  976. &cbHashSize,
  977. NULL,
  978. 0);
  979. pbHash=NULL;
  980. if (bResult)
  981. {
  982. // allocate hash
  983. pbHash = LocalAlloc( LPTR, cbHashSize);
  984. }
  985. if (pbHash!=NULL)
  986. {
  987. HCATINFO hPrevCat=NULL;
  988. HANDLE hCatalog=NULL;
  989. WINTRUST_DATA WinTrustData;
  990. WINTRUST_CATALOG_INFO WinTrustCatalogInfo;
  991. GUID guidSubSystemDriver = DRIVER_ACTION_VERIFY;
  992. CRYPTCATATTRIBUTE *lpCat = NULL;
  993. //
  994. // Now get the hash for our file
  995. //
  996. bResult=(*catapi.pCryptCATAdminCalcHashFromFileHandle)(hFile,
  997. &cbHashSize,
  998. pbHash,
  999. 0);
  1000. if (bResult)
  1001. {
  1002. hCatalog=(*catapi.pCryptCATAdminEnumCatalogFromHash)(
  1003. catapi.hCatAdmin,
  1004. pbHash,
  1005. cbHashSize,
  1006. 0,
  1007. &hPrevCat);
  1008. }
  1009. //
  1010. // Initialize the structures that
  1011. // will be used later on in calls to WinVerifyTrust.
  1012. //
  1013. ZeroMemory(&WinTrustData, sizeof(WINTRUST_DATA));
  1014. WinTrustData.cbStruct = sizeof(WINTRUST_DATA);
  1015. WinTrustData.dwUIChoice = WTD_UI_NONE;
  1016. WinTrustData.fdwRevocationChecks = WTD_REVOKE_NONE;
  1017. WinTrustData.dwUnionChoice = WTD_CHOICE_CATALOG;
  1018. WinTrustData.dwStateAction = WTD_STATEACTION_AUTO_CACHE;
  1019. WinTrustData.pPolicyCallbackData = (LPVOID)&VerInfo;
  1020. ZeroMemory(&VerInfo, sizeof(DRIVER_VER_INFO));
  1021. VerInfo.cbStruct = sizeof(DRIVER_VER_INFO);
  1022. WinTrustData.pCatalog = &WinTrustCatalogInfo;
  1023. ZeroMemory(&WinTrustCatalogInfo, sizeof(WINTRUST_CATALOG_INFO));
  1024. WinTrustCatalogInfo.cbStruct = sizeof(WINTRUST_CATALOG_INFO);
  1025. WinTrustCatalogInfo.pbCalculatedFileHash = pbHash;
  1026. WinTrustCatalogInfo.cbCalculatedFileHash = cbHashSize;
  1027. WinTrustCatalogInfo.pcwszMemberTag = lpFileName;
  1028. while (hCatalog)
  1029. {
  1030. CATALOG_INFO CatInfo;
  1031. ZeroMemory(&CatInfo, sizeof(CATALOG_INFO));
  1032. CatInfo.cbStruct = sizeof(CATALOG_INFO);
  1033. if((*catapi.pCryptCATCatalogInfoFromContext)(hCatalog, &CatInfo, 0))
  1034. {
  1035. HRESULT hRes;
  1036. WinTrustCatalogInfo.pcwszCatalogFilePath = CatInfo.wszCatalogFile;
  1037. // Now verify that the file is an actual member of the catalog.
  1038. hRes = (*catapi.pWinVerifyTrust)
  1039. (NULL, &guidSubSystemDriver, &WinTrustData);
  1040. if (hRes == ERROR_SUCCESS)
  1041. {
  1042. //
  1043. // Our driver is certified! Now see if the cat
  1044. // info contains the WHQL level
  1045. //
  1046. CRYPTCATATTRIBUTE *lpCat = NULL;
  1047. HANDLE hCat;
  1048. dwWHQLLevel=1; // return "certified"
  1049. hCat = (*catapi.pCryptCATOpen)(CatInfo.wszCatalogFile, (DWORD)CRYPTCAT_OPEN_EXISTING, (HCRYPTPROV)NULL, 0, 0);
  1050. lpCat = (*catapi.pCryptCATGetCatAttrInfo) (hCat, L"KV_DISPLAY");
  1051. if( lpCat != NULL )
  1052. {
  1053. WideCharToMultiByte(CP_ACP, 0, (PUSHORT)lpCat->pbValue, -1, szBuffer, 50, NULL, NULL);
  1054. // The value looks like "1:yyyy-mm-dd".
  1055. lpAttr = _strstr( szBuffer, ":");
  1056. lpAttr++;
  1057. lpAttr[4] = '\0';
  1058. dwWHQLLevel = atoi( lpAttr ) * 0x10000;
  1059. lpAttr[7] = '\0';
  1060. dwWHQLLevel |= atoi( &lpAttr[5]) * 0x100;
  1061. dwWHQLLevel |= atoi( &lpAttr[8]);
  1062. }
  1063. (*catapi.pCryptCATClose)(hCat);
  1064. break;
  1065. }
  1066. }
  1067. //
  1068. // iterate through catalogs...
  1069. //
  1070. hPrevCat=hCatalog;
  1071. hCatalog=(*catapi.pCryptCATAdminEnumCatalogFromHash)(
  1072. catapi.hCatAdmin,
  1073. pbHash,
  1074. cbHashSize,
  1075. 0,
  1076. &hPrevCat);
  1077. }
  1078. //
  1079. // we might have to free a catalog context!
  1080. //
  1081. if (hCatalog)
  1082. {
  1083. (*catapi.pCryptCATAdminReleaseCatalogContext)
  1084. (catapi.hCatAdmin, hCatalog, 0);
  1085. }
  1086. //
  1087. // free hash
  1088. //
  1089. LocalFree(pbHash);
  1090. }
  1091. CloseHandle(hFile);
  1092. }
  1093. }
  1094. ReleaseCATAPI(&catapi);
  1095. return dwWHQLLevel;
  1096. }