[SHELL32_APITEST] -Add some tests for SHParseDisplayName for CORE-12882.
[reactos.git] / rostests / apitests / appshim / dispmode.c
index 00107f2..d904e92 100644 (file)
 #include <strsafe.h>
 #include "wine/test.h"
 
-extern DWORD get_host_winver(void);
-static DWORD g_WinVersion;
+static DWORD g_Version;
 #define WINVER_ANY     0
-#define WINVER_VISTA   0x0600
 
 
 /* apphelp.dll */
 static BOOL(WINAPI* pSdbGetAppPatchDir)(PVOID, LPWSTR, DWORD);
 
-/* aclayers.dll */
+/* aclayers.dll / acgenral.dll */
 static PVOID(WINAPI* pGetHookAPIs)(LPCSTR, LPCWSTR, PDWORD);
 static BOOL(WINAPI* pNotifyShims)(DWORD fdwReason, PVOID ptr);
 
+DWORD get_module_version(HMODULE mod)
+{
+    DWORD dwVersion = 0;
+    HRSRC hResInfo = FindResource(mod, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);
+    DWORD dwSize = SizeofResource(mod, hResInfo);
+    if (hResInfo && dwSize)
+    {
+        VS_FIXEDFILEINFO *lpFfi;
+        UINT uLen;
+
+        HGLOBAL hResData = LoadResource(mod, hResInfo);
+        LPVOID pRes = LockResource(hResData);
+        HLOCAL pResCopy = LocalAlloc(LMEM_FIXED, dwSize);
+
+        CopyMemory(pResCopy, pRes, dwSize);
+        FreeResource(hResData);
+
+        if (VerQueryValueW(pResCopy, L"\\", (LPVOID*)&lpFfi, &uLen))
+        {
+            dwVersion = (HIWORD(lpFfi->dwProductVersionMS) << 8) | LOWORD(lpFfi->dwProductVersionMS);
+            if (!dwVersion)
+                dwVersion = (HIWORD(lpFfi->dwFileVersionMS) << 8) | LOWORD(lpFfi->dwFileVersionMS);
+        }
 
-static LONG g_Count;
+        LocalFree(pResCopy);
+    }
+
+    return dwVersion;
+}
+
+static LONG g_ChangeCount;
 static DEVMODEA g_LastDevmode;
 static DWORD g_LastFlags;
 
 static LONG (WINAPI *pChangeDisplaySettingsA)(_In_opt_ PDEVMODEA lpDevMode, _In_ DWORD dwflags);
 LONG WINAPI mChangeDisplaySettingsA(_In_opt_ PDEVMODEA lpDevMode, _In_ DWORD dwflags)
 {
-    g_Count++;
+    g_ChangeCount++;
     g_LastDevmode = *lpDevMode;
     g_LastFlags = dwflags;
 
     return DISP_CHANGE_FAILED;
 }
 
+static LONG g_EnumCount;
+static BOOL bFix = TRUE;
+
+static BOOL (WINAPI *pEnumDisplaySettingsA)(_In_opt_ LPCSTR lpszDeviceName, _In_ DWORD iModeNum, _Inout_ PDEVMODEA lpDevMode);
+BOOL WINAPI mEnumDisplaySettingsA(_In_opt_ LPCSTR lpszDeviceName, _In_ DWORD iModeNum, _Inout_ PDEVMODEA lpDevMode)
+{
+    g_EnumCount++;
+    if (pEnumDisplaySettingsA(lpszDeviceName, iModeNum, lpDevMode))
+    {
+        if (bFix)
+        {
+            if (lpDevMode && lpDevMode->dmBitsPerPel == 8)
+            {
+                trace("Running at 8bpp, faking 16\n");
+                lpDevMode->dmBitsPerPel = 16;
+            }
+            if (lpDevMode && lpDevMode->dmPelsWidth == 640 && lpDevMode->dmPelsHeight == 480)
+            {
+                trace("Running at 640x480, faking 800x600\n");
+                lpDevMode->dmPelsWidth = 800;
+                lpDevMode->dmPelsHeight = 600;
+            }
+        }
+        else
+        {
+            if (lpDevMode)
+            {
+                lpDevMode->dmBitsPerPel = 8;
+                lpDevMode->dmPelsWidth = 640;
+                lpDevMode->dmPelsHeight = 480;
+            }
+        }
+        return TRUE;
+    }
+    return FALSE;
+}
+
+
+
 static LONG g_ThemeCount;
 static DWORD g_LastThemeFlags;
 
