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.

2378 lines
72 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. check.c
  5. Abstract:
  6. This module implements the main API that CreateProcess
  7. calls to check if an EXE is shimmed or apphelpped.
  8. Author:
  9. vadimb created sometime in 2000
  10. Revision History:
  11. clupu cleanup 12/27/2000
  12. andyseti added ApphelpCheckExe 03/29/2001
  13. andyseti added ApphelpCheckInstallShieldPackage 06/28/2001
  14. --*/
  15. #include "apphelp.h"
  16. #define STRSAFE_NO_CB_FUNCTIONS
  17. #include <strsafe.h>
  18. static const WCHAR ShimEngine_ModuleName[] = L"Shimeng.dll";
  19. static const CHAR DynamicShimProcedureName[] = "SE_DynamicShim";
  20. static const CHAR DynamicUnshimProcedureName[] = "SE_DynamicUnshim";
  21. typedef BOOL (WINAPI *_pfn_SE_DynamicShim)(LPCWSTR , HSDB , SDBQUERYRESULT*, LPCSTR, LPDWORD);
  22. typedef BOOL (WINAPI *_pfn_SE_DynamicUnshim)(DWORD);
  23. typedef struct tagEXE_DYN_SHIM_INFO {
  24. LIST_ENTRY entry;
  25. LPWSTR pwszFullPath; // full path to the executable.
  26. DWORD dwToken; // the dynamic shimming token associated with this exe.
  27. } EXE_DYN_SHIM_INFO, *PEXE_DYN_SHIM_INFO;
  28. LIST_ENTRY g_ExeDynShimInfoList;
  29. BOOL
  30. AddExeDynShimInfoToList(
  31. IN LPCWSTR pwszFullPath,
  32. IN DWORD dwToken
  33. );
  34. BOOL
  35. RemoveExeDynShimInfoFromList(
  36. IN LPCWSTR pwszFullPath
  37. );
  38. extern HINSTANCE ghInstance;
  39. //
  40. // Prototypes of internal functions
  41. //
  42. void
  43. GetExeNTVDMData(
  44. IN HSDB hSDB, // the SDB context
  45. IN PSDBQUERYRESULT psdbQuery, // the EXEs and LAYERs that are active
  46. OUT WCHAR* pszCompatLayer, // The new compat layer variable. with format:
  47. // "Alpha Bravo Charlie"
  48. OUT PNTVDM_FLAGS pFlags // The flags
  49. );
  50. //
  51. // Appcompat Infrastructure disable-via-policy-flag
  52. //
  53. DWORD gdwInfrastructureFlags; // initialized to 0
  54. #define APPCOMPAT_INFRA_DISABLED 0x00000001
  55. #define APPCOMPAT_INFRA_VALID_FLAG 0x80000000
  56. #define IsAppcompatInfrastructureDisabled() \
  57. (!!( (gdwInfrastructureFlags & APPCOMPAT_INFRA_VALID_FLAG) ? \
  58. (gdwInfrastructureFlags & APPCOMPAT_INFRA_DISABLED) : \
  59. (CheckAppcompatInfrastructureFlags() & APPCOMPAT_INFRA_DISABLED)) )
  60. DWORD
  61. CheckAppcompatInfrastructureFlags(
  62. VOID
  63. );
  64. #if DBG
  65. BOOL
  66. bDebugChum(
  67. void
  68. )
  69. /*++
  70. Return: TRUE on success, FALSE otherwise.
  71. Desc: Checks an env var. If the var is present return TRUE.
  72. --*/
  73. {
  74. UNICODE_STRING ustrDebugChum;
  75. UNICODE_STRING ustrDebugChumVal = { 0 };
  76. NTSTATUS Status;
  77. RtlInitUnicodeString(&ustrDebugChum, L"DEBUG_OFFLINE_CONTENT");
  78. Status = RtlQueryEnvironmentVariable_U(NULL,
  79. &ustrDebugChum,
  80. &ustrDebugChumVal);
  81. if (Status == STATUS_BUFFER_TOO_SMALL) {
  82. return TRUE;
  83. }
  84. return FALSE;
  85. }
  86. #else // DBG
  87. #define bDebugChum() TRUE
  88. #endif // DBG
  89. BOOL
  90. GetExeID(
  91. IN PDB pdb, // the pointer to the database
  92. IN TAGID tiExe, // the TAGID of the EXE for which we need the ID
  93. OUT GUID* pGuid // will receive the EXE's ID
  94. )
  95. /*++
  96. Return: TRUE on success, FALSE otherwise.
  97. Desc: Reads the EXE's ID from the database using the EXE's tag id.
  98. --*/
  99. {
  100. TAGID tiExeID;
  101. tiExeID = SdbFindFirstTag(pdb, tiExe, TAG_EXE_ID);
  102. if (tiExeID == TAGID_NULL) {
  103. DBGPRINT((sdlError, "GetExeID", "EXE tag 0x%x without an ID !\n", tiExe));
  104. return FALSE;
  105. }
  106. if (!SdbReadBinaryTag(pdb, tiExeID, (PBYTE)pGuid, sizeof(*pGuid))) {
  107. DBGPRINT((sdlError, "GetExeID", "Cannot read the ID for EXE tag 0x%x.\n", tiExe));
  108. return FALSE;
  109. }
  110. return TRUE;
  111. }
  112. BOOL
  113. GetExeIDByTagRef(
  114. IN HSDB hSDB, // handle to the database object
  115. IN TAGREF trExe, // EXE tag ref
  116. OUT GUID* pGuid // will receive the EXE's ID
  117. )
  118. /*++
  119. Return: TRUE on success, FALSE otherwise.
  120. Desc: Reads the EXE's ID from the database using the EXE's tag ref.
  121. --*/
  122. {
  123. PDB pdb;
  124. TAGID tiExe;
  125. TAGID tiExeID;
  126. if (!SdbTagRefToTagID(hSDB, trExe, &pdb, &tiExe)) {
  127. DBGPRINT((sdlError,
  128. "GetExeIDByTagRef",
  129. "Failed to get the tag id from EXE tag ref 0x%x.\n",
  130. tiExe));
  131. return FALSE;
  132. }
  133. return GetExeID(pdb, tiExe, pGuid);
  134. }
  135. #define APPHELP_CLSID_REG_PATH L"\\Registry\\Machine\\Software\\Classes\\CLSID\\"
  136. #define APPHELP_INPROCSERVER32 L"\\InProcServer32"
  137. DWORD
  138. ResolveCOMServer(
  139. IN REFCLSID CLSID,
  140. OUT LPWSTR lpPath,
  141. OUT DWORD dwBufSize)
  142. {
  143. DWORD dwReqBufSize = 0;
  144. UNICODE_STRING ustrKey = { 0 };
  145. UNICODE_STRING ustrValueName = { 0 };
  146. UNICODE_STRING ustrGuid = { 0 };
  147. UNICODE_STRING ustrUnexpandedValue = { 0 };
  148. UNICODE_STRING ustrValue = { 0 };
  149. NTSTATUS Status;
  150. OBJECT_ATTRIBUTES ObjectAttributes;
  151. HANDLE KeyHandle = NULL;
  152. PKEY_VALUE_FULL_INFORMATION pKeyValueInfo = NULL;
  153. DWORD dwKeyValueInfoSize = 0;
  154. DWORD dwKeyValueInfoReqSize = 0;
  155. LPWSTR wszCLSIDRegFullPath = NULL;
  156. DWORD dwCLSIDRegFullPathSize = 0;
  157. WCHAR wszCLSID[41] = { 0 };
  158. // Enough for path + CLSID in string form
  159. dwCLSIDRegFullPathSize = wcslen(APPHELP_CLSID_REG_PATH) +
  160. wcslen(APPHELP_INPROCSERVER32) + 64;
  161. wszCLSIDRegFullPath = RtlAllocateHeap(
  162. RtlProcessHeap(),
  163. HEAP_ZERO_MEMORY,
  164. dwCLSIDRegFullPathSize * sizeof(WCHAR));
  165. if (wszCLSIDRegFullPath == NULL) {
  166. DBGPRINT((sdlInfo,
  167. "SdbResolveCOMServer",
  168. "Memory allocation failure\n"));
  169. goto Done;
  170. }
  171. StringCchCopyW(wszCLSIDRegFullPath, dwCLSIDRegFullPathSize, APPHELP_CLSID_REG_PATH);
  172. Status = RtlStringFromGUID(CLSID, &ustrGuid);
  173. if (!NT_SUCCESS(Status)) {
  174. DBGPRINT((sdlInfo,
  175. "SdbResolveCOMServer",
  176. "Malformed CLSID\n"));
  177. goto Done;
  178. }
  179. if (ustrGuid.Length/sizeof(WCHAR) > 40) {
  180. DBGPRINT((sdlInfo,
  181. "SdbResolveCOMServer",
  182. "CLSID more than 40 characters\n"));
  183. goto Done;
  184. }
  185. RtlMoveMemory(wszCLSID,
  186. ustrGuid.Buffer,
  187. ustrGuid.Length);
  188. wszCLSID[ustrGuid.Length/sizeof(WCHAR)] = L'\0';
  189. StringCchCatW(wszCLSIDRegFullPath, dwCLSIDRegFullPathSize, wszCLSID);
  190. StringCchCatW(wszCLSIDRegFullPath, dwCLSIDRegFullPathSize, APPHELP_INPROCSERVER32);
  191. RtlInitUnicodeString(&ustrKey, wszCLSIDRegFullPath);
  192. RtlInitUnicodeString(&ustrValueName, L"");
  193. InitializeObjectAttributes(&ObjectAttributes,
  194. &ustrKey,
  195. OBJ_CASE_INSENSITIVE,
  196. NULL,
  197. NULL);
  198. Status = NtOpenKey(&KeyHandle,
  199. GENERIC_READ,
  200. &ObjectAttributes);
  201. if (!NT_SUCCESS(Status)) {
  202. DBGPRINT((sdlInfo,
  203. "SdbResolveCOMServer",
  204. "Failed to open Key \"%s\" Status 0x%x\n",
  205. wszCLSIDRegFullPath,
  206. Status));
  207. goto Done;
  208. }
  209. if (lpPath == NULL &&
  210. dwBufSize != 0) {
  211. DBGPRINT((sdlInfo,
  212. "SdbResolveCOMServer",
  213. "Bad parameters\n"));
  214. goto Done;
  215. }
  216. pKeyValueInfo = RtlAllocateHeap(RtlProcessHeap(),
  217. HEAP_ZERO_MEMORY,
  218. dwBufSize * 2);
  219. if (pKeyValueInfo == NULL) {
  220. DBGPRINT((sdlInfo,
  221. "SdbResolveCOMServer",
  222. "Memory allocation failure\n"));
  223. goto Done;
  224. }
  225. dwKeyValueInfoSize = dwBufSize * 2;
  226. Status = NtQueryValueKey(KeyHandle,
  227. &ustrValueName,
  228. KeyValueFullInformation,
  229. pKeyValueInfo,
  230. dwKeyValueInfoSize,
  231. &dwKeyValueInfoReqSize);
  232. if (!NT_SUCCESS(Status)) {
  233. if (Status == STATUS_BUFFER_TOO_SMALL) {
  234. RtlFreeHeap(RtlProcessHeap(), 0, pKeyValueInfo);
  235. pKeyValueInfo = RtlAllocateHeap(RtlProcessHeap(),
  236. HEAP_ZERO_MEMORY,
  237. dwKeyValueInfoReqSize);
  238. if (pKeyValueInfo == NULL) {
  239. DBGPRINT((sdlInfo,
  240. "SdbResolveCOMServer",
  241. "Memory allocation failure\n"));
  242. goto Done;
  243. }
  244. dwKeyValueInfoSize = dwKeyValueInfoReqSize;
  245. Status = NtQueryValueKey(KeyHandle,
  246. &ustrValueName,
  247. KeyValueFullInformation,
  248. pKeyValueInfo,
  249. dwKeyValueInfoSize,
  250. &dwKeyValueInfoReqSize);
  251. if (!NT_SUCCESS(Status)) {
  252. DBGPRINT((sdlInfo,
  253. "SdbResolveCOMServer",
  254. "Failed to retrieve default key value for \"%s\" Status 0x%x\n",
  255. wszCLSIDRegFullPath,
  256. Status));
  257. goto Done;
  258. }
  259. } else {
  260. DBGPRINT((sdlInfo,
  261. "SdbResolveCOMServer",
  262. "Failed to retrieve default key value for \"%s\" Status 0x%x\n",
  263. wszCLSIDRegFullPath,
  264. Status));
  265. goto Done;
  266. }
  267. }
  268. if (pKeyValueInfo->Type == REG_SZ) {
  269. dwReqBufSize = pKeyValueInfo->DataLength + (1 * sizeof(WCHAR));
  270. if (dwBufSize >= dwReqBufSize) {
  271. RtlMoveMemory(lpPath, ((PBYTE) pKeyValueInfo) + pKeyValueInfo->DataOffset, pKeyValueInfo->DataLength);
  272. lpPath[pKeyValueInfo->DataLength / sizeof(WCHAR)] = '\0';
  273. }
  274. } else if (pKeyValueInfo->Type == REG_EXPAND_SZ) {
  275. ustrUnexpandedValue.Buffer = (PWSTR) (((PBYTE) pKeyValueInfo) + pKeyValueInfo->DataOffset);
  276. ustrUnexpandedValue.Length = (USHORT) pKeyValueInfo->DataLength;
  277. ustrUnexpandedValue.MaximumLength = (USHORT) pKeyValueInfo->DataLength;
  278. ustrValue.Buffer = lpPath;
  279. ustrValue.Length = 0;
  280. ustrValue.MaximumLength = (USHORT) dwBufSize;
  281. Status = RtlExpandEnvironmentStrings_U(NULL,
  282. &ustrUnexpandedValue,
  283. &ustrValue,
  284. &dwReqBufSize);
  285. if (Status == STATUS_BUFFER_TOO_SMALL) {
  286. goto Done;
  287. } else if (!NT_SUCCESS(Status)) {
  288. DBGPRINT((sdlInfo,
  289. "SdbResolveCOMServer",
  290. "Failed to expand key value for \"%s\" Status 0x%x\n",
  291. wszCLSIDRegFullPath,
  292. Status));
  293. goto Done;
  294. }
  295. }
  296. DBGPRINT((sdlInfo,
  297. "SdbResolveCOMServer",
  298. "CLSID %s resolved to \"%s\"\n",
  299. wszCLSID, lpPath));
  300. Done:
  301. if (KeyHandle != NULL) {
  302. NtClose(KeyHandle);
  303. }
  304. if (wszCLSIDRegFullPath != NULL) {
  305. RtlFreeHeap(RtlProcessHeap(), 0, wszCLSIDRegFullPath);
  306. }
  307. if (pKeyValueInfo != NULL) {
  308. RtlFreeHeap(RtlProcessHeap(), 0, pKeyValueInfo);
  309. }
  310. if (ustrGuid.Buffer != NULL) {
  311. RtlFreeUnicodeString(&ustrGuid);
  312. }
  313. return dwReqBufSize;
  314. }
  315. VOID
  316. ParseSdbQueryResult(
  317. IN HSDB hSDB,
  318. IN PSDBQUERYRESULT pQuery,
  319. OUT TAGREF* ptrAppHelp, // apphelp tagref, optional
  320. OUT PAPPHELP_DATA pApphelpData, // apphelp data, optional
  321. OUT TAGREF* ptrSxsData // fusion tagref, optional
  322. )
  323. {
  324. DWORD dwIndex;
  325. BOOL bAppHelp = FALSE;
  326. BOOL bFusionFix = FALSE;
  327. TAGREF trExe;
  328. TAGREF trAppHelp = TAGREF_NULL;
  329. TAGREF trSxsData = TAGREF_NULL;
  330. //
  331. // scan matching exes; we extract fusion fix (the first one we find) and apphelp data,
  332. // also the first one we find
  333. //
  334. for (dwIndex = 0; dwIndex < pQuery->dwExeCount; ++dwIndex) {
  335. trExe = pQuery->atrExes[dwIndex];
  336. if (ptrAppHelp != NULL && !bAppHelp) {
  337. bAppHelp = SdbReadApphelpData(hSDB, trExe, pApphelpData);
  338. if (bAppHelp) {
  339. trAppHelp = trExe;
  340. if (ptrSxsData == NULL || bFusionFix) {
  341. break;
  342. }
  343. }
  344. }
  345. // see if we have sxs fix as well
  346. if (ptrSxsData != NULL && !bFusionFix) {
  347. bFusionFix = GetExeSxsData(hSDB, trExe, NULL, NULL);
  348. if (bFusionFix) {
  349. trSxsData = trExe;
  350. }
  351. if (bFusionFix && (ptrAppHelp == NULL || bAppHelp)) {
  352. break;
  353. }
  354. }
  355. }
  356. if (ptrAppHelp != NULL) {
  357. *ptrAppHelp = trAppHelp;
  358. }
  359. if (ptrSxsData != NULL) {
  360. *ptrSxsData = trSxsData;
  361. }
  362. }
  363. BOOL
  364. InternalCheckRunApp(
  365. IN HANDLE hFile, // [Optional] Handle to an open file to check
  366. IN LPCWSTR pwszPath, // path to the app in NT format
  367. IN LPCWSTR pEnvironment, // pointer to the environment of the process that is
  368. // being created or NULL.
  369. IN USHORT uExeType, // executable's image type
  370. IN OUT PDWORD pdwReason, // collection of flags hinting at why we were called
  371. OUT PVOID* ppData, // this will contain the pointer to the allocated buffer
  372. // containing the appcompat data.
  373. OUT PDWORD pcbData, // if appcompat data is found, the size of the buffer
  374. // is returned here.
  375. OUT PVOID* ppSxsData, // out: Sxs data block from the compatibility database
  376. OUT PDWORD pcbSxsData, // out: sxs data block size
  377. OUT PDWORD pdwFusionFlags, // out: flags for sxs
  378. IN BOOL bNTVDMMode, // Are we doing the special NTVDM stuff?
  379. IN LPCWSTR szModuleName, // the module name (for NTVDM only)
  380. OUT LPWSTR pszCompatLayer, // The new compat layer variable. with format:
  381. // "__COMPAT_LAYER=Alpha Bravo Charlie"
  382. OUT PNTVDM_FLAGS pFlags, // The flags
  383. OUT PAPPHELP_INFO pAHInfo, // If there is apphelp to display, this will be filled
  384. // in with non-null values
  385. OUT HSDB* phSDB, // The handle to the database.
  386. OUT PSDBQUERYRESULT pQueryResult // The query result.
  387. )
  388. /*++
  389. Return: FALSE if the app should be blocked from running, TRUE otherwise.
  390. Desc: This is the main API of apphelp.dll. It is called from CreateProcess
  391. to retrieve application compatibility information for the current process.
  392. This function does not check whether the appcompat infrastructure has been
  393. disabled, (kernel32 checks that)
  394. --*/
  395. {
  396. APPHELP_DATA ApphelpData;
  397. BOOL bSuccess;
  398. BOOL bRunApp = TRUE; // run by default
  399. BOOL bAppHelp = FALSE;
  400. WCHAR* pwszDosPath = NULL;
  401. BOOL bBypassCache = FALSE; // this is set if cache bypass occured (as opposed to entry not being found
  402. BOOL bGetSxsData = TRUE;
  403. BOOL bFusionFix = FALSE;
  404. HSDB hSDB = NULL;
  405. SDBQUERYRESULT sdbQuery;
  406. PSDBQUERYRESULT pSdbQuery = NULL;
  407. NTSTATUS Status;
  408. TAGREF trAppHelp = TAGREF_NULL;
  409. TAGREF trFusionFix = TAGREF_NULL;
  410. ULARGE_INTEGER uliFusionFlags = {0};
  411. UNICODE_STRING ExePath;
  412. RTL_UNICODE_STRING_BUFFER DosPathBuffer;
  413. UCHAR BufferPath[MAX_PATH*2];
  414. if (phSDB) {
  415. *phSDB = NULL;
  416. }
  417. if (pQueryResult) {
  418. pSdbQuery = pQueryResult;
  419. } else {
  420. pSdbQuery = &sdbQuery;
  421. }
  422. RtlZeroMemory(pSdbQuery, sizeof(sdbQuery));
  423. RtlInitUnicodeStringBuffer(&DosPathBuffer, BufferPath, sizeof(BufferPath));
  424. RtlInitUnicodeString(&ExePath, pwszPath);
  425. Status = RtlAssignUnicodeStringBuffer(&DosPathBuffer, &ExePath);
  426. if (NT_SUCCESS(Status)) {
  427. Status = RtlNtPathNameToDosPathName(0, &DosPathBuffer, NULL, NULL);
  428. }
  429. if (!NT_SUCCESS(Status)) {
  430. DBGPRINT((sdlError, "InternalCheckRunApp", "Failed to convert path \"%S\" to DOS.\n", pwszPath));
  431. goto Done;
  432. }
  433. //
  434. // we have been successful, this is 0-terminated dos path
  435. //
  436. pwszDosPath = DosPathBuffer.String.Buffer;
  437. //
  438. // Cache lookup was bypassed by one reason or the other.
  439. // We do not update cache after it had been bypassed.
  440. //
  441. if (pdwReason) {
  442. bBypassCache = !!(*pdwReason & SHIM_CACHE_BYPASS);
  443. } else {
  444. bBypassCache = TRUE;
  445. }
  446. hSDB = SdbInitDatabaseEx(0, NULL, uExeType);
  447. if (phSDB) {
  448. *phSDB = hSDB;
  449. }
  450. if (hSDB == NULL) {
  451. DBGPRINT((sdlError,
  452. "InternalCheckRunApp",
  453. "Failed to initialize the database.\n"));
  454. goto Done;
  455. }
  456. //
  457. // We didn't find this EXE in the cache. Query the database
  458. // to get all the info about this EXE.
  459. //
  460. SdbGetMatchingExe(hSDB, pwszDosPath, szModuleName, pEnvironment, 0, pSdbQuery);
  461. if (pSdbQuery->dwFlags & SHIMREG_DISABLE_SXS) {
  462. bGetSxsData = FALSE;
  463. }
  464. //
  465. // get the flags for fusion.
  466. //
  467. SdbQueryFlagMask(hSDB, pSdbQuery, TAG_FLAG_MASK_FUSION, &uliFusionFlags.QuadPart, NULL);
  468. if (pdwFusionFlags) {
  469. *pdwFusionFlags = (DWORD)uliFusionFlags.QuadPart;
  470. }
  471. //
  472. // find apphelp/and/or Fusion fix
  473. //
  474. ParseSdbQueryResult(hSDB,
  475. pSdbQuery,
  476. &trAppHelp,
  477. &ApphelpData,
  478. bGetSxsData ? &trFusionFix : NULL);
  479. bAppHelp = (trAppHelp != TAGREF_NULL);
  480. if (bAppHelp) {
  481. //
  482. // Check whether the disable bit is set (the dwFlags has been retrieved from the
  483. // registry via the SdbReadApphelpData call)
  484. //
  485. if (!(pSdbQuery->dwFlags & SHIMREG_DISABLE_APPHELP)) {
  486. BOOL bNoUI;
  487. //
  488. // See whether the user has checked "Don't show this anymore" box before.
  489. //
  490. bNoUI = ((pSdbQuery->dwFlags & SHIMREG_APPHELP_NOUI) != 0);
  491. if (bNoUI) {
  492. DBGPRINT((sdlInfo,
  493. "InternalCheckRunApp",
  494. "NoUI flag is set, apphelp UI disabled for this app.\n"));
  495. }
  496. //
  497. // Depending on severity of the problem...
  498. //
  499. switch (ApphelpData.dwSeverity) {
  500. case APPHELP_MINORPROBLEM:
  501. case APPHELP_HARDBLOCK:
  502. case APPHELP_NOBLOCK:
  503. case APPHELP_REINSTALL:
  504. //
  505. // NTVDM needs the severity info.
  506. //
  507. if (pAHInfo) {
  508. pAHInfo->dwSeverity = ApphelpData.dwSeverity;
  509. }
  510. if (bNoUI) {
  511. bRunApp = (ApphelpData.dwSeverity != APPHELP_HARDBLOCK);
  512. } else {
  513. DWORD dwRet;
  514. //
  515. // We need to show apphelp -- pack up the info
  516. // so we can hand it off to shimeng or ntvdm.
  517. //
  518. pSdbQuery->trAppHelp = trAppHelp;
  519. if (pAHInfo) {
  520. PDB pdb;
  521. TAGID tiWhich;
  522. if (SdbTagRefToTagID(hSDB, trAppHelp, &pdb, &tiWhich)) {
  523. if (SdbGetDatabaseGUID(hSDB, pdb, &(pAHInfo->guidDB))) {
  524. pAHInfo->tiExe = tiWhich;
  525. }
  526. }
  527. }
  528. bRunApp = TRUE;
  529. }
  530. break;
  531. default:
  532. //
  533. // Some other case was found (e.g. VERSIONSUB which should be replaced
  534. // by shims in most cases).
  535. //
  536. DBGPRINT((sdlWarning,
  537. "InternalCheckRunApp",
  538. "Unhandled severity flag 0x%x.\n",
  539. ApphelpData.dwSeverity));
  540. break;
  541. }
  542. }
  543. }
  544. //
  545. // Apphelp verification is done. Check for shims if we should still run the app.
  546. //
  547. if (bRunApp) {
  548. if (ppData &&
  549. (pSdbQuery->atrExes[0] != TAGREF_NULL ||
  550. pSdbQuery->atrLayers[0] != TAGREF_NULL ||
  551. pSdbQuery->trAppHelp)) {
  552. //
  553. // There are shims for this EXE. Pack the appcompat data
  554. // so it can be sent to ntdll in the context of the starting EXE.
  555. //
  556. SdbPackAppCompatData(hSDB, pSdbQuery, ppData, pcbData);
  557. }
  558. if (ppSxsData && bGetSxsData && trFusionFix != TAGREF_NULL) {
  559. //
  560. // See if we have Fusion data to report.
  561. //
  562. GetExeSxsData(hSDB, trFusionFix, ppSxsData, pcbSxsData);
  563. bFusionFix = (ppSxsData != NULL && *ppSxsData != NULL);
  564. }
  565. if (bNTVDMMode) {
  566. GetExeNTVDMData(hSDB, pSdbQuery, pszCompatLayer, pFlags);
  567. }
  568. }
  569. //
  570. // Update the cache now.
  571. //
  572. if (!bBypassCache) {
  573. //
  574. // Do not update the cache if we got the EXE entry from a local database.
  575. //
  576. bBypassCache = (pSdbQuery->atrExes[0] != TAGREF_NULL &&
  577. !SdbIsTagrefFromMainDB(pSdbQuery->atrExes[0]));
  578. }
  579. if (!bBypassCache) {
  580. //
  581. // We remove from cache only if we have some appcompat data
  582. //
  583. BOOL
  584. bCleanApp = pSdbQuery->atrExes[0] == TAGREF_NULL &&
  585. pSdbQuery->atrLayers[0] == TAGREF_NULL &&
  586. !bAppHelp &&
  587. pSdbQuery->dwFlags == 0 &&
  588. !bFusionFix;
  589. if (hFile != INVALID_HANDLE_VALUE) {
  590. *pdwReason |= SHIM_CACHE_ACTION;
  591. if (bCleanApp) {
  592. *pdwReason |= SHIM_CACHE_UPDATE;
  593. }
  594. }
  595. }
  596. Done:
  597. RtlFreeUnicodeStringBuffer(&DosPathBuffer);
  598. //
  599. // NTVDM needs to have the database handle open.
  600. //
  601. if (!bNTVDMMode) {
  602. if (hSDB != NULL) {
  603. SdbReleaseDatabase(hSDB);
  604. }
  605. }
  606. return bRunApp;
  607. }
  608. BOOL
  609. ApphelpQueryExe(
  610. IN HSDB hSDB,
  611. IN LPCWSTR pwszPath, // Unicode path to the executable (DOS_PATH)
  612. IN BOOL bAppHelpIfNecessary, // Produce AppHelp dialog if necessary
  613. IN DWORD dwGetMatchingExeFlags,
  614. OUT SDBQUERYRESULT* pQueryResult // Shim Database Query Result
  615. )
  616. /*++
  617. Return: FALSE if the app should be blocked from running, TRUE otherwise.
  618. Desc: This function is similar with ApphelpCheckRunApp but without validating
  619. cache and Layer flags and doesn't return application compatibility
  620. information for given app name. It is intended to be called from
  621. a shim / user mode to verify whether an executable is allowed to run or not.
  622. --*/
  623. {
  624. BOOL bRunApp = TRUE; // run by default
  625. DWORD dwDatabaseType = 0;
  626. DWORD dwSeverity = 0;
  627. TAGREF trAppHelp = TAGREF_NULL;
  628. HAPPHELPINFOCONTEXT hApphelpInfoContext = NULL;
  629. //
  630. // Query the database to get all the info about this EXE.
  631. // Note:
  632. // This function is intended to be called from user mode.
  633. // It doesn't require a call to ConvertToDosPath to string \??\ from the filepath.
  634. //
  635. DBGPRINT((sdlInfo,
  636. "ApphelpCheckExe",
  637. "Calling SdbGetMatchingExe for \"%s\"\n",
  638. pwszPath));
  639. SdbGetMatchingExe(hSDB, pwszPath, NULL, NULL, dwGetMatchingExeFlags, pQueryResult);
  640. //
  641. // get info out of the query
  642. //
  643. ParseSdbQueryResult(hSDB,
  644. pQueryResult,
  645. &trAppHelp,
  646. NULL, // Apphelp Information api is used here
  647. NULL); // no sxs fixes are needed
  648. //
  649. // The last EXE in the list is always the more specific one, and the one we want to
  650. // use for checking IDs and flags and whatnot.
  651. //
  652. if (trAppHelp != TAGREF_NULL) {
  653. //
  654. // Read the apphelp data if available for this EXE.
  655. //
  656. if (SdbIsTagrefFromMainDB(trAppHelp)) {
  657. dwDatabaseType |= SDB_DATABASE_MAIN;
  658. }
  659. hApphelpInfoContext = SdbOpenApphelpInformationByID(hSDB,
  660. trAppHelp,
  661. dwDatabaseType);
  662. }
  663. //
  664. // Check whether the disable bit is set (the dwFlags has been retrieved from the
  665. // registry via the SdbReadApphelpData call)
  666. //
  667. if (hApphelpInfoContext != NULL) {
  668. if (!(pQueryResult->dwFlags & SHIMREG_DISABLE_APPHELP)) {
  669. BOOL bNoUI;
  670. //
  671. // See whether the user has checked "Don't show this anymore" box before.
  672. //
  673. bNoUI = ((pQueryResult->dwFlags & SHIMREG_APPHELP_NOUI) != 0);
  674. if (bNoUI) {
  675. DBGPRINT((sdlInfo,
  676. "ApphelpCheckExe",
  677. "NoUI flag is set, apphelp UI disabled for this app.\n"));
  678. }
  679. SdbQueryApphelpInformation(hApphelpInfoContext,
  680. ApphelpProblemSeverity,
  681. &dwSeverity,
  682. sizeof(dwSeverity));
  683. if (!bAppHelpIfNecessary) {
  684. bNoUI = TRUE;
  685. }
  686. //
  687. // depending on severity of the problem...
  688. //
  689. switch (dwSeverity) {
  690. case APPHELP_MINORPROBLEM:
  691. case APPHELP_HARDBLOCK:
  692. case APPHELP_NOBLOCK:
  693. case APPHELP_REINSTALL:
  694. bRunApp = (dwSeverity != APPHELP_HARDBLOCK);
  695. if (!bNoUI) {
  696. DWORD dwRet;
  697. APPHELP_INFO AHInfo = { 0 };
  698. SdbQueryApphelpInformation(hApphelpInfoContext,
  699. ApphelpDatabaseGUID,
  700. &AHInfo.guidDB,
  701. sizeof(AHInfo.guidDB));
  702. SdbQueryApphelpInformation(hApphelpInfoContext,
  703. ApphelpExeTagID,
  704. &AHInfo.tiExe,
  705. sizeof(AHInfo.tiExe));
  706. AHInfo.bOfflineContent = bDebugChum();
  707. SdbShowApphelpDialog(&AHInfo,
  708. NULL,
  709. &bRunApp); // either we succeeded or bInstall package is treated
  710. // the same way as No UI
  711. }
  712. break;
  713. default:
  714. //
  715. // Some other case was found (e.g. VERSIONSUB which should be replaced
  716. // by shims in most cases).
  717. //
  718. DBGPRINT((sdlWarning,
  719. "ApphelpCheckExe",
  720. "Unhandled severity flag 0x%x.\n",
  721. dwSeverity));
  722. break;
  723. }
  724. }
  725. }
  726. //
  727. // Apphelp verification is done.
  728. //
  729. if (hApphelpInfoContext != NULL) {
  730. SdbCloseApphelpInformation(hApphelpInfoContext);
  731. }
  732. return bRunApp;
  733. }
  734. /*++
  735. // This code was used to check for include/exclude list in the database
  736. // to eliminate confusion entries should ALWAYS provide the list
  737. //
  738. // CheckIncludeExcludeList
  739. // returns: TRUE - database provides the list
  740. // FALSE - no list is provided in the database
  741. //
  742. BOOL
  743. CheckIncludeExcludeList(
  744. IN HSDB hSDB,
  745. IN SDBQUERYRESULT* pQueryResult
  746. )
  747. {
  748. INT i;
  749. TAGREF trExe;
  750. TAGREF trFix;
  751. TAGREF trInexclude;
  752. for (i = 0; i < SDB_MAX_EXES && pQueryResult->atrExes[i] != TAGREF_NULL; ++i) {
  753. trExe = pQueryResult->atrExes[i];
  754. trFix = SdbFindFirstTagRef(hSDB, trExe, TAG_SHIM_REF);
  755. while (trFix != TAGREF_NULL) {
  756. trInexclude = SdbFindFirstTagRef(hSDB, trFix, TAG_INEXCLUDE);
  757. if (trInexclude != TAGREF_NULL) {
  758. return TRUE;
  759. }
  760. trFix = SdbFindNextTagRef(hSDB, trExe, trFix);
  761. }
  762. }
  763. //
  764. // layers have their own inclusion/exclusion scheme
  765. //
  766. return FALSE;
  767. }
  768. --*/
  769. BOOL
  770. AddExeDynShimInfoToList(
  771. IN LPCWSTR pwszFullPath,
  772. IN DWORD dwToken
  773. )
  774. {
  775. BOOL bResult = FALSE;
  776. PEXE_DYN_SHIM_INFO pDynShimInfo = NULL;
  777. DWORD dwLen = 0;
  778. static BOOL bInitialized = FALSE;
  779. if (pwszFullPath == NULL) {
  780. return TRUE;
  781. }
  782. RtlEnterCriticalSection(&g_csDynShimInfo);
  783. if (!bInitialized) {
  784. bInitialized = TRUE;
  785. InitializeListHead(&g_ExeDynShimInfoList);
  786. }
  787. pDynShimInfo =
  788. RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, sizeof (EXE_DYN_SHIM_INFO));
  789. if (pDynShimInfo == NULL) {
  790. DBGPRINT((sdlError,"AddExeDynShimInfoToList",
  791. "Failed to allocate a new dynamic shim info entry for %s\n",
  792. pwszFullPath));
  793. goto Done;
  794. }
  795. dwLen = wcslen(pwszFullPath) + 1;
  796. pDynShimInfo->pwszFullPath =
  797. RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, dwLen * sizeof(WCHAR));
  798. if (pDynShimInfo->pwszFullPath == NULL) {
  799. DBGPRINT((sdlError,"AddExeDynShimInfoToList",
  800. "Failed to allocate a new dynamic shim info entry for %s\n",
  801. pwszFullPath));
  802. goto Done;
  803. }
  804. StringCchCopyW(pDynShimInfo->pwszFullPath, dwLen, pwszFullPath);
  805. pDynShimInfo->dwToken = dwToken;
  806. InsertHeadList(&g_ExeDynShimInfoList, &pDynShimInfo->entry);
  807. DBGPRINT((sdlInfo,"AddExeDynShimInfoToList",
  808. "Added %s(token: %d) to the list\n",
  809. pwszFullPath,
  810. dwToken));
  811. bResult = TRUE;
  812. Done:
  813. if (!bResult) {
  814. if (pDynShimInfo) {
  815. if (pDynShimInfo->pwszFullPath) {
  816. RtlFreeHeap(RtlProcessHeap(), 0, pDynShimInfo->pwszFullPath);
  817. }
  818. RtlFreeHeap(RtlProcessHeap(), 0, pDynShimInfo);
  819. }
  820. }
  821. RtlLeaveCriticalSection(&g_csDynShimInfo);
  822. return bResult;
  823. }
  824. BOOL
  825. RemoveExeDynShimInfoFromList(
  826. IN LPCWSTR pwszFullPath
  827. )
  828. {
  829. BOOL bResult = FALSE;
  830. _pfn_SE_DynamicUnshim pfnDynamicUnshim = NULL;
  831. HMODULE hmodShimEngine = 0;
  832. PEXE_DYN_SHIM_INFO pDynShimInfo = NULL;
  833. PLIST_ENTRY pEntry, pTempEntry;
  834. PLIST_ENTRY pHead = &g_ExeDynShimInfoList;
  835. if (pwszFullPath == NULL) {
  836. return TRUE;
  837. }
  838. hmodShimEngine = LoadLibraryW(ShimEngine_ModuleName);
  839. if (hmodShimEngine == NULL) {
  840. DBGPRINT((sdlError,"RemoveExeDynShimInfoFromList",
  841. "Failed to get ShimEngine module handle.\n"));
  842. goto Done;
  843. }
  844. pfnDynamicUnshim = (_pfn_SE_DynamicUnshim) GetProcAddress(hmodShimEngine, DynamicUnshimProcedureName);
  845. if (NULL == pfnDynamicUnshim) {
  846. DBGPRINT((sdlError,
  847. "RemoveExeDynShimInfoFromList",
  848. "Failed to get Dynamic Shim procedure address from ShimEngine module.\n"));
  849. goto Done;
  850. }
  851. RtlEnterCriticalSection(&g_csDynShimInfo);
  852. pEntry = pHead->Flink;
  853. while (pEntry != pHead) {
  854. pDynShimInfo = CONTAINING_RECORD(pEntry, EXE_DYN_SHIM_INFO, entry);
  855. if (_wcsicmp(pDynShimInfo->pwszFullPath, pwszFullPath) == 0) {
  856. pTempEntry = pEntry->Flink;
  857. RemoveEntryList(pEntry);
  858. if (!(*pfnDynamicUnshim)(pDynShimInfo->dwToken)) {
  859. DBGPRINT((sdlInfo,"RemoveExeDynShimInfoFromList",
  860. "Unshimming %s(token: %d) failed\n",
  861. pwszFullPath,
  862. pDynShimInfo->dwToken));
  863. bResult = FALSE;
  864. break;
  865. }
  866. DBGPRINT((sdlInfo,"RemoveExeDynShimInfoFromList",
  867. "Removed %s(token: %d) from the list\n",
  868. pwszFullPath,
  869. pDynShimInfo->dwToken));
  870. RtlFreeHeap(RtlProcessHeap(), 0, pDynShimInfo->pwszFullPath);
  871. RtlFreeHeap(RtlProcessHeap(), 0, pDynShimInfo);
  872. bResult = TRUE;
  873. //
  874. // We need to remove all the entries for this exe so keep going.
  875. //
  876. pEntry = pTempEntry;
  877. } else {
  878. pEntry = pEntry->Flink;
  879. }
  880. }
  881. RtlLeaveCriticalSection(&g_csDynShimInfo);
  882. Done:
  883. return bResult;
  884. }
  885. BOOL
  886. ApphelpFixExe(
  887. IN HSDB hSDB,
  888. IN LPCWSTR pwszPath, // Unicode path to the executable (DOS_PATH)
  889. IN SDBQUERYRESULT* pQueryResult, // QueryResult
  890. IN BOOL bUseModuleName // if false, module name is not used for dynamic shimming
  891. )
  892. {
  893. static _pfn_SE_DynamicShim pfnDynamicShim = NULL;
  894. HMODULE hmodShimEngine = 0;
  895. BOOL bResult = FALSE;
  896. ANSI_STRING AnsiModuleName = { 0 };
  897. UNICODE_STRING UnicodeModuleName;
  898. NTSTATUS Status;
  899. LPCSTR pszModuleName = NULL;
  900. LPCWSTR pwszModuleName;
  901. DWORD dwDynamicToken = 0;
  902. //
  903. // Do we need to do anything?
  904. //
  905. if (pQueryResult->atrExes[0] == TAGREF_NULL &&
  906. pQueryResult->atrLayers[0] == TAGREF_NULL) {
  907. //
  908. // Nothing for the shim engine to do.
  909. //
  910. bResult = TRUE;
  911. goto Done;
  912. }
  913. //
  914. // Load additional shims for this exe.
  915. //
  916. DBGPRINT((sdlInfo,"ApphelpFixExe", "Loading ShimEngine for \"%s\"\n", pwszPath));
  917. hmodShimEngine = LoadLibraryW(ShimEngine_ModuleName);
  918. if (hmodShimEngine == NULL) {
  919. DBGPRINT((sdlError,"ApphelpFixExe", "Failed to get ShimEngine module handle.\n"));
  920. goto Done;
  921. }
  922. pfnDynamicShim = (_pfn_SE_DynamicShim) GetProcAddress(hmodShimEngine, DynamicShimProcedureName);
  923. if (NULL == pfnDynamicShim) {
  924. DBGPRINT((sdlError,
  925. "ApphelpFixExe",
  926. "Failed to get Dynamic Shim procedure address from ShimEngine module.\n"));
  927. goto Done;
  928. }
  929. //
  930. // check inclusion/exclusion list
  931. //
  932. if (pwszPath != NULL && bUseModuleName) {
  933. //
  934. // no inclusion/exclusion in the xml -- determine module name
  935. //
  936. pwszModuleName = wcsrchr(pwszPath, L'\\'); // last backslash please
  937. if (pwszModuleName == NULL) {
  938. pwszModuleName = pwszPath;
  939. } else {
  940. ++pwszModuleName;
  941. }
  942. //
  943. // convert to ansi
  944. //
  945. RtlInitUnicodeString(&UnicodeModuleName, pwszModuleName);
  946. Status = RtlUnicodeStringToAnsiString(&AnsiModuleName,
  947. &UnicodeModuleName,
  948. TRUE);
  949. if (!NT_SUCCESS(Status)) {
  950. DBGPRINT((sdlError, "ApphelpFixExe",
  951. "Failed to convert unicode string \"%s\" to ansi, Status 0x%lx.\n",
  952. pwszModuleName, Status));
  953. goto Done;
  954. }
  955. pszModuleName = AnsiModuleName.Buffer; // this will be allocated by RtlUnicodeStringToAnsiString
  956. }
  957. bResult = (*pfnDynamicShim)(pwszPath,
  958. hSDB,
  959. pQueryResult,
  960. pszModuleName,
  961. &dwDynamicToken);
  962. if (FALSE == bResult) {
  963. DBGPRINT((sdlError, "ApphelpFixExe", "Failed to call Dynamic Shim.\n"));
  964. goto Done;
  965. }
  966. if (pszModuleName == NULL) {
  967. if (!AddExeDynShimInfoToList(pwszPath, dwDynamicToken)) {
  968. DBGPRINT((sdlError, "ApphelpFixExe",
  969. "Failed to add %s(token: %d) to the list\n",
  970. pwszPath,
  971. dwDynamicToken));
  972. goto Done;
  973. }
  974. }
  975. bResult = TRUE;
  976. Done:
  977. RtlFreeAnsiString(&AnsiModuleName); // this will do nothing if string is empty
  978. return bResult;
  979. }
  980. BOOL
  981. ApphelpCheckExe(
  982. IN LPCWSTR pwszPath, // Unicode path to the executable (DOS_PATH)
  983. IN BOOL bAppHelpIfNecessary, // Only present AppHelp this executable if TRUE
  984. IN BOOL bShimIfNecessary, // Only load shim for this executable if TRUE
  985. IN BOOL bUseModuleName // use module name when inclusion/exclusion list is not provided
  986. )
  987. /*++
  988. Return: FALSE if the app should be blocked from running, TRUE otherwise.
  989. Desc: If you are calling this API with the last parameter set to FALSE and it returns
  990. TRUE, you'll have to call ApphelpReleaseExe when you are done running this exe.
  991. --*/
  992. {
  993. BOOL bRunApp = TRUE;
  994. SDBQUERYRESULT QueryResult;
  995. HSDB hSDB;
  996. if (IsAppcompatInfrastructureDisabled()) {
  997. goto Done;
  998. }
  999. RtlZeroMemory(&QueryResult, sizeof(QueryResult));
  1000. hSDB = SdbInitDatabaseEx(0, NULL, IMAGE_FILE_MACHINE_I386);
  1001. if (hSDB == NULL) {
  1002. DBGPRINT((sdlError, "ApphelpCheckExe", "Failed to initialize database.\n"));
  1003. goto Done;
  1004. }
  1005. bRunApp = ApphelpQueryExe(hSDB,
  1006. pwszPath,
  1007. bAppHelpIfNecessary,
  1008. SDBGMEF_IGNORE_ENVIRONMENT,
  1009. &QueryResult);
  1010. if (TRUE == bRunApp && TRUE == bShimIfNecessary) {
  1011. ApphelpFixExe(hSDB, pwszPath, &QueryResult, bUseModuleName);
  1012. }
  1013. SdbReleaseDatabase(hSDB);
  1014. Done:
  1015. return bRunApp;
  1016. }
  1017. BOOL
  1018. ApphelpReleaseExe(
  1019. IN LPCWSTR pwszPath // Unicode path to the executable (DOS_PATH)
  1020. )
  1021. {
  1022. return RemoveExeDynShimInfoFromList(pwszPath);
  1023. }
  1024. BOOL
  1025. ApphelpCheckIME(
  1026. IN LPCWSTR pwszPath // Unicode path to the exe
  1027. )
  1028. {
  1029. BOOL bRunApp = TRUE;
  1030. SDBQUERYRESULT QueryResult;
  1031. HSDB hSDB;
  1032. BOOL bCleanApp;
  1033. if (IsAppcompatInfrastructureDisabled()) {
  1034. return TRUE;
  1035. }
  1036. RtlZeroMemory(&QueryResult, sizeof(QueryResult));
  1037. hSDB = SdbInitDatabase(0, NULL);
  1038. if (hSDB == NULL) {
  1039. DBGPRINT((sdlError, "ApphelpCheckIME", "Failed to initialize database.\n"));
  1040. goto Done;
  1041. }
  1042. bRunApp = ApphelpQueryExe(hSDB,
  1043. pwszPath,
  1044. TRUE,
  1045. SDBGMEF_IGNORE_ENVIRONMENT,
  1046. &QueryResult);
  1047. if (TRUE == bRunApp) {
  1048. ApphelpFixExe(hSDB, pwszPath, &QueryResult, FALSE);
  1049. }
  1050. SdbReleaseDatabase(hSDB);
  1051. //
  1052. // see that it's in the cache if no fixes
  1053. //
  1054. bCleanApp = QueryResult.atrExes[0] == TAGREF_NULL &&
  1055. QueryResult.atrLayers[0] == TAGREF_NULL &&
  1056. QueryResult.trAppHelp == TAGREF_NULL &&
  1057. QueryResult.dwFlags == 0;
  1058. #ifndef WIN2K_NOCACHE
  1059. BaseUpdateAppcompatCache(pwszPath, INVALID_HANDLE_VALUE, !bCleanApp);
  1060. #endif
  1061. Done:
  1062. return bRunApp;
  1063. }
  1064. BOOL
  1065. ApphelpCheckShellObject(
  1066. IN REFCLSID ObjectCLSID,
  1067. IN BOOL bShimIfNecessary,
  1068. OUT ULONGLONG* pullFlags
  1069. )
  1070. /*++
  1071. Return: FALSE if the object should be blocked from instantiating, TRUE otherwise.
  1072. Desc: This is a helper function for Explorer and Internet Explorer that will
  1073. allow those applications to detect bad extension objects and either
  1074. block them from running or fix them.
  1075. pullFlags is filled with a 64-bit flag mask that can be used to turn
  1076. on 'hack' flags in Explorer/IE. These are pulled out of the App Compat
  1077. database.
  1078. If the database indicates that a shim should be used to fix the extension
  1079. and bShimIfNecessary is TRUE, this function will load SHIMENG.DLL and
  1080. apply the fix.
  1081. --*/
  1082. {
  1083. BOOL bGoodObject = TRUE;
  1084. LPWSTR szComServer = NULL;
  1085. LPWSTR szDLLName = NULL;
  1086. DWORD dwBufSize = 0;
  1087. DWORD dwReqBufSize = 0;
  1088. SDBQUERYRESULT QueryResult;
  1089. HSDB hSDB = NULL;
  1090. PVOID pModuleHandle = NULL;
  1091. UNICODE_STRING ustrDLLName = { 0 };
  1092. UNICODE_STRING ustrNtPath = { 0 };
  1093. NTSTATUS status;
  1094. HANDLE hDLL = INVALID_HANDLE_VALUE;
  1095. DWORD dwReason;
  1096. OBJECT_ATTRIBUTES ObjectAttributes;
  1097. IO_STATUS_BLOCK IoStatusBlock;
  1098. if (IsAppcompatInfrastructureDisabled()) {
  1099. return TRUE;
  1100. }
  1101. if (pullFlags != NULL) {
  1102. *pullFlags = 0;
  1103. }
  1104. szComServer = RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH);
  1105. if (szComServer == NULL) {
  1106. DBGPRINT((sdlInfo,"ApphelpCheckShellObject", "Memory allocation error\n"));
  1107. goto Done;
  1108. }
  1109. dwBufSize = MAX_PATH;
  1110. //
  1111. // Turn the CLSID into a filename (ie, the DLL that serves the object)
  1112. //
  1113. dwReqBufSize = ResolveCOMServer(ObjectCLSID, szComServer, dwBufSize);
  1114. if (dwReqBufSize == 0) {
  1115. //
  1116. // CLSID could not be resolved to a DLL.
  1117. //
  1118. goto Done;
  1119. }
  1120. if (dwReqBufSize > dwBufSize) {
  1121. RtlFreeHeap(RtlProcessHeap(), 0, szComServer);
  1122. szComServer = RtlAllocateHeap(RtlProcessHeap(), HEAP_ZERO_MEMORY, dwReqBufSize);
  1123. if (szComServer == NULL) {
  1124. DBGPRINT((sdlInfo,"ApphelpCheckShellObject", "Memory allocation error\n"));
  1125. goto Done;
  1126. }
  1127. dwBufSize = dwReqBufSize;
  1128. dwReqBufSize = ResolveCOMServer(ObjectCLSID, szComServer, dwBufSize);
  1129. if (dwReqBufSize > dwBufSize || dwReqBufSize == 0) {
  1130. //
  1131. // What? Buffer size changed. This could happen if registration of an
  1132. // object took place between the time we first queried and the next time.
  1133. // Just being paranoid...
  1134. //
  1135. DBGPRINT((sdlInfo,"ApphelpCheckShellObject", "Memory allocation error\n"));
  1136. goto Done;
  1137. }
  1138. }
  1139. //
  1140. // Determine DLL name (w/o path). Walk back to first backslash.
  1141. //
  1142. szDLLName = szComServer + dwReqBufSize/sizeof(WCHAR);
  1143. while (szDLLName >= szComServer) {
  1144. if (*szDLLName == L'\\') {
  1145. break;
  1146. }
  1147. szDLLName--;
  1148. }
  1149. szDLLName++;
  1150. //
  1151. // Check if this DLL is already loaded. If so, no need to try and do anything
  1152. // since it's really too late anyway.
  1153. //
  1154. RtlInitUnicodeString(&ustrDLLName, szDLLName);
  1155. status = LdrGetDllHandle(NULL,
  1156. NULL,
  1157. &ustrDLLName,
  1158. &pModuleHandle);
  1159. if (NT_SUCCESS(status)) {
  1160. //
  1161. // Already loaded.
  1162. //
  1163. goto Done;
  1164. }
  1165. if (!RtlDosPathNameToNtPathName_U(szComServer,
  1166. &ustrNtPath,
  1167. NULL,
  1168. NULL)) {
  1169. DBGPRINT((sdlError,
  1170. "ApphelpCheckShellObject",
  1171. "RtlDosPathNameToNtPathName_U failed, path \"%s\"\n",
  1172. szComServer));
  1173. goto Done;
  1174. }
  1175. InitializeObjectAttributes(&ObjectAttributes,
  1176. &ustrNtPath,
  1177. OBJ_CASE_INSENSITIVE,
  1178. NULL,
  1179. NULL);
  1180. status = NtCreateFile(&hDLL,
  1181. GENERIC_READ | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  1182. &ObjectAttributes,
  1183. &IoStatusBlock,
  1184. 0,
  1185. FILE_ATTRIBUTE_NORMAL,
  1186. FILE_SHARE_READ,
  1187. FILE_OPEN,
  1188. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  1189. NULL,
  1190. 0);
  1191. if (!NT_SUCCESS(status)) {
  1192. DBGPRINT((sdlError,
  1193. "ApphelpCheckShellObject",
  1194. "SdbpOpenFile failed, path \"%s\"\n",
  1195. szComServer));
  1196. goto Done;
  1197. }
  1198. if (BaseCheckAppcompatCache(ustrNtPath.Buffer, hDLL, NULL, &dwReason)) {
  1199. //
  1200. // We have this in cache
  1201. //
  1202. goto Done;
  1203. }
  1204. RtlZeroMemory(&QueryResult, sizeof(QueryResult));
  1205. hSDB = SdbInitDatabase(0, NULL);
  1206. if (hSDB == NULL) {
  1207. DBGPRINT((sdlError, "ApphelpCheckShellObject", "Failed to initialize database.\n"));
  1208. goto Done;
  1209. }
  1210. bGoodObject = ApphelpQueryExe(hSDB,
  1211. szComServer,
  1212. FALSE,
  1213. SDBGMEF_IGNORE_ENVIRONMENT,
  1214. &QueryResult);
  1215. if (TRUE == bGoodObject && TRUE == bShimIfNecessary) {
  1216. ApphelpFixExe(hSDB, szComServer, &QueryResult, FALSE);
  1217. }
  1218. SdbQueryFlagMask(hSDB, &QueryResult, TAG_FLAG_MASK_SHELL, pullFlags, NULL);
  1219. //
  1220. // we might want to use Apphelp api for this -- but shell does pass the right
  1221. // thing to us (most likely)
  1222. //
  1223. BaseUpdateAppcompatCache(ustrNtPath.Buffer,
  1224. hDLL,
  1225. !(QueryResult.atrExes[0] == TAGREF_NULL &&
  1226. QueryResult.atrLayers[0] == TAGREF_NULL));
  1227. Done:
  1228. RtlFreeUnicodeString(&ustrNtPath);
  1229. if (hSDB != NULL) {
  1230. SdbReleaseDatabase(hSDB);
  1231. }
  1232. if (hDLL != INVALID_HANDLE_VALUE) {
  1233. NtClose(hDLL);
  1234. }
  1235. if (szComServer != NULL) {
  1236. RtlFreeHeap(RtlProcessHeap(), 0, szComServer);
  1237. }
  1238. return bGoodObject;
  1239. }
  1240. BOOL
  1241. ApphelpGetNTVDMInfo(
  1242. IN LPCWSTR pwszPath, // path to the app in NT format
  1243. IN LPCWSTR pwszModule, // module name
  1244. IN LPCWSTR pEnvironment, // pointer to the environment of the task that is
  1245. // being created or NULL if we are to use the main NTVDM
  1246. // environment block.
  1247. OUT LPWSTR pszCompatLayer, // The new compat layer variable. with format:
  1248. // "Alpha Bravo Charlie" -- allow 256 chars for this.
  1249. OUT PNTVDM_FLAGS pFlags, // The flags
  1250. OUT PAPPHELP_INFO pAHInfo, // If there is apphelp to display, this will be filled
  1251. // in with non-null values
  1252. OUT HSDB* phSDB, // The handle to the database.
  1253. OUT PSDBQUERYRESULT pQueryResult // The query result.
  1254. )
  1255. /*++
  1256. Return: FALSE if the app should be blocked from running, TRUE otherwise.
  1257. Desc: This is essentially the equivalent of ApphelpCheckRunApp, but specific
  1258. to NTVDM.
  1259. --*/
  1260. {
  1261. DWORD dwReason = 0;
  1262. if (IsAppcompatInfrastructureDisabled()) {
  1263. return TRUE;
  1264. }
  1265. return InternalCheckRunApp(INVALID_HANDLE_VALUE, pwszPath, pEnvironment,
  1266. IMAGE_FILE_MACHINE_I386, &dwReason,
  1267. NULL, NULL, NULL, NULL, NULL, TRUE,
  1268. pwszModule, pszCompatLayer, pFlags, pAHInfo,
  1269. phSDB, pQueryResult);
  1270. }
  1271. void
  1272. GetExeNTVDMData(
  1273. IN HSDB hSDB, // the SDB context
  1274. IN PSDBQUERYRESULT psdbQuery, // the EXEs and LAYERs that are active
  1275. OUT WCHAR* pszCompatLayer, // The new compat layer variable. with format:
  1276. // "Alpha Bravo Charlie"
  1277. OUT PNTVDM_FLAGS pFlags // The flags
  1278. )
  1279. {
  1280. DWORD i;
  1281. ULARGE_INTEGER uliFlags;
  1282. LPVOID pFlagContext = NULL;
  1283. HRESULT hr;
  1284. ZeroMemory(pFlags, sizeof(NTVDM_FLAGS));
  1285. //
  1286. // Build the layer variable, and look for the two "special" layers
  1287. //
  1288. if (pszCompatLayer) {
  1289. pszCompatLayer[0] = 0;
  1290. for (i = 0; i < SDB_MAX_LAYERS && psdbQuery->atrLayers[i] != TAGREF_NULL; ++i) {
  1291. WCHAR* pszEnvVar;
  1292. //
  1293. // Get the environment var and tack it onto the full string
  1294. //
  1295. pszEnvVar = SdbGetLayerName(hSDB, psdbQuery->atrLayers[i]);
  1296. if (pszEnvVar) {
  1297. //
  1298. // check for one of the two "special" layers
  1299. //
  1300. if (_wcsicmp(pszEnvVar, L"640X480") == 0) {
  1301. //
  1302. // set the 640x480 flag -- found in base\mvdm\inc\wowcmpat.h
  1303. //
  1304. // NOTE: we don't have this flag yet -- waiting on WOW guys
  1305. }
  1306. if (_wcsicmp(pszEnvVar, L"256COLOR") == 0) {
  1307. //
  1308. // set the 256 color flag -- found in base\mvdm\inc\wowcmpat.h
  1309. //
  1310. pFlags->dwWOWCompatFlagsEx |= 0x00000002;
  1311. }
  1312. hr = StringCchCatW(pszCompatLayer, COMPATLAYERMAXLEN, pszEnvVar);
  1313. if (hr == S_OK) {
  1314. hr = StringCchCatW(pszCompatLayer, COMPATLAYERMAXLEN, L" ");
  1315. }
  1316. if (hr == STRSAFE_E_INSUFFICIENT_BUFFER) {
  1317. DBGPRINT((sdlError, "GetExeNTVDMData", "pszCompatLayer not big enough.\n"));
  1318. //
  1319. // If the buffer is not big enough, we just set it to an empty string -
  1320. // we don't want to fill in incomplete data.
  1321. //
  1322. pszCompatLayer[0] = 0;
  1323. break;
  1324. }
  1325. }
  1326. }
  1327. }
  1328. //
  1329. // Look for compat flags
  1330. //
  1331. SdbQueryFlagMask(hSDB, psdbQuery, TAG_FLAGS_NTVDM1, &uliFlags.QuadPart, &pFlagContext);
  1332. pFlags->dwWOWCompatFlags |= uliFlags.LowPart;
  1333. pFlags->dwWOWCompatFlagsEx |= uliFlags.HighPart;
  1334. SdbQueryFlagMask(hSDB, psdbQuery, TAG_FLAGS_NTVDM2, &uliFlags.QuadPart, &pFlagContext);
  1335. pFlags->dwUserWOWCompatFlags |= uliFlags.LowPart;
  1336. pFlags->dwWOWCompatFlags2 |= uliFlags.HighPart;
  1337. SdbQueryFlagMask(hSDB, psdbQuery, TAG_FLAGS_NTVDM3, &uliFlags.QuadPart, &pFlagContext);
  1338. pFlags->dwWOWCompatFlagsFE |= uliFlags.LowPart;
  1339. // High Part is unused for now.
  1340. // now pack command line parameters
  1341. SdbpPackCmdLineInfo(pFlagContext, &pFlags->pFlagsInfo);
  1342. SdbpFreeFlagInfoList(pFlagContext);
  1343. }
  1344. BOOL
  1345. ApphelpCheckRunApp(
  1346. IN HANDLE hFile, // [Optional] Handle to an open file to check
  1347. IN WCHAR* pwszPath, // path to the app in NT format
  1348. IN WCHAR* pEnvironment, // pointer to the environment of the process that is
  1349. // being created or NULL.
  1350. IN USHORT uExeType, // executable's image type
  1351. IN PDWORD pdwReason, // collection of flags hinting at why we were called
  1352. OUT PVOID* ppData, // this will contain the pointer to the allocated buffer
  1353. // containing the appcompat data.
  1354. OUT PDWORD pcbData, // if appcompat data is found, the size of the buffer
  1355. // is returned here.
  1356. OUT PVOID* ppSxsData, // BUGBUG: describe
  1357. OUT PDWORD pcbSxsData, // BUGBUG: describe
  1358. OUT PDWORD pdwFusionFlags
  1359. )
  1360. /*++
  1361. Return: FALSE if the app should be blocked from running, TRUE otherwise.
  1362. Desc: This is the main API of apphelp.dll. It is called from CreateProcess
  1363. to retrieve application compatibility information for the current process.
  1364. --*/
  1365. {
  1366. return InternalCheckRunApp(hFile, pwszPath, pEnvironment, uExeType, pdwReason,
  1367. ppData, pcbData, ppSxsData, pcbSxsData,pdwFusionFlags,
  1368. FALSE, NULL, NULL, NULL, NULL, NULL, NULL);
  1369. }
  1370. //
  1371. // =============================================================================================
  1372. // InstallShield 7 Support
  1373. // =============================================================================================
  1374. //
  1375. BOOL
  1376. ApphelpCheckInstallShieldPackage(
  1377. IN REFCLSID PackageID,
  1378. IN LPCWSTR lpszPackageFullPath
  1379. )
  1380. {
  1381. BOOL bPackageGood = TRUE; // This return value MUST TRUE otherwise InstallShield7 will cancel its processes.
  1382. TAGREF trExe = TAGREF_NULL;
  1383. DWORD dwNumExes = 0;
  1384. DWORD dwDataType = 0;
  1385. DWORD dwSize = 0;
  1386. DWORD dwReturn = 0;
  1387. BOOL bMatchFound = FALSE;
  1388. NTSTATUS Status;
  1389. BOOL bAppHelpIfNecessary = FALSE;
  1390. BOOL bResult = TRUE;
  1391. WCHAR wszCLSID[41];
  1392. WCHAR wszPackageCode[41];
  1393. GUID guidPackageID;
  1394. GUID guidPackageCode;
  1395. HSDB hSDB = NULL;
  1396. SDBQUERYRESULT QueryResult;
  1397. if (IsAppcompatInfrastructureDisabled()) {
  1398. goto Done;
  1399. }
  1400. if (NULL == lpszPackageFullPath) {
  1401. DBGPRINT((sdlInfo,
  1402. "ApphelpCheckInstallShieldPackage",
  1403. "lpszPackageFullPath is NULL\n"));
  1404. goto Done;
  1405. }
  1406. SdbGUIDToString((GUID *)&PackageID, wszCLSID, CHARCOUNT(wszCLSID));
  1407. DBGPRINT((sdlWarning,
  1408. "ApphelpCheckInstallShieldPackage",
  1409. "InstallShield package detected. CLSID: %s FullPath: %s\n",
  1410. wszCLSID, lpszPackageFullPath));
  1411. RtlZeroMemory(&QueryResult, sizeof(QueryResult));
  1412. hSDB = SdbInitDatabase(0, NULL);
  1413. if (hSDB == NULL) {
  1414. DBGPRINT((sdlError, "ApphelpCheckExe", "Failed to initialize database.\n"));
  1415. goto Done;
  1416. }
  1417. bMatchFound = ApphelpQueryExe(hSDB,
  1418. lpszPackageFullPath,
  1419. bAppHelpIfNecessary,
  1420. SDBGMEF_IGNORE_ENVIRONMENT,
  1421. &QueryResult);
  1422. if (!bMatchFound)
  1423. {
  1424. DBGPRINT((sdlError, "ApphelpCheckInstallShieldPackage", "No match found.\n"));
  1425. goto Done;
  1426. }
  1427. for (dwNumExes = 0; dwNumExes < SDB_MAX_EXES; ++dwNumExes)
  1428. {
  1429. if (TAGREF_NULL == QueryResult.atrExes[dwNumExes]) {
  1430. break;
  1431. }
  1432. trExe = QueryResult.atrExes[dwNumExes];
  1433. DBGPRINT((sdlInfo, "ApphelpCheckInstallShieldPackage", "Processing TAGREF atrExes[%d] = 0x%8x.\n", dwNumExes, trExe));
  1434. dwSize = sizeof(wszPackageCode);
  1435. *wszPackageCode = L'\0';
  1436. dwReturn = SdbQueryData( hSDB,
  1437. trExe,
  1438. L"PackageCode",
  1439. &dwDataType,
  1440. wszPackageCode,
  1441. &dwSize);
  1442. if (dwReturn == ERROR_SUCCESS)
  1443. {
  1444. DBGPRINT((sdlInfo, "ApphelpCheckInstallShieldPackage", "SdbQueryData returns dwSize = %d and dwDataType = %d.\n", dwSize, dwDataType));
  1445. if ((dwSize > 0) && (dwSize < sizeof(wszPackageCode)))
  1446. {
  1447. // we have some data
  1448. // check the type (should be string)
  1449. if (REG_SZ != dwDataType)
  1450. {
  1451. DBGPRINT((sdlError, "ApphelpCheckInstallShieldPackage", "SdbQueryData returns non STRING PackageCode data. Exiting.\n"));
  1452. goto Done;
  1453. }
  1454. DBGPRINT((sdlInfo, "ApphelpCheckInstallShieldPackage", "Comparing PackageId = %s and PackageCode = %s.\n", wszCLSID, wszPackageCode));
  1455. // convert to guid
  1456. if (FALSE == SdbGUIDFromString(wszPackageCode, &guidPackageCode))
  1457. {
  1458. DBGPRINT((sdlError, "ApphelpCheckInstallShieldPackage", "Can not convert PackageCode to GUID. Exiting.\n"));
  1459. goto Done;
  1460. }
  1461. if (RtlEqualMemory(PackageID, &guidPackageCode, sizeof(guidPackageCode) ))
  1462. {
  1463. DBGPRINT((sdlWarning, "ApphelpCheckInstallShieldPackage",
  1464. "Found InstallShield package matched with PackageCode: %s.\n",
  1465. wszPackageCode));
  1466. if (TRUE != ApphelpFixExe(hSDB, lpszPackageFullPath, &QueryResult, FALSE))
  1467. {
  1468. DBGPRINT((sdlError, "ApphelpCheckInstallShieldPackage", "Can not load additional shim dynamically for this executable.\n"));
  1469. }
  1470. goto Done;
  1471. }
  1472. }
  1473. }
  1474. } // for
  1475. DBGPRINT((sdlError, "ApphelpCheckInstallShieldPackage", "No match found.\n"));
  1476. Done:
  1477. if (hSDB != NULL) {
  1478. SdbReleaseDatabase(hSDB);
  1479. }
  1480. return bPackageGood;
  1481. }
  1482. //
  1483. // =============================================================================================
  1484. // MSI Support
  1485. // =============================================================================================
  1486. //
  1487. BOOL
  1488. SDBAPI
  1489. ApphelpCheckMsiPackage(
  1490. IN GUID* pguidDB, // database id
  1491. IN GUID* pguidID, // match id
  1492. IN DWORD dwFlags, // not used now, set to 0
  1493. IN BOOL bNoUI
  1494. )
  1495. {
  1496. WCHAR szDatabasePath[MAX_PATH];
  1497. DWORD dwDatabaseType = 0;
  1498. DWORD dwPackageFlags = 0;
  1499. DWORD dwLength;
  1500. BOOL bInstallPackage = TRUE;
  1501. HSDB hSDB = NULL;
  1502. TAGREF trPackage = TAGREF_NULL;
  1503. HAPPHELPINFOCONTEXT hApphelpInfoContext = NULL;
  1504. DWORD dwSeverity = 0;
  1505. if (IsAppcompatInfrastructureDisabled()) {
  1506. goto out;
  1507. }
  1508. hSDB = SdbInitDatabase(HID_NO_DATABASE, NULL);
  1509. if (hSDB == NULL) {
  1510. DBGPRINT((sdlError, "ApphelpCheckMsiPackage",
  1511. "Failed to initialize database\n"));
  1512. goto out;
  1513. }
  1514. SdbSetImageType(hSDB, IMAGE_FILE_MSI);
  1515. //
  1516. // First, we need to resolve a db
  1517. //
  1518. dwLength = SdbResolveDatabase(hSDB,
  1519. pguidDB,
  1520. &dwDatabaseType,
  1521. szDatabasePath,
  1522. CHARCOUNT(szDatabasePath));
  1523. if (dwLength == 0 || dwLength > CHARCOUNT(szDatabasePath)) {
  1524. DBGPRINT((sdlError, "ApphelpCheckMsiPackage",
  1525. "Failed to resolve database path\n"));
  1526. goto out;
  1527. }
  1528. //
  1529. // open database
  1530. //
  1531. if (!SdbOpenLocalDatabase(hSDB, szDatabasePath)) {
  1532. DBGPRINT((sdlError, "ApphelpCheckMsiPackage",
  1533. "Failed to open database \"%s\"\n", szDatabasePath));
  1534. goto out;
  1535. }
  1536. //
  1537. // find the entry
  1538. //
  1539. trPackage = SdbFindMsiPackageByID(hSDB, pguidID);
  1540. if (trPackage == TAGREF_NULL) {
  1541. DBGPRINT((sdlError, "ApphelpCheckMsiPackage",
  1542. "Failed to find msi package by guid id\n"));
  1543. goto out;
  1544. }
  1545. hApphelpInfoContext = SdbOpenApphelpInformationByID(hSDB,
  1546. trPackage,
  1547. dwDatabaseType);
  1548. if (hApphelpInfoContext == NULL) {
  1549. DBGPRINT((sdlInfo, "ApphelpCheckMsiPackage",
  1550. "Apphelp information has not been found\n"));
  1551. goto out;
  1552. }
  1553. //
  1554. // we have apphelp data, check to see if we have flags for this exe
  1555. //
  1556. if (!SdbGetEntryFlags(pguidID, &dwPackageFlags)) {
  1557. DBGPRINT((sdlWarning, "ApphelpCheckMsiPackage",
  1558. "No flags for trPackage 0x%x\n", trPackage));
  1559. dwPackageFlags = 0;
  1560. }
  1561. //
  1562. // Check whether the disable bit is set (the dwFlags has been retrieved from the
  1563. // registry via the SdbReadApphelpData call)
  1564. //
  1565. if (dwPackageFlags & SHIMREG_DISABLE_APPHELP) {
  1566. goto out;
  1567. }
  1568. bNoUI |= !!(dwPackageFlags & SHIMREG_APPHELP_NOUI);
  1569. if (bNoUI) {
  1570. DBGPRINT((sdlInfo, "ApphelpCheckMsiPackage",
  1571. "NoUI flag is set, apphelp UI disabled for this app.\n"));
  1572. }
  1573. SdbQueryApphelpInformation(hApphelpInfoContext,
  1574. ApphelpProblemSeverity,
  1575. &dwSeverity,
  1576. sizeof(dwSeverity));
  1577. //
  1578. // depending on severity of the problem...
  1579. //
  1580. switch (dwSeverity) {
  1581. case APPHELP_MINORPROBLEM:
  1582. case APPHELP_HARDBLOCK:
  1583. case APPHELP_NOBLOCK:
  1584. case APPHELP_REINSTALL:
  1585. //
  1586. //
  1587. //
  1588. bInstallPackage = (APPHELP_HARDBLOCK != dwSeverity);
  1589. if (!bNoUI) {
  1590. DWORD dwRet;
  1591. APPHELP_INFO AHInfo = { 0 };
  1592. AHInfo.guidDB = *pguidDB;
  1593. AHInfo.bMSI = TRUE;
  1594. SdbQueryApphelpInformation(hApphelpInfoContext,
  1595. ApphelpExeTagID,
  1596. &AHInfo.tiExe,
  1597. sizeof(AHInfo.tiExe));
  1598. if (AHInfo.tiExe != TAGID_NULL) {
  1599. AHInfo.bOfflineContent = bDebugChum();
  1600. SdbShowApphelpDialog(&AHInfo, NULL, &bInstallPackage);
  1601. // either we succeeded or bInstall package is treated
  1602. // the same way as No UI
  1603. }
  1604. }
  1605. break;
  1606. default:
  1607. //
  1608. // Some other case was found (e.g. VERSIONSUB which should be replaced
  1609. // by shims in most cases).
  1610. //
  1611. DBGPRINT((sdlInfo, "ApphelpCheckMsiPackage",
  1612. "Unhandled severity flag 0x%x.\n", dwSeverity));
  1613. break;
  1614. }
  1615. //
  1616. // at this point we know whether we want to install the package or not
  1617. //
  1618. out:
  1619. if (hApphelpInfoContext != NULL) {
  1620. SdbCloseApphelpInformation(hApphelpInfoContext);
  1621. }
  1622. if (hSDB != NULL) {
  1623. SdbReleaseDatabase(hSDB);
  1624. }
  1625. return bInstallPackage;
  1626. }
  1627. BOOL
  1628. SDBAPI
  1629. ApphelpFixMsiPackage(
  1630. IN GUID* pguidDB,
  1631. IN GUID* pguidID,
  1632. IN LPCWSTR pszFileName,
  1633. IN LPCWSTR pszActionName,
  1634. IN DWORD dwFlags
  1635. )
  1636. {
  1637. WCHAR szDatabasePath[MAX_PATH];
  1638. DWORD dwDatabaseType = 0;
  1639. HSDB hSDB = NULL;
  1640. TAGREF trPackage = TAGREF_NULL;
  1641. TAGREF trAction = TAGREF_NULL;
  1642. SDBQUERYRESULT QueryResult;
  1643. BOOL bSuccess = FALSE;
  1644. DWORD dwLength;
  1645. TAGREF trLayer, trLayerRef;
  1646. DWORD dwLayers = 0;
  1647. if (IsAppcompatInfrastructureDisabled()) {
  1648. bSuccess = TRUE;
  1649. goto out;
  1650. }
  1651. //
  1652. // open database. In this case we need to have the default database
  1653. // for this platform being opened, later on we modify the context
  1654. // Fixes will be looked up in a default main db though
  1655. //
  1656. hSDB = SdbInitDatabase(0, NULL);
  1657. if (hSDB == NULL) {
  1658. DBGPRINT((sdlError, "ApphelpCheckMsiPackage",
  1659. "Failed to initialize database\n"));
  1660. goto out;
  1661. }
  1662. SdbSetImageType(hSDB, IMAGE_FILE_MSI);
  1663. //
  1664. // from this point on, all resolutions will be based on msi image type
  1665. // however all the fixes will come from the database that is standard for
  1666. // this platform
  1667. //
  1668. //
  1669. // First, we need to resolve a db
  1670. //
  1671. dwLength = SdbResolveDatabase(hSDB,
  1672. pguidDB,
  1673. &dwDatabaseType,
  1674. szDatabasePath,
  1675. CHARCOUNT(szDatabasePath));
  1676. if (dwLength == 0 || dwLength > CHARCOUNT(szDatabasePath)) {
  1677. DBGPRINT((sdlError, "ApphelpCheckMsiPackage",
  1678. "Failed to resolve database path\n"));
  1679. goto out;
  1680. }
  1681. //
  1682. // open database
  1683. //
  1684. if (!SdbOpenLocalDatabase(hSDB, szDatabasePath)) {
  1685. DBGPRINT((sdlError, "ApphelpCheckMsiPackage",
  1686. "Failed to open database \"%s\"\n", szDatabasePath));
  1687. goto out;
  1688. }
  1689. //
  1690. // find the entry
  1691. //
  1692. trPackage = SdbFindMsiPackageByID(hSDB, pguidID);
  1693. if (trPackage == TAGREF_NULL) {
  1694. DBGPRINT((sdlError, "ApphelpCheckMsiPackage",
  1695. "Failed to find msi package by guid id\n"));
  1696. goto out;
  1697. }
  1698. if (SdbGetEntryFlags(pguidID, &dwFlags) && (dwFlags & SHIMREG_DISABLE_SHIM)) {
  1699. DBGPRINT((sdlInfo, "ApphelpCheckMsiPackage",
  1700. "Shims for this package are disabled\n"));
  1701. goto out;
  1702. }
  1703. trAction = SdbFindCustomActionForPackage(hSDB, trPackage, pszActionName);
  1704. if (trAction == TAGREF_NULL) {
  1705. DBGPRINT((sdlInfo, "ApphelpCheckMsiPackage",
  1706. "Failed to find custom action \"%s\"\n", pszActionName));
  1707. goto out;
  1708. }
  1709. //
  1710. // we have custom action on our hands which appears to have fixes
  1711. // attached to it, shim it!
  1712. //
  1713. RtlZeroMemory(&QueryResult, sizeof(QueryResult));
  1714. QueryResult.guidID = *pguidID;
  1715. QueryResult.atrExes[0] = trAction;
  1716. //
  1717. // get all the layers for this entry
  1718. // also remember that tthe layers and shims alike might not be in the default
  1719. // database initialized in the beginning of this call
  1720. //
  1721. trLayerRef = SdbFindFirstTagRef(hSDB, trAction, TAG_LAYER);
  1722. while (trLayerRef != TAGREF_NULL && dwLayers < SDB_MAX_LAYERS) {
  1723. trLayer = SdbGetNamedLayer(hSDB, trLayerRef);
  1724. if (trLayer != TAGREF_NULL) {
  1725. QueryResult.atrLayers[dwLayers++] = trLayer;
  1726. }
  1727. trLayerRef = SdbFindNextTagRef(hSDB, trAction, trLayerRef);
  1728. }
  1729. //
  1730. // ready to shim
  1731. //
  1732. bSuccess = ApphelpFixExe(hSDB, pszFileName, &QueryResult, TRUE);
  1733. if (bSuccess) {
  1734. DBGPRINT((sdlInfo, "ApphelpFixMsiPackage",
  1735. "Custom action \"%s\" successfully shimmed file \"%s\"\n",
  1736. pszActionName, pszFileName));
  1737. }
  1738. out:
  1739. if (hSDB != NULL) {
  1740. SdbReleaseDatabase(hSDB);
  1741. }
  1742. return(bSuccess);
  1743. }
  1744. BOOL
  1745. SDBAPI
  1746. ApphelpFixMsiPackageExe(
  1747. IN GUID* pguidDB,
  1748. IN GUID* pguidID,
  1749. IN LPCWSTR pszActionName,
  1750. IN OUT LPWSTR pwszEnv,
  1751. IN OUT LPDWORD pdwBufferSize
  1752. )
  1753. {
  1754. WCHAR szDatabasePath[MAX_PATH];
  1755. DWORD dwDatabaseType = 0;
  1756. HSDB hSDB = NULL;
  1757. TAGREF trPackage = TAGREF_NULL;
  1758. TAGREF trAction = TAGREF_NULL;
  1759. SDBQUERYRESULT QueryResult;
  1760. DWORD dwLength;
  1761. DWORD dwBufferSize;
  1762. BOOL bSuccess = FALSE;
  1763. DWORD dwFlags;
  1764. int i;
  1765. TAGREF trLayer;
  1766. if (pwszEnv != NULL) {
  1767. *pwszEnv = TEXT('\0');
  1768. }
  1769. if (IsAppcompatInfrastructureDisabled()) {
  1770. goto out;
  1771. }
  1772. hSDB = SdbInitDatabaseEx(HID_NO_DATABASE, NULL, IMAGE_FILE_MSI);
  1773. if (hSDB == NULL) {
  1774. DBGPRINT((sdlError, "ApphelpCheckMsiPackage",
  1775. "Failed to initialize database\n"));
  1776. goto out;
  1777. }
  1778. //
  1779. // First, we need to resolve a db
  1780. //
  1781. dwLength = SdbResolveDatabase(hSDB,
  1782. pguidDB,
  1783. &dwDatabaseType,
  1784. szDatabasePath,
  1785. CHARCOUNT(szDatabasePath));
  1786. if (dwLength == 0 || dwLength > CHARCOUNT(szDatabasePath)) {
  1787. DBGPRINT((sdlError, "ApphelpCheckMsiPackage",
  1788. "Failed to resolve database path\n"));
  1789. goto out;
  1790. }
  1791. //
  1792. // open database
  1793. //
  1794. if (!SdbOpenLocalDatabase(hSDB, szDatabasePath)) {
  1795. DBGPRINT((sdlError, "ApphelpCheckMsiPackage",
  1796. "Failed to open database \"%s\"\n", szDatabasePath));
  1797. goto out;
  1798. }
  1799. //
  1800. // find the entry
  1801. //
  1802. trPackage = SdbFindMsiPackageByID(hSDB, pguidID);
  1803. if (trPackage == TAGREF_NULL) {
  1804. DBGPRINT((sdlError, "ApphelpCheckMsiPackage",
  1805. "Failed to find msi package by guid id\n"));
  1806. goto out;
  1807. }
  1808. if (SdbGetEntryFlags(pguidID, &dwFlags) && (dwFlags & SHIMREG_DISABLE_SHIM)) {
  1809. DBGPRINT((sdlInfo, "ApphelpCheckMsiPackage",
  1810. "Shims for this package are disabled\n"));
  1811. goto out;
  1812. }
  1813. trAction = SdbFindCustomActionForPackage(hSDB, trPackage, pszActionName);
  1814. if (trAction == TAGREF_NULL) {
  1815. DBGPRINT((sdlInfo, "ApphelpCheckMsiPackage",
  1816. "Failed to find custom action \"%s\"\n", pszActionName));
  1817. goto out;
  1818. }
  1819. //
  1820. // now -- this action is an exe, do it right for him
  1821. //
  1822. RtlZeroMemory(&QueryResult, sizeof(QueryResult));
  1823. QueryResult.guidID = *pguidID;
  1824. for (i = 0; i < SDB_MAX_LAYERS; ++i) {
  1825. //
  1826. // check to see if we are doing the first layer, if so - call
  1827. // find first to obtain the layer, else find the next applicable layer
  1828. //
  1829. if (i == 0) {
  1830. trLayer = SdbFindFirstTagRef(hSDB, trAction, TAG_LAYER);
  1831. } else {
  1832. trLayer = SdbFindNextTagRef (hSDB, trAction, trLayer);
  1833. }
  1834. if (trLayer == TAGREF_NULL) {
  1835. break;
  1836. }
  1837. QueryResult.atrLayers[i] = trLayer;
  1838. }
  1839. dwLength = 0;
  1840. if (pdwBufferSize != NULL) {
  1841. dwLength = *pdwBufferSize;
  1842. }
  1843. //
  1844. // build compat layer
  1845. //
  1846. dwBufferSize = SdbBuildCompatEnvVariables(hSDB,
  1847. &QueryResult,
  1848. 0,
  1849. NULL,
  1850. pwszEnv,
  1851. dwLength,
  1852. NULL);
  1853. if (pdwBufferSize != NULL) {
  1854. *pdwBufferSize = dwBufferSize;
  1855. }
  1856. bSuccess = TRUE;
  1857. out:
  1858. if (hSDB != NULL) {
  1859. SdbReleaseDatabase(hSDB);
  1860. }
  1861. return bSuccess;
  1862. }
  1863. /*++
  1864. Function:
  1865. CheckAppcompatInfrastructureFlags
  1866. Description:
  1867. Checks various registry places for infrastructure global flags (just the disabled bit for now)
  1868. The flags are set into the global variable gdwInfrastructureFlags. Function is used via the macro
  1869. for perf reasons
  1870. Return:
  1871. global infrastructure flags
  1872. --*/
  1873. DWORD
  1874. CheckAppcompatInfrastructureFlags(
  1875. VOID
  1876. )
  1877. {
  1878. gdwInfrastructureFlags = 0; // initialize just in case
  1879. if (BaseIsAppcompatInfrastructureDisabled()) {
  1880. gdwInfrastructureFlags |= APPCOMPAT_INFRA_DISABLED;
  1881. }
  1882. //
  1883. // make the bits valid
  1884. //
  1885. gdwInfrastructureFlags |= APPCOMPAT_INFRA_VALID_FLAG;
  1886. return gdwInfrastructureFlags;
  1887. }
  1888. /*++
  1889. Function:
  1890. SdbInitDatabaseExport
  1891. Description:
  1892. This is "exported" version of the function SdbInitDatabase
  1893. that checks for the "diabled" flag -- otherwise calls into SdbInitDatabase
  1894. Return:
  1895. see SdbInitDatabase
  1896. --*/
  1897. HSDB
  1898. SDBAPI
  1899. SdbInitDatabaseExport(
  1900. IN DWORD dwFlags, // flags that tell how the database should be
  1901. // initialized.
  1902. IN LPCWSTR pszDatabasePath // the OPTIONAL full path to the database to
  1903. // be used.
  1904. )
  1905. {
  1906. if (IsAppcompatInfrastructureDisabled()) {
  1907. return NULL;
  1908. }
  1909. return SdbInitDatabase(dwFlags, pszDatabasePath);
  1910. }