1 /*
2  * PROJECT:     apphelp_apitest
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     Tests showing shim artifacts in the environment
5  * COPYRIGHT:   Copyright 2016,2017 Mark Jansen (mark.jansen@reactos.org)
6  */
7 
8 #include <ntstatus.h>
9 #define WIN32_NO_STATUS
10 #include <windows.h>
11 #include <shlwapi.h>
12 #include <winnt.h>
13 #include <userenv.h>
14 #ifdef __REACTOS__
15 #include <ntndk.h>
16 #else
17 #include <winternl.h>
18 #endif
19 #include <winerror.h>
20 #include <stdio.h>
21 
22 #include "wine/test.h"
23 
24 #include "apphelp_apitest.h"
25 
26 typedef void* HSDB;
27 typedef void* PDB;
28 typedef DWORD TAGREF;
29 typedef WORD TAG;
30 
31 
32 
33 static HMODULE hdll;
34 
35 BOOL(WINAPI *pSdbGetMatchingExe)(HSDB hsdb, LPCWSTR szPath, LPCWSTR szModuleName, LPCWSTR pszEnvironment, DWORD dwFlags, PSDBQUERYRESULT_VISTA pQueryResult);
36 HSDB (WINAPI *pSdbInitDatabase)(DWORD dwFlags, LPCWSTR pszDatabasePath);
37 void (WINAPI *pSdbReleaseDatabase)(HSDB hsdb);
38 BOOL (WINAPI *pSdbTagRefToTagID)(HSDB hsdb, TAGREF trWhich, PDB* ppdb, TAGID* ptiWhich);
39 TAG (WINAPI *pSdbGetTagFromTagID)(PDB pdb, TAGID tiWhich);
40 TAGREF (WINAPI *pSdbGetLayerTagRef)(HSDB hsdb, LPCWSTR layerName);
41 
42 
43 /* TODO: Investigate ApphelpCheckRunApp, for some reason there is not AppCompatData generated... */
44 
45 BOOL (WINAPI *pApphelpCheckRunAppEx_w7)(HANDLE FileHandle, PVOID Unk1, PVOID Unk2, PWCHAR ApplicationName, PVOID Environment, USHORT ExeType, PULONG Reason,
46                                    PVOID* SdbQueryAppCompatData, PULONG SdbQueryAppCompatDataSize, PVOID* SxsData, PULONG SxsDataSize,
47                                    PULONG FusionFlags, PULONG64 SomeFlag1, PULONG SomeFlag2);
48 
49 BOOL (WINAPI *pApphelpCheckRunAppEx_w10)(HANDLE FileHandle, PVOID Unk1, PVOID Unk2, PWCHAR ApplicationName, PVOID Environment, PVOID Unk3, USHORT ExeType, PULONG Reason,
50                                         PVOID* SdbQueryAppCompatData, PULONG SdbQueryAppCompatDataSize, PVOID* SxsData, PULONG SxsDataSize,
51                                         PULONG FusionFlags, PULONG64 SomeFlag1, PULONG SomeFlag2);
52 
53 
54 BOOL (WINAPI *pSdbPackAppCompatData)(HSDB hsdb, PSDBQUERYRESULT_VISTA pQueryResult, PVOID* ppData, DWORD *dwSize);
55 BOOL (WINAPI *pSdbUnpackAppCompatData)(HSDB hsdb, LPCWSTR pszImageName, PVOID pData, PSDBQUERYRESULT_VISTA pQueryResult);
56 DWORD (WINAPI *pSdbGetAppCompatDataSize)(PVOID pData);
57 
58 
59 static HSDB g_LayerDB;
60 static DWORD g_ShimDataSize;
61 static DWORD g_ModuleVersion;
62 static const SDBQUERYRESULT_VISTA empty_result = { { 0 } };
63 static const SDBQUERYRESULT_VISTA almost_empty = { { 0 }, { 0 }, { 0 }, 0, 0, 0, 0, { 0 }, SHIMREG_DISABLE_LAYER, 0 };
64 
65 
66 #define SHIMDATA_MAGIC  0xAC0DEDAB
67 #define MAX_LAYER_LENGTH            256
68 
69 
70 typedef struct ShimData_Win2k3
71 {
72     WCHAR szModule[34];
73     DWORD dwSize;
74     DWORD dwMagic;
75 
76     TAGREF atrExes[SDB_MAX_EXES_2k3];
77     TAGREF atrLayers[SDB_MAX_LAYERS];
78     DWORD dwUnk0;
79     DWORD dwUnk1;
80     DWORD dwCustomSDBMap;
81     GUID rgGuidDB[SDB_MAX_SDBS];
82 } ShimData_Win2k3;
83 
84 
85 
86 typedef struct ShimData_Win7
87 {
88     WCHAR szModule[260];
89     DWORD dwSize;
90     DWORD dwMagic;
91     SDBQUERYRESULT_VISTA Query;
92     WCHAR szLayer[MAX_LAYER_LENGTH];
93     DWORD unknown;  // 0x14c
94 } ShimData_Win7;
95 
96 typedef struct ShimData_Win10_v1
97 {
98     WCHAR szModule[260];
99     DWORD dwSize;
100     DWORD dwMagic;
101     DWORD unk1;
102     SDBQUERYRESULT_VISTA Query;
103     WCHAR szLayer[MAX_LAYER_LENGTH];
104     char padding1[0x200];
105     char padding2[0x404];   // Contains some data at the start
106     DWORD unk2;
107     DWORD unk3;
108     WCHAR processname[MAX_PATH];
109     WCHAR szLayerEnv[MAX_LAYER_LENGTH];
110     WCHAR unk4[MAX_LAYER_LENGTH];
111     char padding4[120];
112 } ShimData_Win10_v1;
113 
114 typedef struct ShimData_Win10_v2
115 {
116     DWORD dwSize;
117     DWORD dwMagic;
118     DWORD unk1;
119     DWORD unk2;
120     SDBQUERYRESULT_VISTA Query;
121     WCHAR szLayer[MAX_LAYER_LENGTH];
122     char padding1[0x200];
123     char padding2[0x2ae + 0x54 + 0x2a + 0x16 + 0x16];
124     DWORD unk3;
125     DWORD unk4;
126     WCHAR processname[MAX_PATH-2];
127     WCHAR szLayerEnv[MAX_LAYER_LENGTH];
128     WCHAR unk5[MAX_LAYER_LENGTH];
129     char padding4[76];
130 } ShimData_Win10_v2;
131 
132 typedef struct ShimData_QueryOffset
133 {
134     DWORD dwSize_10_v2;
135     DWORD dwMagic_10_v2;
136 
137     char spacing1[60];
138 
139     DWORD dwSize_2k3;
140     DWORD dwMagic_2k3;
141 
142     char spacing2[444];
143 
144     DWORD dwSize_7_10;
145     DWORD dwMagic_7_10;
146 } ShimData_QueryOffset;
147 
148 
149 C_ASSERT(sizeof(ShimData_Win2k3) == 392);
150 C_ASSERT(sizeof(ShimData_Win7) == 1500);
151 C_ASSERT(sizeof(ShimData_Win10_v1) == 4712);
152 C_ASSERT(sizeof(ShimData_Win10_v2) == 3976);
153 
154 C_ASSERT(offsetof(ShimData_Win10_v2, dwSize) == 0);
155 C_ASSERT(offsetof(ShimData_Win2k3, dwSize) == 68);
156 C_ASSERT(offsetof(ShimData_Win7, dwSize) == 520);
157 C_ASSERT(offsetof(ShimData_Win10_v1, dwSize) == 520);
158 
159 C_ASSERT(offsetof(ShimData_Win10_v2, dwMagic) == 4);
160 C_ASSERT(offsetof(ShimData_Win2k3, dwMagic) == 72);
161 C_ASSERT(offsetof(ShimData_Win7, dwMagic) == 524);
162 C_ASSERT(offsetof(ShimData_Win10_v1, dwMagic) == 524);
163 
164 C_ASSERT(offsetof(ShimData_QueryOffset, dwSize_10_v2) == 0);
165 C_ASSERT(offsetof(ShimData_QueryOffset, dwSize_2k3) == 68);
166 C_ASSERT(offsetof(ShimData_QueryOffset, dwSize_7_10) == 520);
167 
168 C_ASSERT(offsetof(ShimData_QueryOffset, dwMagic_10_v2) == 4);
169 C_ASSERT(offsetof(ShimData_QueryOffset, dwMagic_2k3) == 72);
170 C_ASSERT(offsetof(ShimData_QueryOffset, dwMagic_7_10) == 524);
171 
172 
173 
174 #define SDB_DATABASE_MAIN_SHIM  0x80030000
175 
176 #define SDBGMEF_IGNORE_ENVIRONMENT 0x1
177 
178 
179 typedef struct test_RemoteShimInfo
180 {
181     ULARGE_INTEGER AppCompatFlags;
182     ULARGE_INTEGER AppCompatFlagsUser;
183     PVOID pShimData;
184     DWORD ShimDataSize;
185     PVOID AppCompatInfo;
186 } test_RemoteShimInfo;
187 
188 
189 static BOOL readproc(HANDLE proc, LPVOID address, PVOID target, DWORD size)
190 {
191     SIZE_T dwRead;
192     if (ReadProcessMemory(proc, address, target, size, &dwRead))
193     {
194         ok(dwRead == size, "Expected to read %u bytes, got %lu\n", size, dwRead);
195         return dwRead == size;
196     }
197     ok(0, "RPM failed with %u\n", GetLastError());
198     return FALSE;
199 }
200 
201 static BOOL get_shiminfo(HANDLE proc, test_RemoteShimInfo* info)
202 {
203     PROCESS_BASIC_INFORMATION pbi = { 0 };
204     ULONG sizeOut = 0;
205     NTSTATUS status = NtQueryInformationProcess(proc, ProcessBasicInformation, &pbi, sizeof(pbi), &sizeOut);
206     ok(NT_SUCCESS(status), "Expected NtQI to succeed, but failed with: %x\n", status);
207     memset(info, 0, sizeof(*info));
208     if (NT_SUCCESS(status))
209     {
210         PEB peb = { 0 };
211         if (readproc(proc, pbi.PebBaseAddress, &peb, sizeof(peb)))
212         {
213             MEMORY_BASIC_INFORMATION mbi = { 0 };
214             SIZE_T dwRead;
215 
216             info->AppCompatFlags = peb.AppCompatFlags;
217             info->AppCompatFlagsUser = peb.AppCompatFlagsUser;
218             info->AppCompatInfo = peb.AppCompatInfo;
219             if (peb.pShimData == NULL)
220                 return TRUE;
221 
222             dwRead = VirtualQueryEx(proc, (LPCVOID)peb.pShimData, &mbi, sizeof(mbi));
223             ok(dwRead == sizeof(mbi), "Expected VQE to return %u, got %lu\n", sizeof(mbi), dwRead);
224             if (dwRead == sizeof(mbi) || peb.pShimData == NULL)
225             {
226                 info->ShimDataSize = mbi.RegionSize;
227                 info->pShimData = malloc(mbi.RegionSize);
228                 if (readproc(proc, peb.pShimData, info->pShimData, mbi.RegionSize))
229                     return TRUE;
230                 free(info->pShimData);
231                 info->pShimData = NULL;
232             }
233         }
234     }
235     return FALSE;
236 }
237 
238 static HANDLE create_proc(BOOL suspended)
239 {
240     static char proc_name[MAX_PATH] = { 0 };
241     STARTUPINFOA si = {sizeof(si)};
242     PROCESS_INFORMATION pi;
243     BOOL res;
244     if (!proc_name[0])
245     {
246         GetModuleFileNameA(NULL, proc_name, MAX_PATH);
247     }
248 
249     res = CreateProcessA(NULL, proc_name, NULL, NULL, TRUE, suspended ? CREATE_SUSPENDED : 0, NULL, NULL, &si, &pi);
250     if (!res)
251         return NULL;
252     CloseHandle(pi.hThread);
253     return pi.hProcess;
254 }
255 
256 static void create_environ(const char* layers[], size_t num)
257 {
258     char buf[256] = { 0 };
259     size_t n;
260     for (n = 0; n < num; ++n)
261     {
262         if (n)
263             strcat(buf, " ");
264         strcat(buf, layers[n]);
265     }
266     SetEnvironmentVariableA("__COMPAT_LAYER", buf);
267 }
268 
269 static void ValidateShim(TAGREF trLayer, const char* name)
270 {
271     HSDB hsdb = pSdbInitDatabase(SDB_DATABASE_MAIN_SHIM, NULL);
272     ok(hsdb != NULL, "Expected a valid handle\n");
273     if (hsdb)
274     {
275         PDB pdb = NULL;
276         TAGID tagid = 0xdeadbeef;
277         WCHAR nameW[256] = { 0 };
278         BOOL ret;
279 
280         mbstowcs(nameW, name, strlen(name));
281 
282         ret = pSdbTagRefToTagID(hsdb, trLayer, &pdb, &tagid);
283         ok(ret == TRUE, "Expected pSdbTagRefToTagID to succeed\n");
284         if (ret)
285         {
286             TAG tag;
287             ok(pdb != NULL, "Expected pdb to be a valid pointer\n");
288             ok(tagid != 0 && tagid != 0xdeadbeef, "Expected tagid to be a valid tag id, was: 0x%x\n", tagid);
289             tag = pSdbGetTagFromTagID(pdb, tagid);
290             ok(tag == 0x700b, "Expected tag to be 0x700b, was 0x%x\n", (DWORD)tag);
291         }
292 
293         pSdbReleaseDatabase(hsdb);
294     }
295 }
296 
297 
298 static void Validate_ShimData_Win2k3(PVOID data, size_t count, const char* layers[])
299 {
300     //size_t n;
301     ShimData_Win2k3* pShimData = (ShimData_Win2k3*)data;
302 
303     ok(!lstrcmpW(pShimData->szModule, L"ShimEng.dll"), "Expected pShimData->Module to be %s, was %s\n", wine_dbgstr_w(L"ShimEng.dll"), wine_dbgstr_w(pShimData->szModule));
304     ok(pShimData->dwMagic == SHIMDATA_MAGIC, "Expected pShimData->dwMagic to be 0x%x, was 0x%x\n", SHIMDATA_MAGIC, pShimData->dwMagic);
305     ok(pShimData->dwSize == sizeof(ShimData_Win2k3), "Expected pShimData->dwSize to be %u, was %u\n", sizeof(ShimData_Win2k3), pShimData->dwSize);
306     ok(pShimData->dwCustomSDBMap == 1, "Expected pShimData->dwCustomSDBMap to be 1, was %u\n", pShimData->dwCustomSDBMap);
307 }
308 
309 static void Validate_ShimData_Win7(PVOID data, WCHAR szApphelp[256], size_t count, const char* layers[])
310 {
311     size_t n;
312     ShimData_Win7* pShimData = (ShimData_Win7*)data;
313 
314     ok(!lstrcmpW(pShimData->szModule, szApphelp), "Expected pShimData->Module to be %s, was %s\n",
315         wine_dbgstr_w(szApphelp), wine_dbgstr_w(pShimData->szModule));
316     ok(pShimData->dwMagic == SHIMDATA_MAGIC, "Expected pShimData->dwMagic to be 0x%x, was 0x%x\n",
317         SHIMDATA_MAGIC, pShimData->dwMagic);
318     ok(pShimData->dwSize == sizeof(ShimData_Win7), "Expected pShimData->dwSize to be %u, was %u\n",
319         sizeof(ShimData_Win7), pShimData->dwSize);
320     if (pShimData->Query.dwLayerCount != min(count, SDB_MAX_LAYERS))
321     {
322         char buf[250] = {0};
323         GetEnvironmentVariableA("__COMPAT_LAYER", buf, _countof(buf));
324         trace("At test: %s\n", buf);
325     }
326     ok(pShimData->Query.dwLayerCount == min(count, SDB_MAX_LAYERS),
327         "Expected LayerCount to be %u, was %u\n", min(count, SDB_MAX_LAYERS), pShimData->Query.dwLayerCount);
328     for (n = 0; n < SDB_MAX_LAYERS; ++n)
329     {
330         if (n < count)
331         {
332             ok(pShimData->Query.atrLayers[n] != 0, "Expected to find a valid layer in index %u / %u\n", n, count);
333             ValidateShim(pShimData->Query.atrLayers[n], layers[n]);
334         }
335         else
336             ok(pShimData->Query.atrLayers[n] == 0, "Expected to find an empty layer in index %u / %u\n", n, count);
337     }
338     ok(pShimData->unknown == 0x14c, "Expected pShimData->unknown to be 0x14c, was 0x%x\n", pShimData->unknown);
339 }
340 
341 static void Validate_ShimData_Win10_v2(PVOID data, WCHAR szApphelp[256], size_t count, const char* layers[])
342 {
343     size_t n;
344     ShimData_Win10_v2* pShimData = (ShimData_Win10_v2*)data;
345 
346     if (pShimData->dwMagic != SHIMDATA_MAGIC)
347     {
348         skip("Yet another unknown shimdata variant...\n");
349         return;
350     }
351 
352     ok(pShimData->dwSize == sizeof(ShimData_Win10_v2), "Expected pShimData->dwSize to be %u, was %u\n",
353        sizeof(ShimData_Win10_v2), pShimData->dwSize);
354     if (pShimData->Query.dwLayerCount != min(count, SDB_MAX_LAYERS))
355     {
356         char buf[250] = {0};
357         GetEnvironmentVariableA("__COMPAT_LAYER", buf, _countof(buf));
358         trace("At test: %s\n", buf);
359     }
360     ok(pShimData->Query.dwLayerCount == min(count, SDB_MAX_LAYERS),
361        "Expected LayerCount to be %u, was %u\n", min(count, SDB_MAX_LAYERS), pShimData->Query.dwLayerCount);
362     for (n = 0; n < SDB_MAX_LAYERS; ++n)
363     {
364         if (n < count)
365         {
366             ok(pShimData->Query.atrLayers[n] != 0, "Expected to find a valid layer in index %u / %u\n", n, count);
367             ValidateShim(pShimData->Query.atrLayers[n], layers[n]);
368         }
369         else
370             ok(pShimData->Query.atrLayers[n] == 0, "Expected to find an empty layer in index %u / %u\n", n, count);
371     }
372 
373 }
374 
375 static void Validate_ShimData_Win10(PVOID data, WCHAR szApphelp[256], size_t count, const char* layers[])
376 {
377     size_t n;
378     ShimData_Win10_v1* pShimData = (ShimData_Win10_v1*)data;
379 
380     if (pShimData->dwMagic != SHIMDATA_MAGIC)
381     {
382         Validate_ShimData_Win10_v2(data, szApphelp, count, layers);
383         return;
384     }
385 
386 
387     ok(!lstrcmpiW(pShimData->szModule, szApphelp), "Expected pShimData->Module to be %s, was %s\n",
388         wine_dbgstr_w(szApphelp), wine_dbgstr_w(pShimData->szModule));
389     ok(pShimData->dwSize == sizeof(ShimData_Win10_v1), "Expected pShimData->dwSize to be %u, was %u\n",
390         sizeof(ShimData_Win10_v1), pShimData->dwSize);
391     if (pShimData->Query.dwLayerCount != min(count, SDB_MAX_LAYERS))
392     {
393         char buf[250] = {0};
394         GetEnvironmentVariableA("__COMPAT_LAYER", buf, _countof(buf));
395         trace("At test: %s\n", buf);
396     }
397     ok(pShimData->Query.dwLayerCount == min(count, SDB_MAX_LAYERS),
398         "Expected LayerCount to be %u, was %u\n", min(count, SDB_MAX_LAYERS), pShimData->Query.dwLayerCount);
399     for (n = 0; n < SDB_MAX_LAYERS; ++n)
400     {
401         if (n < count)
402         {
403             ok(pShimData->Query.atrLayers[n] != 0, "Expected to find a valid layer in index %u / %u\n", n, count);
404             ValidateShim(pShimData->Query.atrLayers[n], layers[n]);
405         }
406         else
407             ok(pShimData->Query.atrLayers[n] == 0, "Expected to find an empty layer in index %u / %u\n", n, count);
408     }
409 }
410 
411 static void Validate_EmptyShimData_Win10(PVOID data)
412 {
413     ShimData_Win10_v1* pShimData = (ShimData_Win10_v1*)data;
414     ok(pShimData != NULL, "Expected pShimData\n");
415     if (!pShimData)
416         return;
417 
418     if (pShimData->dwMagic != SHIMDATA_MAGIC)
419     {
420         ShimData_Win10_v2* pShimData2 = (ShimData_Win10_v2*)data;
421         if (pShimData2->dwMagic != SHIMDATA_MAGIC)
422         {
423             skip("Unknown shimdata (win10)\n");
424             return;
425         }
426 
427         ok(!lstrcmpiW(pShimData2->szLayer, L""), "Expected pShimData->szLayer to be '', was %s\n", wine_dbgstr_w(pShimData2->szLayer));
428         ok(pShimData2->dwSize == sizeof(ShimData_Win10_v2), "Expected pShimData->dwSize to be %u, was %u\n", sizeof(ShimData_Win10_v2), pShimData2->dwSize);
429         ok(!memcmp(&pShimData2->Query, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
430     }
431     else
432     {
433         ok(!lstrcmpiW(pShimData->szModule, L""), "Expected pShimData->Module to be '', was %s\n", wine_dbgstr_w(pShimData->szModule));
434         ok(!lstrcmpiW(pShimData->szLayer, L""), "Expected pShimData->szLayer to be '', was %s\n", wine_dbgstr_w(pShimData->szLayer));
435         ok(pShimData->dwSize == sizeof(ShimData_Win10_v1), "Expected pShimData->dwSize to be %u, was %u\n", sizeof(ShimData_Win10_v1), pShimData->dwSize);
436         ok(!memcmp(&pShimData->Query, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
437     }
438 }
439 
440 static void Test_layers(WCHAR szApphelp[256])
441 {
442     static const char* layers[] = {
443         "256Color", "NT4SP5", "DisableNXHideUI", "DisableNXShowUI",
444         "WIN2000SP3", "640X480", /*"DISABLEDWM",*/ "HIGHDPIAWARE",
445         /*"RUNASADMIN",*/ "DISABLETHEMES" /*, "Layer_Win95VersionLie"*/ };
446 
447     size_t n;
448     HANDLE proc;
449     test_RemoteShimInfo info;
450     BOOL res;
451 
452     for (n = 0; n <= (sizeof(layers) / sizeof(layers[0])); ++n)
453     {
454         create_environ(layers, n);
455 
456         proc = create_proc(TRUE);
457         res = get_shiminfo(proc, &info);
458         TerminateProcess(proc, 0);
459         CloseHandle(proc);
460 
461         if (!res)
462         {
463             ok(0, "Unable to get process info (%u)!\n", n);
464             continue;
465         }
466 
467         if (n == 0)
468         {
469             ok(info.AppCompatFlags.QuadPart == 0, "Expected AppCompatFlags to be 0, was: %s\n", wine_dbgstr_longlong(info.AppCompatFlags.QuadPart));
470             ok(info.AppCompatFlagsUser.QuadPart == 0, "Expected AppCompatFlagsUser to be 0, was: %s\n", wine_dbgstr_longlong(info.AppCompatFlagsUser.QuadPart));
471             ok(info.AppCompatInfo == NULL, "Expected AppCompatInfo to be NULL, was: %p\n", info.AppCompatInfo);
472             if (g_WinVersion < WINVER_WIN10)
473             {
474                 ok(info.pShimData == NULL, "Expected pShimData to be NULL, was: %p\n", info.pShimData);
475             }
476             else
477             {
478                 Validate_EmptyShimData_Win10(info.pShimData);
479             }
480         }
481         else
482         {
483             ok(info.AppCompatFlags.QuadPart == 0, "Expected AppCompatFlags to be 0, was: %s\n", wine_dbgstr_longlong(info.AppCompatFlags.QuadPart));
484             ok(info.AppCompatFlagsUser.QuadPart == 0, "Expected AppCompatFlagsUser to be 0, was: %s\n", wine_dbgstr_longlong(info.AppCompatFlagsUser.QuadPart));
485             ok(info.AppCompatInfo == NULL, "Expected AppCompatInfo to be NULL, was: %p\n", info.AppCompatInfo);
486             ok(info.pShimData != NULL, "Expected pShimData to be valid, was NULL\n");
487             ok(info.ShimDataSize == g_ShimDataSize, "Expected ShimDataSize to be %u, was: %u\n", g_ShimDataSize, info.ShimDataSize);
488             if (info.pShimData)
489             {
490                 if (g_WinVersion < WINVER_VISTA)
491                     Validate_ShimData_Win2k3(info.pShimData, n, layers);
492                 else if (g_WinVersion < WINVER_WIN10)
493                     Validate_ShimData_Win7(info.pShimData, szApphelp, n, layers);
494                 else
495                     Validate_ShimData_Win10(info.pShimData, szApphelp, n, layers);
496             }
497         }
498         free(info.pShimData);
499     }
500 }
501 
502 
503 /*
504 [Warn][SdbGetMatchingExe   ] __COMPAT_LAYER name cannot exceed 256 characters.
505 [Info][SdbpGetPermLayersInternal] Failed to read value info from Key "\Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers" Status 0xc0000034
506 [Info][SdbpGetPermLayersInternal] Failed to read value info from Key "\REGISTRY\USER\S-1-5-21-4051718696-421402927-393408651-2638\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers" Status 0xc0000034
507 [Warn][SdbpEnumUserSdb     ] Failed to open key "\Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Custom\NotepadReplacer.exe" Status 0xc0000034
508 */
509 static void Test_repeatlayer(WCHAR szApphelp[256])
510 {
511     static const char* layers[] = {
512         "256Color", "256Color", "256Color", "256Color",
513         "256Color", "256Color", "256Color", "256Color" };
514 
515     HANDLE proc;
516     test_RemoteShimInfo info;
517     BOOL res;
518 
519     SetEnvironmentVariableA("__COMPAT_LAYER", "256Color 256Color 256Color 256Color 256Color 256Color 256Color 256Color");
520 
521 
522     proc = create_proc(TRUE);
523     res = get_shiminfo(proc, &info);
524     TerminateProcess(proc, 0);
525     CloseHandle(proc);
526 
527     if (res)
528     {
529         ok(info.AppCompatFlags.QuadPart == 0, "Expected AppCompatFlags to be 0, was: %s\n", wine_dbgstr_longlong(info.AppCompatFlags.QuadPart));
530         ok(info.AppCompatFlagsUser.QuadPart == 0, "Expected AppCompatFlagsUser to be 0, was: %s\n", wine_dbgstr_longlong(info.AppCompatFlagsUser.QuadPart));
531         ok(info.AppCompatInfo == 0, "Expected AppCompatInfo to be 0, was: %p\n", info.AppCompatInfo);
532         ok(info.pShimData != NULL, "Expected pShimData to be valid, was NULL\n");
533         ok(info.ShimDataSize == g_ShimDataSize, "Expected ShimDataSize to be %u, was: %u\n", g_ShimDataSize, info.ShimDataSize);
534         if (info.pShimData)
535         {
536             /* Win10 only 'loads' one layer */
537             if (g_WinVersion < WINVER_VISTA)
538                 Validate_ShimData_Win2k3(info.pShimData, SDB_MAX_LAYERS, layers);
539             else if (g_WinVersion < WINVER_WIN10)
540                 Validate_ShimData_Win7(info.pShimData, szApphelp, SDB_MAX_LAYERS, layers);
541             else
542                 Validate_ShimData_Win10(info.pShimData, szApphelp, 1, layers);
543         }
544     }
545     else
546     {
547         ok(0, "Unable to get process info!\n");
548     }
549 
550 }
551 
552 
553 TAGREF find_layer(const char* szLayerStart, const char* szLayerEnd)
554 {
555     char layer[100] = { 0 };
556     WCHAR layerW[100] = { 0 };
557     strncpy(layer, szLayerStart, szLayerEnd - szLayerStart);
558 
559     if (!g_LayerDB)
560     {
561         g_LayerDB = pSdbInitDatabase(SDB_DATABASE_MAIN_SHIM, 0);
562     }
563 
564     mbstowcs(layerW, layer, strlen(layer));
565     return pSdbGetLayerTagRef(g_LayerDB, layerW);
566 }
567 
568 static void expect_layeronly_imp(SDBQUERYRESULT_VISTA* result, const char* layers, DWORD flags)
569 {
570     DWORD dwLayerCount = 0, n;
571     TAGREF atrLayers[SDB_MAX_LAYERS] = { 0 };
572 
573     const char* layer = layers, *nextlayer;
574     while (layer && *layer)
575     {
576         nextlayer = strchr(layer, ' ');
577         atrLayers[dwLayerCount++] = find_layer(layer, nextlayer ? nextlayer : (layer + strlen(layer)));
578         layer = nextlayer ? (nextlayer+1) : NULL;
579     }
580 
581     if (g_ModuleVersion < WINVER_VISTA)
582     {
583         SDBQUERYRESULT_2k3* result2 = (SDBQUERYRESULT_2k3*)result;
584         result = NULL;
585 
586         winetest_ok(!memcmp(&result2->atrExes, &empty_result.atrExes, sizeof(result2->atrExes)), "Expected atrExes to be empty\n");
587         winetest_ok(!memcmp(&result2->atrLayers[dwLayerCount], &empty_result.atrLayers[dwLayerCount], sizeof(result2->atrLayers) - dwLayerCount * sizeof(result2->atrLayers[0])), "Expected atrLayers[+1] to be empty\n");
588         for (n = 0; n < dwLayerCount; ++n)
589         {
590             winetest_ok(result2->atrLayers[n] == atrLayers[n], "Expected atrLayers[%u] to be %x, was %x\n",
591                 n, atrLayers[n], result2->atrLayers[n]);
592         }
593         winetest_ok(result2->dwLayerFlags == 0, "Expected dwLayerFlags to be 0, was %u\n", result2->dwLayerFlags);
594         winetest_ok(result2->trApphelp == 0, "Expected trApphelp to be 0, was %u\n", result2->trApphelp);
595         winetest_ok(result2->dwExeCount == 0, "Expected dwExeCount to be 0, was %u\n", result2->dwExeCount);
596         winetest_ok(result2->dwLayerCount == dwLayerCount, "Expected dwLayerCount to be %u, was %u\n", dwLayerCount, result2->dwLayerCount);
597         winetest_ok(!memcmp(&result2->guidID, &empty_result.guidID, sizeof(result2->guidID)), "Expected guidID to be empty\n");
598         winetest_ok(result2->dwFlags == flags, "Expected dwFlags to be 0x%x, was 0x%x\n", flags, result2->dwFlags);
599         winetest_ok(result2->dwCustomSDBMap == 1, "Expected dwCustomSDBMap to be 1, was %u\n", result2->dwCustomSDBMap);
600         winetest_ok(!memcmp(&result2->rgGuidDB[1], &empty_result.rgGuidDB[1], sizeof(result2->rgGuidDB) - sizeof(result2->rgGuidDB[0])), "Expected rgGuidDB[+1] to be empty\n");
601     }
602     else
603     {
604         winetest_ok(!memcmp(&result->atrExes, &empty_result.atrExes, sizeof(empty_result.atrExes)), "Expected atrExes to be empty\n");
605         winetest_ok(!memcmp(&result->adwExeFlags, &empty_result.adwExeFlags, sizeof(empty_result.adwExeFlags)), "Expected adwExeFlags to be empty\n");
606         winetest_ok(!memcmp(&result->atrLayers[dwLayerCount], &empty_result.atrLayers[dwLayerCount], sizeof(empty_result.atrLayers) - dwLayerCount * sizeof(empty_result.atrLayers[0])), "Expected atrLayers[+1] to be empty\n");
607         for (n = 0; n < dwLayerCount; ++n)
608         {
609             winetest_ok(result->atrLayers[n] == atrLayers[n], "Expected atrLayers[%u] to be %x, was %x\n",
610                 n, atrLayers[n], result->atrLayers[n]);
611         }
612         winetest_ok(result->dwLayerFlags == 0, "Expected dwLayerFlags to be 0, was %u\n", result->dwLayerFlags);
613         winetest_ok(result->trApphelp == 0, "Expected trApphelp to be 0, was %u\n", result->trApphelp);
614         winetest_ok(result->dwExeCount == 0, "Expected dwExeCount to be 0, was %u\n", result->dwExeCount);
615         winetest_ok(result->dwLayerCount == dwLayerCount, "Expected dwLayerCount to be %u, was %u\n", dwLayerCount, result->dwLayerCount);
616         winetest_ok(!memcmp(&result->guidID, &empty_result.guidID, sizeof(empty_result.guidID)), "Expected guidID to be empty\n");
617         winetest_ok(result->dwFlags == flags, "Expected dwFlags to be 0x%x, was 0x%x\n", flags, result->dwFlags);
618         winetest_ok(result->dwCustomSDBMap == 1, "Expected dwCustomSDBMap to be 1, was %u\n", result->dwCustomSDBMap);
619         winetest_ok(!memcmp(&result->rgGuidDB[1], &empty_result.rgGuidDB[1], sizeof(empty_result.rgGuidDB) - sizeof(empty_result.rgGuidDB[0])), "Expected rgGuidDB[+1] to be empty\n");
620     }
621 }
622 
623 static void Test_Shimdata(SDBQUERYRESULT_VISTA* result, const WCHAR* szLayer)
624 {
625     BOOL ret;
626     PVOID pData;
627     DWORD dwSize;
628 
629     pData = NULL;
630     dwSize = 0;
631     ret = pSdbPackAppCompatData(g_LayerDB, result, &pData, &dwSize);
632     ok(ret == TRUE, "Expected ret to be TRUE\n");
633 
634     if (pData)
635     {
636         ShimData_Win2k3* pWin2k3;
637         ShimData_Win7* pWin7;
638         ShimData_Win10_v1* pWin10;
639         ShimData_Win10_v2* pWin10_v2;
640         SDBQUERYRESULT_VISTA result2 = { { 0 } };
641 
642         DWORD res = pSdbGetAppCompatDataSize(pData);
643         ok_int(dwSize, res);
644         switch(dwSize)
645         {
646         case sizeof(ShimData_Win2k3):
647             pWin2k3 = (ShimData_Win2k3*)pData;
648             ok_hex(pWin2k3->dwMagic, SHIMDATA_MAGIC);
649             ok_int(pWin2k3->dwSize, dwSize);
650             ok(pWin2k3->dwCustomSDBMap == 1, "Expected pWin2k3->dwCustomSDBMap to equal 1, was %u for %s\n", pWin2k3->dwCustomSDBMap, wine_dbgstr_w(szLayer));
651             //ok(!memcmp(&pWin2k3->Query, result, sizeof(SDBQUERYRESULT_2k3)), "Expected pWin2k3->Query to equal result\n");
652             //ok_wstr(pWin7->szLayer, szLayer);
653             break;
654         case sizeof(ShimData_Win7):
655             pWin7 = (ShimData_Win7*)pData;
656             ok_hex(pWin7->dwMagic, SHIMDATA_MAGIC);
657             ok_int(pWin7->dwSize, dwSize);
658             ok(!memcmp(&pWin7->Query, result, sizeof(*result)), "Expected pWin7->Query to equal result\n");
659             ok_wstr(pWin7->szLayer, szLayer);
660             break;
661         case sizeof(ShimData_Win10_v1):
662             pWin10 = (ShimData_Win10_v1*)pData;
663             ok_hex(pWin10->dwMagic, SHIMDATA_MAGIC);
664             ok_int(pWin10->dwSize, dwSize);
665             ok(!memcmp(&pWin10->Query, result, sizeof(*result)), "Expected pWin10->Query to equal result\n");
666             ok_wstr(pWin10->szLayerEnv, szLayer);
667             ok_wstr(pWin10->szLayer, L"");
668             break;
669         case sizeof(ShimData_Win10_v2):
670             pWin10_v2 = (ShimData_Win10_v2*)pData;
671             ok_hex(pWin10_v2->dwMagic, SHIMDATA_MAGIC);
672             ok_int(pWin10_v2->dwSize, dwSize);
673             ok(!memcmp(&pWin10_v2->Query, result, sizeof(*result)), "Expected pWin10->Query to equal result\n");
674             ok_wstr(pWin10_v2->szLayerEnv, szLayer);
675             ok_wstr(pWin10_v2->szLayer, L"");
676             break;
677         default:
678             skip("Unknown size %d\n", dwSize);
679             break;
680         }
681 
682         ret = pSdbUnpackAppCompatData(g_LayerDB, NULL, pData, &result2);
683         ok(ret == TRUE, "Expected ret to be TRUE\n");
684         /* TODO: For some reason 2k3 does not seem to output the database GUIDs,
685             investigate when we have support for multible db's! */
686         if (dwSize == sizeof(ShimData_Win2k3))
687         {
688             SDBQUERYRESULT_2k3* input = (SDBQUERYRESULT_2k3*)result;
689             SDBQUERYRESULT_2k3* output = (SDBQUERYRESULT_2k3*)&result2;
690             const GUID rgGuidDB0 = {0x11111111, 0x1111, 0x1111, {0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}};
691 
692             // Check expected data.
693             ok(input->dwLayerCount == 1,
694                "Expected input->dwLayerCount to be 1, was %u for %s\n",
695                input->dwLayerCount, wine_dbgstr_w(szLayer));
696             ok(input->dwCustomSDBMap == 1,
697                "Expected input->dwCustomSDBMap to be 1, was %u for %s\n",
698                input->dwCustomSDBMap, wine_dbgstr_w(szLayer));
699             ok(IsEqualGUID(&input->rgGuidDB[0], &rgGuidDB0),
700                "Expected input->rgGuidDB[0] to be %s, was %s for %s\n",
701                wine_dbgstr_guid(&rgGuidDB0), wine_dbgstr_guid(&input->rgGuidDB[0]), wine_dbgstr_w(szLayer));
702 
703             // Check missing data.
704             ok(output->dwLayerCount == 0,
705                "Expected output->dwLayerCount to be 0, was %u for %s\n",
706                output->dwLayerCount, wine_dbgstr_w(szLayer));
707             ok(output->dwCustomSDBMap == 0,
708                "Expected output->dwCustomSDBMap to be 0, was %u for %s\n",
709                output->dwCustomSDBMap, wine_dbgstr_w(szLayer));
710             ok(IsEqualGUID(&output->rgGuidDB[0], &empty_result.rgGuidDB[0]),
711                "Expected output->rgGuidDB[0] to be empty, was %s for %s\n",
712                wine_dbgstr_guid(&output->rgGuidDB[0]), wine_dbgstr_w(szLayer));
713 
714             // Fake it for now, so the memcmp works.
715             output->dwLayerCount = input->dwLayerCount;
716             output->dwCustomSDBMap = input->dwCustomSDBMap;
717             output->rgGuidDB[0] = input->rgGuidDB[0];
718         }
719         ok(!memcmp(&result2, result, sizeof(*result)), "Expected result2 to equal result for %s\n", wine_dbgstr_w(szLayer));
720 
721         RtlFreeHeap(GetProcessHeap(), 0, pData);
722     }
723 }
724 
725 
726 #define expect_layeronly    (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_layeronly_imp
727 
728 
729 static void Test_GetMatchingExe(void)
730 {
731     BOOL ret;
732     SDBQUERYRESULT_VISTA result = { { 0 } };
733     WCHAR self[MAX_PATH];
734     DWORD flags = (g_WinVersion < WINVER_VISTA) ? 0 : ((g_WinVersion < WINVER_WIN10) ? 1 : 0x21);
735 
736     GetModuleFileNameW(NULL, self, MAX_PATH);
737     SetEnvironmentVariableA("__COMPAT_LAYER", NULL);
738 
739     /* szPath cannot be NULL! */
740     ret = pSdbGetMatchingExe(NULL, L"", NULL, NULL, 0, &result);
741     ok(ret == FALSE, "Expected ret to be FALSE\n");
742     ok(!memcmp(&result, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
743 
744     result = empty_result;
745 
746     ret = pSdbGetMatchingExe(NULL, self, NULL, NULL, 0, &result);
747     ok(ret == FALSE, "Expected ret to be FALSE\n");
748     ok(!memcmp(&result, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
749 
750     result = empty_result;
751     SetEnvironmentVariableA("__COMPAT_LAYER", "Some_invalid_layer_name");
752 
753     ret = pSdbGetMatchingExe(NULL, self, NULL, NULL, 0, &result);
754     ok(ret == FALSE, "Expected ret to be FALSE\n");
755     if (g_WinVersion < WINVER_WIN10)
756         ok(!memcmp(&result, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
757     else
758         ok(!memcmp(&result, &almost_empty, sizeof(almost_empty)), "Expected result to be almost empty\n");
759 
760     result = empty_result;
761     SetEnvironmentVariableA("__COMPAT_LAYER", "256Color");
762 
763     ret = pSdbGetMatchingExe(NULL, self, NULL, NULL, 0, &result);
764     ok(ret == TRUE, "Expected ret to be TRUE\n");
765     expect_layeronly(&result, "256Color", flags);
766 
767     Test_Shimdata(&result, L"256Color");
768 
769     result = empty_result;
770     SetEnvironmentVariableA("__COMPAT_LAYER", "640X480");
771 
772     ret = pSdbGetMatchingExe(NULL, self, NULL, NULL, 0, &result);
773     ok(ret == TRUE, "Expected ret to be TRUE\n");
774     expect_layeronly(&result, "640X480", flags);
775 
776     Test_Shimdata(&result, L"640X480");
777 
778     /* HIGHDPIAWARE does not exist in 2k3 */
779     if (g_WinVersion > WINVER_2003)
780     {
781         result = empty_result;
782         SetEnvironmentVariableA("__COMPAT_LAYER", "HIGHDPIAWARE");
783 
784         ret = pSdbGetMatchingExe(NULL, self, NULL, NULL, 0, &result);
785         ok(ret == TRUE, "Expected ret to be TRUE\n");
786         expect_layeronly(&result, "HIGHDPIAWARE", flags);
787 
788         Test_Shimdata(&result, L"HIGHDPIAWARE");
789 
790         result = empty_result;
791         SetEnvironmentVariableA("__COMPAT_LAYER", "256Color HIGHDPIAWARE   640X480");
792 
793         ret = pSdbGetMatchingExe(NULL, self, NULL, NULL, 0, &result);
794         ok(ret == TRUE, "Expected ret to be TRUE\n");
795         expect_layeronly(&result, "256Color HIGHDPIAWARE 640X480", flags);
796 
797         Test_Shimdata(&result, L"256Color HIGHDPIAWARE   640X480");
798     }
799 }
800 
801 
802 HANDLE xOpenFile(WCHAR* ApplicationName)
803 {
804     UNICODE_STRING FileName;
805     OBJECT_ATTRIBUTES ObjectAttributes;
806     IO_STATUS_BLOCK IoStatusBlock;
807     NTSTATUS Status;
808     HANDLE FileHandle;
809 
810     if (!RtlDosPathNameToNtPathName_U(ApplicationName, &FileName, NULL, NULL))
811     {
812         skip("Unable to translate %s to Nt path\n", wine_dbgstr_w(ApplicationName));
813         return NULL;
814     }
815 
816 
817     InitializeObjectAttributes(&ObjectAttributes, &FileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
818     Status = NtOpenFile(&FileHandle,
819                         SYNCHRONIZE |
820                         FILE_READ_ATTRIBUTES |
821                         FILE_READ_DATA |
822                         FILE_EXECUTE,
823                         &ObjectAttributes,
824                         &IoStatusBlock,
825                         FILE_SHARE_READ | FILE_SHARE_DELETE,
826                         FILE_SYNCHRONOUS_IO_NONALERT |
827                         FILE_NON_DIRECTORY_FILE);
828 
829     RtlFreeUnicodeString(&FileName);
830 
831     if (!NT_SUCCESS(Status))
832         return NULL;
833 
834     return FileHandle;
835 }
836 
837 
838 #define RESET_CHECKRUNAPP_VARS()\
839     do { \
840         if (AppCompatData && AppCompatData != &Query) { RtlFreeHeap(RtlGetProcessHeap(), 0, AppCompatData); } \
841         ExeType = IMAGE_FILE_MACHINE_I386; \
842         SxsDataSize = FusionFlags = Reason = 0; \
843         SxsData = NULL; \
844         memset(&Query, 0, sizeof(Query)); \
845         AppCompatData = &Query; \
846         AppCompatDataSize = 123456; \
847     } while (0)
848 
849 #define CHECK_BASICS()\
850     do { \
851         ok_hex(ret, TRUE); \
852         ok(AppCompatData != NULL && AppCompatData != &Query, "Expected the pointer to be valid\n"); \
853         ok_hex(AppCompatDataSize, sizeof(SDBQUERYRESULT_VISTA)); \
854         ok(SxsData == NULL, "Expected the pointer to be NULL\n"); \
855         ok_hex(SxsDataSize, 0); \
856         ok_hex(FusionFlags, 0); \
857     } while (0)
858 
859 /* W10 does not seem to use the flags at all, so with this macro we can still test it below 10. */
860 #define CHECKREASON(value, w10dum) (g_ModuleVersion < WINVER_WIN10 ? value : w10dum)
861 
862 
863 static BOOL call_ApphelpCheckRunApp(HANDLE FileHandle, PWCHAR ApplicationName, PVOID Environment, USHORT ExeType,
864                                     PULONG Reason, PVOID* SdbQueryAppCompatData, PULONG SdbQueryAppCompatDataSize,
865                                     PVOID* SxsData, PULONG SxsDataSize, PULONG FusionFlags)
866 {
867     ULONG64 SomeFlag1 = 0;
868     ULONG SomeFlag2 = 0;
869 
870     if (pApphelpCheckRunAppEx_w7)
871     {
872         return pApphelpCheckRunAppEx_w7(FileHandle, NULL, NULL, ApplicationName, Environment, ExeType, Reason,
873                                         SdbQueryAppCompatData, SdbQueryAppCompatDataSize, SxsData, SxsDataSize,
874                                         FusionFlags, &SomeFlag1, &SomeFlag2);
875     }
876 
877     if (pApphelpCheckRunAppEx_w10)
878     {
879         return pApphelpCheckRunAppEx_w10(FileHandle, NULL, NULL, ApplicationName, Environment, NULL, ExeType, Reason,
880                                         SdbQueryAppCompatData, SdbQueryAppCompatDataSize, SxsData, SxsDataSize,
881                                         FusionFlags, &SomeFlag1, &SomeFlag2);
882     }
883 
884     return FALSE;
885 }
886 
887 
888 
889 
890 
891 static void Test_ApphelpCheckRunApp(WCHAR szApphelp[256])
892 {
893     BOOL ret;
894     HANDLE FileHandle = NULL;
895     WCHAR ApplicationName[MAX_PATH], EmptyName[1] = { 0 };
896     DWORD expect_flags = (g_WinVersion < WINVER_WIN10) ? 1 : 0x21;
897 
898     USHORT ExeType;
899     PVOID AppCompatData = NULL, SxsData, DuplicatedEnv, Environment;
900     ULONG AppCompatDataSize, SxsDataSize, FusionFlags;
901     ULONG Reason;
902     SDBQUERYRESULT_VISTA Query;
903     int n;
904     /* this are the only interesting bits (with the exception of '1', which is there to invoke the 'default' case) */
905     const int kTestBits = 0x70503;
906 
907     if (!pApphelpCheckRunAppEx_w7 && !pApphelpCheckRunAppEx_w10)
908     {
909         skip("No usable ApphelpCheckRunAppEx\n");
910         return;
911     }
912 
913     GetModuleFileNameW(NULL, ApplicationName, MAX_PATH);
914 
915     FileHandle = xOpenFile(ApplicationName);
916     SetEnvironmentVariableA("__COMPAT_LAYER", NULL);
917     if (!CreateEnvironmentBlock(&DuplicatedEnv, NULL, TRUE))
918         DuplicatedEnv = NULL;
919     ok(DuplicatedEnv != NULL, "Invalid env (%u)\n", GetLastError());
920 
921     /* First with the environment without __COMPAT_LAYER */
922     RESET_CHECKRUNAPP_VARS();
923 
924     ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, DuplicatedEnv, ExeType, &Reason,
925         &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
926 
927     CHECK_BASICS();
928     ok_hex(Reason, CHECKREASON(0x30000, 0));
929     ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
930 
931     /* We need this to be set for tests later on. */
932     SetEnvironmentVariableA("__COMPAT_LAYER", "256Color");
933 
934     if (g_ModuleVersion < WINVER_WIN10)
935     {
936         /* Showing that when an environment is passed in, that is used instead of the current.
937            In Win10 this behavior is no longer observed */
938 
939         RESET_CHECKRUNAPP_VARS();
940 
941         ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, DuplicatedEnv, ExeType, &Reason,
942             &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
943 
944         CHECK_BASICS();
945         ok_hex(Reason, CHECKREASON(0x30000, 0));
946         ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
947     }
948 
949     for (n = 0; n < 32; ++n)
950     {
951         ULONG ExpectedReason;
952         if (!(kTestBits & (1<<n)))
953             continue;
954         RESET_CHECKRUNAPP_VARS();
955         ExpectedReason = Reason = (1 << n);
956         ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, DuplicatedEnv, ExeType, &Reason,
957             &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
958 
959         CHECK_BASICS();
960         if (ExpectedReason == 2)
961             ExpectedReason = 2;
962         else if (ExpectedReason == 0x100)
963             ExpectedReason = 0x30000;
964         else
965             ExpectedReason |= 0x30000;
966         ok_hex(Reason, CHECKREASON(ExpectedReason, (1 << n)));
967         ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
968     }
969 
970     if (g_ModuleVersion < WINVER_WIN10)
971     {
972         /* Now, using a NULL env, showing that the current environment is used.
973            W10 does no longer do this, so we skip this test here. */
974         Environment = NULL;
975 
976         RESET_CHECKRUNAPP_VARS();
977 
978         ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
979             &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
980 
981         CHECK_BASICS();
982         ok_hex(Reason, CHECKREASON(0x50000, 0));
983         if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
984             expect_layeronly(AppCompatData, "256Color", expect_flags);
985 
986         for (n = 0; n < 32; ++n)
987         {
988             ULONG ExpectedReason;
989             RESET_CHECKRUNAPP_VARS();
990             if (!(kTestBits & (1<<n)))
991                 continue;
992             ExpectedReason = Reason = (1 << n);
993             ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
994                 &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
995 
996             CHECK_BASICS();
997             if (ExpectedReason == 2)
998                 ExpectedReason = 2;
999             else if (ExpectedReason == 0x100)
1000                 ExpectedReason = 0x50000;
1001             else if (ExpectedReason == 0x400)
1002                 ExpectedReason = 0x30400;
1003             else
1004                 ExpectedReason |= 0x50000;
1005             ok_hex(Reason, CHECKREASON(ExpectedReason, (1 << n)));
1006             if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1007             {
1008                 if (ExpectedReason != 0x30400)
1009                     expect_layeronly(AppCompatData, "256Color", expect_flags);
1010                 else
1011                     ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
1012             }
1013         }
1014     }
1015 
1016     /* Passing in an environment with __COMPAT_LAYER set */
1017     Environment = GetEnvironmentStringsW();
1018 
1019     RESET_CHECKRUNAPP_VARS();
1020 
1021     ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
1022         &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1023 
1024     CHECK_BASICS();
1025     ok_hex(Reason, CHECKREASON(0x50000, 0));
1026     if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1027         expect_layeronly(AppCompatData, "256Color", expect_flags);
1028 
1029     for (n = 0; n < 32; ++n)
1030     {
1031         ULONG ExpectedReason;
1032         if (!(kTestBits & (1<<n)))
1033             continue;
1034         RESET_CHECKRUNAPP_VARS();
1035         ExpectedReason = Reason = (1 << n);
1036         ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
1037             &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1038 
1039         CHECK_BASICS();
1040         if (ExpectedReason == 2)
1041             ExpectedReason = 2;
1042         else if (ExpectedReason == 0x100)
1043             ExpectedReason = 0x50000;
1044         else if (ExpectedReason == 0x400)
1045             ExpectedReason = 0x30400;
1046         else
1047             ExpectedReason |= 0x50000;
1048         ok_hex(Reason, CHECKREASON(ExpectedReason, (1 << n)));
1049         if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1050         {
1051             if (ExpectedReason != 0x30400 || g_ModuleVersion >= WINVER_WIN10)
1052                 expect_layeronly(AppCompatData, "256Color", expect_flags);
1053             else
1054                 ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
1055         }
1056     }
1057 
1058     /* NULL file handle still works */
1059     RESET_CHECKRUNAPP_VARS();
1060 
1061     ret = call_ApphelpCheckRunApp(NULL, ApplicationName, Environment, ExeType, &Reason,
1062         &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1063 
1064     CHECK_BASICS();
1065     ok_hex(Reason, CHECKREASON(0x50000, 0));
1066     if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1067         expect_layeronly(AppCompatData, "256Color", expect_flags);
1068 
1069     for (n = 0; n < 32; ++n)
1070     {
1071         ULONG ExpectedReason;
1072         RESET_CHECKRUNAPP_VARS();
1073         if (!(kTestBits & (1<<n)))
1074             continue;
1075         ExpectedReason = Reason = (1 << n);
1076         ret = call_ApphelpCheckRunApp(NULL, ApplicationName, Environment, ExeType, &Reason,
1077             &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1078 
1079         CHECK_BASICS();
1080         if (ExpectedReason == 2)
1081             ExpectedReason = 2;
1082         else if (ExpectedReason == 0x100)
1083             ExpectedReason = 0x50000;
1084         else if (ExpectedReason == 0x400)
1085             ExpectedReason = 0x30400;
1086         else
1087             ExpectedReason |= 0x50000;
1088         ok_hex(Reason, CHECKREASON(ExpectedReason, (1 << n)));
1089         if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1090         {
1091             /* W10 does not use the flags anymore? */
1092             if (ExpectedReason != 0x30400 || g_ModuleVersion >= WINVER_WIN10)
1093                 expect_layeronly(AppCompatData, "256Color", expect_flags);
1094             else
1095                 ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
1096         }
1097     }
1098 
1099 
1100     /* INVALID_HANDLE_VALUE file handle results in failure (according to flags!), but still results in AppCompatData */
1101     RESET_CHECKRUNAPP_VARS();
1102 
1103     ret = call_ApphelpCheckRunApp(INVALID_HANDLE_VALUE, ApplicationName, Environment, ExeType, &Reason,
1104         &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1105 
1106     CHECK_BASICS();
1107     ok_hex(Reason, 0);
1108     if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1109         expect_layeronly(AppCompatData, "256Color", expect_flags);
1110 
1111     for (n = 0; n < 32; ++n)
1112     {
1113         ULONG ExpectedReason;
1114         if (!(kTestBits & (1<<n)))
1115             continue;
1116         RESET_CHECKRUNAPP_VARS();
1117         ExpectedReason = Reason = (1 << n);
1118         ret = call_ApphelpCheckRunApp(INVALID_HANDLE_VALUE, NULL, Environment, ExeType, &Reason,
1119             &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1120 
1121         CHECK_BASICS();
1122         if (ExpectedReason == 0x100)
1123             ExpectedReason = 0;
1124         ok_hex(Reason, CHECKREASON(ExpectedReason, (1 << n)));
1125         if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1126         {
1127             if (ExpectedReason != 0x400 && g_ModuleVersion < WINVER_WIN7)
1128                 expect_layeronly(AppCompatData, "256Color", expect_flags);
1129             else
1130                 ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
1131         }
1132     }
1133 
1134     /* NULL filename crashes, showing this in the log before going down:
1135 [Err ][SdbpGetLongFileName ] Failed to get NT path name for ""
1136 [Err ][SdbpCreateSearchDBContext] Unable to parse executable path for "".
1137 [Err ][SdbGetMatchingExe   ] Failed to create search DB context.
1138 */
1139     RESET_CHECKRUNAPP_VARS();
1140 
1141     ret = call_ApphelpCheckRunApp(FileHandle, EmptyName, Environment, ExeType, &Reason,
1142         &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1143 
1144     CHECK_BASICS();
1145     ok_hex(Reason, CHECKREASON(0x30000, 0));
1146     if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1147         ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
1148 
1149     /* 0 ExeType = don't care? */
1150     RESET_CHECKRUNAPP_VARS();
1151     ExeType = 0;
1152 
1153     ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
1154         &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1155 
1156     CHECK_BASICS();
1157     ok_hex(Reason, CHECKREASON(0x50000, 0));
1158     if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1159         expect_layeronly(AppCompatData, "256Color", expect_flags);
1160 
1161     for (n = 0; n < 32; ++n)
1162     {
1163         ULONG ExpectedReason;
1164         if (!(kTestBits & (1<<n)))
1165             continue;
1166         RESET_CHECKRUNAPP_VARS();
1167         ExeType = 0;
1168         ExpectedReason = Reason = (1 << n);
1169         ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
1170             &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1171 
1172         CHECK_BASICS();
1173         if (ExpectedReason == 2)
1174             ExpectedReason = 2;
1175         else if (ExpectedReason == 0x100)
1176             ExpectedReason = 0x50000;
1177         else if (ExpectedReason == 0x400)
1178             ExpectedReason = 0x30400;
1179         else
1180             ExpectedReason |= 0x50000;
1181         ok_hex(Reason, CHECKREASON(ExpectedReason, (1 << n)));
1182         if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1183         {
1184             if (ExpectedReason != 0x30400 || g_ModuleVersion >= WINVER_WIN10)
1185                 expect_layeronly(AppCompatData, "256Color", expect_flags);
1186             else
1187                 ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
1188         }
1189     }
1190 
1191 
1192     RESET_CHECKRUNAPP_VARS();
1193     ExeType = IMAGE_FILE_MACHINE_POWERPCFP;
1194 
1195     ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
1196         &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1197 
1198     CHECK_BASICS();
1199     ok_hex(Reason, CHECKREASON(0x50000, 0));
1200     if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1201         expect_layeronly(AppCompatData, "256Color", expect_flags);
1202 
1203     for (n = 0; n < 32; ++n)
1204     {
1205         ULONG ExpectedReason;
1206         if (!(kTestBits & (1<<n)))
1207             continue;
1208         RESET_CHECKRUNAPP_VARS();
1209         ExeType = IMAGE_FILE_MACHINE_POWERPCFP;
1210         ExpectedReason = Reason = (1 << n);
1211         ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
1212             &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1213 
1214         CHECK_BASICS();
1215         if (ExpectedReason == 2)
1216             ExpectedReason = 2;
1217         else if (ExpectedReason == 0x100)
1218             ExpectedReason = 0x50000;
1219         else if (ExpectedReason == 0x400)
1220             ExpectedReason = 0x30400;
1221         else
1222             ExpectedReason |= 0x50000;
1223         ok_hex(Reason, CHECKREASON(ExpectedReason, (1 << n)));
1224         if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1225         {
1226             if (ExpectedReason != 0x30400 || g_ModuleVersion >= WINVER_WIN10)
1227                 expect_layeronly(AppCompatData, "256Color", expect_flags);
1228             else
1229                 ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
1230         }
1231     }
1232 
1233 
1234     if (AppCompatData && AppCompatData != &Query)
1235         RtlFreeHeap(RtlGetProcessHeap(), 0, AppCompatData);
1236 
1237     FreeEnvironmentStringsW(Environment);
1238     DestroyEnvironmentBlock(DuplicatedEnv);
1239     NtClose(FileHandle);
1240 }
1241 
1242 
1243 START_TEST(env)
1244 {
1245     WCHAR szApphelp[MAX_PATH];
1246     ShimData_QueryOffset QueryOffset;
1247     DWORD ShimDataType;
1248     NTSTATUS ExceptionStatus = STATUS_SUCCESS;
1249 
1250     //SetEnvironmentVariable("SHIM_DEBUG_LEVEL", "127");
1251     //SetEnvironmentVariable("SHIMENG_DEBUG_LEVEL", "127");
1252 
1253     silence_debug_output();
1254 
1255     hdll = LoadLibraryA("apphelp.dll");
1256 
1257 
1258 
1259     g_WinVersion = get_host_winver();
1260     g_ModuleVersion = get_module_version(hdll);
1261     trace("Detected host: 0x%x, module: 0x%x\n", g_WinVersion, g_ModuleVersion);
1262 
1263     GetModuleFileNameW(hdll, szApphelp, _countof(szApphelp));
1264 
1265 
1266     pSdbGetMatchingExe = (void*)GetProcAddress(hdll, "SdbGetMatchingExe");
1267     pSdbInitDatabase = (void*)GetProcAddress(hdll, "SdbInitDatabase");
1268     pSdbReleaseDatabase = (void*)GetProcAddress(hdll, "SdbReleaseDatabase");
1269     pSdbTagRefToTagID = (void*)GetProcAddress(hdll, "SdbTagRefToTagID");
1270     pSdbGetTagFromTagID = (void*)GetProcAddress(hdll, "SdbGetTagFromTagID");
1271     pSdbGetLayerTagRef = (void*)GetProcAddress(hdll, "SdbGetLayerTagRef");
1272 
1273     switch (g_ModuleVersion)
1274     {
1275     case WINVER_WIN7:
1276         pApphelpCheckRunAppEx_w7 = (void*)GetProcAddress(hdll, "ApphelpCheckRunAppEx");
1277         break;
1278     case WINVER_WIN10:
1279         pApphelpCheckRunAppEx_w10 = (void*)GetProcAddress(hdll, "ApphelpCheckRunAppEx");
1280         break;
1281     default:
1282         skip("Unknown apphelp.dll version %x, cannot determine which ApphelpCheckRunApp(Ex) function to use\n", g_ModuleVersion);
1283         break;
1284     }
1285 
1286     pSdbPackAppCompatData = (void*)GetProcAddress(hdll, "SdbPackAppCompatData");
1287     pSdbUnpackAppCompatData = (void*)GetProcAddress(hdll, "SdbUnpackAppCompatData");
1288     pSdbGetAppCompatDataSize = (void*)GetProcAddress(hdll, "SdbGetAppCompatDataSize");
1289 
1290 
1291     memset(&QueryOffset, 0, sizeof(QueryOffset));
1292     QueryOffset.dwMagic_2k3 = QueryOffset.dwMagic_7_10 = QueryOffset.dwMagic_10_v2 = SHIMDATA_MAGIC;
1293     QueryOffset.dwSize_2k3 = 1;
1294     QueryOffset.dwSize_7_10 = 2;
1295     QueryOffset.dwSize_10_v2 = 3;
1296 
1297     g_ShimDataSize = g_WinVersion < WINVER_WIN10 ? 4096 : 8192;
1298     _SEH2_TRY
1299     {
1300         ShimDataType = pSdbGetAppCompatDataSize(&QueryOffset);
1301     }
1302     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1303     {
1304         ExceptionStatus = _SEH2_GetExceptionCode();
1305     }
1306     _SEH2_END;
1307 
1308     ok(ExceptionStatus == STATUS_SUCCESS, "Exception 0x%08x, expected 0x%08x\n", ExceptionStatus, STATUS_SUCCESS);
1309     if (ExceptionStatus != STATUS_SUCCESS)
1310     {
1311         skip("SdbGetAppCompatDataSize not functional\n");
1312         return;
1313     }
1314 
1315     /* New version of Win10.. */
1316     if (g_WinVersion == WINVER_WIN10 && ShimDataType == 3)
1317         g_ShimDataSize = 4096;
1318 
1319     if (g_WinVersion == g_ModuleVersion)
1320     {
1321         Test_layers(szApphelp);
1322         Test_repeatlayer(szApphelp);
1323     }
1324     else
1325     {
1326         skip("Tests requiring process launch, reported OS version (0x%x) does not match apphelp version (0x%x)\n", g_WinVersion, g_ModuleVersion);
1327     }
1328 
1329     {
1330         Test_GetMatchingExe();
1331     }
1332 
1333     Test_ApphelpCheckRunApp(szApphelp);
1334     if (g_LayerDB)
1335         pSdbReleaseDatabase(g_LayerDB);
1336 }
1337 
1338