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.

1359 lines
34 KiB

  1. /***************************************************************************
  2. * This file contains functions that are specific for the shim mechanism
  3. * implemented in Whistler
  4. *
  5. * Author: clupu (Feb 16, 2000)
  6. *
  7. * History:
  8. *
  9. * rparsons - 11/27/2000 - Fixed a bug that caused SDB name to be truncated.
  10. * Example: Yoda's Challenege became Yoda's
  11. *
  12. \**************************************************************************/
  13. #include "windows.h"
  14. #include "commctrl.h"
  15. #include "shlwapi.h"
  16. #include <tchar.h>
  17. #include "qfixapp.h"
  18. #include "dbSupport.h"
  19. #include "resource.h"
  20. #define _WANT_TAG_INFO
  21. extern "C" {
  22. #include "shimdb.h"
  23. BOOL
  24. ShimdbcExecute(
  25. LPCWSTR lpszCmdLine
  26. );
  27. }
  28. extern HINSTANCE g_hInstance;
  29. extern HWND g_hDlg;
  30. extern TCHAR g_szSDBToDelete[MAX_PATH];
  31. extern TCHAR g_szAppTitle[64];
  32. #define MAX_CMD_LINE 1024
  33. #define MAX_SHIM_DESCRIPTION 1024
  34. #define MAX_SHIM_NAME 128
  35. #define MAX_BUFFER_SIZE 1024
  36. #define SHIM_FILE_LOG_NAME _T("QFixApp.log")
  37. // Temp buffer to read UNICODE strings from the database.
  38. TCHAR g_szData[MAX_BUFFER_SIZE];
  39. #define MAX_XML_SIZE 1024 * 16
  40. TCHAR g_szXML[MAX_XML_SIZE];
  41. TCHAR g_szQFixAppLayerName[] = _T("!#RunLayer");
  42. INT_PTR CALLBACK
  43. ShowXMLDlgProc(
  44. HWND hdlg,
  45. UINT uMsg,
  46. WPARAM wParam,
  47. LPARAM lParam
  48. )
  49. /*++
  50. ShowXMLDlgProc
  51. Description: Show the dialog with the XML for the current selections.
  52. --*/
  53. {
  54. int wCode = LOWORD(wParam);
  55. int wNotifyCode = HIWORD(wParam);
  56. switch (uMsg) {
  57. case WM_INITDIALOG:
  58. CenterWindow(hdlg);
  59. SetDlgItemText(hdlg, IDC_XML, (LPTSTR)lParam);
  60. break;
  61. case WM_COMMAND:
  62. switch (wCode) {
  63. case IDCANCEL:
  64. EndDialog(hdlg, TRUE);
  65. break;
  66. case IDC_SAVE_XML:
  67. DoFileSave(hdlg);
  68. EndDialog(hdlg, TRUE);
  69. break;
  70. default:
  71. return FALSE;
  72. }
  73. break;
  74. default:
  75. return FALSE;
  76. }
  77. return TRUE;
  78. }
  79. LPTSTR
  80. ReadAndAllocateString(
  81. PDB pdb,
  82. TAGID tiString
  83. )
  84. {
  85. TCHAR* psz;
  86. g_szData[0] = 0;
  87. SdbReadStringTag(pdb, tiString, g_szData, MAX_BUFFER_SIZE);
  88. if (g_szData[0] == 0) {
  89. LogMsg(_T("[ReadAndAllocateString] Couldn't read the string.\n"));
  90. return NULL;
  91. }
  92. psz = (LPTSTR)HeapAlloc(GetProcessHeap(),
  93. HEAP_ZERO_MEMORY,
  94. sizeof(TCHAR) * (lstrlen(g_szData) + 1));
  95. if (NULL == psz) {
  96. return NULL;
  97. } else {
  98. lstrcpy(psz, g_szData);
  99. }
  100. return psz;
  101. }
  102. PFIX
  103. ParseTagFlag(
  104. PDB pdb,
  105. TAGID tiFlag,
  106. BOOL bAllFlags
  107. )
  108. /*++
  109. ParseTagFlag
  110. Description: Parse a Flag tag for the NAME, DESCRIPTION and MASK
  111. --*/
  112. {
  113. TAGID tiFlagInfo;
  114. TAG tWhichInfo;
  115. PFIX pFix = NULL;
  116. TCHAR* pszName = NULL;
  117. TCHAR* pszDesc = NULL;
  118. ULONGLONG ull;
  119. BOOL bGeneral = (bAllFlags ? TRUE : FALSE);
  120. tiFlagInfo = SdbGetFirstChild(pdb, tiFlag);
  121. while (tiFlagInfo != 0) {
  122. tWhichInfo = SdbGetTagFromTagID(pdb, tiFlagInfo);
  123. switch (tWhichInfo) {
  124. case TAG_GENERAL:
  125. bGeneral = TRUE;
  126. break;
  127. case TAG_NAME:
  128. pszName = ReadAndAllocateString(pdb, tiFlagInfo);
  129. break;
  130. case TAG_DESCRIPTION:
  131. pszDesc = ReadAndAllocateString(pdb, tiFlagInfo);
  132. break;
  133. case TAG_FLAG_MASK_KERNEL:
  134. case TAG_FLAG_MASK_USER:
  135. //
  136. // Read the mask even if we're not using it anywhere yet...
  137. //
  138. ull = SdbReadQWORDTag(pdb, tiFlagInfo, 0);
  139. break;
  140. default:
  141. break;
  142. }
  143. tiFlagInfo = SdbGetNextChild(pdb, tiFlag, tiFlagInfo);
  144. }
  145. if (!bGeneral) {
  146. goto cleanup;
  147. }
  148. //
  149. // Done. Add the fix to the list.
  150. //
  151. pFix = (PFIX)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FIX));
  152. if (pFix == NULL || pszName == NULL) {
  153. cleanup:
  154. if (pFix != NULL) {
  155. HeapFree(GetProcessHeap(), 0, pFix);
  156. }
  157. if (pszName != NULL) {
  158. HeapFree(GetProcessHeap(), 0, pszName);
  159. }
  160. if (pszDesc != NULL) {
  161. HeapFree(GetProcessHeap(), 0, pszDesc);
  162. }
  163. return NULL;
  164. }
  165. pFix->pszName = pszName;
  166. pFix->bLayer = FALSE;
  167. pFix->bFlag = TRUE;
  168. pFix->ullFlagMask = ull;
  169. if (pszDesc != NULL) {
  170. pFix->pszDesc = pszDesc;
  171. } else {
  172. TCHAR* pszNone;
  173. pszNone = (TCHAR*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH);
  174. if (NULL == pszNone) {
  175. return NULL;
  176. }
  177. *pszNone = 0;
  178. LoadString(g_hInstance, IDS_NO_DESCR_AVAIL, pszNone, MAX_PATH);
  179. pFix->pszDesc = pszNone;
  180. }
  181. return pFix;
  182. }
  183. PFIX
  184. ParseTagShim(
  185. PDB pdb,
  186. TAGID tiShim,
  187. BOOL bAllShims
  188. )
  189. /*++
  190. ParseTagShim
  191. Description: Parse a Shim tag for the NAME, SHORTNAME, DESCRIPTION ...
  192. --*/
  193. {
  194. TAGID tiShimInfo;
  195. TAG tWhichInfo;
  196. PFIX pFix = NULL;
  197. TCHAR* pszName = NULL;
  198. TCHAR* pszDesc = NULL;
  199. BOOL bGeneral = (bAllShims ? TRUE : FALSE);
  200. tiShimInfo = SdbGetFirstChild(pdb, tiShim);
  201. while (tiShimInfo != 0) {
  202. tWhichInfo = SdbGetTagFromTagID(pdb, tiShimInfo);
  203. switch (tWhichInfo) {
  204. case TAG_GENERAL:
  205. bGeneral = TRUE;
  206. break;
  207. case TAG_NAME:
  208. pszName = ReadAndAllocateString(pdb, tiShimInfo);
  209. break;
  210. case TAG_DESCRIPTION:
  211. pszDesc = ReadAndAllocateString(pdb, tiShimInfo);
  212. break;
  213. default:
  214. break;
  215. }
  216. tiShimInfo = SdbGetNextChild(pdb, tiShim, tiShimInfo);
  217. }
  218. if (!bGeneral) {
  219. goto cleanup;
  220. }
  221. //
  222. // Done. Add the fix to the list.
  223. //
  224. pFix = (PFIX)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FIX));
  225. if (pFix == NULL || pszName == NULL) {
  226. cleanup:
  227. if (pFix != NULL) {
  228. HeapFree(GetProcessHeap(), 0, pFix);
  229. }
  230. if (pszName != NULL) {
  231. HeapFree(GetProcessHeap(), 0, pszName);
  232. }
  233. if (pszDesc != NULL) {
  234. HeapFree(GetProcessHeap(), 0, pszDesc);
  235. }
  236. return NULL;
  237. }
  238. pFix->pszName = pszName;
  239. pFix->bLayer = FALSE;
  240. pFix->bFlag = FALSE;
  241. //
  242. // If we didn't find a description, load it from the resource table.
  243. //
  244. if (pszDesc != NULL) {
  245. pFix->pszDesc = pszDesc;
  246. } else {
  247. TCHAR* pszNone;
  248. pszNone = (TCHAR*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH);
  249. if (NULL == pszNone) {
  250. return NULL;
  251. }
  252. *pszNone = 0;
  253. LoadString(g_hInstance, IDS_NO_DESCR_AVAIL, pszNone, MAX_PATH);
  254. pFix->pszDesc = pszNone;
  255. }
  256. return pFix;
  257. }
  258. PFIX
  259. ParseTagLayer(
  260. PDB pdb,
  261. TAGID tiLayer,
  262. PFIX pFixHead
  263. )
  264. /*++
  265. ParseTagLayer
  266. Description: Parse a LAYER tag for the NAME and the SHIMs that it contains.
  267. --*/
  268. {
  269. PFIX pFix = NULL;
  270. TAGID tiName;
  271. TAGID tiShim;
  272. int nShimCount, nInd;
  273. TCHAR* pszName = NULL;
  274. PFIX* parrShim = NULL;
  275. TCHAR** parrCmdLine = NULL;
  276. tiName = SdbFindFirstTag(pdb, tiLayer, TAG_NAME);
  277. if (tiName == TAGID_NULL) {
  278. LogMsg(_T("[ParseTagLayer] Failed to get the name of the layer.\n"));
  279. return NULL;
  280. }
  281. pszName = ReadAndAllocateString(pdb, tiName);
  282. //
  283. // Now loop through all the SHIMs that this LAYER consists of and
  284. // allocate an array to keep all the pointers to the SHIMs' pFix
  285. // structures. We do this in 2 passes. First we calculate how many
  286. // SHIMs are in the layer, then we lookup their appropriate pFix-es.
  287. //
  288. tiShim = SdbFindFirstTag(pdb, tiLayer, TAG_SHIM_REF);
  289. nShimCount = 0;
  290. while (tiShim != TAGID_NULL) {
  291. nShimCount++;
  292. tiShim = SdbFindNextTag(pdb, tiLayer, tiShim);
  293. }
  294. parrShim = (PFIX*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PFIX) * (nShimCount + 1));
  295. parrCmdLine = (TCHAR**)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TCHAR*) * (nShimCount + 1));
  296. //
  297. // Done. Add the fix to the list.
  298. //
  299. pFix = (PFIX)HeapAlloc(GetProcessHeap(), 0, sizeof(FIX));
  300. if (pFix == NULL || parrCmdLine == NULL || pszName == NULL || parrShim == NULL) {
  301. cleanup:
  302. if (pFix != NULL) {
  303. HeapFree(GetProcessHeap(), 0, pFix);
  304. }
  305. if (parrCmdLine != NULL) {
  306. HeapFree(GetProcessHeap(), 0, parrCmdLine);
  307. }
  308. if (parrShim != NULL) {
  309. HeapFree(GetProcessHeap(), 0, parrShim);
  310. }
  311. if (pszName != NULL) {
  312. HeapFree(GetProcessHeap(), 0, pszName);
  313. }
  314. LogMsg(_T("[ParseTagLayer] Memory allocation error.\n"));
  315. return NULL;
  316. }
  317. //
  318. // Now fill out the array of PFIX pointers and cmd lines.
  319. //
  320. tiShim = SdbFindFirstTag(pdb, tiLayer, TAG_SHIM_REF);
  321. nInd = 0;
  322. while (tiShim != TAGID_NULL) {
  323. TCHAR szShimName[MAX_SHIM_NAME] = _T("");
  324. PFIX pFixWalk;
  325. tiName = SdbFindFirstTag(pdb, tiShim, TAG_NAME);
  326. if (tiName == TAGID_NULL) {
  327. LogMsg(_T("[ParseTagLayer] Failed to get the name of the Shim.\n"));
  328. goto cleanup;
  329. }
  330. SdbReadStringTag(pdb, tiName, szShimName, MAX_SHIM_NAME);
  331. if (szShimName[0] == 0) {
  332. LogMsg(_T("[ParseTagLayer] Couldn't read the name of the Shim.\n"));
  333. goto cleanup;
  334. }
  335. pFixWalk = pFixHead;
  336. while (pFixWalk != NULL) {
  337. if (!pFixWalk->bLayer) {
  338. if (lstrcmpi(pFixWalk->pszName, szShimName) == 0) {
  339. parrShim[nInd] = pFixWalk;
  340. //
  341. // Now get the command line for this Shim in the layer.
  342. //
  343. tiName = SdbFindFirstTag(pdb, tiShim, TAG_COMMAND_LINE);
  344. if (tiName != TAGID_NULL) {
  345. parrCmdLine[nInd] = ReadAndAllocateString(pdb, tiName);
  346. }
  347. nInd++;
  348. break;
  349. }
  350. }
  351. pFixWalk = pFixWalk->pNext;
  352. }
  353. tiShim = SdbFindNextTag(pdb, tiLayer, tiShim);
  354. }
  355. pFix->pszName = pszName;
  356. pFix->bLayer = TRUE;
  357. pFix->bFlag = FALSE;
  358. pFix->parrShim = parrShim;
  359. pFix->parrCmdLine = parrCmdLine;
  360. return pFix;
  361. }
  362. BOOL
  363. IsSDBFromSP2(
  364. void
  365. )
  366. /*++
  367. IsSDBFromSP2
  368. Description: Determine if the SDB is from Service Pack 2.
  369. --*/
  370. {
  371. BOOL fResult = FALSE;
  372. PDB pdb;
  373. TAGID tiDatabase;
  374. TAGID tiLibrary;
  375. TAGID tiChild;
  376. PFIX pFix;
  377. TCHAR szSDBPath[MAX_PATH];
  378. if (!GetSystemWindowsDirectory(szSDBPath, MAX_PATH)) {
  379. return FALSE;
  380. }
  381. _tcscat(szSDBPath, _T("\\apppatch\\sysmain.sdb"));
  382. //
  383. // Open the shim database.
  384. //
  385. pdb = SdbOpenDatabase(szSDBPath, DOS_PATH);
  386. if (!pdb) {
  387. LogMsg(_T("[IsSDBFromSP2] Cannot open shim DB '%s'\n"), szSDBPath);
  388. return FALSE;
  389. }
  390. //
  391. // Now browse the shim DB and look only for tags Shim within
  392. // the LIBRARY list tag.
  393. //
  394. tiDatabase = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE);
  395. if (tiDatabase == TAGID_NULL) {
  396. LogMsg(_T("[IsSDBFromSP2] Cannot find TAG_DATABASE under the root tag\n"));
  397. goto Cleanup;
  398. }
  399. //
  400. // Get TAG_LIBRARY.
  401. //
  402. tiLibrary = SdbFindFirstTag(pdb, tiDatabase, TAG_LIBRARY);
  403. if (tiLibrary == TAGID_NULL) {
  404. LogMsg(_T("[IsSDBFromSP2] Cannot find TAG_LIBRARY under the TAG_DATABASE tag\n"));
  405. goto Cleanup;
  406. }
  407. //
  408. // Loop get the first shim in the library.
  409. //
  410. tiChild = SdbFindFirstTag(pdb, tiLibrary, TAG_SHIM);
  411. if (tiChild == NULL) {
  412. goto Cleanup;
  413. }
  414. //
  415. // Get information about the first shim listed.
  416. //
  417. pFix = ParseTagShim(pdb, tiChild, TRUE);
  418. if (NULL == pFix) {
  419. goto Cleanup;
  420. }
  421. //
  422. // If the first shim listed is 2GbGetDiskFreeSpace, this is SP2.
  423. //
  424. if (!(_tcsicmp(pFix->pszName, _T("2GbGetDiskFreeSpace.dll")))) {
  425. fResult = TRUE;
  426. }
  427. Cleanup:
  428. SdbCloseDatabase(pdb);
  429. return (fResult);
  430. }
  431. PFIX
  432. ReadFixesFromSdb(
  433. LPTSTR pszSdb,
  434. BOOL bAllFixes
  435. )
  436. /*++
  437. ReadFixesFromSdb
  438. Description: Query the database and enumerate all available shims fixes.
  439. --*/
  440. {
  441. int nLen = 0;
  442. TCHAR* pszShimDB = NULL;
  443. PDB pdb;
  444. TAGID tiDatabase;
  445. TAGID tiLibrary;
  446. TAGID tiChild;
  447. PFIX pFixHead = NULL;
  448. PFIX pFix;
  449. nLen = lstrlen(pszSdb);
  450. if (0 == nLen) {
  451. LogMsg(_T("[ReadFixesFromSdb] Invalid SDB path passed through pszSdb\n"));
  452. return NULL;
  453. }
  454. pszShimDB = (TCHAR*)HeapAlloc(GetProcessHeap(),
  455. HEAP_ZERO_MEMORY,
  456. (nLen + MAX_PATH)*sizeof(TCHAR));
  457. if (pszShimDB == NULL) {
  458. LogMsg(_T("[ReadFixesFromSdb] Failed to allocate memory\n"));
  459. return NULL;
  460. }
  461. GetSystemWindowsDirectory(pszShimDB, MAX_PATH);
  462. lstrcat(pszShimDB, _T("\\AppPatch\\"));
  463. lstrcat(pszShimDB, pszSdb);
  464. //
  465. // Open the shim database.
  466. //
  467. pdb = SdbOpenDatabase(pszShimDB, DOS_PATH);
  468. if (!pdb) {
  469. LogMsg(_T("[ReadFixesFromSdb] Cannot open shim DB '%s'\n"), pszShimDB);
  470. return NULL;
  471. }
  472. //
  473. // Now browse the shim DB and look only for tags Shim within
  474. // the LIBRARY list tag.
  475. //
  476. tiDatabase = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE);
  477. if (tiDatabase == TAGID_NULL) {
  478. LogMsg(_T("[ReadFixesFromSdb] Cannot find TAG_DATABASE under the root tag\n"));
  479. goto Cleanup;
  480. }
  481. //
  482. // Get TAG_LIBRARY.
  483. //
  484. tiLibrary = SdbFindFirstTag(pdb, tiDatabase, TAG_LIBRARY);
  485. if (tiLibrary == TAGID_NULL) {
  486. LogMsg(_T("[ReadFixesFromSdb] Cannot find TAG_LIBRARY under the TAG_DATABASE tag\n"));
  487. goto Cleanup;
  488. }
  489. //
  490. // Loop through all TAG_SHIM tags within TAG_LIBRARY.
  491. //
  492. tiChild = SdbFindFirstTag(pdb, tiLibrary, TAG_SHIM);
  493. while (tiChild != TAGID_NULL) {
  494. pFix = ParseTagShim(pdb, tiChild, bAllFixes);
  495. if (pFix != NULL) {
  496. pFix->pNext = pFixHead;
  497. pFixHead = pFix;
  498. }
  499. tiChild = SdbFindNextTag(pdb, tiLibrary, tiChild);
  500. }
  501. //
  502. // Loop through all TAG_FLAG tags within TAG_LIBRARY.
  503. //
  504. tiChild = SdbFindFirstTag(pdb, tiLibrary, TAG_FLAG);
  505. while (tiChild != TAGID_NULL) {
  506. pFix = ParseTagFlag(pdb, tiChild, bAllFixes);
  507. if (pFix != NULL) {
  508. pFix->pNext = pFixHead;
  509. pFixHead = pFix;
  510. }
  511. tiChild = SdbFindNextTag(pdb, tiLibrary, tiChild);
  512. }
  513. //
  514. // Loop through all TAG_LAYER tags within TAG_DATABASE.
  515. //
  516. tiChild = SdbFindFirstTag(pdb, tiDatabase, TAG_LAYER);
  517. while (tiChild != TAGID_NULL) {
  518. pFix = ParseTagLayer(pdb, tiChild, pFixHead);
  519. if (pFix != NULL) {
  520. pFix->pNext = pFixHead;
  521. pFixHead = pFix;
  522. }
  523. tiChild = SdbFindNextTag(pdb, tiDatabase, tiChild);
  524. }
  525. Cleanup:
  526. SdbCloseDatabase(pdb);
  527. HeapFree(GetProcessHeap(), 0, pszShimDB);
  528. return pFixHead;
  529. }
  530. #define ADD_AND_CHECK(cbSizeX, cbCrtSizeX, pszDst) \
  531. { \
  532. TCHAR* pszSrc = szBuffer; \
  533. \
  534. while (*pszSrc != 0) { \
  535. \
  536. if (cbSizeX - cbCrtSizeX <= 5) { \
  537. LogMsg(_T("[ADD_AND_CHECK] Out of space.\n")); \
  538. return FALSE; \
  539. } \
  540. \
  541. if (*pszSrc == _T('&')) { \
  542. lstrcpy(pszDst, _T("&amp;")); \
  543. pszDst += 5; \
  544. cbCrtSizeX += 5; \
  545. } else { \
  546. *pszDst++ = *pszSrc; \
  547. cbCrtSizeX++; \
  548. } \
  549. pszSrc++; \
  550. } \
  551. *pszDst = 0; \
  552. cbCrtSizeX++; \
  553. }
  554. BOOL
  555. CollectShims(
  556. HWND hListShims,
  557. LPTSTR pszXML,
  558. LPCTSTR pszLayerName,
  559. BOOL fAddW2K,
  560. int cbSize
  561. )
  562. /*++
  563. CollectShims
  564. Description: Collects all the shims from the list view
  565. and generates the XML in pszXML
  566. --*/
  567. {
  568. int cShims = 0, nShimsApplied = 0, nIndex;
  569. int cbCrtSize = 0;
  570. BOOL fReturn = FALSE;
  571. LVITEM lvi;
  572. TCHAR szBuffer[1024];
  573. //
  574. // Build the header, then walk each of the shims and
  575. // determine if they're selected.
  576. //
  577. wsprintf(szBuffer, _T(" <LIBRARY>\r\n <LAYER NAME=\"%s\">\r\n"), pszLayerName + 2);
  578. ADD_AND_CHECK(cbSize, cbCrtSize, pszXML);
  579. cShims = ListView_GetItemCount(hListShims);
  580. for (nIndex = 0; nIndex < cShims; nIndex++) {
  581. fReturn = ListView_GetCheckState(hListShims, nIndex);
  582. if (fReturn) {
  583. //
  584. // This shim is selected - add it to the XML.
  585. //
  586. lvi.mask = LVIF_PARAM;
  587. lvi.iItem = nIndex;
  588. lvi.iSubItem = 0;
  589. ListView_GetItem(hListShims, &lvi);
  590. PFIX pFix = (PFIX)lvi.lParam;
  591. PMODULE pModule = pFix->pModule;
  592. if (pFix->bFlag) {
  593. wsprintf(szBuffer, _T(" <FLAG NAME=\"%s\"/>\r\n"),
  594. pFix->pszName);
  595. } else {
  596. //
  597. // Check for module include/exclude so we know how to open/close the XML.
  598. //
  599. if (NULL != pModule) {
  600. if (NULL != pFix->pszCmdLine) {
  601. wsprintf(szBuffer, _T(" <SHIM NAME=\"%s\" COMMAND_LINE=\"%s\">\r\n"),
  602. pFix->pszName,
  603. pFix->pszCmdLine);
  604. } else {
  605. wsprintf(szBuffer, _T(" <SHIM NAME=\"%s\">\r\n"),
  606. pFix->pszName);
  607. }
  608. ADD_AND_CHECK(cbSize, cbCrtSize, pszXML);
  609. //
  610. // Add the modules to the XML.
  611. //
  612. while (NULL != pModule) {
  613. wsprintf(szBuffer, _T(" <%s MODULE=\"%s\"/>\r\n"),
  614. pModule->fInclude ? _T("INCLUDE") : _T("EXCLUDE"),
  615. pModule->pszName);
  616. pModule = pModule->pNext;
  617. ADD_AND_CHECK(cbSize, cbCrtSize, pszXML);
  618. }
  619. //
  620. // Close the SHIM tag.
  621. //
  622. wsprintf(szBuffer, _T(" </SHIM>\r\n"),
  623. pFix->pszName);
  624. } else {
  625. //
  626. // No include/exclude was provided - just build the shim tag normally.
  627. //
  628. if (NULL != pFix->pszCmdLine) {
  629. wsprintf(szBuffer, _T(" <SHIM NAME=\"%s\" COMMAND_LINE=\"%s\"/>\r\n"),
  630. pFix->pszName,
  631. pFix->pszCmdLine);
  632. } else {
  633. wsprintf(szBuffer, _T(" <SHIM NAME=\"%s\"/>\r\n"),
  634. pFix->pszName);
  635. }
  636. }
  637. }
  638. ADD_AND_CHECK(cbSize, cbCrtSize, pszXML);
  639. nShimsApplied++;
  640. }
  641. }
  642. //
  643. // If this is Windows 2000, add Win2kPropagateLayer.
  644. //
  645. if (fAddW2K) {
  646. lstrcpy(szBuffer, _T(" <SHIM NAME=\"Win2kPropagateLayer\"/>\r\n"));
  647. ADD_AND_CHECK(cbSize, cbCrtSize, pszXML);
  648. }
  649. LogMsg(_T("[CollectShims] %d shim(s) selected\n"), nShimsApplied);
  650. //
  651. // Close the open tags.
  652. //
  653. lstrcpy(szBuffer, _T(" </LAYER>\r\n </LIBRARY>\r\n"));
  654. ADD_AND_CHECK(cbSize, cbCrtSize, pszXML);
  655. return TRUE;
  656. }
  657. BOOL
  658. CollectFileAttributes(
  659. HWND hTreeFiles,
  660. LPTSTR pszXML,
  661. int cbSize,
  662. LPCTSTR pszShortName,
  663. DWORD binaryType
  664. )
  665. /*++
  666. CollectFileAttributes
  667. Description: Collects the attributes of all the files in the tree
  668. and generates the XML in pszXML.
  669. --*/
  670. {
  671. HTREEITEM hBinItem;
  672. HTREEITEM hItem;
  673. PATTRINFO pAttrInfo;
  674. UINT State;
  675. TVITEM item;
  676. int cbCrtSize = 0;
  677. TCHAR szItem[MAX_PATH];
  678. TCHAR szBuffer[1024];
  679. wsprintf(szBuffer,
  680. _T(" <APP NAME=\"%s\" VENDOR=\"Unknown\">\r\n")
  681. _T(" <%s NAME=\"%s\""),
  682. pszShortName,
  683. (binaryType == SCS_32BIT_BINARY ? _T("EXE") : _T("EXE - ERROR: 16 BIT BINARY")),
  684. pszShortName);
  685. ADD_AND_CHECK(cbSize, cbCrtSize, pszXML);
  686. //
  687. // First get the main EXE.
  688. //
  689. hBinItem = TreeView_GetChild(hTreeFiles, TVI_ROOT);
  690. item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_TEXT;
  691. item.hItem = hBinItem;
  692. item.pszText = szItem;
  693. item.cchTextMax = MAX_PATH;
  694. TreeView_GetItem(hTreeFiles, &item);
  695. pAttrInfo = (PATTRINFO)(item.lParam);
  696. hItem = TreeView_GetChild(hTreeFiles, hBinItem);
  697. while (hItem != NULL) {
  698. item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_TEXT;
  699. item.hItem = hItem;
  700. TreeView_GetItem(hTreeFiles, &item);
  701. State = item.state & TVIS_STATEIMAGEMASK;
  702. if (State) {
  703. if (((State >> 12) & 0x03) == 2) {
  704. wsprintf(szBuffer, _T(" %s"), (LPSTR)item.pszText);
  705. ADD_AND_CHECK(cbSize, cbCrtSize, pszXML);
  706. }
  707. }
  708. hItem = TreeView_GetNextSibling(hTreeFiles, hItem);
  709. }
  710. lstrcpy(szBuffer, _T(">\r\n"));
  711. ADD_AND_CHECK(cbSize, cbCrtSize, pszXML);
  712. //
  713. // Done with the main binary. Now enumerate the matching files.
  714. //
  715. hBinItem = TreeView_GetNextSibling(hTreeFiles, hBinItem);
  716. while (hBinItem != NULL) {
  717. item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_TEXT;
  718. item.hItem = hBinItem;
  719. item.pszText = szItem;
  720. item.cchTextMax = MAX_PATH;
  721. TreeView_GetItem(hTreeFiles, &item);
  722. pAttrInfo = (PATTRINFO)(item.lParam);
  723. wsprintf(szBuffer, _T(" <MATCHING_FILE NAME=\"%s\""), szItem);
  724. ADD_AND_CHECK(cbSize, cbCrtSize, pszXML);
  725. hItem = TreeView_GetChild(hTreeFiles, hBinItem);
  726. while (hItem != NULL) {
  727. item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE | TVIF_TEXT;
  728. item.hItem = hItem;
  729. TreeView_GetItem(hTreeFiles, &item);
  730. State = item.state & TVIS_STATEIMAGEMASK;
  731. if (State) {
  732. if (((State >> 12) & 0x03) == 2) {
  733. wsprintf(szBuffer, _T(" %s"), (LPSTR)item.pszText);
  734. ADD_AND_CHECK(cbSize, cbCrtSize, pszXML);
  735. }
  736. }
  737. hItem = TreeView_GetNextSibling(hTreeFiles, hItem);
  738. }
  739. lstrcpy(szBuffer, _T("/>\r\n"));
  740. ADD_AND_CHECK(cbSize, cbCrtSize, pszXML);
  741. hBinItem = TreeView_GetNextSibling(hTreeFiles, hBinItem);
  742. }
  743. return TRUE;
  744. }
  745. BOOL
  746. CreateSDBFile(
  747. LPCTSTR pszShortName,
  748. LPTSTR pszSDBName
  749. )
  750. /*++
  751. CreateSDBFile
  752. Description: Creates the XML file on the user's hard drive and
  753. generates the SDB using shimdbc.
  754. --*/
  755. {
  756. TCHAR* psz = NULL;
  757. TCHAR* pszTemp = NULL;
  758. TCHAR szXMLFile[128];
  759. TCHAR szSDBFile[128];
  760. TCHAR szAppPatchDir[MAX_PATH] = _T("");
  761. WCHAR szCompiler[MAX_PATH];
  762. HANDLE hFile;
  763. DWORD dwBytesWritten = 0;
  764. //
  765. // Create the XML file.
  766. //
  767. GetSystemWindowsDirectory(szAppPatchDir, MAX_PATH);
  768. lstrcat(szAppPatchDir, _T("\\AppPatch"));
  769. SetCurrentDirectory(szAppPatchDir);
  770. pszTemp = (TCHAR*)HeapAlloc(GetProcessHeap(),
  771. HEAP_ZERO_MEMORY,
  772. (lstrlen(pszShortName)+1)*sizeof(TCHAR));
  773. if (NULL == pszTemp) {
  774. LogMsg(_T("[CreateSDBFile] Failed to allocate memory\n"));
  775. return FALSE;
  776. }
  777. lstrcpy(pszTemp, pszShortName);
  778. psz = PathFindExtension(pszTemp);
  779. if (NULL == psz) {
  780. return FALSE;
  781. } else {
  782. *psz = '\0';
  783. }
  784. // Build the XML file path
  785. wsprintf(szXMLFile, _T("%s\\%s.xml"), szAppPatchDir, pszTemp);
  786. // Build the SDB file path
  787. wsprintf(szSDBFile, _T("%s\\%s.sdb"), szAppPatchDir, pszTemp);
  788. hFile = CreateFile(szXMLFile,
  789. GENERIC_WRITE,
  790. 0,
  791. NULL,
  792. CREATE_ALWAYS,
  793. FILE_ATTRIBUTE_NORMAL,
  794. NULL);
  795. if (hFile == INVALID_HANDLE_VALUE) {
  796. LogMsg(_T("[CreateSDBFile] CreateFile '%s' failed 0x%X.\n"),
  797. szXMLFile, GetLastError());
  798. return FALSE;
  799. }
  800. if (!(WriteFile(hFile,
  801. g_szXML,
  802. lstrlen(g_szXML) * sizeof(TCHAR),
  803. &dwBytesWritten,
  804. NULL))) {
  805. LogMsg(_T("[CreateSDBFile] WriteFile '%s' failed 0x%X.\n"),
  806. szXMLFile, GetLastError());
  807. CloseHandle(hFile);
  808. return FALSE;
  809. }
  810. CloseHandle(hFile);
  811. //
  812. // Set up the command line for shimdbc and generate an SDB.
  813. //
  814. wsprintf(szCompiler,
  815. _T("shimdbc.exe fix -q \"%s\" \"%s\""),
  816. szXMLFile,
  817. szSDBFile);
  818. if (!ShimdbcExecute(szCompiler)) {
  819. LogMsg(_T("[CreateSDBFile] CreateProcess \"%s\" failed 0x%X\n"),
  820. szCompiler, GetLastError());
  821. return FALSE;
  822. }
  823. // Give the SDB name back to the caller if they want it.
  824. if (pszSDBName) {
  825. lstrcpy(pszSDBName, szSDBFile);
  826. }
  827. return TRUE;
  828. }
  829. BOOL
  830. CollectFix(
  831. HWND hListLayers,
  832. HWND hListShims,
  833. HWND hTreeFiles,
  834. LPCTSTR pszShortName,
  835. LPCTSTR pszFullPath,
  836. DWORD dwFlags,
  837. LPTSTR pszFileCreated
  838. )
  839. /*++
  840. CollectFix
  841. Description: Adds the necessary support to apply shim(s) for
  842. the specified app.
  843. --*/
  844. {
  845. BOOL fAddW2K = FALSE;
  846. TCHAR* pszXML;
  847. TCHAR szError[MAX_PATH];
  848. TCHAR szXmlFile[MAX_PATH];
  849. TCHAR* pszLayerName = NULL;
  850. TCHAR szBuffer[1024];
  851. TCHAR szLayer[128] = _T("!#");
  852. TCHAR szUnicodeHdr[2] = { 0xFEFF, 0 };
  853. int cbCrtXmlSize = 0, cbLength;
  854. int cbXmlSize = MAX_XML_SIZE;
  855. DWORD dwBinaryType = SCS_32BIT_BINARY;
  856. g_szXML[0] = 0;
  857. pszXML = g_szXML;
  858. //
  859. // Create a layer to run all the apps under it.
  860. //
  861. if (dwFlags & CFF_USELAYERTAB) {
  862. LRESULT lSel;
  863. lSel = SendMessage(hListLayers, LB_GETCURSEL, 0, 0);
  864. if (lSel == LB_ERR) {
  865. LoadString(g_hInstance, IDS_LAYER_SELECT, szError, MAX_PATH);
  866. MessageBox(g_hDlg, szError, g_szAppTitle, MB_OK | MB_ICONEXCLAMATION);
  867. return TRUE;
  868. }
  869. SendMessage(hListLayers, LB_GETTEXT, lSel, (LPARAM)(szLayer + 2));
  870. pszLayerName = szLayer;
  871. } else {
  872. pszLayerName = g_szQFixAppLayerName;
  873. }
  874. //
  875. // Determine the binary type.
  876. //
  877. GetBinaryType(pszFullPath, &dwBinaryType);
  878. //
  879. // Build the header for the XML.
  880. //
  881. wsprintf(szBuffer,
  882. _T("%s<?xml version=\"1.0\" encoding=\"UTF-16\"?>\r\n")
  883. _T("<DATABASE NAME=\"%s custom database\">\r\n"),
  884. szUnicodeHdr,
  885. pszShortName);
  886. ADD_AND_CHECK(cbXmlSize, cbCrtXmlSize, pszXML);
  887. //
  888. // If this is Windows 2000 and they're not using
  889. // a predefined layer, add Win2kPropagateLayer.
  890. //
  891. if ((dwFlags & CFF_ADDW2KSUPPORT) && !(dwFlags & CFF_USELAYERTAB)) {
  892. fAddW2K = TRUE;
  893. }
  894. //
  895. // If we're not using a predefined layer, build one manually.
  896. //
  897. if (!(dwFlags & CFF_USELAYERTAB)) {
  898. CollectShims(hListShims,
  899. pszXML,
  900. pszLayerName,
  901. fAddW2K,
  902. cbXmlSize - cbCrtXmlSize);
  903. }
  904. cbLength = lstrlen(pszXML);
  905. pszXML += cbLength;
  906. cbCrtXmlSize += cbLength + 1;
  907. //
  908. // Retrieve attributes and matching files from the tree.
  909. // If we're displaying the XML, pass the real binary type.
  910. // If we're not, which means we're creating fix support or
  911. // running the application, let the callee think it's a 32-bit module.
  912. //
  913. if (dwFlags & CFF_SHOWXML) {
  914. CollectFileAttributes(hTreeFiles,
  915. pszXML,
  916. cbXmlSize - cbCrtXmlSize,
  917. pszShortName,
  918. dwBinaryType);
  919. } else {
  920. CollectFileAttributes(hTreeFiles,
  921. pszXML,
  922. cbXmlSize - cbCrtXmlSize,
  923. pszShortName,
  924. SCS_32BIT_BINARY);
  925. }
  926. cbLength = lstrlen(pszXML);
  927. pszXML += cbLength;
  928. cbCrtXmlSize += cbLength + 1;
  929. //
  930. // Add our layer to this EXE.
  931. //
  932. wsprintf(szBuffer, _T(" <LAYER NAME=\"%s\"/>\r\n"), pszLayerName + 2);
  933. ADD_AND_CHECK(cbXmlSize, cbCrtXmlSize, pszXML);
  934. //
  935. // Finally, close the open tags.
  936. //
  937. lstrcpy(szBuffer, _T(" </EXE>\r\n </APP>\r\n</DATABASE>"));
  938. ADD_AND_CHECK(cbXmlSize, cbCrtXmlSize, pszXML);
  939. LogMsg(_T("[CollectFix] XML:\n%s\n"), g_szXML);
  940. //
  941. // Display the XML if the user wants to see it.
  942. //
  943. if (dwFlags & CFF_SHOWXML) {
  944. DialogBoxParam(g_hInstance,
  945. MAKEINTRESOURCE(IDD_XML),
  946. g_hDlg,
  947. ShowXMLDlgProc,
  948. (LPARAM)(g_szXML + 1));
  949. return TRUE;
  950. }
  951. //
  952. // Create the SDB file for the user.
  953. //
  954. if (!(CreateSDBFile(pszShortName, pszFileCreated))) {
  955. return FALSE;
  956. }
  957. //
  958. // Delete the XML file that we created.
  959. //
  960. lstrcpy(szXmlFile, pszFileCreated);
  961. PathRenameExtension(szXmlFile, _T(".xml"));
  962. DeleteFile(szXmlFile);
  963. //
  964. // Set the SHIM_FILE_LOG env var.
  965. //
  966. if (dwFlags & CFF_SHIMLOG) {
  967. DeleteFile(SHIM_FILE_LOG_NAME);
  968. SetEnvironmentVariable(_T("SHIM_FILE_LOG"), SHIM_FILE_LOG_NAME);
  969. }
  970. return TRUE;
  971. }
  972. void
  973. CleanupSupportForApp(
  974. TCHAR* pszShortName
  975. )
  976. /*++
  977. CleanupSupportForApp
  978. Description: Cleanup the mess after we're done with
  979. the specified app.
  980. --*/
  981. {
  982. TCHAR* pszShimDB = NULL;
  983. int nLen = 0;
  984. nLen = lstrlen(pszShortName);
  985. pszShimDB = (TCHAR*)HeapAlloc(GetProcessHeap(),
  986. HEAP_ZERO_MEMORY,
  987. (nLen + MAX_PATH)*sizeof(TCHAR));
  988. if (NULL == pszShimDB) {
  989. LogMsg(_T("[CleanupSupportForApp] Failed to allocate memory\n"));
  990. return;
  991. }
  992. GetSystemWindowsDirectory(pszShimDB, MAX_PATH);
  993. lstrcat(pszShimDB, _T("\\AppPatch"));
  994. SetCurrentDirectory(pszShimDB);
  995. lstrcat(pszShimDB, _T("\\"));
  996. lstrcat(pszShimDB, pszShortName);
  997. //
  998. // Attempt to delete the XML file.
  999. //
  1000. PathRenameExtension(pszShimDB, _T(".xml"));
  1001. DeleteFile(pszShimDB);
  1002. //
  1003. // Remove the previous SDB file, if one exists.
  1004. //
  1005. if (g_szSDBToDelete[0]) {
  1006. InstallSDB(g_szSDBToDelete, FALSE);
  1007. DeleteFile(g_szSDBToDelete);
  1008. }
  1009. HeapFree(GetProcessHeap(), 0, pszShimDB);
  1010. }
  1011. void
  1012. ShowShimLog(
  1013. void
  1014. )
  1015. /*++
  1016. ShowShimLog
  1017. Description: Show the shim log file in notepad.
  1018. --*/
  1019. {
  1020. STARTUPINFO si;
  1021. PROCESS_INFORMATION pi;
  1022. TCHAR szCmd[MAX_PATH] = _T("");
  1023. TCHAR szError[MAX_PATH];
  1024. GetSystemWindowsDirectory(szCmd, MAX_PATH);
  1025. SetCurrentDirectory(szCmd);
  1026. if (GetFileAttributes(_T("AppPatch\\") SHIM_FILE_LOG_NAME) == -1) {
  1027. LoadString(g_hInstance, IDS_NO_LOGFILE, szError, MAX_PATH);
  1028. MessageBox(NULL, szError, g_szAppTitle, MB_ICONEXCLAMATION | MB_OK);
  1029. return;
  1030. }
  1031. lstrcat(szCmd, _T("\\notepad.exe AppPatch\\") SHIM_FILE_LOG_NAME);
  1032. ZeroMemory(&si, sizeof(si));
  1033. si.cb = sizeof(si);
  1034. if (!CreateProcess(NULL,
  1035. szCmd,
  1036. NULL,
  1037. NULL,
  1038. FALSE,
  1039. NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW,
  1040. NULL,
  1041. NULL,
  1042. &si,
  1043. &pi)) {
  1044. LogMsg(_T("[ShowShimLog] CreateProcess \"%s\" failed 0x%X\n"),
  1045. szCmd, GetLastError());
  1046. return;
  1047. }
  1048. CloseHandle(pi.hThread);
  1049. CloseHandle(pi.hProcess);
  1050. }