2 * Copyright 2016 Mark Jansen
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #define WIN32_NO_STATUS
29 #include "wine/test.h"
30 #include "apitest_iathook.h"
32 static DWORD g_Version
;
37 static BOOL(WINAPI
* pSdbGetAppPatchDir
)(PVOID
, LPWSTR
, DWORD
);
39 /* aclayers.dll / acgenral.dll */
40 static PVOID(WINAPI
* pGetHookAPIs
)(LPCSTR
, LPCWSTR
, PDWORD
);
41 static BOOL(WINAPI
* pNotifyShims
)(DWORD fdwReason
, PVOID ptr
);
43 DWORD
get_module_version(HMODULE mod
)
46 HRSRC hResInfo
= FindResource(mod
, MAKEINTRESOURCE(VS_VERSION_INFO
), RT_VERSION
);
47 DWORD dwSize
= SizeofResource(mod
, hResInfo
);
48 if (hResInfo
&& dwSize
)
50 VS_FIXEDFILEINFO
*lpFfi
;
53 HGLOBAL hResData
= LoadResource(mod
, hResInfo
);
54 LPVOID pRes
= LockResource(hResData
);
55 HLOCAL pResCopy
= LocalAlloc(LMEM_FIXED
, dwSize
);
57 CopyMemory(pResCopy
, pRes
, dwSize
);
58 FreeResource(hResData
);
60 if (VerQueryValueW(pResCopy
, L
"\\", (LPVOID
*)&lpFfi
, &uLen
))
62 dwVersion
= (HIWORD(lpFfi
->dwProductVersionMS
) << 8) | LOWORD(lpFfi
->dwProductVersionMS
);
64 dwVersion
= (HIWORD(lpFfi
->dwFileVersionMS
) << 8) | LOWORD(lpFfi
->dwFileVersionMS
);
73 static LONG g_ChangeCount
;
74 static DEVMODEA g_LastDevmode
;
75 static DWORD g_LastFlags
;
77 static LONG (WINAPI
*pChangeDisplaySettingsA
)(_In_opt_ PDEVMODEA lpDevMode
, _In_ DWORD dwflags
);
78 LONG WINAPI
mChangeDisplaySettingsA(_In_opt_ PDEVMODEA lpDevMode
, _In_ DWORD dwflags
)
81 g_LastDevmode
= *lpDevMode
;
82 g_LastFlags
= dwflags
;
84 return DISP_CHANGE_FAILED
;
87 static LONG g_EnumCount
;
88 static BOOL bFix
= TRUE
;
90 static BOOL (WINAPI
*pEnumDisplaySettingsA
)(_In_opt_ LPCSTR lpszDeviceName
, _In_ DWORD iModeNum
, _Inout_ PDEVMODEA lpDevMode
);
91 BOOL WINAPI
mEnumDisplaySettingsA(_In_opt_ LPCSTR lpszDeviceName
, _In_ DWORD iModeNum
, _Inout_ PDEVMODEA lpDevMode
)
94 if (pEnumDisplaySettingsA(lpszDeviceName
, iModeNum
, lpDevMode
))
98 if (lpDevMode
&& lpDevMode
->dmBitsPerPel
== 8)
100 trace("Running at 8bpp, faking 16\n");
101 lpDevMode
->dmBitsPerPel
= 16;
103 if (lpDevMode
&& lpDevMode
->dmPelsWidth
== 640 && lpDevMode
->dmPelsHeight
== 480)
105 trace("Running at 640x480, faking 800x600\n");
106 lpDevMode
->dmPelsWidth
= 800;
107 lpDevMode
->dmPelsHeight
= 600;
114 lpDevMode
->dmBitsPerPel
= 8;
115 lpDevMode
->dmPelsWidth
= 640;
116 lpDevMode
->dmPelsHeight
= 480;
126 static LONG g_ThemeCount
;
127 static DWORD g_LastThemeFlags
;
129 static void (WINAPI
*pSetThemeAppProperties
)(DWORD dwFlags
);
130 void WINAPI
mSetThemeAppProperties(DWORD dwFlags
)
133 g_LastThemeFlags
= dwFlags
;
137 static const WCHAR
* shim_dll(const WCHAR
* name
)
139 static WCHAR buf
[MAX_PATH
];
140 pSdbGetAppPatchDir(NULL
, buf
, MAX_PATH
);
141 StringCchCatW(buf
, _countof(buf
), name
);
145 static void pre_8bit(void)
148 memset(&g_LastDevmode
, 0, sizeof(g_LastDevmode
));
149 g_LastFlags
= 0xffffffff;
153 static void pre_8bit_2(void)
160 static void post_8bit(void)
162 ok_int(g_ChangeCount
, 1);
163 ok_hex(g_LastDevmode
.dmFields
& DM_BITSPERPEL
, DM_BITSPERPEL
);
164 ok_int(g_LastDevmode
.dmBitsPerPel
, 8);
165 ok_hex(g_LastFlags
, CDS_FULLSCREEN
);
166 ok_int(g_EnumCount
, 1);
169 static void post_8bit_2(void)
171 ok_int(g_ChangeCount
, 0);
172 ok_hex(g_LastFlags
, 0xffffffff);
173 ok_int(g_EnumCount
, 1);
178 static void post_8bit_no(void)
180 if (g_Version
== _WIN32_WINNT_WS03
)
182 ok_int(g_ChangeCount
, 1);
183 ok_hex(g_LastDevmode
.dmFields
& DM_BITSPERPEL
, DM_BITSPERPEL
);
184 ok_int(g_LastDevmode
.dmBitsPerPel
, 8);
185 ok_hex(g_LastFlags
, CDS_FULLSCREEN
);
186 ok_int(g_EnumCount
, 1);
190 ok_int(g_ChangeCount
, 0);
191 ok_hex(g_LastFlags
, 0xffffffff);
192 ok_int(g_EnumCount
, 0);
198 static void post_8bit_2_no(void)
200 if (g_Version
== _WIN32_WINNT_WS03
)
202 ok_int(g_ChangeCount
, 0);
203 ok_hex(g_LastFlags
, 0xffffffff);
204 ok_int(g_EnumCount
, 1);
208 ok_int(g_ChangeCount
, 0);
209 ok_hex(g_LastFlags
, 0xffffffff);
210 ok_int(g_EnumCount
, 0);
216 static void pre_640(void)
219 memset(&g_LastDevmode
, 0, sizeof(g_LastDevmode
));
220 g_LastFlags
= 0xffffffff;
224 static void pre_640_2(void)
231 static void post_640(void)
233 ok_int(g_ChangeCount
, 1);
234 ok_hex(g_LastDevmode
.dmFields
& (DM_PELSWIDTH
| DM_PELSHEIGHT
), (DM_PELSWIDTH
| DM_PELSHEIGHT
));
235 ok_int(g_LastDevmode
.dmPelsWidth
, 640);
236 ok_int(g_LastDevmode
.dmPelsHeight
, 480);
237 ok_hex(g_LastFlags
, CDS_FULLSCREEN
);
238 ok_int(g_EnumCount
, 1);
241 static void post_640_2(void)
243 ok_int(g_ChangeCount
, 0);
244 ok_hex(g_LastFlags
, 0xffffffff);
245 ok_int(g_EnumCount
, 1);
250 static void post_640_no(void)
252 if (g_Version
== _WIN32_WINNT_WS03
)
254 ok_int(g_ChangeCount
, 1);
255 ok_hex(g_LastDevmode
.dmFields
& (DM_PELSWIDTH
| DM_PELSHEIGHT
), (DM_PELSWIDTH
| DM_PELSHEIGHT
));
256 ok_int(g_LastDevmode
.dmPelsWidth
, 640);
257 ok_int(g_LastDevmode
.dmPelsHeight
, 480);
258 ok_hex(g_LastFlags
, CDS_FULLSCREEN
);
259 ok_int(g_EnumCount
, 1);
263 ok_int(g_ChangeCount
, 0);
264 ok_hex(g_LastFlags
, 0xffffffff);
265 ok_int(g_EnumCount
, 0);
271 static void post_640_2_no(void)
273 if (g_Version
== _WIN32_WINNT_WS03
)
275 ok_int(g_ChangeCount
, 0);
276 ok_hex(g_LastFlags
, 0xffffffff);
277 ok_int(g_EnumCount
, 1);
281 ok_int(g_ChangeCount
, 0);
282 ok_hex(g_LastFlags
, 0xffffffff);
283 ok_int(g_EnumCount
, 0);
289 static void pre_theme(void)
292 g_LastThemeFlags
= 0xffffffff;
295 static void post_theme(void)
297 ok_int(g_ThemeCount
, 1);
298 ok_hex(g_LastThemeFlags
, 0);
301 static void post_theme_no(void)
303 if (g_Version
== _WIN32_WINNT_WS03
)
305 ok_int(g_ThemeCount
, 1);
306 ok_hex(g_LastThemeFlags
, 0);
310 ok_int(g_ThemeCount
, 0);
311 ok_hex(g_LastThemeFlags
, 0xffffffff);
316 static BOOL
hook_disp(HMODULE dll
)
318 return RedirectIat(dll
, "user32.dll", "ChangeDisplaySettingsA", (ULONG_PTR
)mChangeDisplaySettingsA
, (ULONG_PTR
*)&pChangeDisplaySettingsA
) &&
319 RedirectIat(dll
, "user32.dll", "EnumDisplaySettingsA", (ULONG_PTR
)mEnumDisplaySettingsA
, (ULONG_PTR
*)&pEnumDisplaySettingsA
);
322 static VOID
unhook_disp(HMODULE dll
)
324 RestoreIat(dll
, "user32.dll", "ChangeDisplaySettingsA", (ULONG_PTR
)pChangeDisplaySettingsA
);
325 RestoreIat(dll
, "user32.dll", "EnumDisplaySettingsA", (ULONG_PTR
)pEnumDisplaySettingsA
);
328 static BOOL
hook_theme(HMODULE dll
)
330 return RedirectIat(dll
, "uxtheme.dll", "SetThemeAppProperties", (ULONG_PTR
)mSetThemeAppProperties
, (ULONG_PTR
*)&pSetThemeAppProperties
);
333 static VOID
unhook_theme(HMODULE dll
)
335 RestoreIat(dll
, "uxtheme.dll", "SetThemeAppProperties", (ULONG_PTR
)pSetThemeAppProperties
);
338 static void test_one(LPCSTR shim
, DWORD dwReason
, void(*pre
)(), void(*post
)(), void(*second
)(void))
341 WCHAR wide_shim
[50] = { 0 };
344 MultiByteToWideChar(CP_ACP
, 0, shim
, -1, wide_shim
, 50);
349 hook
= pGetHookAPIs("", wide_shim
, &num_shims
);
352 skip("Skipping tests for layers (%s) not present in this os (0x%x)\n", shim
, g_Version
);
355 ok(hook
!= NULL
, "Expected hook to be a valid pointer for %s\n", shim
);
356 ok(num_shims
== 0, "Expected not to find any apihooks, got: %u for %s\n", num_shims
, shim
);
358 ret
= pNotifyShims(dwReason
, NULL
);
360 /* Win7 and Win10 return 1, w2k3 returns a pointer */
361 ok(ret
!= 0, "Expected pNotifyShims to succeed (%i)\n", ret
);
366 /* Invoking it a second time does not call the init functions again! */
371 ret
= pNotifyShims(dwReason
, NULL
);
372 ok(ret
!= 0, "Expected pNotifyShims to succeed (%i)\n", ret
);
378 /* In 2k3 0, 2, 4, 6, 8 are not guarded against re-initializations! */
379 static struct test_info
385 BOOL(*hook
)(HMODULE
);
386 void(*unhook
)(HMODULE
);
393 { "Force8BitColor", L
"\\aclayers.dll", WINVER_ANY
, 1, hook_disp
, unhook_disp
, pre_8bit
, post_8bit
, post_8bit_no
},
394 { "Force8BitColor", L
"\\aclayers.dll", _WIN32_WINNT_VISTA
, 100, hook_disp
, unhook_disp
,pre_8bit
, post_8bit
, post_8bit_no
},
395 { "Force640x480", L
"\\aclayers.dll", WINVER_ANY
, 1, hook_disp
, unhook_disp
, pre_640
, post_640
, post_640_no
},
396 { "Force640x480", L
"\\aclayers.dll", _WIN32_WINNT_VISTA
, 100, hook_disp
, unhook_disp
, pre_640
, post_640
, post_640_no
},
397 { "DisableThemes", L
"\\acgenral.dll", WINVER_ANY
, 1, hook_theme
, unhook_theme
, pre_theme
, post_theme
, post_theme_no
},
398 { "DisableThemes", L
"\\acgenral.dll", _WIN32_WINNT_VISTA
, 100, hook_theme
, unhook_theme
, pre_theme
, post_theme
, post_theme_no
},
400 /* No need to change anything */
401 { "Force8BitColor", L
"\\aclayers.dll", WINVER_ANY
, 1, hook_disp
, unhook_disp
, pre_8bit_2
, post_8bit_2
, post_8bit_2_no
},
402 { "Force8BitColor", L
"\\aclayers.dll", _WIN32_WINNT_VISTA
, 100, hook_disp
, unhook_disp
, pre_8bit_2
, post_8bit_2
, post_8bit_2_no
},
403 { "Force640x480", L
"\\aclayers.dll", WINVER_ANY
, 1, hook_disp
, unhook_disp
, pre_640_2
, post_640_2
, post_640_2_no
},
404 { "Force640x480", L
"\\aclayers.dll", _WIN32_WINNT_VISTA
, 100, hook_disp
, unhook_disp
, pre_640_2
, post_640_2
, post_640_2_no
},
408 static void run_test(size_t n
, BOOL unload
)
412 const WCHAR
* buf
= shim_dll(tests
[n
].dll
);
414 dll
= LoadLibraryW(shim_dll(tests
[n
].dll
));
415 pGetHookAPIs
= (void*)GetProcAddress(dll
, "GetHookAPIs");
416 pNotifyShims
= (void*)GetProcAddress(dll
, "NotifyShims");
418 if (!pGetHookAPIs
|| !pNotifyShims
)
420 skip("aclayers.dll not loaded, or does not export GetHookAPIs or pNotifyShims (%s, %p, %p)\n",
421 tests
[n
].name
, pGetHookAPIs
, pNotifyShims
);
425 g_Version
= get_module_version(dll
);
429 g_Version
= _WIN32_WINNT_WS03
;
430 trace("Module %s has no version, faking 2k3\n", wine_dbgstr_w(tests
[n
].dll
));
433 if (g_Version
>= tests
[n
].winver
)
435 ret
= tests
[n
].hook(dll
);
438 test_one(tests
[n
].name
, tests
[n
].reason
, tests
[n
].pre
, tests
[n
].post
, tests
[n
].second
);
442 ok(0, "Unable to redirect functions!\n");
448 dll
= GetModuleHandleW(buf
);
449 ok(dll
== NULL
, "Unable to unload %s\n", wine_dbgstr_w(buf
));
456 HMODULE dll
= LoadLibraryA("apphelp.dll");
461 pSdbGetAppPatchDir
= (void*)GetProcAddress(dll
, "SdbGetAppPatchDir");
462 if (!pSdbGetAppPatchDir
)
464 skip("apphelp.dll not loaded, or does not export SdbGetAppPatchDir\n");
468 argc
= winetest_get_mainargs(&argv
);
471 WCHAR path
[MAX_PATH
];
472 GetModuleFileNameW(NULL
, path
, _countof(path
));
473 dll
= GetModuleHandleW(shim_dll(L
"\\aclayers.dll"));
475 dll
= GetModuleHandleW(shim_dll(L
"\\acgenral.dll"));
477 trace("Loaded under a shim, running each test in it's own process\n");
479 for (n
= 0; n
< _countof(tests
); ++n
)
481 LONG failures
= winetest_get_failures();
489 WCHAR buf
[MAX_PATH
+40];
490 STARTUPINFOW si
= { sizeof(si
) };
491 PROCESS_INFORMATION pi
;
494 StringCchPrintfW(buf
, _countof(buf
), L
"\"%ls\" dispmode %u", path
, n
);
495 created
= CreateProcessW(NULL
, buf
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
496 ok(created
, "Expected CreateProcess to succeed\n");
499 winetest_wait_child_process(pi
.hProcess
);
500 CloseHandle(pi
.hThread
);
501 CloseHandle(pi
.hProcess
);
505 ok(failures
== winetest_get_failures(), "Last %u failures are from %d (%s)\n",
506 winetest_get_failures() - failures
, n
, tests
[n
].name
);
511 n
= (size_t)atoi(argv
[2]);
512 if (n
>= 0 && n
< _countof(tests
))
518 ok(0, "Test out of range: %u\n", n
);