@@ -77,33 +143,146 @@ static const WCHAR* shim_dll(const WCHAR* name)
 
 static void pre_8bit(void)
 {
-    g_Count = 0;
+    g_ChangeCount = 0;
     memset(&g_LastDevmode, 0, sizeof(g_LastDevmode));
     g_LastFlags = 0xffffffff;
+    g_EnumCount = 0;
+}
+
+static void pre_8bit_2(void)
+{
+    bFix = FALSE;
+
+    pre_8bit();
 }
 
 static void post_8bit(void)
 {
-    ok_int(g_Count, 1);
+    ok_int(g_ChangeCount, 1);
     ok_hex(g_LastDevmode.dmFields & DM_BITSPERPEL, DM_BITSPERPEL);
     ok_int(g_LastDevmode.dmBitsPerPel, 8);
     ok_hex(g_LastFlags, CDS_FULLSCREEN);
+    ok_int(g_EnumCount, 1);
+}
+
+static void post_8bit_2(void)
+{
+    ok_int(g_ChangeCount, 0);
+    ok_hex(g_LastFlags, 0xffffffff);
+    ok_int(g_EnumCount, 1);
+
+    bFix = TRUE;
+}
+
+static void post_8bit_no(void)
+{
+    if (g_Version == _WIN32_WINNT_WS03)
+    {
+        ok_int(g_ChangeCount, 1);
+        ok_hex(g_LastDevmode.dmFields & DM_BITSPERPEL, DM_BITSPERPEL);
+        ok_int(g_LastDevmode.dmBitsPerPel, 8);
+        ok_hex(g_LastFlags, CDS_FULLSCREEN);
+        ok_int(g_EnumCount, 1);
+    }
+    else
+    {
+        ok_int(g_ChangeCount, 0);
+        ok_hex(g_LastFlags, 0xffffffff);
+        ok_int(g_EnumCount, 0);
+    }
+
+    bFix = TRUE;
+}
+
+static void post_8bit_2_no(void)
+{
+    if (g_Version == _WIN32_WINNT_WS03)
+    {
+        ok_int(g_ChangeCount, 0);
+        ok_hex(g_LastFlags, 0xffffffff);
+        ok_int(g_EnumCount, 1);
+    }
+    else
+    {
+        ok_int(g_ChangeCount, 0);
+        ok_hex(g_LastFlags, 0xffffffff);
+        ok_int(g_EnumCount, 0);
+    }
+
+    bFix = TRUE;
 }
 
 static void pre_640(void)
 {
-    g_Count = 0;
+    g_ChangeCount = 0;
     memset(&g_LastDevmode, 0, sizeof(g_LastDevmode));
     g_LastFlags = 0xffffffff;
+    g_EnumCount = 0;
+}
+
+static void pre_640_2(void)
+{
+    bFix = FALSE;
+
+    pre_640();
 }
 
 static void post_640(void)
 {
-    ok_int(g_Count, 1);
+    ok_int(g_ChangeCount, 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);
+    ok_int(g_EnumCount, 1);
+}
+
+static void post_640_2(void)
+{
+    ok_int(g_ChangeCount, 0);
+    ok_hex(g_LastFlags, 0xffffffff);
+    ok_int(g_EnumCount, 1);
+
+    bFix = TRUE;
+}
+
+static void post_640_no(void)
+{
+    if (g_Version == _WIN32_WINNT_WS03)
+    {
+        ok_int(g_ChangeCount, 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);
+        ok_int(g_EnumCount, 1);
+    }
+    else
+    {
+        ok_int(g_ChangeCount, 0);
+        ok_hex(g_LastFlags, 0xffffffff);
+        ok_int(g_EnumCount, 0);
+    }
+
+    bFix = TRUE;
+}
+
+static void post_640_2_no(void)
+{
+    if (g_Version == _WIN32_WINNT_WS03)
+    {
+        ok_int(g_ChangeCount, 0);
+        ok_hex(g_LastFlags, 0xffffffff);
+        ok_int(g_EnumCount, 1);
+    }
+    else
+    {
+        ok_int(g_ChangeCount, 0);
+        ok_hex(g_LastFlags, 0xffffffff);
+        ok_int(g_EnumCount, 0);
+    }
+
+    bFix = TRUE;
 }
 
 static void pre_theme(void)
