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.

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