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.

627 lines
18 KiB

  1. ////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // File: registry.cpp
  4. //
  5. // History: 21-Mar-00 markder Created.
  6. // 13-Dec-00 markder Renamed from appshelp.cpp
  7. //
  8. // Desc: This file contains all code needed to produce matching info registry
  9. // files and setup files (INX) for the Windows 2000 (RTM) shim mechanism.
  10. //
  11. ////////////////////////////////////////////////////////////////////////////////////
  12. #include "stdafx.h"
  13. #include "registry.h"
  14. ////////////////////////////////////////////////////////////////////////////////////
  15. //
  16. // Func: DumpString, DumpDword, DumpBinVersion, InsertString
  17. //
  18. // Desc: Helper functions for CreateMessageBlob.
  19. //
  20. void DumpString( DWORD dwId, PBYTE* ppBlob, LONG* pnTotalBytes, CString& csString )
  21. {
  22. DWORD dwLen;
  23. **(DWORD**)ppBlob = dwId;
  24. *ppBlob += sizeof(DWORD);
  25. dwLen = csString.GetLength();
  26. **(DWORD**)ppBlob = ( dwLen + 1) * sizeof(WCHAR);
  27. *ppBlob += sizeof(DWORD);
  28. CopyMemory(*ppBlob, T2W((LPTSTR) (LPCTSTR) csString), (dwLen + 1) * sizeof(WCHAR));
  29. *ppBlob += (dwLen + 1) * sizeof(WCHAR);
  30. *pnTotalBytes += ((dwLen + 1) * sizeof(WCHAR) + 2 * sizeof(DWORD));
  31. }
  32. void DumpDword( DWORD dwId, PBYTE* ppBlob, LONG* pnTotalBytes, DWORD dwVal )
  33. {
  34. **(DWORD**)ppBlob = dwId;
  35. *ppBlob += sizeof(DWORD);
  36. **(DWORD**)ppBlob = sizeof(DWORD);
  37. *ppBlob += sizeof(DWORD);
  38. **(DWORD**)ppBlob = dwVal;
  39. *ppBlob += sizeof(DWORD);
  40. *pnTotalBytes += 3 * sizeof(DWORD);
  41. }
  42. void DumpBinVersion(DWORD dwId, PBYTE* ppBlob, LONG* pnTotalBytes, ULONGLONG ullVersion)
  43. {
  44. ULONGLONG ullMask = 0;
  45. ULONGLONG ullVer = 0;
  46. WORD wVerPart = 0;
  47. LONG j;
  48. PBYTE pBlob = *ppBlob;
  49. for( j = 0; j < 4; j++ ) {
  50. wVerPart = (WORD) (ullVersion >> (j*16));
  51. if (wVerPart != 0xFFFF) {
  52. ullVer += ((ULONGLONG)wVerPart) << (j*16);
  53. ullMask += ((ULONGLONG) 0xFFFF) << (j*16);
  54. }
  55. }
  56. //
  57. // id
  58. //
  59. *(DWORD*)pBlob = dwId;
  60. pBlob += sizeof(DWORD);
  61. // size
  62. *(DWORD*)pBlob = 2 * sizeof(ULONGLONG);
  63. pBlob += sizeof(DWORD);
  64. // version
  65. CopyMemory(pBlob, &ullVer, sizeof(ULONGLONG));
  66. pBlob += sizeof(ULONGLONG);
  67. // mask
  68. CopyMemory(pBlob, &ullMask, sizeof(ULONGLONG));
  69. pBlob += sizeof(ULONGLONG);
  70. *pnTotalBytes += (2 * sizeof(ULONGLONG) + 2 * sizeof(DWORD));
  71. *ppBlob = pBlob;
  72. }
  73. void InsertString( CString* pcs, DWORD dwIndex, CString csInsertedString )
  74. {
  75. *pcs = pcs->Left( dwIndex ) + csInsertedString + pcs->Right( pcs->GetLength() - dwIndex );
  76. }
  77. BOOL WriteStringToFile(
  78. HANDLE hFile,
  79. CString& csString)
  80. {
  81. CHAR szBuffer[1024];
  82. DWORD dwConvBufReqSize;
  83. DWORD dwConvBufSize = sizeof(szBuffer);
  84. BOOL b; // this will be set if default char is used, we make no use of this
  85. LPSTR szConvBuf = szBuffer;
  86. BOOL bAllocated = FALSE;
  87. BOOL bSuccess;
  88. DWORD dwBytesWritten;
  89. dwConvBufReqSize = WideCharToMultiByte(CP_ACP, 0, csString, -1, NULL, NULL, 0, &b);
  90. if (dwConvBufReqSize > sizeof(szBuffer)) {
  91. szConvBuf = (LPSTR) new CHAR[dwConvBufReqSize];
  92. dwConvBufSize = dwConvBufReqSize;
  93. bAllocated = TRUE;
  94. }
  95. WideCharToMultiByte(CP_ACP, 0, csString, -1, szConvBuf, dwConvBufSize, 0, &b);
  96. bSuccess = WriteFile( hFile, szConvBuf, dwConvBufReqSize - 1, &dwBytesWritten, NULL);
  97. if (bAllocated) {
  98. delete [] szConvBuf;
  99. }
  100. return bSuccess;
  101. }
  102. ////////////////////////////////////////////////////////////////////////////////////
  103. //
  104. // Func: FreeRegistryBlob, CreateRegistryBlob
  105. //
  106. // Desc: Creates a binary blob in the format of Windows 2000's
  107. // Message registry keys.
  108. //
  109. void FreeRegistryBlob( PBYTE pBlob )
  110. {
  111. delete pBlob;
  112. }
  113. BOOL CreateRegistryBlob(
  114. SdbExe* pExe,
  115. PBYTE* ppBlob,
  116. DWORD* pdwSize,
  117. DWORD dwMessageID = 0, // these two are optional
  118. DWORD dwBlobType = 6)
  119. {
  120. USES_CONVERSION;
  121. BOOL bSuccess = FALSE;
  122. PBYTE pBlob = (PBYTE) new BYTE[4096];
  123. PBYTE pStartOfBlob = pBlob;
  124. DWORD dwBufSize = 4096;
  125. DWORD dwReqBufSize = 0;
  126. LONG nTotalBytes = 0;
  127. LONG i, j;
  128. LONG nBytes;
  129. SdbMatchingFile* pMFile;
  130. FILETIME FileTime;
  131. CString* pcsFilename;
  132. ULONGLONG ullMask = 0;
  133. WORD wVerPart = 0;
  134. ULONGLONG ullVer = 0;
  135. *pdwSize = 0;
  136. // Prolog
  137. *((DWORD*)pBlob + 0) = 3 * sizeof(DWORD);
  138. // message id
  139. *((DWORD*)pBlob + 1) = dwMessageID;
  140. // type is not shim anymore
  141. *((DWORD*)pBlob + 2) = dwBlobType; // shim type
  142. pBlob += 3 * sizeof(DWORD);
  143. nTotalBytes += 3 * sizeof(DWORD);
  144. for( i = 0; i < pExe->m_rgMatchingFiles.GetSize(); i++ )
  145. {
  146. pMFile = (SdbMatchingFile *) pExe->m_rgMatchingFiles[i];
  147. if( pMFile->m_csName == _T("*") ) {
  148. pcsFilename = &(pExe->m_csName);
  149. } else {
  150. pcsFilename = &(pMFile->m_csName);
  151. }
  152. DumpString( VTID_REQFILE, &pBlob, &nTotalBytes, *pcsFilename );
  153. if( pMFile->m_dwMask & SDB_MATCHINGINFO_SIZE )
  154. DumpDword( VTID_FILESIZE, &pBlob, &nTotalBytes, pMFile->m_dwSize );
  155. if( pMFile->m_dwMask & SDB_MATCHINGINFO_CHECKSUM )
  156. DumpDword( VTID_CHECKSUM, &pBlob, &nTotalBytes, pMFile->m_dwChecksum );
  157. if( pMFile->m_dwMask & SDB_MATCHINGINFO_COMPANY_NAME )
  158. DumpString( VTID_COMPANYNAME, &pBlob, &nTotalBytes, pMFile->m_csCompanyName );
  159. if( pMFile->m_dwMask & SDB_MATCHINGINFO_PRODUCT_NAME )
  160. DumpString( VTID_PRODUCTNAME, &pBlob, &nTotalBytes, pMFile->m_csProductName );
  161. if( pMFile->m_dwMask & SDB_MATCHINGINFO_PRODUCT_VERSION )
  162. DumpString( VTID_PRODUCTVERSION, &pBlob, &nTotalBytes, pMFile->m_csProductVersion );
  163. if( pMFile->m_dwMask & SDB_MATCHINGINFO_FILE_DESCRIPTION )
  164. DumpString( VTID_FILEDESCRIPTION, &pBlob, &nTotalBytes, pMFile->m_csFileDescription );
  165. if( pMFile->m_dwMask & SDB_MATCHINGINFO_BIN_FILE_VERSION )
  166. DumpBinVersion(VTID_BINFILEVER, &pBlob, &nTotalBytes, pMFile->m_ullBinFileVersion);
  167. if( pMFile->m_dwMask & SDB_MATCHINGINFO_BIN_PRODUCT_VERSION )
  168. DumpBinVersion(VTID_BINPRODUCTVER, &pBlob, &nTotalBytes, pMFile->m_ullBinProductVersion);
  169. if (pMFile->m_dwMask & SDB_MATCHINGINFO_MODULE_TYPE)
  170. DumpDword( VTID_EXETYPE, &pBlob, &nTotalBytes, pMFile->m_dwModuleType );
  171. if (pMFile->m_dwMask & SDB_MATCHINGINFO_VERFILEDATEHI)
  172. DumpDword( VTID_FILEDATEHI, &pBlob, &nTotalBytes, pMFile->m_dwFileDateMS );
  173. if (pMFile->m_dwMask & SDB_MATCHINGINFO_VERFILEDATELO)
  174. DumpDword( VTID_FILEDATELO, &pBlob, &nTotalBytes, pMFile->m_dwFileDateLS );
  175. if (pMFile->m_dwMask & SDB_MATCHINGINFO_VERFILEOS)
  176. DumpDword( VTID_FILEVEROS, &pBlob, &nTotalBytes, pMFile->m_dwFileOS );
  177. if (pMFile->m_dwMask & SDB_MATCHINGINFO_VERFILETYPE)
  178. DumpDword( VTID_FILEVERTYPE, &pBlob, &nTotalBytes, pMFile->m_dwFileType );
  179. if (pMFile->m_dwMask & SDB_MATCHINGINFO_PE_CHECKSUM)
  180. DumpDword( VTID_PECHECKSUM, &pBlob, &nTotalBytes, (DWORD)pMFile->m_ulPECheckSum );
  181. if (pMFile->m_dwMask & SDB_MATCHINGINFO_FILE_VERSION)
  182. DumpString( VTID_FILEVERSION, &pBlob, &nTotalBytes, pMFile->m_csFileVersion );
  183. if (pMFile->m_dwMask & SDB_MATCHINGINFO_ORIGINAL_FILENAME)
  184. DumpString( VTID_ORIGINALFILENAME, &pBlob, &nTotalBytes, pMFile->m_csOriginalFileName );
  185. if (pMFile->m_dwMask & SDB_MATCHINGINFO_INTERNAL_NAME)
  186. DumpString( VTID_INTERNALNAME, &pBlob, &nTotalBytes, pMFile->m_csInternalName );
  187. if (pMFile->m_dwMask & SDB_MATCHINGINFO_LEGAL_COPYRIGHT)
  188. DumpString( VTID_LEGALCOPYRIGHT, &pBlob, &nTotalBytes, pMFile->m_csLegalCopyright );
  189. if (pMFile->m_dwMask & SDB_MATCHINGINFO_16BIT_DESCRIPTION)
  190. DumpString( VTID_16BITDESCRIPTION, &pBlob, &nTotalBytes, pMFile->m_cs16BitDescription );
  191. if (pMFile->m_dwMask & SDB_MATCHINGINFO_UPTO_BIN_PRODUCT_VERSION)
  192. DumpBinVersion(VTID_UPTOBINPRODUCTVER, &pBlob, &nTotalBytes, pMFile->m_ullUpToBinProductVersion);
  193. if (pMFile->m_dwMask & SDB_MATCHINGINFO_LINK_DATE) {
  194. SDBERROR(_T("LINK_DATE not allowed for Win2k registry matching."));
  195. goto eh;
  196. }
  197. if (pMFile->m_dwMask & SDB_MATCHINGINFO_UPTO_LINK_DATE) {
  198. SDBERROR(_T("UPTO_LINK_DATE not allowed for Win2k registry matching."));
  199. goto eh;
  200. }
  201. }
  202. // Terminator
  203. *((DWORD*)pBlob) = 0;
  204. pBlob += sizeof(DWORD);
  205. nTotalBytes += sizeof(DWORD);
  206. bSuccess = TRUE;
  207. eh:
  208. if( bSuccess ) {
  209. *pdwSize = nTotalBytes;
  210. *ppBlob = pStartOfBlob;
  211. } else if( pStartOfBlob ) {
  212. FreeRegistryBlob( pStartOfBlob );
  213. *pdwSize = 0;
  214. *ppBlob = NULL;
  215. }
  216. return bSuccess;
  217. }
  218. BOOL RegistryBlobToString(PBYTE pBlob, DWORD dwBlobSize, CString& csBlob)
  219. {
  220. DWORD i;
  221. CString csTemp;
  222. csBlob = "";
  223. for (i = 0; i < dwBlobSize; i++, ++pBlob) {
  224. csTemp.Format( _T("%02X"), (DWORD)*pBlob );
  225. if (i == dwBlobSize - 1) { // this is the last char
  226. csTemp += _T("\r\n");
  227. }
  228. else {
  229. if ((i+1) % 27 == 0) { // time to do end of the line ?
  230. csTemp += _T(",\\\r\n");
  231. }
  232. else {
  233. csTemp += _T(","); // just add comma
  234. }
  235. }
  236. csBlob += csTemp;
  237. }
  238. return(TRUE);
  239. }
  240. ////////////////////////////////////////////////////////////////////////////////////
  241. //
  242. // Func: CreateMessageRegEntry, WriteMessageRegistryFiles
  243. //
  244. // Desc: These functions create Win2k-style registry entries for the old
  245. // Message mechanism, which exists in SHELL32!ShellExecute.
  246. //
  247. BOOL CreateMessageRegEntry(
  248. SdbExe* pExe,
  249. DWORD dwExeCount,
  250. CString& csReg,
  251. CString& csInx)
  252. {
  253. PBYTE pBlob = NULL;
  254. BOOL bSuccess = FALSE;
  255. DWORD dwBlobSize = 0;
  256. CString csRegEntry, csInxEntry;
  257. CString csApp;
  258. CString csBlob;
  259. CString csTemp;
  260. if (!CreateRegistryBlob(pExe,
  261. &pBlob,
  262. &dwBlobSize,
  263. (DWORD)_ttol(pExe->m_AppHelpRef.m_pAppHelp->m_csName),
  264. pExe->m_AppHelpRef.m_pAppHelp->m_Type)) {
  265. SDBERROR(_T("Error in CreateRegistryBlob()"));
  266. goto eh;
  267. }
  268. csApp = pExe->m_pApp->m_csName;
  269. csApp.Remove(_T(' '));
  270. csTemp.Format(_T("[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility\\%s]\r\n\"%05X %s\"=hex:"),
  271. pExe->m_csName, dwExeCount, csApp.Left(25));
  272. csRegEntry = csTemp;
  273. csTemp.Format(_T("HKLM,\"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility\\%s\",\"%05X %s\",0x00030003,\\\r\n"),
  274. pExe->m_csName, dwExeCount, csApp.Left(25) );
  275. csInxEntry = csTemp;
  276. //
  277. // now grab the blob
  278. //
  279. if (!RegistryBlobToString(pBlob, dwBlobSize, csBlob)) {
  280. SDBERROR(_T("Error in RegistryBlobToString()"));
  281. goto eh;
  282. }
  283. csRegEntry += csBlob;
  284. csInxEntry += csBlob;
  285. csReg = csRegEntry;
  286. csInx = csInxEntry;
  287. bSuccess = TRUE;
  288. eh:
  289. if (NULL != pBlob) {
  290. FreeRegistryBlob( pBlob );
  291. }
  292. return(bSuccess);
  293. }
  294. ////////////////////////////////////////////////////////////////////////////////////
  295. //
  296. // Func: CreateRegistryBlob, WriteRegistryFiles
  297. //
  298. // Desc: These functions create a Win2k-style registry entries for both
  299. // Message as well as a stub entry for shimming that provides no
  300. // additional matching info past EXE name. This allows the 'new'
  301. // Win2k version of the shim engine to 'bootstrap' itself into memory
  302. // via the original mechanism and then perform more detailed matching
  303. // in its own way.
  304. //
  305. BOOL CreateWin2kExeStubRegistryBlob(
  306. SdbExe* pExe,
  307. PBYTE* ppBlob,
  308. DWORD* pdwSize,
  309. DWORD dwMessageID = 0, // these two are optional
  310. DWORD dwBlobType = 6)
  311. {
  312. USES_CONVERSION;
  313. BOOL bSuccess = FALSE;
  314. DWORD dwBufSize = sizeof(DWORD) * 4;
  315. LONG nTotalBytes = 0;
  316. PBYTE pStartOfBlob;
  317. PBYTE pBlob = (PBYTE) new BYTE[dwBufSize];
  318. pStartOfBlob = pBlob;
  319. *pdwSize = 0;
  320. if (NULL != pBlob) {
  321. // Prolog
  322. *((DWORD*)pBlob + 0) = 3 * sizeof(DWORD); // 0x0C 00 00 00
  323. // message id
  324. *((DWORD*)pBlob + 1) = dwMessageID; // 0x00 00 00 00
  325. // type is shim
  326. *((DWORD*)pBlob + 2) = dwBlobType; // 0x06 00 00 00
  327. pBlob += 3 * sizeof(DWORD);
  328. nTotalBytes += 3 * sizeof(DWORD);
  329. // Terminator
  330. *((DWORD*)pBlob) = 0;
  331. pBlob += sizeof(DWORD);
  332. nTotalBytes += sizeof(DWORD);
  333. *pdwSize = (DWORD)nTotalBytes;
  334. *ppBlob = pStartOfBlob;
  335. bSuccess = TRUE;
  336. }
  337. return bSuccess;
  338. }
  339. BOOL WriteRegistryFiles(
  340. SdbDatabase* pDatabase,
  341. CString csRegFile,
  342. CString csInxFile,
  343. BOOL bAddExeStubs)
  344. {
  345. CString csRegEntry, csInxEntry, csTemp, csCmdLineREG, csCmdLineINX,
  346. csTemp1, csApp, csExeName;
  347. SdbExe* pExe;
  348. SdbApp* pApp;
  349. long i, j, l, m;
  350. DWORD k, dwBlobSize, dwBytesWritten, dwExeCount = 0;
  351. PBYTE pBlob;
  352. BOOL b, bSuccess = FALSE;
  353. CMapStringToPtr mapNames;
  354. SdbApp* pAppValue;
  355. HANDLE hRegFile = NULL;
  356. HANDLE hInxFile = NULL;
  357. hRegFile = CreateFile( csRegFile, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  358. hInxFile = CreateFile( csInxFile, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  359. if( hRegFile == INVALID_HANDLE_VALUE ||
  360. hInxFile == INVALID_HANDLE_VALUE ) {
  361. SDBERROR_FORMAT((_T("Error creating registry files:\n%s\n%s\n"), csRegFile, csInxFile));
  362. goto eh;
  363. }
  364. if( ! WriteFile( hRegFile, "REGEDIT4\r\n\r\n", strlen("REGEDIT4\r\n\r\n"), &dwBytesWritten, NULL ) ) {
  365. SDBERROR(_T("Error writing header to .reg file.\n"));
  366. goto eh;
  367. }
  368. //
  369. // loop through all the apps, make apphelp entries
  370. //
  371. for (i = 0; i < pDatabase->m_rgExes.GetSize(); i++) {
  372. pExe = (SdbExe *) pDatabase->m_rgExes[i];
  373. if (pExe->m_AppHelpRef.m_pAppHelp == NULL) { // not an apphelp entry
  374. continue;
  375. }
  376. if (!(pExe->m_dwFilter & g_dwCurrentWriteFilter)) {
  377. continue;
  378. }
  379. b = CreateMessageRegEntry(pExe, dwExeCount, csRegEntry, csInxEntry);
  380. if (!b) {
  381. SDBERROR(_T("Error creating reg entry.\n"));
  382. goto eh;
  383. }
  384. if (!WriteStringToFile(hRegFile, csRegEntry)) {
  385. SDBERROR(_T("Error writing reg entry.\n"));
  386. goto eh;
  387. }
  388. if (!WriteStringToFile(hInxFile, csInxEntry)) {
  389. SDBERROR(_T("Error writing inx entry.\n"));
  390. goto eh;
  391. }
  392. ++dwExeCount;
  393. }
  394. //
  395. // Add the Win2k EXE stubs to bootstrap the new shim mechanism
  396. //
  397. if (bAddExeStubs) {
  398. for( i = 0; i < pDatabase->m_rgApps.GetSize(); i++ )
  399. {
  400. pApp = (SdbApp *) pDatabase->m_rgApps[i];
  401. csApp = pApp->m_csName;
  402. csApp.Remove(_T(' '));
  403. for( j = 0; j < pApp->m_rgExes.GetSize(); j++ )
  404. {
  405. pExe = (SdbExe *) pApp->m_rgExes[j];
  406. //
  407. // check whether this entry is apphelp-only
  408. // if so, skip to the next exe
  409. //
  410. if (pExe->m_AppHelpRef.m_pAppHelp) {
  411. if (pExe->m_AppHelpRef.m_bApphelpOnly) {
  412. continue;
  413. }
  414. }
  415. if (pExe->m_bWildcardInName) {
  416. continue;
  417. }
  418. if (!(pExe->m_dwFilter & g_dwCurrentWriteFilter)) {
  419. continue;
  420. }
  421. csExeName = pExe->m_csName;
  422. csExeName.MakeUpper();
  423. // now we have to create an application entry -- if we have not hit this
  424. // exe name before
  425. if (mapNames.Lookup(csExeName, (VOID*&)pAppValue)) {
  426. continue;
  427. }
  428. csRegEntry.Empty();
  429. csInxEntry.Empty();
  430. if (!CreateWin2kExeStubRegistryBlob(pExe, &pBlob, &dwBlobSize)) {
  431. SDBERROR(_T("Error creating EXE stub.\n"));
  432. goto eh;
  433. }
  434. //
  435. // To reduce the amount of space that we take, we substitute
  436. // app name for something short
  437. //
  438. csApp = _T("x");
  439. csTemp.Format( _T("[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility\\%s]\r\n\"%s\"=hex:"),
  440. pExe->m_csName, csApp.Left(25) );
  441. csRegEntry += csTemp;
  442. csTemp.Format( _T("HKLM,\"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility\\%s\",\"%s\",0x00030003,\\\r\n"),
  443. pExe->m_csName, csApp.Left(25) );
  444. csInxEntry += csTemp;
  445. RegistryBlobToString(pBlob, dwBlobSize, csTemp);
  446. csRegEntry += csTemp;
  447. csInxEntry += csTemp;
  448. csCmdLineREG.Empty();
  449. csCmdLineINX.Empty();
  450. csTemp.Format( _T("\"DllPatch-%s\"=\"%s\"\r\n"),
  451. csApp.Left(25), csCmdLineREG );
  452. csRegEntry += csTemp;
  453. csTemp.Format( _T("HKLM,\"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility\\%s\",\"DllPatch-%s\",0x00000002,\"%s\"\r\n"),
  454. pExe->m_csName, csApp.Left(25), csCmdLineINX );
  455. csInxEntry += csTemp;
  456. csRegEntry += _T("\r\n");
  457. csInxEntry += _T("\r\n");
  458. if (!WriteStringToFile(hRegFile, csRegEntry)) {
  459. SDBERROR(_T("Error writing reg line.\n"));
  460. goto eh;
  461. }
  462. if (!WriteStringToFile(hInxFile, csInxEntry)) {
  463. SDBERROR(_T("Error writing inx line.\n"));
  464. goto eh;
  465. }
  466. ++dwExeCount;
  467. // now update the map
  468. mapNames.SetAt(csExeName, (PVOID)pExe);
  469. FreeRegistryBlob( pBlob );
  470. }
  471. }
  472. }
  473. bSuccess = TRUE;
  474. eh:
  475. if( hRegFile )
  476. CloseHandle( hRegFile );
  477. if( hInxFile )
  478. CloseHandle( hInxFile );
  479. return bSuccess;
  480. }