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             /* Fake it for now, so the memcmp works. */
689             SDBQUERYRESULT_2k3* input = (SDBQUERYRESULT_2k3*)result;
690             SDBQUERYRESULT_2k3* output = (SDBQUERYRESULT_2k3*)&result2;
691             ok(output->dwCustomSDBMap == 0, "Expected output->dwCustomSDBMap to be 0, was %u for %s\n", output->dwCustomSDBMap, wine_dbgstr_w(szLayer));
692             output->dwCustomSDBMap = input->dwCustomSDBMap;
693             output->rgGuidDB[0] = input->rgGuidDB[0];
694         }
695         ok(!memcmp(&result2, result, sizeof(result)), "Expected result2 to equal result for %s\n", wine_dbgstr_w(szLayer));
696 
697         RtlFreeHeap(GetProcessHeap(), 0, pData);
698     }
699 }
700 
701 
702 #define expect_layeronly    (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_layeronly_imp
703 
704 
705 static void Test_GetMatchingExe(void)
706 {
707     BOOL ret;
708     SDBQUERYRESULT_VISTA result = { { 0 } };
709     WCHAR self[MAX_PATH];
710     DWORD flags = (g_WinVersion < WINVER_VISTA) ? 0 : ((g_WinVersion < WINVER_WIN10) ? 1 : 0x21);
711 
712     GetModuleFileNameW(NULL, self, MAX_PATH);
713     SetEnvironmentVariableA("__COMPAT_LAYER", NULL);
714 
715     /* szPath cannot be NULL! */
716     ret = pSdbGetMatchingExe(NULL, L"", NULL, NULL, 0, &result);
717     ok(ret == FALSE, "Expected ret to be FALSE\n");
718     ok(!memcmp(&result, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
719 
720     result = empty_result;
721 
722     ret = pSdbGetMatchingExe(NULL, self, NULL, NULL, 0, &result);
723     ok(ret == FALSE, "Expected ret to be FALSE\n");
724     ok(!memcmp(&result, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
725 
726     result = empty_result;
727     SetEnvironmentVariableA("__COMPAT_LAYER", "Some_invalid_layer_name");
728 
729     ret = pSdbGetMatchingExe(NULL, self, NULL, NULL, 0, &result);
730     ok(ret == FALSE, "Expected ret to be FALSE\n");
731     if (g_WinVersion < WINVER_WIN10)
732         ok(!memcmp(&result, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
733     else
734         ok(!memcmp(&result, &almost_empty, sizeof(almost_empty)), "Expected result to be almost empty\n");
735 
736     result = empty_result;
737     SetEnvironmentVariableA("__COMPAT_LAYER", "256Color");
738 
739     ret = pSdbGetMatchingExe(NULL, self, NULL, NULL, 0, &result);
740     ok(ret == TRUE, "Expected ret to be TRUE\n");
741     expect_layeronly(&result, "256Color", flags);
742 
743     Test_Shimdata(&result, L"256Color");
744 
745     result = empty_result;
746     SetEnvironmentVariableA("__COMPAT_LAYER", "640X480");
747 
748     ret = pSdbGetMatchingExe(NULL, self, NULL, NULL, 0, &result);
749     ok(ret == TRUE, "Expected ret to be TRUE\n");
750     expect_layeronly(&result, "640X480", flags);
751 
752     Test_Shimdata(&result, L"640X480");
753 
754     /* HIGHDPIAWARE does not exist in 2k3 */
755     if (g_WinVersion > WINVER_2003)
756     {
757         result = empty_result;
758         SetEnvironmentVariableA("__COMPAT_LAYER", "HIGHDPIAWARE");
759 
760         ret = pSdbGetMatchingExe(NULL, self, NULL, NULL, 0, &result);
761         ok(ret == TRUE, "Expected ret to be TRUE\n");
762         expect_layeronly(&result, "HIGHDPIAWARE", flags);
763 
764         Test_Shimdata(&result, L"HIGHDPIAWARE");
765 
766         result = empty_result;
767         SetEnvironmentVariableA("__COMPAT_LAYER", "256Color HIGHDPIAWARE   640X480");
768 
769         ret = pSdbGetMatchingExe(NULL, self, NULL, NULL, 0, &result);
770         ok(ret == TRUE, "Expected ret to be TRUE\n");
771         expect_layeronly(&result, "256Color HIGHDPIAWARE 640X480", flags);
772 
773         Test_Shimdata(&result, L"256Color HIGHDPIAWARE   640X480");
774     }
775 }
776 
777 
778 HANDLE xOpenFile(WCHAR* ApplicationName)
779 {
780     UNICODE_STRING FileName;
781     OBJECT_ATTRIBUTES ObjectAttributes;
782     IO_STATUS_BLOCK IoStatusBlock;
783     NTSTATUS Status;
784     HANDLE FileHandle;
785 
786     if (!RtlDosPathNameToNtPathName_U(ApplicationName, &FileName, NULL, NULL))
787     {
788         skip("Unable to translate %s to Nt path\n", wine_dbgstr_w(ApplicationName));
789         return NULL;
790     }
791 
792 
793     InitializeObjectAttributes(&ObjectAttributes, &FileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
794     Status = NtOpenFile(&FileHandle,
795                         SYNCHRONIZE |
796                         FILE_READ_ATTRIBUTES |
797                         FILE_READ_DATA |
798                         FILE_EXECUTE,
799                         &ObjectAttributes,
800                         &IoStatusBlock,
801                         FILE_SHARE_READ | FILE_SHARE_DELETE,
802                         FILE_SYNCHRONOUS_IO_NONALERT |
803                         FILE_NON_DIRECTORY_FILE);
804 
805     RtlFreeUnicodeString(&FileName);
806 
807     if (!NT_SUCCESS(Status))
808         return NULL;
809 
810     return FileHandle;
811 }
812 
813 
814 #define RESET_CHECKRUNAPP_VARS()\
815     do { \
816         if (AppCompatData && AppCompatData != &Query) { RtlFreeHeap(RtlGetProcessHeap(), 0, AppCompatData); } \
817         ExeType = IMAGE_FILE_MACHINE_I386; \
818         SxsDataSize = FusionFlags = Reason = 0; \
819         SxsData = NULL; \
820         memset(&Query, 0, sizeof(Query)); \
821         AppCompatData = &Query; \
822         AppCompatDataSize = 123456; \
823     } while (0)
824 
825 #define CHECK_BASICS()\
826     do { \
827         ok_hex(ret, TRUE); \
828         ok(AppCompatData != NULL && AppCompatData != &Query, "Expected the pointer to be valid\n"); \
829         ok_hex(AppCompatDataSize, sizeof(SDBQUERYRESULT_VISTA)); \
830         ok(SxsData == NULL, "Expected the pointer to be NULL\n"); \
831         ok_hex(SxsDataSize, 0); \
832         ok_hex(FusionFlags, 0); \
833     } while (0)
834 
835 /* W10 does not seem to use the flags at all, so with this macro we can still test it below 10. */
836 #define CHECKREASON(value, w10dum) (g_ModuleVersion < WINVER_WIN10 ? value : w10dum)
837 
838 
839 static BOOL call_ApphelpCheckRunApp(HANDLE FileHandle, PWCHAR ApplicationName, PVOID Environment, USHORT ExeType,
840                                     PULONG Reason, PVOID* SdbQueryAppCompatData, PULONG SdbQueryAppCompatDataSize,
841                                     PVOID* SxsData, PULONG SxsDataSize, PULONG FusionFlags)
842 {
843     ULONG64 SomeFlag1 = 0;
844     ULONG SomeFlag2 = 0;
845 
846     if (pApphelpCheckRunAppEx_w7)
847     {
848         return pApphelpCheckRunAppEx_w7(FileHandle, NULL, NULL, ApplicationName, Environment, ExeType, Reason,
849                                         SdbQueryAppCompatData, SdbQueryAppCompatDataSize, SxsData, SxsDataSize,
850                                         FusionFlags, &SomeFlag1, &SomeFlag2);
851     }
852 
853     if (pApphelpCheckRunAppEx_w10)
854     {
855         return pApphelpCheckRunAppEx_w10(FileHandle, NULL, NULL, ApplicationName, Environment, NULL, ExeType, Reason,
856                                         SdbQueryAppCompatData, SdbQueryAppCompatDataSize, SxsData, SxsDataSize,
857                                         FusionFlags, &SomeFlag1, &SomeFlag2);
858     }
859 
860     return FALSE;
861 }
862 
863 
864 
865 
866 
867 static void Test_ApphelpCheckRunApp(WCHAR szApphelp[256])
868 {
869     BOOL ret;
870     HANDLE FileHandle = NULL;
871     WCHAR ApplicationName[MAX_PATH], EmptyName[1] = { 0 };
872     DWORD expect_flags = (g_WinVersion < WINVER_WIN10) ? 1 : 0x21;
873 
874     USHORT ExeType;
875     PVOID AppCompatData = NULL, SxsData, DuplicatedEnv, Environment;
876     ULONG AppCompatDataSize, SxsDataSize, FusionFlags;
877     ULONG Reason;
878     SDBQUERYRESULT_VISTA Query;
879     int n;
880     /* this are the only interesting bits (with the exception of '1', which is there to invoke the 'default' case) */
881     const int kTestBits = 0x70503;
882 
883     if (!pApphelpCheckRunAppEx_w7 && !pApphelpCheckRunAppEx_w10)
884     {
885         skip("No usable ApphelpCheckRunAppEx\n");
886         return;
887     }
888 
889     GetModuleFileNameW(NULL, ApplicationName, MAX_PATH);
890 
891     FileHandle = xOpenFile(ApplicationName);
892     SetEnvironmentVariableA("__COMPAT_LAYER", NULL);
893     if (!CreateEnvironmentBlock(&DuplicatedEnv, NULL, TRUE))
894         DuplicatedEnv = NULL;
895     ok(DuplicatedEnv != NULL, "Invalid env (%u)\n", GetLastError());
896 
897     /* First with the environment without __COMPAT_LAYER */
898     RESET_CHECKRUNAPP_VARS();
899 
900     ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, DuplicatedEnv, ExeType, &Reason,
901         &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
902 
903     CHECK_BASICS();
904     ok_hex(Reason, CHECKREASON(0x30000, 0));
905     ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
906 
907     /* We need this to be set for tests later on. */
908     SetEnvironmentVariableA("__COMPAT_LAYER", "256Color");
909 
910     if (g_ModuleVersion < WINVER_WIN10)
911     {
912         /* Showing that when an environment is passed in, that is used instead of the current.
913            In Win10 this behavior is no longer observed */
914 
915         RESET_CHECKRUNAPP_VARS();
916 
917         ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, DuplicatedEnv, ExeType, &Reason,
918             &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
919 
920         CHECK_BASICS();
921         ok_hex(Reason, CHECKREASON(0x30000, 0));
922         ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
923     }
924 
925     for (n = 0; n < 32; ++n)
926     {
927         ULONG ExpectedReason;
928         if (!(kTestBits & (1<<n)))
929             continue;
930         RESET_CHECKRUNAPP_VARS();
931         ExpectedReason = Reason = (1 << n);
932         ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, DuplicatedEnv, ExeType, &Reason,
933             &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
934 
935         CHECK_BASICS();
936         if (ExpectedReason == 2)
937             ExpectedReason = 2;
938         else if (ExpectedReason == 0x100)
939             ExpectedReason = 0x30000;
940         else
941             ExpectedReason |= 0x30000;
942         ok_hex(Reason, CHECKREASON(ExpectedReason, (1 << n)));
943         ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
944     }
945 
946     if (g_ModuleVersion < WINVER_WIN10)
947     {
948         /* Now, using a NULL env, showing that the current environment is used.
949            W10 does no longer do this, so we skip this test here. */
950         Environment = NULL;
951 
952         RESET_CHECKRUNAPP_VARS();
953 
954         ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
955             &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
956 
957         CHECK_BASICS();
958         ok_hex(Reason, CHECKREASON(0x50000, 0));
959         if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
960             expect_layeronly(AppCompatData, "256Color", expect_flags);
961 
962         for (n = 0; n < 32; ++n)
963         {
964             ULONG ExpectedReason;
965             RESET_CHECKRUNAPP_VARS();
966             if (!(kTestBits & (1<<n)))
967                 continue;
968             ExpectedReason = Reason = (1 << n);
969             ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
970                 &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
971 
972             CHECK_BASICS();
973             if (ExpectedReason == 2)
974                 ExpectedReason = 2;
975             else if (ExpectedReason == 0x100)
976                 ExpectedReason = 0x50000;
977             else if (ExpectedReason == 0x400)
978                 ExpectedReason = 0x30400;
979             else
980                 ExpectedReason |= 0x50000;
981             ok_hex(Reason, CHECKREASON(ExpectedReason, (1 << n)));
982             if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
983             {
984                 if (ExpectedReason != 0x30400)
985                     expect_layeronly(AppCompatData, "256Color", expect_flags);
986                 else
987                     ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
988             }
989         }
990     }
991 
992     /* Passing in an environment with __COMPAT_LAYER set */
993     Environment = GetEnvironmentStringsW();
994 
995     RESET_CHECKRUNAPP_VARS();
996 
997     ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
998         &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
999 
1000     CHECK_BASICS();
1001     ok_hex(Reason, CHECKREASON(0x50000, 0));
1002     if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1003         expect_layeronly(AppCompatData, "256Color", expect_flags);
1004 
1005     for (n = 0; n < 32; ++n)
1006     {
1007         ULONG ExpectedReason;
1008         if (!(kTestBits & (1<<n)))
1009             continue;
1010         RESET_CHECKRUNAPP_VARS();
1011         ExpectedReason = Reason = (1 << n);
1012         ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
1013             &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1014 
1015         CHECK_BASICS();
1016         if (ExpectedReason == 2)
1017             ExpectedReason = 2;
1018         else if (ExpectedReason == 0x100)
1019             ExpectedReason = 0x50000;
1020         else if (ExpectedReason == 0x400)
1021             ExpectedReason = 0x30400;
1022         else
1023             ExpectedReason |= 0x50000;
1024         ok_hex(Reason, CHECKREASON(ExpectedReason, (1 << n)));
1025         if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1026         {
1027             if (ExpectedReason != 0x30400 || g_ModuleVersion >= WINVER_WIN10)
1028                 expect_layeronly(AppCompatData, "256Color", expect_flags);
1029             else
1030                 ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
1031         }
1032     }
1033 
1034     /* NULL file handle still works */
1035     RESET_CHECKRUNAPP_VARS();
1036 
1037     ret = call_ApphelpCheckRunApp(NULL, ApplicationName, Environment, ExeType, &Reason,
1038         &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1039 
1040     CHECK_BASICS();
1041     ok_hex(Reason, CHECKREASON(0x50000, 0));
1042     if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1043         expect_layeronly(AppCompatData, "256Color", expect_flags);
1044 
1045     for (n = 0; n < 32; ++n)
1046     {
1047         ULONG ExpectedReason;
1048         RESET_CHECKRUNAPP_VARS();
1049         if (!(kTestBits & (1<<n)))
1050             continue;
1051         ExpectedReason = Reason = (1 << n);
1052         ret = call_ApphelpCheckRunApp(NULL, ApplicationName, Environment, ExeType, &Reason,
1053             &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1054 
1055         CHECK_BASICS();
1056         if (ExpectedReason == 2)
1057             ExpectedReason = 2;
1058         else if (ExpectedReason == 0x100)
1059             ExpectedReason = 0x50000;
1060         else if (ExpectedReason == 0x400)
1061             ExpectedReason = 0x30400;
1062         else
1063             ExpectedReason |= 0x50000;
1064         ok_hex(Reason, CHECKREASON(ExpectedReason, (1 << n)));
1065         if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1066         {
1067             /* W10 does not use the flags anymore? */
1068             if (ExpectedReason != 0x30400 || g_ModuleVersion >= WINVER_WIN10)
1069                 expect_layeronly(AppCompatData, "256Color", expect_flags);
1070             else
1071                 ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
1072         }
1073     }
1074 
1075 
1076     /* INVALID_HANDLE_VALUE file handle results in failure (according to flags!), but still results in AppCompatData */
1077     RESET_CHECKRUNAPP_VARS();
1078 
1079     ret = call_ApphelpCheckRunApp(INVALID_HANDLE_VALUE, ApplicationName, Environment, ExeType, &Reason,
1080         &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1081 
1082     CHECK_BASICS();
1083     ok_hex(Reason, 0);
1084     if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1085         expect_layeronly(AppCompatData, "256Color", expect_flags);
1086 
1087     for (n = 0; n < 32; ++n)
1088     {
1089         ULONG ExpectedReason;
1090         if (!(kTestBits & (1<<n)))
1091             continue;
1092         RESET_CHECKRUNAPP_VARS();
1093         ExpectedReason = Reason = (1 << n);
1094         ret = call_ApphelpCheckRunApp(INVALID_HANDLE_VALUE, NULL, Environment, ExeType, &Reason,
1095             &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1096 
1097         CHECK_BASICS();
1098         if (ExpectedReason == 0x100)
1099             ExpectedReason = 0;
1100         ok_hex(Reason, CHECKREASON(ExpectedReason, (1 << n)));
1101         if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1102         {
1103             if (ExpectedReason != 0x400 && g_ModuleVersion < WINVER_WIN7)
1104                 expect_layeronly(AppCompatData, "256Color", expect_flags);
1105             else
1106                 ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
1107         }
1108     }
1109 
1110     /* NULL filename crashes, showing this in the log before going down:
1111 [Err ][SdbpGetLongFileName ] Failed to get NT path name for ""
1112 [Err ][SdbpCreateSearchDBContext] Unable to parse executable path for "".
1113 [Err ][SdbGetMatchingExe   ] Failed to create search DB context.
1114 */
1115     RESET_CHECKRUNAPP_VARS();
1116 
1117     ret = call_ApphelpCheckRunApp(FileHandle, EmptyName, Environment, ExeType, &Reason,
1118         &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1119 
1120     CHECK_BASICS();
1121     ok_hex(Reason, CHECKREASON(0x30000, 0));
1122     if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1123         ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
1124 
1125     /* 0 ExeType = don't care? */
1126     RESET_CHECKRUNAPP_VARS();
1127     ExeType = 0;
1128 
1129     ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
1130         &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1131 
1132     CHECK_BASICS();
1133     ok_hex(Reason, CHECKREASON(0x50000, 0));
1134     if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1135         expect_layeronly(AppCompatData, "256Color", expect_flags);
1136 
1137     for (n = 0; n < 32; ++n)
1138     {
1139         ULONG ExpectedReason;
1140         if (!(kTestBits & (1<<n)))
1141             continue;
1142         RESET_CHECKRUNAPP_VARS();
1143         ExeType = 0;
1144         ExpectedReason = Reason = (1 << n);
1145         ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
1146             &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1147 
1148         CHECK_BASICS();
1149         if (ExpectedReason == 2)
1150             ExpectedReason = 2;
1151         else if (ExpectedReason == 0x100)
1152             ExpectedReason = 0x50000;
1153         else if (ExpectedReason == 0x400)
1154             ExpectedReason = 0x30400;
1155         else
1156             ExpectedReason |= 0x50000;
1157         ok_hex(Reason, CHECKREASON(ExpectedReason, (1 << n)));
1158         if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1159         {
1160             if (ExpectedReason != 0x30400 || g_ModuleVersion >= WINVER_WIN10)
1161                 expect_layeronly(AppCompatData, "256Color", expect_flags);
1162             else
1163                 ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
1164         }
1165     }
1166 
1167 
1168     RESET_CHECKRUNAPP_VARS();
1169     ExeType = IMAGE_FILE_MACHINE_POWERPCFP;
1170 
1171     ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
1172         &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1173 
1174     CHECK_BASICS();
1175     ok_hex(Reason, CHECKREASON(0x50000, 0));
1176     if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1177         expect_layeronly(AppCompatData, "256Color", expect_flags);
1178 
1179     for (n = 0; n < 32; ++n)
1180     {
1181         ULONG ExpectedReason;
1182         if (!(kTestBits & (1<<n)))
1183             continue;
1184         RESET_CHECKRUNAPP_VARS();
1185         ExeType = IMAGE_FILE_MACHINE_POWERPCFP;
1186         ExpectedReason = Reason = (1 << n);
1187         ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason,
1188             &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags);
1189 
1190         CHECK_BASICS();
1191         if (ExpectedReason == 2)
1192             ExpectedReason = 2;
1193         else if (ExpectedReason == 0x100)
1194             ExpectedReason = 0x50000;
1195         else if (ExpectedReason == 0x400)
1196             ExpectedReason = 0x30400;
1197         else
1198             ExpectedReason |= 0x50000;
1199         ok_hex(Reason, CHECKREASON(ExpectedReason, (1 << n)));
1200         if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA))
1201         {
1202             if (ExpectedReason != 0x30400 || g_ModuleVersion >= WINVER_WIN10)
1203                 expect_layeronly(AppCompatData, "256Color", expect_flags);
1204             else
1205                 ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n");
1206         }
1207     }
1208 
1209 
1210     if (AppCompatData && AppCompatData != &Query)
1211         RtlFreeHeap(RtlGetProcessHeap(), 0, AppCompatData);
1212 
1213     FreeEnvironmentStringsW(Environment);
1214     DestroyEnvironmentBlock(DuplicatedEnv);
1215     NtClose(FileHandle);
1216 }
1217 
1218 
1219 START_TEST(env)
1220 {
1221     WCHAR szApphelp[MAX_PATH];
1222     ShimData_QueryOffset QueryOffset;
1223     DWORD ShimDataType;
1224     NTSTATUS ExceptionStatus = STATUS_SUCCESS;
1225 
1226     //SetEnvironmentVariable("SHIM_DEBUG_LEVEL", "127");
1227     //SetEnvironmentVariable("SHIMENG_DEBUG_LEVEL", "127");
1228 
1229     silence_debug_output();
1230 
1231     hdll = LoadLibraryA("apphelp.dll");
1232 
1233 
1234 
1235     g_WinVersion = get_host_winver();
1236     g_ModuleVersion = get_module_version(hdll);
1237     trace("Detected host: 0x%x, module: 0x%x\n", g_WinVersion, g_ModuleVersion);
1238 
1239     GetModuleFileNameW(hdll, szApphelp, _countof(szApphelp));
1240 
1241 
1242     pSdbGetMatchingExe = (void*)GetProcAddress(hdll, "SdbGetMatchingExe");
1243     pSdbInitDatabase = (void*)GetProcAddress(hdll, "SdbInitDatabase");
1244     pSdbReleaseDatabase = (void*)GetProcAddress(hdll, "SdbReleaseDatabase");
1245     pSdbTagRefToTagID = (void*)GetProcAddress(hdll, "SdbTagRefToTagID");
1246     pSdbGetTagFromTagID = (void*)GetProcAddress(hdll, "SdbGetTagFromTagID");
1247     pSdbGetLayerTagRef = (void*)GetProcAddress(hdll, "SdbGetLayerTagRef");
1248 
1249     switch (g_ModuleVersion)
1250     {
1251     case WINVER_WIN7:
1252         pApphelpCheckRunAppEx_w7 = (void*)GetProcAddress(hdll, "ApphelpCheckRunAppEx");
1253         break;
1254     case WINVER_WIN10:
1255         pApphelpCheckRunAppEx_w10 = (void*)GetProcAddress(hdll, "ApphelpCheckRunAppEx");
1256         break;
1257     default:
1258         skip("Unknown apphelp.dll version %x, cannot determine which ApphelpCheckRunApp(Ex) function to use\n", g_ModuleVersion);
1259         break;
1260     }
1261 
1262     pSdbPackAppCompatData = (void*)GetProcAddress(hdll, "SdbPackAppCompatData");
1263     pSdbUnpackAppCompatData = (void*)GetProcAddress(hdll, "SdbUnpackAppCompatData");
1264     pSdbGetAppCompatDataSize = (void*)GetProcAddress(hdll, "SdbGetAppCompatDataSize");
1265 
1266 
1267     memset(&QueryOffset, 0, sizeof(QueryOffset));
1268     QueryOffset.dwMagic_2k3 = QueryOffset.dwMagic_7_10 = QueryOffset.dwMagic_10_v2 = SHIMDATA_MAGIC;
1269     QueryOffset.dwSize_2k3 = 1;
1270     QueryOffset.dwSize_7_10 = 2;
1271     QueryOffset.dwSize_10_v2 = 3;
1272 
1273     g_ShimDataSize = g_WinVersion < WINVER_WIN10 ? 4096 : 8192;
1274     _SEH2_TRY
1275     {
1276         ShimDataType = pSdbGetAppCompatDataSize(&QueryOffset);
1277     }
1278     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1279     {
1280         ExceptionStatus = _SEH2_GetExceptionCode();
1281     }
1282     _SEH2_END;
1283 
1284     ok(ExceptionStatus == STATUS_SUCCESS, "Exception 0x%08x, expected 0x%08x\n", ExceptionStatus, STATUS_SUCCESS);
1285     if (ExceptionStatus != STATUS_SUCCESS)
1286     {
1287         skip("SdbGetAppCompatDataSize not functional\n");
1288         return;
1289     }
1290 
1291     /* New version of Win10.. */
1292     if (g_WinVersion == WINVER_WIN10 && ShimDataType == 3)
1293         g_ShimDataSize = 4096;
1294 
1295     if (g_WinVersion == g_ModuleVersion)
1296     {
1297         Test_layers(szApphelp);
1298         Test_repeatlayer(szApphelp);
1299     }
1300     else
1301     {
1302         skip("Tests requiring process launch, reported OS version (0x%x) does not match apphelp version (0x%x)\n", g_WinVersion, g_ModuleVersion);
1303     }
1304 
1305     {
1306         Test_GetMatchingExe();
1307     }
1308 
1309     Test_ApphelpCheckRunApp(szApphelp);
1310     if (g_LayerDB)
1311         pSdbReleaseDatabase(g_LayerDB);
1312 }
1313 
1314