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