@@ -118,6 +297,20 @@ static void post_theme(void)
     ok_hex(g_LastThemeFlags, 0);
 }
 
+static void post_theme_no(void)
+{
+    if (g_Version == _WIN32_WINNT_WS03)
+    {
+        ok_int(g_ThemeCount, 1);
+        ok_hex(g_LastThemeFlags, 0);
+    }
+    else
+    {
+        ok_int(g_ThemeCount, 0);
+        ok_hex(g_LastThemeFlags, 0xffffffff);
+    }
+}
+
 static PIMAGE_IMPORT_DESCRIPTOR FindImportDescriptor(PBYTE DllBase, PCSTR DllName)
 {
     ULONG Size;
@@ -173,7 +366,8 @@ static BOOL RedirectIat(HMODULE TargetDll, PCSTR DllName, PCSTR FunctionName, UL
 
 static BOOL hook_disp(HMODULE dll)
 {
-    return RedirectIat(dll, "user32.dll", "ChangeDisplaySettingsA", (ULONG_PTR)mChangeDisplaySettingsA, (ULONG_PTR*)&pChangeDisplaySettingsA);
+    return RedirectIat(dll, "user32.dll", "ChangeDisplaySettingsA", (ULONG_PTR)mChangeDisplaySettingsA, (ULONG_PTR*)&pChangeDisplaySettingsA) &&
+        RedirectIat(dll, "user32.dll", "EnumDisplaySettingsA", (ULONG_PTR)mEnumDisplaySettingsA, (ULONG_PTR*)&pEnumDisplaySettingsA);
 }
 
 static BOOL hook_theme(HMODULE dll)
@@ -182,7 +376,7 @@ static BOOL hook_theme(HMODULE dll)
 }
 
 
-static void test_one(LPCSTR shim, DWORD dwReason, void(*pre)(), void(*post)())
+static void test_one(LPCSTR shim, DWORD dwReason, void(*pre)(), void(*post)(), void(*second)(void))
 {
     DWORD num_shims = 0;
     WCHAR wide_shim[50] = { 0 };
@@ -196,7 +390,7 @@ static void test_one(LPCSTR shim, DWORD dwReason, void(*pre)(), void(*post)())
     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);
+        skip("Skipping tests for layers (%s) not present in this os (0x%x)\n", shim, g_Version);
         return;
     }
     ok(hook != NULL, "Expected hook to be a valid pointer for %s\n", shim);
@@ -209,8 +403,20 @@ static void test_one(LPCSTR shim, DWORD dwReason, void(*pre)(), void(*post)())
 
     if (post)
         post();
+
+    /* Invoking it a second time does not call the init functions again! */
+    if (pre && second)
+    {
+        pre();
+
+        ret = pNotifyShims(dwReason, NULL);
+        ok(ret != 0, "Expected pNotifyShims to succeed (%i)\n", ret);
+
+        second();
+    }
 }
 
