From d39ff22033c90adda097a8065b448d2fe3aaa274 Mon Sep 17 00:00:00 2001 From: Mark Jansen Date: Sat, 3 Dec 2016 21:24:47 +0000 Subject: [PATCH] [APPSHIM_APITEST] Add tests for display mode shims. CORE-11927 svn path=/trunk/; revision=73421 --- rostests/apitests/appshim/CMakeLists.txt | 1 + rostests/apitests/appshim/dispmode.c | 301 +++++++++++++++++++++++ rostests/apitests/appshim/testlist.c | 2 + rostests/apitests/appshim/versionlie.c | 19 -- 4 files changed, 304 insertions(+), 19 deletions(-) create mode 100644 rostests/apitests/appshim/dispmode.c diff --git a/rostests/apitests/appshim/CMakeLists.txt b/rostests/apitests/appshim/CMakeLists.txt index 45f4098c660..efb6594406e 100644 --- a/rostests/apitests/appshim/CMakeLists.txt +++ b/rostests/apitests/appshim/CMakeLists.txt @@ -2,6 +2,7 @@ project(appcompat) add_definitions(-D__ROS_LONG64__) list(APPEND SOURCE + dispmode.c versionlie.c testlist.c) diff --git a/rostests/apitests/appshim/dispmode.c b/rostests/apitests/appshim/dispmode.c new file mode 100644 index 00000000000..99f1bdf3387 --- /dev/null +++ b/rostests/apitests/appshim/dispmode.c @@ -0,0 +1,301 @@ +/* + * Copyright 2016 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 +#ifdef __REACTOS__ +#include +#else +#include +#endif +#include +#include +#include "wine/test.h" + +extern DWORD get_host_winver(void); +static DWORD g_WinVersion; +#define WINVER_ANY 0 +#define WINVER_VISTA 0x0600 + + +/* apphelp.dll */ +static BOOL(WINAPI* pSdbGetAppPatchDir)(PVOID, LPWSTR, DWORD); + +/* aclayers.dll */ +static PVOID(WINAPI* pGetHookAPIs)(LPCSTR, LPCWSTR, PDWORD); +static BOOL(WINAPI* pNotifyShims)(DWORD fdwReason, PVOID ptr); + + +static LONG g_Count; +static DEVMODEA g_LastDevmode; +static DWORD g_LastFlags; + +LONG (WINAPI *pChangeDisplaySettingsA)(_In_opt_ PDEVMODEA lpDevMode, _In_ DWORD dwflags); +LONG WINAPI mChangeDisplaySettingsA(_In_opt_ PDEVMODEA lpDevMode, _In_ DWORD dwflags) +{ + g_Count++; + g_LastDevmode = *lpDevMode; + g_LastFlags = dwflags; + + return DISP_CHANGE_FAILED; +} + + +static void pre_8bit() +{ + g_Count = 0; + memset(&g_LastDevmode, 0, sizeof(g_LastDevmode)); + g_LastFlags = 0xffffffff; +} + +static void post_8bit() +{ + ok_int(g_Count, 1); + ok_hex(g_LastDevmode.dmFields & DM_BITSPERPEL, DM_BITSPERPEL); + ok_int(g_LastDevmode.dmBitsPerPel, 8); + ok_hex(g_LastFlags, CDS_FULLSCREEN); +} + +static void pre_640() +{ + g_Count = 0; + memset(&g_LastDevmode, 0, sizeof(g_LastDevmode)); + g_LastFlags = 0xffffffff; +} + +static void post_640() +{ + ok_int(g_Count, 1); + ok_hex(g_LastDevmode.dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT), (DM_PELSWIDTH | DM_PELSHEIGHT)); + ok_int(g_LastDevmode.dmPelsWidth, 640); + ok_int(g_LastDevmode.dmPelsHeight, 480); + ok_hex(g_LastFlags, CDS_FULLSCREEN); +} + + + + +static PIMAGE_IMPORT_DESCRIPTOR FindImportDescriptor(PBYTE DllBase, PCSTR DllName) +{ + ULONG Size; + PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor = RtlImageDirectoryEntryToData((HMODULE)DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &Size); + while (ImportDescriptor->Name && ImportDescriptor->OriginalFirstThunk) + { + PCHAR Name = (PCHAR)(DllBase + ImportDescriptor->Name); + if (!lstrcmpiA(Name, DllName)) + { + return ImportDescriptor; + } + ImportDescriptor++; + } + return NULL; +} + +static BOOL RedirectIat(HMODULE TargetDll, PCSTR DllName, PCSTR FunctionName, ULONG_PTR NewFunction, ULONG_PTR* OriginalFunction) +{ + PBYTE DllBase = (PBYTE)TargetDll; + PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor = FindImportDescriptor(DllBase, DllName); + if (ImportDescriptor) + { + // On loaded images, OriginalFirstThunk points to the name / ordinal of the function + PIMAGE_THUNK_DATA OriginalThunk = (PIMAGE_THUNK_DATA)(DllBase + ImportDescriptor->OriginalFirstThunk); + // FirstThunk points to the resolved address. + PIMAGE_THUNK_DATA FirstThunk = (PIMAGE_THUNK_DATA)(DllBase + ImportDescriptor->FirstThunk); + while (OriginalThunk->u1.AddressOfData && FirstThunk->u1.Function) + { + if (!IMAGE_SNAP_BY_ORDINAL32(OriginalThunk->u1.AddressOfData)) + { + PIMAGE_IMPORT_BY_NAME ImportName = (PIMAGE_IMPORT_BY_NAME)(DllBase + OriginalThunk->u1.AddressOfData); + if (!lstrcmpiA((PCSTR)ImportName->Name, FunctionName)) + { + DWORD dwOld; + VirtualProtect(&FirstThunk->u1.Function, sizeof(ULONG_PTR), PAGE_EXECUTE_READWRITE, &dwOld); + *OriginalFunction = FirstThunk->u1.Function; + FirstThunk->u1.Function = NewFunction; + VirtualProtect(&FirstThunk->u1.Function, sizeof(ULONG_PTR), dwOld, &dwOld); + return TRUE; + } + } + OriginalThunk++; + FirstThunk++; + } + skip("Unable to find the Import %s!%s\n", DllName, FunctionName); + } + else + { + skip("Unable to find the ImportDescriptor for %s\n", DllName); + } + return FALSE; +} + + + +static void test_one(LPCSTR shim, DWORD dwReason, void(*pre)(), void(*post)()) +{ + DWORD num_shims = 0; + WCHAR wide_shim[50] = { 0 }; + PVOID hook; + BOOL ret; + MultiByteToWideChar(CP_ACP, 0, shim, -1, wide_shim, 50); + + if (pre) + pre(); + + hook = pGetHookAPIs("", wide_shim, &num_shims); + if (hook == NULL) + { + skip("Skipping tests for layers (%s) not present in this os (0x%x)\n", shim, g_WinVersion); + return; + } + ok(hook != NULL, "Expected hook to be a valid pointer for %s\n", shim); + ok(num_shims == 0, "Expected not to find any apihooks, got: %u for %s\n", num_shims, shim); + + ret = pNotifyShims(dwReason, NULL); + + /* Win7 and Win10 return 1, w2k3 returns a pointer */ + ok(ret != 0, "Expected pNotifyShims to succeed (%i)\n", ret); + + if (post) + post(); +} + +static struct test_info +{ + const char* name; + DWORD winver; + DWORD reason; + void(*pre)(); + void(*post)(); +} tests[] = +{ + { "Force8BitColor", WINVER_ANY, 1, pre_8bit, post_8bit }, + { "Force8BitColor", WINVER_VISTA, 100, pre_8bit, post_8bit }, + { "Force640x480", WINVER_ANY, 1, pre_640, post_640 }, + { "Force640x480", WINVER_VISTA, 100, pre_640, post_640 }, + /* { "DisableThemes" }, AcGenral.dll */ +}; + + +static void run_test(size_t n, WCHAR* buf, BOOL unload) +{ + BOOL ret; + HMODULE dll; + + trace("Running %d (%s)\n", n, tests[n].name); + + dll = LoadLibraryW(buf); + pGetHookAPIs = (void*)GetProcAddress(dll, "GetHookAPIs"); + pNotifyShims = (void*)GetProcAddress(dll, "NotifyShims"); + + if (!pGetHookAPIs || !pNotifyShims) + { + skip("aclayers.dll not loaded, or does not export GetHookAPIs or pNotifyShims (%s, %p, %p)\n", + tests[n].name, pGetHookAPIs, pNotifyShims); + return; + } + + ret = RedirectIat(dll, "user32.dll", "ChangeDisplaySettingsA", (ULONG_PTR)mChangeDisplaySettingsA, (ULONG_PTR*)&pChangeDisplaySettingsA); + if (ret) + { + test_one(tests[n].name, tests[n].reason, tests[n].pre, tests[n].post); + } + else + { + ok(0, "Unable to redirect ChangeDisplaySettingsA!\n"); + } + FreeLibrary(dll); + if (unload) + { + dll = GetModuleHandleW(buf); + ok(dll == NULL, "Unable to unload %s\n", wine_dbgstr_w(buf)); + } +} + + +START_TEST(dispmode) +{ + HMODULE dll = LoadLibraryA("apphelp.dll"); + WCHAR buf[MAX_PATH]; + WCHAR aclayers[] = L"\\aclayers.dll"; + size_t n; + int argc; + char **argv; + + pSdbGetAppPatchDir = (void*)GetProcAddress(dll, "SdbGetAppPatchDir"); + if (!pSdbGetAppPatchDir) + { + skip("apphelp.dll not loaded, or does not export SdbGetAppPatchDir\n"); + return; + } + + g_WinVersion = get_host_winver(); + + pSdbGetAppPatchDir(NULL, buf, MAX_PATH); + StringCchCatW(buf, _countof(buf), aclayers); + + argc = winetest_get_mainargs(&argv); + if (argc < 3) + { + WCHAR path[MAX_PATH]; + GetModuleFileNameW(NULL, path, _countof(path)); + dll = GetModuleHandleW(buf); + if (dll != NULL) + trace("Loaded under a shim, running each test in it's own process\n"); + + for (n = 0; n < _countof(tests); ++n) + { + if (g_WinVersion < tests[n].winver) + continue; + + if (dll == NULL) + { + run_test(n, buf, TRUE); + } + else + { + WCHAR buf[MAX_PATH+40]; + STARTUPINFOW si = { sizeof(si) }; + PROCESS_INFORMATION pi; + BOOL created; + + StringCchPrintfW(buf, _countof(buf), L"\"%ls\" dispmode %u", path, n); + created = CreateProcessW(NULL, buf, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + ok(created, "Expected CreateProcess to succeed\n"); + if (created) + { + winetest_wait_child_process(pi.hProcess); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + } + } + } + } + else + { + n = (size_t)atoi(argv[2]); + if (n >= 0 && n < _countof(tests)) + { + run_test(n, buf, FALSE); + } + else + { + ok(0, "Test out of range: %u\n", n); + } + } +} diff --git a/rostests/apitests/appshim/testlist.c b/rostests/apitests/appshim/testlist.c index 68032a72795..b3b8a216dbf 100644 --- a/rostests/apitests/appshim/testlist.c +++ b/rostests/apitests/appshim/testlist.c @@ -3,10 +3,12 @@ #define STANDALONE #include +extern void func_dispmode(void); extern void func_versionlie(void); const struct test winetest_testlist[] = { + { "dispmode", func_dispmode }, { "versionlie", func_versionlie }, { 0, 0 } }; diff --git a/rostests/apitests/appshim/versionlie.c b/rostests/apitests/appshim/versionlie.c index 14fdcbd659b..be8ca833ac8 100644 --- a/rostests/apitests/appshim/versionlie.c +++ b/rostests/apitests/appshim/versionlie.c @@ -279,21 +279,6 @@ static void run_test(LPCSTR shim, const VersionLieInfo* info) } } -static void hookless_shim(LPCSTR shim) -{ - DWORD num_shims = 0; - WCHAR wide_shim[50] = { 0 }; - PHOOKAPI hook; - MultiByteToWideChar(CP_ACP, 0, shim, -1, wide_shim, 50); - hook = pGetHookAPIs("", wide_shim, &num_shims); - if (hook == NULL) - { - skip("Skipping tests for layers (%s) not present in this os (0x%x)\n", shim, g_WinVersion); - return; - } - ok(hook != NULL, "Expected hook to be a valid pointer for %s\n", shim); - ok(num_shims == 0, "Expected not to find any apihooks, got: %u for %s\n", num_shims, shim); -} VersionLieInfo g_Win95 = { 0xC3B60004, 4, 0, 950, VER_PLATFORM_WIN32_WINDOWS, 0, 0 }; VersionLieInfo g_WinNT4SP5 = { 0x05650004, 4, 0, 1381, VER_PLATFORM_WIN32_NT, 5, 0 }; @@ -370,8 +355,4 @@ START_TEST(versionlie) run_test("VistaSP1VersionLie", &g_WinVistaSP1); run_test("VistaSP2VersionLie", &g_WinVistaSP2); run_test("Win7RTMVersionLie", &g_Win7RTM); - - hookless_shim("Force8BitColor"); - hookless_shim("Force640x480"); - hookless_shim("DisableThemes"); }