From be0666cf16076820e7609f9c3be226dd884268ac Mon Sep 17 00:00:00 2001 From: Mark Jansen Date: Sat, 10 Jun 2017 20:31:58 +0000 Subject: [PATCH] [APPHELP_APITEST] Add tests for ApphelpCheckRunApp[Ex], SdbGetMatchingExe, Sdb[Un]PackAppCompatData. CORE-13284 svn path=/trunk/; revision=74986 --- rostests/apitests/apphelp/CMakeLists.txt | 2 + rostests/apitests/apphelp/apphelp.c | 5 - rostests/apitests/apphelp/apphelp_apitest.h | 64 + rostests/apitests/apphelp/db.cpp | 69 +- rostests/apitests/apphelp/env.c | 1323 +++++++++++++++++++ rostests/apitests/apphelp/testlist.c | 2 + 6 files changed, 1397 insertions(+), 68 deletions(-) create mode 100644 rostests/apitests/apphelp/env.c diff --git a/rostests/apitests/apphelp/CMakeLists.txt b/rostests/apitests/apphelp/CMakeLists.txt index 2a890276f14..454723f3440 100644 --- a/rostests/apitests/apphelp/CMakeLists.txt +++ b/rostests/apitests/apphelp/CMakeLists.txt @@ -5,10 +5,12 @@ list(APPEND SOURCE apphelp.c data.c db.cpp + env.c layerapi.c testlist.c) add_executable(apphelp_apitest ${SOURCE}) set_module_type(apphelp_apitest win32cui) +target_link_libraries(apphelp_apitest ${PSEH_LIB}) add_importlibs(apphelp_apitest advapi32 userenv version shlwapi msvcrt kernel32 ntdll) add_rostests_file(TARGET apphelp_apitest) diff --git a/rostests/apitests/apphelp/apphelp.c b/rostests/apitests/apphelp/apphelp.c index 6bfd978a471..81d61ac8123 100644 --- a/rostests/apitests/apphelp/apphelp.c +++ b/rostests/apitests/apphelp/apphelp.c @@ -41,11 +41,6 @@ #include "apphelp_apitest.h" -typedef WORD TAG; -typedef DWORD TAGID; -typedef DWORD TAGREF; -typedef UINT64 QWORD; - #define TAG_TYPE_MASK 0xF000 #define TAG_TYPE_NULL 0x1000 diff --git a/rostests/apitests/apphelp/apphelp_apitest.h b/rostests/apitests/apphelp/apphelp_apitest.h index 88af65281fe..471c4f968b9 100644 --- a/rostests/apitests/apphelp/apphelp_apitest.h +++ b/rostests/apitests/apphelp/apphelp_apitest.h @@ -32,6 +32,70 @@ static DWORD g_WinVersion; #define WINVER_WIN8 0x0602 #define WINVER_WIN10 0x0a00 + +typedef WORD TAG; +typedef DWORD TAGID; +typedef DWORD TAGREF; +typedef UINT64 QWORD; +typedef VOID* PDB; +typedef VOID* HSDB; +typedef INT PATH_TYPE; + + + +#define SDB_MAX_SDBS 16 +#define SDB_MAX_EXES_VISTA 16 +#define SDB_MAX_LAYERS 8 +#define SHIMREG_DISABLE_LAYER (0x00000020) + +#define SDBQUERYRESULT_EXPECTED_SIZE_VISTA 456 + + + +typedef struct tagSDBQUERYRESULT_VISTA +{ + TAGREF atrExes[SDB_MAX_EXES_VISTA]; + DWORD adwExeFlags[SDB_MAX_EXES_VISTA]; + TAGREF atrLayers[SDB_MAX_LAYERS]; + DWORD dwLayerFlags; + TAGREF trApphelp; + DWORD dwExeCount; + DWORD dwLayerCount; + GUID guidID; + DWORD dwFlags; + DWORD dwCustomSDBMap; + GUID rgGuidDB[SDB_MAX_SDBS]; +} SDBQUERYRESULT_VISTA, *PSDBQUERYRESULT_VISTA; + + +#define SDBQUERYRESULT_EXPECTED_SIZE_2k3 344 + +#define SDB_MAX_EXES_2k3 4 + +typedef struct tagSDBQUERYRESULT_2k3 +{ + TAGREF atrExes[SDB_MAX_EXES_2k3]; + TAGREF atrLayers[SDB_MAX_LAYERS]; + DWORD dwLayerFlags; + TAGREF trApphelp; // probably? + DWORD dwExeCount; + DWORD dwLayerCount; + GUID guidID; // probably? + DWORD dwFlags; // probably? + DWORD dwCustomSDBMap; + GUID rgGuidDB[SDB_MAX_SDBS]; +} SDBQUERYRESULT_2k3, *PSDBQUERYRESULT_2k3; + + + + + +C_ASSERT(sizeof(SDBQUERYRESULT_VISTA) == SDBQUERYRESULT_EXPECTED_SIZE_VISTA); +C_ASSERT(sizeof(SDBQUERYRESULT_2k3) == SDBQUERYRESULT_EXPECTED_SIZE_2k3); + + + + #ifdef __cplusplus } // extern "C" #endif diff --git a/rostests/apitests/apphelp/db.cpp b/rostests/apitests/apphelp/db.cpp index 7ceb9a7e138..e16f9032b13 100644 --- a/rostests/apitests/apphelp/db.cpp +++ b/rostests/apitests/apphelp/db.cpp @@ -39,15 +39,6 @@ #include "apphelp_apitest.h" - -typedef WORD TAG; -typedef DWORD TAGID; -typedef DWORD TAGREF; -typedef UINT64 QWORD; -typedef VOID* PDB; -typedef VOID* HSDB; -typedef INT PATH_TYPE; - #define DOS_PATH 0 #define HID_DATABASE_FULLPATH 2 @@ -139,54 +130,6 @@ typedef INT PATH_TYPE; #define TAG_DATABASE_ID (0x7 | TAG_TYPE_BINARY) -#define SDB_MAX_SDBS_VISTA 16 -#define SDB_MAX_EXES_VISTA 16 -#define SDB_MAX_LAYERS_VISTA 8 - -#define SDBQUERYRESULT_EXPECTED_SIZE_VISTA 456 - -typedef struct tagSDBQUERYRESULT -{ - TAGREF atrExes[SDB_MAX_EXES_VISTA]; - DWORD adwExeFlags[SDB_MAX_EXES_VISTA]; - TAGREF atrLayers[SDB_MAX_LAYERS_VISTA]; - DWORD dwLayerFlags; - TAGREF trApphelp; - DWORD dwExeCount; - DWORD dwLayerCount; - GUID guidID; - DWORD dwFlags; - DWORD dwCustomSDBMap; - GUID rgGuidDB[SDB_MAX_SDBS_VISTA]; -} SDBQUERYRESULT, *PSDBQUERYRESULT; - - -#define SDBQUERYRESULT_EXPECTED_SIZE_2k3 344 - -#define SDB_MAX_EXES_2k3 4 -#define SDB_MAX_LAYERS_2k3 8 - -typedef struct tagSDBQUERYRESULT_2k3 -{ - TAGREF atrExes[SDB_MAX_EXES_2k3]; - TAGREF atrLayers[SDB_MAX_LAYERS_2k3]; - DWORD dwLayerFlags; - TAGREF trApphelp; // probably? - DWORD dwExeCount; - DWORD dwLayerCount; - GUID guidID; // probably? - DWORD dwFlags; // probably? - DWORD dwCustomSDBMap; - GUID rgGuidDB[SDB_MAX_SDBS_VISTA]; -} SDBQUERYRESULT_2k3, *PSDBQUERYRESULT_2k3; - - - - - -C_ASSERT(sizeof(SDBQUERYRESULT) == SDBQUERYRESULT_EXPECTED_SIZE_VISTA); -C_ASSERT(sizeof(SDBQUERYRESULT_2k3) == SDBQUERYRESULT_EXPECTED_SIZE_2k3); - static HMODULE hdll; static LPCWSTR (WINAPI *pSdbTagToString)(TAG); @@ -222,7 +165,7 @@ static BOOL (WINAPI *pSdbGetDatabaseID)(PDB, GUID*); static BOOL (WINAPI *pSdbGUIDToString)(CONST GUID *, PCWSTR, SIZE_T); static HSDB (WINAPI *pSdbInitDatabase)(DWORD, LPCWSTR); static void (WINAPI *pSdbReleaseDatabase)(HSDB); -static BOOL (WINAPI *pSdbGetMatchingExe)(HSDB hsdb, LPCWSTR path, LPCWSTR module_name, LPCWSTR env, DWORD flags, PSDBQUERYRESULT result); +static BOOL (WINAPI *pSdbGetMatchingExe)(HSDB hsdb, LPCWSTR path, LPCWSTR module_name, LPCWSTR env, DWORD flags, PSDBQUERYRESULT_VISTA result); static BOOL (WINAPI *pSdbTagRefToTagID)(HSDB hSDB, TAGREF trWhich, PDB *ppdb, TAGID *ptiWhich); static BOOL (WINAPI *pSdbTagIDToTagRef)(HSDB hSDB, PDB pdb, TAGID tiWhich, TAGREF *ptrWhich); static TAGREF (WINAPI *pSdbGetLayerTagRef)(HSDB hsdb, LPCWSTR layerName); @@ -1162,7 +1105,7 @@ static void test_mode_generic(const char* workdir, HSDB hsdb, int cur) { /* First we try without the file at all. */ DeleteFileA(testfile); - ret = pSdbGetMatchingExe(hsdb, exenameW, NULL, NULL, 0, (SDBQUERYRESULT*)&query); + ret = pSdbGetMatchingExe(hsdb, exenameW, NULL, NULL, 0, (SDBQUERYRESULT_VISTA*)&query); ok(ret == 0, "SdbGetMatchingExe should have failed for %d.\n", cur); /* Now re-try with the correct file */ test_create_file(testfile, "aaaa", 4); @@ -1185,7 +1128,7 @@ static void test_mode_generic(const char* workdir, HSDB hsdb, int cur) SetEnvironmentVariableA("__COMPAT_LAYER", test_exedata[cur].env_var); } - ret = pSdbGetMatchingExe(hsdb, exenameW, NULL, NULL, 0, (SDBQUERYRESULT*)&query); + ret = pSdbGetMatchingExe(hsdb, exenameW, NULL, NULL, 0, (SDBQUERYRESULT_VISTA*)&query); ok(ret, "SdbGetMatchingExe should not fail for %d.\n", cur); exe_count = (test_exedata[cur].env_var == NULL) ? 1 : 0; @@ -1295,7 +1238,7 @@ static void test_mode_generic(const char* workdir, HSDB hsdb, int cur) if (RtlDosPathNameToNtPathName_U(exenameW, &exenameNT, NULL, NULL)) { - ret = pSdbGetMatchingExe(hsdb, exenameNT.Buffer, NULL, NULL, 0, (SDBQUERYRESULT*)&query); + ret = pSdbGetMatchingExe(hsdb, exenameNT.Buffer, NULL, NULL, 0, (SDBQUERYRESULT_VISTA*)&query); ok(ret, "SdbGetMatchingExe should not fail for %d.\n", cur); RtlFreeUnicodeString(&exenameNT); @@ -1594,7 +1537,7 @@ static int validate_SDBQUERYRESULT_size() memset(buffer, 0xab, sizeof(buffer)); GetModuleFileNameW(NULL, path, MAX_PATH); - pSdbGetMatchingExe(NULL, path, NULL, NULL, 0, (SDBQUERYRESULT*)buffer); + pSdbGetMatchingExe(NULL, path, NULL, NULL, 0, (SDBQUERYRESULT_VISTA*)buffer); if (buffer[0] == 0xab) { trace("SdbGetMatchingExe didnt do anything, cannot determine SDBQUERYRESULT size\n"); @@ -1687,7 +1630,7 @@ START_TEST(db) test_MatchApplications(); break; case 2: - test_MatchApplications(); + test_MatchApplications(); break; default: skip("Skipping tests with SDBQUERYRESULT due to a wrong size reported\n"); diff --git a/rostests/apitests/apphelp/env.c b/rostests/apitests/apphelp/env.c new file mode 100644 index 00000000000..c244dd0888d --- /dev/null +++ b/rostests/apitests/apphelp/env.c @@ -0,0 +1,1323 @@ +/* + * Copyright 2016, 2017 Mark Jansen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#define WIN32_NO_STATUS +#include +#include +#include +#include +#ifdef __REACTOS__ +#include +#else +#include +#endif +#include +#include + +#include "wine/test.h" + +#include "apphelp_apitest.h" + +typedef void* HSDB; +typedef void* PDB; +typedef DWORD TAGREF; +typedef WORD TAG; + + + +static HMODULE hdll; + +BOOL(WINAPI *pSdbGetMatchingExe)(HSDB hsdb, LPCWSTR szPath, LPCWSTR szModuleName, LPCWSTR pszEnvironment, DWORD dwFlags, PSDBQUERYRESULT_VISTA pQueryResult); +HSDB (WINAPI *pSdbInitDatabase)(DWORD dwFlags, LPCWSTR pszDatabasePath); +void (WINAPI *pSdbReleaseDatabase)(HSDB hsdb); +BOOL (WINAPI *pSdbTagRefToTagID)(HSDB hsdb, TAGREF trWhich, PDB* ppdb, TAGID* ptiWhich); +TAG (WINAPI *pSdbGetTagFromTagID)(PDB pdb, TAGID tiWhich); +TAGREF (WINAPI *pSdbGetLayerTagRef)(HSDB hsdb, LPCWSTR layerName); + + +/* TODO: Investigate ApphelpCheckRunApp, for some reason there is not AppCompatData generated... */ + +BOOL (WINAPI *pApphelpCheckRunAppEx_w7)(HANDLE FileHandle, PVOID Unk1, PVOID Unk2, PWCHAR ApplicationName, PVOID Environment, USHORT ExeType, PULONG Reason, + PVOID* SdbQueryAppCompatData, PULONG SdbQueryAppCompatDataSize, PVOID* SxsData, PULONG SxsDataSize, + PULONG FusionFlags, PULONG64 SomeFlag1, PULONG SomeFlag2); + +BOOL (WINAPI *pApphelpCheckRunAppEx_w10)(HANDLE FileHandle, PVOID Unk1, PVOID Unk2, PWCHAR ApplicationName, PVOID Environment, PVOID Unk3, USHORT ExeType, PULONG Reason, + PVOID* SdbQueryAppCompatData, PULONG SdbQueryAppCompatDataSize, PVOID* SxsData, PULONG SxsDataSize, + PULONG FusionFlags, PULONG64 SomeFlag1, PULONG SomeFlag2); + + +BOOL (WINAPI *pSdbPackAppCompatData)(HSDB hsdb, PSDBQUERYRESULT_VISTA pQueryResult, PVOID* ppData, DWORD *dwSize); +BOOL (WINAPI *pSdbUnpackAppCompatData)(HSDB hsdb, LPCWSTR pszImageName, PVOID pData, PSDBQUERYRESULT_VISTA pQueryResult); +DWORD (WINAPI *pSdbGetAppCompatDataSize)(PVOID pData); + + +static HSDB g_LayerDB; +static DWORD g_ShimDataSize; +static DWORD g_ModuleVersion; +static const SDBQUERYRESULT_VISTA empty_result = { { 0 } }; +static const SDBQUERYRESULT_VISTA almost_empty = { { 0 }, { 0 }, { 0 }, 0, 0, 0, 0, { 0 }, SHIMREG_DISABLE_LAYER, 0 }; + + +#define SHIMDATA_MAGIC 0xAC0DEDAB +#define MAX_LAYER_LENGTH 256 + + +typedef struct ShimData_Win2k3 +{ + WCHAR szModule[34]; + DWORD dwSize; + DWORD dwMagic; + + TAGREF atrExes[SDB_MAX_EXES_2k3]; + TAGREF atrLayers[SDB_MAX_LAYERS]; + DWORD dwUnk0; + DWORD dwUnk1; + DWORD dwCustomSDBMap; + GUID rgGuidDB[SDB_MAX_SDBS]; +} ShimData_Win2k3; + + + +typedef struct ShimData_Win7 +{ + WCHAR szModule[260]; + DWORD dwSize; + DWORD dwMagic; + SDBQUERYRESULT_VISTA Query; + WCHAR szLayer[MAX_LAYER_LENGTH]; + DWORD unknown; // 0x14c +} ShimData_Win7; + +typedef struct ShimData_Win10_v1 +{ + WCHAR szModule[260]; + DWORD dwSize; + DWORD dwMagic; + DWORD unk1; + SDBQUERYRESULT_VISTA Query; + WCHAR szLayer[MAX_LAYER_LENGTH]; + char padding1[0x200]; + char padding2[0x404]; // Contains some data at the start + DWORD unk2; + DWORD unk3; + WCHAR processname[MAX_PATH]; + WCHAR szLayerEnv[MAX_LAYER_LENGTH]; + WCHAR unk4[MAX_LAYER_LENGTH]; + char padding4[120]; +} ShimData_Win10_v1; + +typedef struct ShimData_Win10_v2 +{ + DWORD dwSize; + DWORD dwMagic; + DWORD unk1; + DWORD unk2; + SDBQUERYRESULT_VISTA Query; + WCHAR szLayer[MAX_LAYER_LENGTH]; + char padding1[0x200]; + char padding2[0x2ae + 0x54 + 0x2a + 0x16 + 0x16]; + DWORD unk3; + DWORD unk4; + WCHAR processname[MAX_PATH-2]; + WCHAR szLayerEnv[MAX_LAYER_LENGTH]; + WCHAR unk5[MAX_LAYER_LENGTH]; + char padding4[76]; +} ShimData_Win10_v2; + +typedef struct ShimData_QueryOffset +{ + DWORD dwSize_10_v2; + DWORD dwMagic_10_v2; + + char spacing1[60]; + + DWORD dwSize_2k3; + DWORD dwMagic_2k3; + + char spacing2[444]; + + DWORD dwSize_7_10; + DWORD dwMagic_7_10; +} ShimData_QueryOffset; + + +C_ASSERT(sizeof(ShimData_Win2k3) == 392); +C_ASSERT(sizeof(ShimData_Win7) == 1500); +C_ASSERT(sizeof(ShimData_Win10_v1) == 4712); +C_ASSERT(sizeof(ShimData_Win10_v2) == 3976); + +C_ASSERT(offsetof(ShimData_Win10_v2, dwSize) == 0); +C_ASSERT(offsetof(ShimData_Win2k3, dwSize) == 68); +C_ASSERT(offsetof(ShimData_Win7, dwSize) == 520); +C_ASSERT(offsetof(ShimData_Win10_v1, dwSize) == 520); + +C_ASSERT(offsetof(ShimData_Win10_v2, dwMagic) == 4); +C_ASSERT(offsetof(ShimData_Win2k3, dwMagic) == 72); +C_ASSERT(offsetof(ShimData_Win7, dwMagic) == 524); +C_ASSERT(offsetof(ShimData_Win10_v1, dwMagic) == 524); + +C_ASSERT(offsetof(ShimData_QueryOffset, dwSize_10_v2) == 0); +C_ASSERT(offsetof(ShimData_QueryOffset, dwSize_2k3) == 68); +C_ASSERT(offsetof(ShimData_QueryOffset, dwSize_7_10) == 520); + +C_ASSERT(offsetof(ShimData_QueryOffset, dwMagic_10_v2) == 4); +C_ASSERT(offsetof(ShimData_QueryOffset, dwMagic_2k3) == 72); +C_ASSERT(offsetof(ShimData_QueryOffset, dwMagic_7_10) == 524); + + + +#define SDB_DATABASE_MAIN_SHIM 0x80030000 + +#define SDBGMEF_IGNORE_ENVIRONMENT 0x1 + + +typedef struct test_RemoteShimInfo +{ + ULARGE_INTEGER AppCompatFlags; + ULARGE_INTEGER AppCompatFlagsUser; + PVOID pShimData; + DWORD ShimDataSize; + PVOID AppCompatInfo; +} test_RemoteShimInfo; + + +static BOOL readproc(HANDLE proc, LPVOID address, PVOID target, DWORD size) +{ + SIZE_T dwRead; + if (ReadProcessMemory(proc, address, target, size, &dwRead)) + { + ok(dwRead == size, "Expected to read %u bytes, got %lu\n", size, dwRead); + return dwRead == size; + } + ok(0, "RPM failed with %u\n", GetLastError()); + return FALSE; +} + +static BOOL get_shiminfo(HANDLE proc, test_RemoteShimInfo* info) +{ + PROCESS_BASIC_INFORMATION pbi = { 0 }; + ULONG sizeOut = 0; + NTSTATUS status = NtQueryInformationProcess(proc, ProcessBasicInformation, &pbi, sizeof(pbi), &sizeOut); + ok(NT_SUCCESS(status), "Expected NtQI to succeed, but failed with: %x\n", status); + memset(info, 0, sizeof(*info)); + if (NT_SUCCESS(status)) + { + PEB peb = { 0 }; + if (readproc(proc, pbi.PebBaseAddress, &peb, sizeof(peb))) + { + MEMORY_BASIC_INFORMATION mbi = { 0 }; + SIZE_T dwRead; + + info->AppCompatFlags = peb.AppCompatFlags; + info->AppCompatFlagsUser = peb.AppCompatFlagsUser; + info->AppCompatInfo = peb.AppCompatInfo; + if (peb.pShimData == NULL) + return TRUE; + + dwRead = VirtualQueryEx(proc, (LPCVOID)peb.pShimData, &mbi, sizeof(mbi)); + ok(dwRead == sizeof(mbi), "Expected VQE to return %u, got %lu\n", sizeof(mbi), dwRead); + if (dwRead == sizeof(mbi) || peb.pShimData == NULL) + { + info->ShimDataSize = mbi.RegionSize; + info->pShimData = malloc(mbi.RegionSize); + if (readproc(proc, peb.pShimData, info->pShimData, mbi.RegionSize)) + return TRUE; + free(info->pShimData); + info->pShimData = NULL; + } + } + } + return FALSE; +} + +static HANDLE create_proc(BOOL suspended) +{ + static char proc_name[MAX_PATH] = { 0 }; + STARTUPINFOA si = {sizeof(si)}; + PROCESS_INFORMATION pi; + BOOL res; + if (!proc_name[0]) + { + GetModuleFileNameA(NULL, proc_name, MAX_PATH); + } + + res = CreateProcessA(NULL, proc_name, NULL, NULL, TRUE, suspended ? CREATE_SUSPENDED : 0, NULL, NULL, &si, &pi); + if (!res) + return NULL; + CloseHandle(pi.hThread); + return pi.hProcess; +} + +static void create_environ(const char* layers[], size_t num) +{ + char buf[256] = { 0 }; + size_t n; + for (n = 0; n < num; ++n) + { + if (n) + strcat(buf, " "); + strcat(buf, layers[n]); + } + SetEnvironmentVariableA("__COMPAT_LAYER", buf); +} + +static void ValidateShim(TAGREF trLayer, const char* name) +{ + HSDB hsdb = pSdbInitDatabase(SDB_DATABASE_MAIN_SHIM, NULL); + ok(hsdb != NULL, "Expected a valid handle\n"); + if (hsdb) + { + PDB pdb = NULL; + TAGID tagid = 0xdeadbeef; + WCHAR nameW[256] = { 0 }; + BOOL ret; + + mbstowcs(nameW, name, strlen(name)); + + ret = pSdbTagRefToTagID(hsdb, trLayer, &pdb, &tagid); + ok(ret == TRUE, "Expected pSdbTagRefToTagID to succeed\n"); + if (ret) + { + TAG tag; + ok(pdb != NULL, "Expected pdb to be a valid pointer\n"); + ok(tagid != 0 && tagid != 0xdeadbeef, "Expected tagid to be a valid tag id, was: 0x%x\n", tagid); + tag = pSdbGetTagFromTagID(pdb, tagid); + ok(tag == 0x700b, "Expected tag to be 0x700b, was 0x%x\n", (DWORD)tag); + } + + pSdbReleaseDatabase(hsdb); + } +} + + +static void Validate_ShimData_Win2k3(PVOID data, size_t count, const char* layers[]) +{ + //size_t n; + ShimData_Win2k3* pShimData = (ShimData_Win2k3*)data; + + 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)); + ok(pShimData->dwMagic == SHIMDATA_MAGIC, "Expected pShimData->dwMagic to be 0x%x, was 0x%x\n", SHIMDATA_MAGIC, pShimData->dwMagic); + ok(pShimData->dwSize == sizeof(ShimData_Win2k3), "Expected pShimData->dwSize to be %u, was %u\n", sizeof(ShimData_Win2k3), pShimData->dwSize); + ok(pShimData->dwCustomSDBMap == 1, "Expected pShimData->dwCustomSDBMap to be 1, was %u\n", pShimData->dwCustomSDBMap); +} + +static void Validate_ShimData_Win7(PVOID data, WCHAR szApphelp[256], size_t count, const char* layers[]) +{ + size_t n; + ShimData_Win7* pShimData = (ShimData_Win7*)data; + + ok(!lstrcmpW(pShimData->szModule, szApphelp), "Expected pShimData->Module to be %s, was %s\n", + wine_dbgstr_w(szApphelp), wine_dbgstr_w(pShimData->szModule)); + ok(pShimData->dwMagic == SHIMDATA_MAGIC, "Expected pShimData->dwMagic to be 0x%x, was 0x%x\n", + SHIMDATA_MAGIC, pShimData->dwMagic); + ok(pShimData->dwSize == sizeof(ShimData_Win7), "Expected pShimData->dwSize to be %u, was %u\n", + sizeof(ShimData_Win7), pShimData->dwSize); + if (pShimData->Query.dwLayerCount != min(count, SDB_MAX_LAYERS)) + { + char buf[250] = {0}; + GetEnvironmentVariableA("__COMPAT_LAYER", buf, _countof(buf)); + trace("At test: %s\n", buf); + } + ok(pShimData->Query.dwLayerCount == min(count, SDB_MAX_LAYERS), + "Expected LayerCount to be %u, was %u\n", min(count, SDB_MAX_LAYERS), pShimData->Query.dwLayerCount); + for (n = 0; n < SDB_MAX_LAYERS; ++n) + { + if (n < count) + { + ok(pShimData->Query.atrLayers[n] != 0, "Expected to find a valid layer in index %u / %u\n", n, count); + ValidateShim(pShimData->Query.atrLayers[n], layers[n]); + } + else + ok(pShimData->Query.atrLayers[n] == 0, "Expected to find an empty layer in index %u / %u\n", n, count); + } + ok(pShimData->unknown == 0x14c, "Expected pShimData->unknown to be 0x14c, was 0x%x\n", pShimData->unknown); +} + +static void Validate_ShimData_Win10_v2(PVOID data, WCHAR szApphelp[256], size_t count, const char* layers[]) +{ + size_t n; + ShimData_Win10_v2* pShimData = (ShimData_Win10_v2*)data; + + if (pShimData->dwMagic != SHIMDATA_MAGIC) + { + skip("Yet another unknown shimdata variant...\n"); + return; + } + + ok(pShimData->dwSize == sizeof(ShimData_Win10_v2), "Expected pShimData->dwSize to be %u, was %u\n", + sizeof(ShimData_Win10_v2), pShimData->dwSize); + if (pShimData->Query.dwLayerCount != min(count, SDB_MAX_LAYERS)) + { + char buf[250] = {0}; + GetEnvironmentVariableA("__COMPAT_LAYER", buf, _countof(buf)); + trace("At test: %s\n", buf); + } + ok(pShimData->Query.dwLayerCount == min(count, SDB_MAX_LAYERS), + "Expected LayerCount to be %u, was %u\n", min(count, SDB_MAX_LAYERS), pShimData->Query.dwLayerCount); + for (n = 0; n < SDB_MAX_LAYERS; ++n) + { + if (n < count) + { + ok(pShimData->Query.atrLayers[n] != 0, "Expected to find a valid layer in index %u / %u\n", n, count); + ValidateShim(pShimData->Query.atrLayers[n], layers[n]); + } + else + ok(pShimData->Query.atrLayers[n] == 0, "Expected to find an empty layer in index %u / %u\n", n, count); + } + +} + +static void Validate_ShimData_Win10(PVOID data, WCHAR szApphelp[256], size_t count, const char* layers[]) +{ + size_t n; + ShimData_Win10_v1* pShimData = (ShimData_Win10_v1*)data; + + if (pShimData->dwMagic != SHIMDATA_MAGIC) + { + Validate_ShimData_Win10_v2(data, szApphelp, count, layers); + return; + } + + + ok(!lstrcmpiW(pShimData->szModule, szApphelp), "Expected pShimData->Module to be %s, was %s\n", + wine_dbgstr_w(szApphelp), wine_dbgstr_w(pShimData->szModule)); + ok(pShimData->dwSize == sizeof(ShimData_Win10_v1), "Expected pShimData->dwSize to be %u, was %u\n", + sizeof(ShimData_Win10_v1), pShimData->dwSize); + if (pShimData->Query.dwLayerCount != min(count, SDB_MAX_LAYERS)) + { + char buf[250] = {0}; + GetEnvironmentVariableA("__COMPAT_LAYER", buf, _countof(buf)); + trace("At test: %s\n", buf); + } + ok(pShimData->Query.dwLayerCount == min(count, SDB_MAX_LAYERS), + "Expected LayerCount to be %u, was %u\n", min(count, SDB_MAX_LAYERS), pShimData->Query.dwLayerCount); + for (n = 0; n < SDB_MAX_LAYERS; ++n) + { + if (n < count) + { + ok(pShimData->Query.atrLayers[n] != 0, "Expected to find a valid layer in index %u / %u\n", n, count); + ValidateShim(pShimData->Query.atrLayers[n], layers[n]); + } + else + ok(pShimData->Query.atrLayers[n] == 0, "Expected to find an empty layer in index %u / %u\n", n, count); + } +} + +static void Validate_EmptyShimData_Win10(PVOID data) +{ + ShimData_Win10_v1* pShimData = (ShimData_Win10_v1*)data; + ok(pShimData != NULL, "Expected pShimData\n"); + if (!pShimData) + return; + + if (pShimData->dwMagic != SHIMDATA_MAGIC) + { + ShimData_Win10_v2* pShimData2 = (ShimData_Win10_v2*)data; + if (pShimData2->dwMagic != SHIMDATA_MAGIC) + { + skip("Unknown shimdata (win10)\n"); + return; + } + + ok(!lstrcmpiW(pShimData2->szLayer, L""), "Expected pShimData->szLayer to be '', was %s\n", wine_dbgstr_w(pShimData2->szLayer)); + ok(pShimData2->dwSize == sizeof(ShimData_Win10_v2), "Expected pShimData->dwSize to be %u, was %u\n", sizeof(ShimData_Win10_v2), pShimData2->dwSize); + ok(!memcmp(&pShimData2->Query, &empty_result, sizeof(empty_result)), "Expected result to be empty\n"); + } + else + { + ok(!lstrcmpiW(pShimData->szModule, L""), "Expected pShimData->Module to be '', was %s\n", wine_dbgstr_w(pShimData->szModule)); + ok(!lstrcmpiW(pShimData->szLayer, L""), "Expected pShimData->szLayer to be '', was %s\n", wine_dbgstr_w(pShimData->szLayer)); + ok(pShimData->dwSize == sizeof(ShimData_Win10_v1), "Expected pShimData->dwSize to be %u, was %u\n", sizeof(ShimData_Win10_v1), pShimData->dwSize); + ok(!memcmp(&pShimData->Query, &empty_result, sizeof(empty_result)), "Expected result to be empty\n"); + } +} + +static void Test_layers(WCHAR szApphelp[256]) +{ + static const char* layers[] = { + "256Color", "NT4SP5", "DisableNXHideUI", "DisableNXShowUI", + "WIN2000SP3", "640X480", /*"DISABLEDWM",*/ "HIGHDPIAWARE", + /*"RUNASADMIN",*/ "DISABLETHEMES" /*, "Layer_Win95VersionLie"*/ }; + + size_t n; + HANDLE proc; + test_RemoteShimInfo info; + BOOL res; + + for (n = 0; n <= (sizeof(layers) / sizeof(layers[0])); ++n) + { + create_environ(layers, n); + + proc = create_proc(TRUE); + res = get_shiminfo(proc, &info); + TerminateProcess(proc, 0); + CloseHandle(proc); + + if (!res) + { + ok(0, "Unable to get process info (%u)!\n", n); + continue; + } + + if (n == 0) + { + ok(info.AppCompatFlags.QuadPart == 0, "Expected AppCompatFlags to be 0, was: %s\n", wine_dbgstr_longlong(info.AppCompatFlags.QuadPart)); + ok(info.AppCompatFlagsUser.QuadPart == 0, "Expected AppCompatFlagsUser to be 0, was: %s\n", wine_dbgstr_longlong(info.AppCompatFlagsUser.QuadPart)); + ok(info.AppCompatInfo == NULL, "Expected AppCompatInfo to be NULL, was: %p\n", info.AppCompatInfo); + if (g_WinVersion < WINVER_WIN10) + { + ok(info.pShimData == NULL, "Expected pShimData to be NULL, was: %p\n", info.pShimData); + } + else + { + Validate_EmptyShimData_Win10(info.pShimData); + } + } + else + { + ok(info.AppCompatFlags.QuadPart == 0, "Expected AppCompatFlags to be 0, was: %s\n", wine_dbgstr_longlong(info.AppCompatFlags.QuadPart)); + ok(info.AppCompatFlagsUser.QuadPart == 0, "Expected AppCompatFlagsUser to be 0, was: %s\n", wine_dbgstr_longlong(info.AppCompatFlagsUser.QuadPart)); + ok(info.AppCompatInfo == NULL, "Expected AppCompatInfo to be NULL, was: %p\n", info.AppCompatInfo); + ok(info.pShimData != NULL, "Expected pShimData to be valid, was NULL\n"); + ok(info.ShimDataSize == g_ShimDataSize, "Expected ShimDataSize to be %u, was: %u\n", g_ShimDataSize, info.ShimDataSize); + if (info.pShimData) + { + if (g_WinVersion < WINVER_VISTA) + Validate_ShimData_Win2k3(info.pShimData, n, layers); + else if (g_WinVersion < WINVER_WIN10) + Validate_ShimData_Win7(info.pShimData, szApphelp, n, layers); + else + Validate_ShimData_Win10(info.pShimData, szApphelp, n, layers); + } + } + free(info.pShimData); + } +} + + +/* +[Warn][SdbGetMatchingExe ] __COMPAT_LAYER name cannot exceed 256 characters. +[Info][SdbpGetPermLayersInternal] Failed to read value info from Key "\Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers" Status 0xc0000034 +[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 +[Warn][SdbpEnumUserSdb ] Failed to open key "\Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Custom\NotepadReplacer.exe" Status 0xc0000034 +*/ +static void Test_repeatlayer(WCHAR szApphelp[256]) +{ + static const char* layers[] = { + "256Color", "256Color", "256Color", "256Color", + "256Color", "256Color", "256Color", "256Color" }; + + HANDLE proc; + test_RemoteShimInfo info; + BOOL res; + + SetEnvironmentVariableA("__COMPAT_LAYER", "256Color 256Color 256Color 256Color 256Color 256Color 256Color 256Color"); + + + proc = create_proc(TRUE); + res = get_shiminfo(proc, &info); + TerminateProcess(proc, 0); + CloseHandle(proc); + + if (res) + { + ok(info.AppCompatFlags.QuadPart == 0, "Expected AppCompatFlags to be 0, was: %s\n", wine_dbgstr_longlong(info.AppCompatFlags.QuadPart)); + ok(info.AppCompatFlagsUser.QuadPart == 0, "Expected AppCompatFlagsUser to be 0, was: %s\n", wine_dbgstr_longlong(info.AppCompatFlagsUser.QuadPart)); + ok(info.AppCompatInfo == 0, "Expected AppCompatInfo to be 0, was: %p\n", info.AppCompatInfo); + ok(info.pShimData != NULL, "Expected pShimData to be valid, was NULL\n"); + ok(info.ShimDataSize == g_ShimDataSize, "Expected ShimDataSize to be %u, was: %u\n", g_ShimDataSize, info.ShimDataSize); + if (info.pShimData) + { + /* Win10 only 'loads' one layer */ + if (g_WinVersion < WINVER_VISTA) + Validate_ShimData_Win2k3(info.pShimData, SDB_MAX_LAYERS, layers); + else if (g_WinVersion < WINVER_WIN10) + Validate_ShimData_Win7(info.pShimData, szApphelp, SDB_MAX_LAYERS, layers); + else + Validate_ShimData_Win10(info.pShimData, szApphelp, 1, layers); + } + } + else + { + ok(0, "Unable to get process info!\n"); + } + +} + + +TAGREF find_layer(const char* szLayerStart, const char* szLayerEnd) +{ + char layer[100] = { 0 }; + WCHAR layerW[100] = { 0 }; + strncpy(layer, szLayerStart, szLayerEnd - szLayerStart); + + if (!g_LayerDB) + { + g_LayerDB = pSdbInitDatabase(SDB_DATABASE_MAIN_SHIM, 0); + } + + mbstowcs(layerW, layer, strlen(layer)); + return pSdbGetLayerTagRef(g_LayerDB, layerW); +} + +static void expect_layeronly_imp(SDBQUERYRESULT_VISTA* result, const char* layers, DWORD flags) +{ + DWORD dwLayerCount = 0, n; + TAGREF atrLayers[SDB_MAX_LAYERS] = { 0 }; + + const char* layer = layers, *nextlayer; + while (layer && *layer) + { + nextlayer = strchr(layer, ' '); + atrLayers[dwLayerCount++] = find_layer(layer, nextlayer ? nextlayer : (layer + strlen(layer))); + layer = nextlayer ? (nextlayer+1) : NULL; + } + + if (g_ModuleVersion < WINVER_VISTA) + { + SDBQUERYRESULT_2k3* result2 = (SDBQUERYRESULT_2k3*)result; + result = NULL; + + winetest_ok(!memcmp(&result2->atrExes, &empty_result.atrExes, sizeof(result2->atrExes)), "Expected atrExes to be empty\n"); + 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"); + for (n = 0; n < dwLayerCount; ++n) + { + winetest_ok(result2->atrLayers[n] == atrLayers[n], "Expected atrLayers[%u] to be %x, was %x\n", + n, atrLayers[n], result2->atrLayers[n]); + } + winetest_ok(result2->dwLayerFlags == 0, "Expected dwLayerFlags to be 0, was %u\n", result2->dwLayerFlags); + winetest_ok(result2->trApphelp == 0, "Expected trApphelp to be 0, was %u\n", result2->trApphelp); + winetest_ok(result2->dwExeCount == 0, "Expected dwExeCount to be 0, was %u\n", result2->dwExeCount); + winetest_ok(result2->dwLayerCount == dwLayerCount, "Expected dwLayerCount to be %u, was %u\n", dwLayerCount, result2->dwLayerCount); + winetest_ok(!memcmp(&result2->guidID, &empty_result.guidID, sizeof(result2->guidID)), "Expected guidID to be empty\n"); + winetest_ok(result2->dwFlags == flags, "Expected dwFlags to be 0x%x, was 0x%x\n", flags, result2->dwFlags); + winetest_ok(result2->dwCustomSDBMap == 1, "Expected dwCustomSDBMap to be 1, was %u\n", result2->dwCustomSDBMap); + winetest_ok(!memcmp(&result2->rgGuidDB[1], &empty_result.rgGuidDB[1], sizeof(result2->rgGuidDB) - sizeof(result2->rgGuidDB[0])), "Expected rgGuidDB[+1] to be empty\n"); + } + else + { + winetest_ok(!memcmp(&result->atrExes, &empty_result.atrExes, sizeof(empty_result.atrExes)), "Expected atrExes to be empty\n"); + winetest_ok(!memcmp(&result->adwExeFlags, &empty_result.adwExeFlags, sizeof(empty_result.adwExeFlags)), "Expected adwExeFlags to be empty\n"); + 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"); + for (n = 0; n < dwLayerCount; ++n) + { + winetest_ok(result->atrLayers[n] == atrLayers[n], "Expected atrLayers[%u] to be %x, was %x\n", + n, atrLayers[n], result->atrLayers[n]); + } + winetest_ok(result->dwLayerFlags == 0, "Expected dwLayerFlags to be 0, was %u\n", result->dwLayerFlags); + winetest_ok(result->trApphelp == 0, "Expected trApphelp to be 0, was %u\n", result->trApphelp); + winetest_ok(result->dwExeCount == 0, "Expected dwExeCount to be 0, was %u\n", result->dwExeCount); + winetest_ok(result->dwLayerCount == dwLayerCount, "Expected dwLayerCount to be %u, was %u\n", dwLayerCount, result->dwLayerCount); + winetest_ok(!memcmp(&result->guidID, &empty_result.guidID, sizeof(empty_result.guidID)), "Expected guidID to be empty\n"); + winetest_ok(result->dwFlags == flags, "Expected dwFlags to be 0x%x, was 0x%x\n", flags, result->dwFlags); + winetest_ok(result->dwCustomSDBMap == 1, "Expected dwCustomSDBMap to be 1, was %u\n", result->dwCustomSDBMap); + 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"); + } +} + +static void Test_Shimdata(SDBQUERYRESULT_VISTA* result, const WCHAR* szLayer) +{ + BOOL ret; + PVOID pData; + DWORD dwSize; + + pData = NULL; + dwSize = 0; + ret = pSdbPackAppCompatData(g_LayerDB, result, &pData, &dwSize); + ok(ret == TRUE, "Expected ret to be TRUE\n"); + + if (pData) + { + ShimData_Win2k3* pWin2k3; + ShimData_Win7* pWin7; + ShimData_Win10_v1* pWin10; + ShimData_Win10_v2* pWin10_v2; + SDBQUERYRESULT_VISTA result2 = { { 0 } }; + + DWORD res = pSdbGetAppCompatDataSize(pData); + ok_int(dwSize, res); + switch(dwSize) + { + case sizeof(ShimData_Win2k3): + pWin2k3 = (ShimData_Win2k3*)pData; + ok_hex(pWin2k3->dwMagic, SHIMDATA_MAGIC); + ok_int(pWin2k3->dwSize, dwSize); + ok(pWin2k3->dwCustomSDBMap == 1, "Expected pWin2k3->dwCustomSDBMap to equal 1, was %u for %s\n", pWin2k3->dwCustomSDBMap, wine_dbgstr_w(szLayer)); + //ok(!memcmp(&pWin2k3->Query, result, sizeof(SDBQUERYRESULT_2k3)), "Expected pWin2k3->Query to equal result\n"); + //ok_wstr(pWin7->szLayer, szLayer); + break; + case sizeof(ShimData_Win7): + pWin7 = (ShimData_Win7*)pData; + ok_hex(pWin7->dwMagic, SHIMDATA_MAGIC); + ok_int(pWin7->dwSize, dwSize); + ok(!memcmp(&pWin7->Query, result, sizeof(*result)), "Expected pWin7->Query to equal result\n"); + ok_wstr(pWin7->szLayer, szLayer); + break; + case sizeof(ShimData_Win10_v1): + pWin10 = (ShimData_Win10_v1*)pData; + ok_hex(pWin10->dwMagic, SHIMDATA_MAGIC); + ok_int(pWin10->dwSize, dwSize); + ok(!memcmp(&pWin10->Query, result, sizeof(*result)), "Expected pWin10->Query to equal result\n"); + ok_wstr(pWin10->szLayerEnv, szLayer); + ok_wstr(pWin10->szLayer, L""); + break; + case sizeof(ShimData_Win10_v2): + pWin10_v2 = (ShimData_Win10_v2*)pData; + ok_hex(pWin10_v2->dwMagic, SHIMDATA_MAGIC); + ok_int(pWin10_v2->dwSize, dwSize); + ok(!memcmp(&pWin10_v2->Query, result, sizeof(*result)), "Expected pWin10->Query to equal result\n"); + ok_wstr(pWin10_v2->szLayerEnv, szLayer); + ok_wstr(pWin10_v2->szLayer, L""); + break; + default: + skip("Unknown size %d\n", dwSize); + break; + } + + ret = pSdbUnpackAppCompatData(g_LayerDB, NULL, pData, &result2); + ok(ret == TRUE, "Expected ret to be TRUE\n"); + /* TODO: For some reason 2k3 does not seem to output the database GUIDs, + investigate when we have support for multible db's! */ + if (dwSize == sizeof(ShimData_Win2k3)) + { + /* Fake it for now, so the memcmp works. */ + SDBQUERYRESULT_2k3* input = (SDBQUERYRESULT_2k3*)result; + SDBQUERYRESULT_2k3* output = (SDBQUERYRESULT_2k3*)&result2; + ok(output->dwCustomSDBMap == 0, "Expected output->dwCustomSDBMap to be 0, was %u for %s\n", output->dwCustomSDBMap, wine_dbgstr_w(szLayer)); + output->dwCustomSDBMap = input->dwCustomSDBMap; + output->rgGuidDB[0] = input->rgGuidDB[0]; + } + ok(!memcmp(&result2, result, sizeof(result)), "Expected result2 to equal result for %s\n", wine_dbgstr_w(szLayer)); + + RtlFreeHeap(GetProcessHeap(), 0, pData); + } +} + + +#define expect_layeronly (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : expect_layeronly_imp + + +static void Test_GetMatchingExe(void) +{ + BOOL ret; + SDBQUERYRESULT_VISTA result = { { 0 } }; + WCHAR self[MAX_PATH]; + DWORD flags = (g_WinVersion < WINVER_VISTA) ? 0 : ((g_WinVersion < WINVER_WIN10) ? 1 : 0x21); + + GetModuleFileNameW(NULL, self, MAX_PATH); + SetEnvironmentVariableA("__COMPAT_LAYER", NULL); + + /* szPath cannot be NULL! */ + ret = pSdbGetMatchingExe(NULL, L"", NULL, NULL, 0, &result); + ok(ret == FALSE, "Expected ret to be FALSE\n"); + ok(!memcmp(&result, &empty_result, sizeof(empty_result)), "Expected result to be empty\n"); + + result = empty_result; + + ret = pSdbGetMatchingExe(NULL, self, NULL, NULL, 0, &result); + ok(ret == FALSE, "Expected ret to be FALSE\n"); + ok(!memcmp(&result, &empty_result, sizeof(empty_result)), "Expected result to be empty\n"); + + result = empty_result; + SetEnvironmentVariableA("__COMPAT_LAYER", "Some_invalid_layer_name"); + + ret = pSdbGetMatchingExe(NULL, self, NULL, NULL, 0, &result); + ok(ret == FALSE, "Expected ret to be FALSE\n"); + if (g_WinVersion < WINVER_WIN10) + ok(!memcmp(&result, &empty_result, sizeof(empty_result)), "Expected result to be empty\n"); + else + ok(!memcmp(&result, &almost_empty, sizeof(almost_empty)), "Expected result to be almost empty\n"); + + result = empty_result; + SetEnvironmentVariableA("__COMPAT_LAYER", "256Color"); + + ret = pSdbGetMatchingExe(NULL, self, NULL, NULL, 0, &result); + ok(ret == TRUE, "Expected ret to be TRUE\n"); + expect_layeronly(&result, "256Color", flags); + + Test_Shimdata(&result, L"256Color"); + + result = empty_result; + SetEnvironmentVariableA("__COMPAT_LAYER", "640X480"); + + ret = pSdbGetMatchingExe(NULL, self, NULL, NULL, 0, &result); + ok(ret == TRUE, "Expected ret to be TRUE\n"); + expect_layeronly(&result, "640X480", flags); + + Test_Shimdata(&result, L"640X480"); + + /* HIGHDPIAWARE does not exist in 2k3 */ + if (g_WinVersion > WINVER_2003) + { + result = empty_result; + SetEnvironmentVariableA("__COMPAT_LAYER", "HIGHDPIAWARE"); + + ret = pSdbGetMatchingExe(NULL, self, NULL, NULL, 0, &result); + ok(ret == TRUE, "Expected ret to be TRUE\n"); + expect_layeronly(&result, "HIGHDPIAWARE", flags); + + Test_Shimdata(&result, L"HIGHDPIAWARE"); + + result = empty_result; + SetEnvironmentVariableA("__COMPAT_LAYER", "256Color HIGHDPIAWARE 640X480"); + + ret = pSdbGetMatchingExe(NULL, self, NULL, NULL, 0, &result); + ok(ret == TRUE, "Expected ret to be TRUE\n"); + expect_layeronly(&result, "256Color HIGHDPIAWARE 640X480", flags); + + Test_Shimdata(&result, L"256Color HIGHDPIAWARE 640X480"); + } +} + + +HANDLE xOpenFile(WCHAR* ApplicationName) +{ + UNICODE_STRING FileName; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS Status; + HANDLE FileHandle; + + if (!RtlDosPathNameToNtPathName_U(ApplicationName, &FileName, NULL, NULL)) + { + skip("Unable to translate %s to Nt path\n", wine_dbgstr_w(ApplicationName)); + return NULL; + } + + + InitializeObjectAttributes(&ObjectAttributes, &FileName, OBJ_CASE_INSENSITIVE, NULL, NULL); + Status = NtOpenFile(&FileHandle, + SYNCHRONIZE | + FILE_READ_ATTRIBUTES | + FILE_READ_DATA | + FILE_EXECUTE, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_SYNCHRONOUS_IO_NONALERT | + FILE_NON_DIRECTORY_FILE); + + RtlFreeUnicodeString(&FileName); + + if (!NT_SUCCESS(Status)) + return NULL; + + return FileHandle; +} + + +#define RESET_CHECKRUNAPP_VARS()\ + do { \ + if (AppCompatData && AppCompatData != &Query) { RtlFreeHeap(RtlGetProcessHeap(), 0, AppCompatData); } \ + ExeType = IMAGE_FILE_MACHINE_I386; \ + SxsDataSize = FusionFlags = Reason = 0; \ + SxsData = NULL; \ + memset(&Query, 0, sizeof(Query)); \ + AppCompatData = &Query; \ + AppCompatDataSize = 123456; \ + } while (0) + +#define CHECK_BASICS()\ + do { \ + ok_hex(ret, TRUE); \ + ok(AppCompatData != NULL && AppCompatData != &Query, "Expected the pointer to be valid\n"); \ + ok_hex(AppCompatDataSize, sizeof(SDBQUERYRESULT_VISTA)); \ + ok(SxsData == NULL, "Expected the pointer to be NULL\n"); \ + ok_hex(SxsDataSize, 0); \ + ok_hex(FusionFlags, 0); \ + } while (0) + +/* W10 does not seem to use the flags at all, so with this macro we can still test it below 10. */ +#define CHECKREASON(value, w10dum) (g_ModuleVersion < WINVER_WIN10 ? value : w10dum) + + +static BOOL call_ApphelpCheckRunApp(HANDLE FileHandle, PWCHAR ApplicationName, PVOID Environment, USHORT ExeType, + PULONG Reason, PVOID* SdbQueryAppCompatData, PULONG SdbQueryAppCompatDataSize, + PVOID* SxsData, PULONG SxsDataSize, PULONG FusionFlags) +{ + ULONG64 SomeFlag1 = 0; + ULONG SomeFlag2 = 0; + + if (pApphelpCheckRunAppEx_w7) + { + return pApphelpCheckRunAppEx_w7(FileHandle, NULL, NULL, ApplicationName, Environment, ExeType, Reason, + SdbQueryAppCompatData, SdbQueryAppCompatDataSize, SxsData, SxsDataSize, + FusionFlags, &SomeFlag1, &SomeFlag2); + } + + if (pApphelpCheckRunAppEx_w10) + { + return pApphelpCheckRunAppEx_w10(FileHandle, NULL, NULL, ApplicationName, Environment, NULL, ExeType, Reason, + SdbQueryAppCompatData, SdbQueryAppCompatDataSize, SxsData, SxsDataSize, + FusionFlags, &SomeFlag1, &SomeFlag2); + } + + return FALSE; +} + + + + + +static void Test_ApphelpCheckRunApp(WCHAR szApphelp[256]) +{ + BOOL ret; + HANDLE FileHandle = NULL; + WCHAR ApplicationName[MAX_PATH], EmptyName[1] = { 0 }; + DWORD expect_flags = (g_WinVersion < WINVER_WIN10) ? 1 : 0x21; + + USHORT ExeType; + PVOID AppCompatData = NULL, SxsData, DuplicatedEnv, Environment; + ULONG AppCompatDataSize, SxsDataSize, FusionFlags; + ULONG Reason; + SDBQUERYRESULT_VISTA Query; + int n; + /* this are the only interesting bits (with the exception of '1', which is there to invoke the 'default' case) */ + const int kTestBits = 0x70503; + + if (!pApphelpCheckRunAppEx_w7 && !pApphelpCheckRunAppEx_w10) + { + skip("No usable ApphelpCheckRunAppEx\n"); + return; + } + + GetModuleFileNameW(NULL, ApplicationName, MAX_PATH); + + FileHandle = xOpenFile(ApplicationName); + SetEnvironmentVariableA("__COMPAT_LAYER", NULL); + if (!CreateEnvironmentBlock(&DuplicatedEnv, NULL, TRUE)) + DuplicatedEnv = NULL; + ok(DuplicatedEnv != NULL, "Invalid env (%u)\n", GetLastError()); + + /* First with the environment without __COMPAT_LAYER */ + RESET_CHECKRUNAPP_VARS(); + + ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, DuplicatedEnv, ExeType, &Reason, + &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags); + + CHECK_BASICS(); + ok_hex(Reason, CHECKREASON(0x30000, 0)); + ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n"); + + /* We need this to be set for tests later on. */ + SetEnvironmentVariableA("__COMPAT_LAYER", "256Color"); + + if (g_ModuleVersion < WINVER_WIN10) + { + /* Showing that when an environment is passed in, that is used instead of the current. + In Win10 this behavior is no longer observed */ + + RESET_CHECKRUNAPP_VARS(); + + ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, DuplicatedEnv, ExeType, &Reason, + &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags); + + CHECK_BASICS(); + ok_hex(Reason, CHECKREASON(0x30000, 0)); + ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n"); + } + + for (n = 0; n < 32; ++n) + { + ULONG ExpectedReason; + if (!(kTestBits & (1<= WINVER_WIN10) + expect_layeronly(AppCompatData, "256Color", expect_flags); + else + ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n"); + } + } + + /* NULL file handle still works */ + RESET_CHECKRUNAPP_VARS(); + + ret = call_ApphelpCheckRunApp(NULL, ApplicationName, Environment, ExeType, &Reason, + &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags); + + CHECK_BASICS(); + ok_hex(Reason, CHECKREASON(0x50000, 0)); + if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA)) + expect_layeronly(AppCompatData, "256Color", expect_flags); + + for (n = 0; n < 32; ++n) + { + ULONG ExpectedReason; + RESET_CHECKRUNAPP_VARS(); + if (!(kTestBits & (1<= WINVER_WIN10) + expect_layeronly(AppCompatData, "256Color", expect_flags); + else + ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n"); + } + } + + + /* INVALID_HANDLE_VALUE file handle results in failure (according to flags!), but still results in AppCompatData */ + RESET_CHECKRUNAPP_VARS(); + + ret = call_ApphelpCheckRunApp(INVALID_HANDLE_VALUE, ApplicationName, Environment, ExeType, &Reason, + &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags); + + CHECK_BASICS(); + ok_hex(Reason, 0); + if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA)) + expect_layeronly(AppCompatData, "256Color", expect_flags); + + for (n = 0; n < 32; ++n) + { + ULONG ExpectedReason; + if (!(kTestBits & (1<= WINVER_WIN10) + expect_layeronly(AppCompatData, "256Color", expect_flags); + else + ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n"); + } + } + + + RESET_CHECKRUNAPP_VARS(); + ExeType = IMAGE_FILE_MACHINE_POWERPCFP; + + ret = call_ApphelpCheckRunApp(FileHandle, ApplicationName, Environment, ExeType, &Reason, + &AppCompatData, &AppCompatDataSize, &SxsData, &SxsDataSize, &FusionFlags); + + CHECK_BASICS(); + ok_hex(Reason, CHECKREASON(0x50000, 0)); + if (AppCompatData && AppCompatDataSize == sizeof(SDBQUERYRESULT_VISTA)) + expect_layeronly(AppCompatData, "256Color", expect_flags); + + for (n = 0; n < 32; ++n) + { + ULONG ExpectedReason; + if (!(kTestBits & (1<= WINVER_WIN10) + expect_layeronly(AppCompatData, "256Color", expect_flags); + else + ok(!memcmp(AppCompatData, &empty_result, sizeof(empty_result)), "Expected result to be empty\n"); + } + } + + + if (AppCompatData && AppCompatData != &Query) + RtlFreeHeap(RtlGetProcessHeap(), 0, AppCompatData); + + FreeEnvironmentStringsW(Environment); + DestroyEnvironmentBlock(DuplicatedEnv); + NtClose(FileHandle); +} + + +START_TEST(env) +{ + WCHAR szApphelp[MAX_PATH]; + ShimData_QueryOffset QueryOffset; + DWORD ShimDataType; + NTSTATUS ExceptionStatus = STATUS_SUCCESS; + + SetEnvironmentVariable("SHIM_DEBUG_LEVEL", "127"); + SetEnvironmentVariable("SHIMENG_DEBUG_LEVEL", "127"); + + //silence_debug_output(); + + hdll = LoadLibraryA("apphelp.dll"); + + + + g_WinVersion = get_host_winver(); + g_ModuleVersion = get_module_version(hdll); + trace("Detected host: 0x%x, module: 0x%x\n", g_WinVersion, g_ModuleVersion); + + GetModuleFileNameW(hdll, szApphelp, _countof(szApphelp)); + + + pSdbGetMatchingExe = (void*)GetProcAddress(hdll, "SdbGetMatchingExe"); + pSdbInitDatabase = (void*)GetProcAddress(hdll, "SdbInitDatabase"); + pSdbReleaseDatabase = (void*)GetProcAddress(hdll, "SdbReleaseDatabase"); + pSdbTagRefToTagID = (void*)GetProcAddress(hdll, "SdbTagRefToTagID"); + pSdbGetTagFromTagID = (void*)GetProcAddress(hdll, "SdbGetTagFromTagID"); + pSdbGetLayerTagRef = (void*)GetProcAddress(hdll, "SdbGetLayerTagRef"); + + switch (g_ModuleVersion) + { + case WINVER_WIN7: + pApphelpCheckRunAppEx_w7 = (void*)GetProcAddress(hdll, "ApphelpCheckRunAppEx"); + break; + case WINVER_WIN10: + pApphelpCheckRunAppEx_w10 = (void*)GetProcAddress(hdll, "ApphelpCheckRunAppEx"); + break; + default: + skip("Unknown apphelp.dll version %x, cannot determine which ApphelpCheckRunApp(Ex) function to use\n", g_ModuleVersion); + break; + } + + pSdbPackAppCompatData = (void*)GetProcAddress(hdll, "SdbPackAppCompatData"); + pSdbUnpackAppCompatData = (void*)GetProcAddress(hdll, "SdbUnpackAppCompatData"); + pSdbGetAppCompatDataSize = (void*)GetProcAddress(hdll, "SdbGetAppCompatDataSize"); + + + memset(&QueryOffset, 0, sizeof(QueryOffset)); + QueryOffset.dwMagic_2k3 = QueryOffset.dwMagic_7_10 = QueryOffset.dwMagic_10_v2 = SHIMDATA_MAGIC; + QueryOffset.dwSize_2k3 = 1; + QueryOffset.dwSize_7_10 = 2; + QueryOffset.dwSize_10_v2 = 3; + + g_ShimDataSize = g_WinVersion < WINVER_WIN10 ? 4096 : 8192; + _SEH2_TRY + { + ShimDataType = pSdbGetAppCompatDataSize(&QueryOffset); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + ExceptionStatus = _SEH2_GetExceptionCode(); + } + _SEH2_END; + + ok(ExceptionStatus == STATUS_SUCCESS, "Exception 0x%08x, expected 0x%08x\n", ExceptionStatus, STATUS_SUCCESS); + if (ExceptionStatus != STATUS_SUCCESS) + { + skip("SdbGetAppCompatDataSize not functional\n"); + return; + } + + if (g_WinVersion == WINVER_WIN10 && ShimDataType == 3) + g_ShimDataSize = 4096; + + if (g_WinVersion == g_ModuleVersion) + { + Test_layers(szApphelp); + Test_repeatlayer(szApphelp); + } + else + { + skip("Tests requiring process launch, reported OS version (0x%x) does not match apphelp version (0x%x)\n", g_WinVersion, g_ModuleVersion); + } + + { + Test_GetMatchingExe(); + } + + Test_ApphelpCheckRunApp(szApphelp); + if (g_LayerDB) + pSdbReleaseDatabase(g_LayerDB); +} + diff --git a/rostests/apitests/apphelp/testlist.c b/rostests/apitests/apphelp/testlist.c index 167bbb369a2..a90da5fba5d 100644 --- a/rostests/apitests/apphelp/testlist.c +++ b/rostests/apitests/apphelp/testlist.c @@ -5,12 +5,14 @@ extern void func_apphelp(void); extern void func_db(void); +extern void func_env(void); extern void func_layerapi(void); const struct test winetest_testlist[] = { { "apphelp", func_apphelp }, { "db", func_db }, + { "env", func_env }, { "layerapi", func_layerapi }, { 0, 0 } }; -- 2.17.1