+/* In 2k3 0, 2, 4, 6, 8 are not guarded against re-initializations! */
 static struct test_info
 {
     const char* name;
@@ -220,14 +426,22 @@ static struct test_info
     BOOL(*hook)(HMODULE);
     void(*pre)(void);
     void(*post)(void);
+    void(*second)(void);
 } tests[] =
 {
-    { "Force8BitColor", L"\\aclayers.dll", WINVER_ANY, 1, hook_disp, pre_8bit, post_8bit },
-    { "Force8BitColor", L"\\aclayers.dll", WINVER_VISTA, 100, hook_disp, pre_8bit, post_8bit },
-    { "Force640x480", L"\\aclayers.dll", WINVER_ANY, 1, hook_disp, pre_640, post_640 },
-    { "Force640x480", L"\\aclayers.dll", WINVER_VISTA, 100, hook_disp, pre_640, post_640 },
-    { "DisableThemes", L"\\acgenral.dll", WINVER_ANY, 1, hook_theme, pre_theme, post_theme },
-    { "DisableThemes", L"\\acgenral.dll", WINVER_VISTA, 100, hook_theme, pre_theme, post_theme },
+    /* Success */
+    { "Force8BitColor", L"\\aclayers.dll", WINVER_ANY, 1, hook_disp, pre_8bit, post_8bit, post_8bit_no },
+    { "Force8BitColor", L"\\aclayers.dll", _WIN32_WINNT_VISTA, 100, hook_disp, pre_8bit, post_8bit, post_8bit_no },
+    { "Force640x480", L"\\aclayers.dll", WINVER_ANY, 1, hook_disp, pre_640, post_640, post_640_no },
+    { "Force640x480", L"\\aclayers.dll", _WIN32_WINNT_VISTA, 100, hook_disp, pre_640, post_640, post_640_no },
+    { "DisableThemes", L"\\acgenral.dll", WINVER_ANY, 1, hook_theme, pre_theme, post_theme, post_theme_no },
+    { "DisableThemes", L"\\acgenral.dll", _WIN32_WINNT_VISTA, 100, hook_theme, pre_theme, post_theme, post_theme_no },
+
+    /* No need to change anything */
+    { "Force8BitColor", L"\\aclayers.dll", WINVER_ANY, 1, hook_disp, pre_8bit_2, post_8bit_2, post_8bit_2_no },
+    { "Force8BitColor", L"\\aclayers.dll", _WIN32_WINNT_VISTA, 100, hook_disp, pre_8bit_2, post_8bit_2, post_8bit_2_no },
+    { "Force640x480", L"\\aclayers.dll", WINVER_ANY, 1, hook_disp, pre_640_2, post_640_2, post_640_2_no },
+    { "Force640x480", L"\\aclayers.dll", _WIN32_WINNT_VISTA, 100, hook_disp, pre_640_2, post_640_2, post_640_2_no },
 };
 
 
@@ -248,14 +462,25 @@ static void run_test(size_t n, BOOL unload)
         return;
     }
 
-    ret = tests[n].hook(dll);
-    if (ret)
+    g_Version = get_module_version(dll);
+
+    if (!g_Version)
     {
-        test_one(tests[n].name, tests[n].reason, tests[n].pre, tests[n].post);
+        g_Version = _WIN32_WINNT_WS03;
+        trace("Module %s has no version, faking 2k3\n", wine_dbgstr_w(tests[n].dll));
     }
-    else
+
+    if (g_Version >= tests[n].winver)
     {
-        ok(0, "Unable to redirect functions!\n");
+        ret = tests[n].hook(dll);
+        if (ret)
+        {
+            test_one(tests[n].name, tests[n].reason, tests[n].pre, tests[n].post, tests[n].second);
+        }
+        else
+        {
+            ok(0, "Unable to redirect functions!\n");
+        }
     }
     FreeLibrary(dll);
     if (unload)
@@ -280,8 +505,6 @@ START_TEST(dispmode)
         return;
     }
 
-    g_WinVersion = get_host_winver();
-
     argc = winetest_get_mainargs(&argv);
     if (argc < 3)
     {
@@ -297,9 +520,6 @@ START_TEST(dispmode)
         {
             LONG failures = winetest_get_failures();
 
-            if (g_WinVersion < tests[n].winver)
-                continue;
-
             if (dll == NULL)
             {
                 run_test(n, TRUE);
@@ -322,10 +542,8 @@ START_TEST(dispmode)
                 }
             }
 
-            if (failures != winetest_get_failures())
-            {
-                trace("Failures from %d (%s)\n", n, tests[n].name);
-            }
+            ok(failures == winetest_get_failures(), "Last %u failures are from %d (%s)\n",
+                winetest_get_failures() - failures, n, tests[n].name);
         }
     }
     else