[USER32_WINETEST]
[reactos.git] / rostests / winetests / user32 / class.c
index 7149163..b7332ac 100755 (executable)
@@ -21,7 +21,6 @@
 /* To get CS_DROPSHADOW with the MSVC headers */
 //#define _WIN32_WINNT 0x0501
 
-#include <assert.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -617,6 +616,7 @@ static void test_builtinproc(void)
     static const WCHAR classW[] = {'d','e','f','t','e','s','t',0};
     WCHAR unistring[] = {0x142, 0x40e, 0x3b4, 0};  /* a string that would be destroyed by a W->A->W conversion */
     WNDPROC pDefWindowProcA, pDefWindowProcW;
+    WNDPROC pNtdllDefWindowProcA, pNtdllDefWindowProcW;
     WNDPROC oldproc;
     WNDCLASSEXA cls;  /* the memory layout of WNDCLASSEXA and WNDCLASSEXW is the same */
     WCHAR buf[128];
@@ -626,45 +626,56 @@ static void test_builtinproc(void)
 
     pDefWindowProcA = (void *)GetProcAddress(GetModuleHandle("user32.dll"), "DefWindowProcA");
     pDefWindowProcW = (void *)GetProcAddress(GetModuleHandle("user32.dll"), "DefWindowProcW");
-
-    for (i = 0; i < 4; i++)
+    pNtdllDefWindowProcA = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtdllDefWindowProc_A");
+    pNtdllDefWindowProcW = (void *)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtdllDefWindowProc_W");
+
+    /* On Vista+, the user32.dll export DefWindowProcA/W is forwarded to  */
+    /* ntdll.NtdllDefWindowProc_A/W. However, the wndproc returned by     */
+    /* GetClassLong/GetWindowLong points to an unexported user32 function */
+    if (pDefWindowProcA == pNtdllDefWindowProcA &&
+        pDefWindowProcW == pNtdllDefWindowProcW)
+        skip("user32.DefWindowProcX forwarded to ntdll.NtdllDefWindowProc_X\n");
+    else
     {
-        ZeroMemory(&cls, sizeof(cls));
-        cls.cbSize = sizeof(cls);
-        cls.hInstance = GetModuleHandle(NULL);
-        cls.hbrBackground = GetStockObject (WHITE_BRUSH);
-        if (i & 1)
-            cls.lpfnWndProc = pDefWindowProcA;
-        else
-            cls.lpfnWndProc = pDefWindowProcW;
-
-        if (i & 2)
+        for (i = 0; i < 4; i++)
         {
-            cls.lpszClassName = classA;
-            atom = RegisterClassExA(&cls);
+            ZeroMemory(&cls, sizeof(cls));
+            cls.cbSize = sizeof(cls);
+            cls.hInstance = GetModuleHandle(NULL);
+            cls.hbrBackground = GetStockObject (WHITE_BRUSH);
+            if (i & 1)
+                cls.lpfnWndProc = pDefWindowProcA;
+            else
+                cls.lpfnWndProc = pDefWindowProcW;
+
+            if (i & 2)
+            {
+                cls.lpszClassName = classA;
+                atom = RegisterClassExA(&cls);
+            }
+            else
+            {
+                cls.lpszClassName = (LPCSTR)classW;
+                atom = RegisterClassExW((WNDCLASSEXW *)&cls);
+            }
+            ok(atom != 0, "Couldn't register class, i=%d, %d\n", i, GetLastError());
+
+            hwnd = CreateWindowA(classA, NULL, 0, 0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), NULL);
+            ok(hwnd != NULL, "Couldn't create window i=%d\n", i);
+
+            ok(GetWindowLongPtrA(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcA, "Wrong ANSI wndproc: %p vs %p\n",
+                (void *)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), pDefWindowProcA);
+            ok(GetClassLongPtrA(hwnd, GCLP_WNDPROC) == (ULONG_PTR)pDefWindowProcA, "Wrong ANSI wndproc: %p vs %p\n",
+                (void *)GetClassLongPtrA(hwnd, GCLP_WNDPROC), pDefWindowProcA);
+
+            ok(GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcW, "Wrong Unicode wndproc: %p vs %p\n",
+                (void *)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), pDefWindowProcW);
+            ok(GetClassLongPtrW(hwnd, GCLP_WNDPROC) == (ULONG_PTR)pDefWindowProcW, "Wrong Unicode wndproc: %p vs %p\n",
+                (void *)GetClassLongPtrW(hwnd, GCLP_WNDPROC), pDefWindowProcW);
+
+            DestroyWindow(hwnd);
+            UnregisterClass((LPSTR)(DWORD_PTR)atom, GetModuleHandle(NULL));
         }
-        else
-        {
-            cls.lpszClassName = (LPCSTR)classW;
-            atom = RegisterClassExW((WNDCLASSEXW *)&cls);
-        }
-        ok(atom != 0, "Couldn't register class, i=%d, %d\n", i, GetLastError());
-
-        hwnd = CreateWindowA(classA, NULL, 0, 0, 0, 100, 100, NULL, NULL, GetModuleHandle(NULL), NULL);
-        ok(hwnd != NULL, "Couldn't create window i=%d\n", i);
-
-        ok(GetWindowLongPtrA(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcA, "Wrong ANSI wndproc: %p vs %p\n",
-            (void *)GetWindowLongPtrA(hwnd, GWLP_WNDPROC), pDefWindowProcA);
-        ok(GetClassLongPtrA(hwnd, GCLP_WNDPROC) == (ULONG_PTR)pDefWindowProcA, "Wrong ANSI wndproc: %p vs %p\n",
-            (void *)GetClassLongPtrA(hwnd, GCLP_WNDPROC), pDefWindowProcA);
-
-        ok(GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == (LONG_PTR)pDefWindowProcW, "Wrong Unicode wndproc: %p vs %p\n",
-            (void *)GetWindowLongPtrW(hwnd, GWLP_WNDPROC), pDefWindowProcW);
-        ok(GetClassLongPtrW(hwnd, GCLP_WNDPROC) == (ULONG_PTR)pDefWindowProcW, "Wrong Unicode wndproc: %p vs %p\n",
-            (void *)GetClassLongPtrW(hwnd, GCLP_WNDPROC), pDefWindowProcW);
-
-        DestroyWindow(hwnd);
-        UnregisterClass((LPSTR)(DWORD_PTR)atom, GetModuleHandle(NULL));
     }
 
     /* built-in winproc - window A/W type automatically detected */
@@ -942,22 +953,80 @@ if (0) { /* crashes under XP */
        "expected ERROR_NOACCESS, got %d\n", GetLastError());
 
     wcx.cbSize = 0;
+    wcx.lpfnWndProc = NULL;
     SetLastError(0xdeadbeef);
     ret = GetClassInfoExA(0, "static", &wcx);
     ok(ret, "GetClassInfoExA() error %d\n", GetLastError());
     ok(wcx.cbSize == 0, "expected 0, got %u\n", wcx.cbSize);
+    ok(wcx.lpfnWndProc != NULL, "got null proc\n");
 
     wcx.cbSize = sizeof(wcx) - 1;
+    wcx.lpfnWndProc = NULL;
     SetLastError(0xdeadbeef);
     ret = GetClassInfoExA(0, "static", &wcx);
     ok(ret, "GetClassInfoExA() error %d\n", GetLastError());
     ok(wcx.cbSize == sizeof(wcx) - 1, "expected sizeof(wcx)-1, got %u\n", wcx.cbSize);
+    ok(wcx.lpfnWndProc != NULL, "got null proc\n");
 
     wcx.cbSize = sizeof(wcx) + 1;
+    wcx.lpfnWndProc = NULL;
     SetLastError(0xdeadbeef);
     ret = GetClassInfoExA(0, "static", &wcx);
     ok(ret, "GetClassInfoExA() error %d\n", GetLastError());
     ok(wcx.cbSize == sizeof(wcx) + 1, "expected sizeof(wcx)+1, got %u\n", wcx.cbSize);
+    ok(wcx.lpfnWndProc != NULL, "got null proc\n");
+}
+
+static void test_icons(void)
+{
+    WNDCLASSEXW wcex, ret_wcex;
+    WCHAR cls_name[] = {'I','c','o','n','T','e','s','t','C','l','a','s','s',0};
+    HWND hwnd;
+    HINSTANCE hinst = GetModuleHandleW(0);
+    HICON hsmicon, hsmallnew;
+    ICONINFO icinf;
+
+    memset(&wcex, 0, sizeof wcex);
+    wcex.cbSize        = sizeof wcex;
+    wcex.lpfnWndProc   = ClassTest_WndProc;
+    wcex.hIcon         = LoadIconW(0, (LPCWSTR)IDI_APPLICATION);
+    wcex.hInstance     = hinst;
+    wcex.lpszClassName = cls_name;
+    ok(RegisterClassExW(&wcex), "RegisterClassExW returned 0\n");
+    hwnd = CreateWindowExW(0, cls_name, NULL, WS_OVERLAPPEDWINDOW,
+                        0, 0, 0, 0, NULL, NULL, hinst, 0);
+    ok(hwnd != NULL, "Window was not created\n");
+
+    ok(GetClassInfoExW(hinst, cls_name, &ret_wcex), "Class info was not retrieved\n");
+    ok(wcex.hIcon == ret_wcex.hIcon, "Icons don't match\n");
+    ok(ret_wcex.hIconSm != NULL, "hIconSm should be non-zero handle\n");
+
+    hsmicon = (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM);
+    ok(hsmicon != NULL, "GetClassLong should return non-zero handle\n");
+
+    hsmallnew = CopyImage(wcex.hIcon, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON),
+                                                GetSystemMetrics(SM_CYSMICON), 0);
+    ok(!SetClassLongPtrW(hwnd, GCLP_HICONSM, (LONG_PTR)hsmallnew),
+                    "Previous hIconSm should be zero\n");
+    ok(hsmallnew == (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM),
+                    "Should return explicitly assigned small icon\n");
+    ok(!GetIconInfo(hsmicon, &icinf), "Previous small icon should be destroyed\n");
+
+    SetClassLongPtrW(hwnd, GCLP_HICONSM, 0);
+    hsmicon = (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM);
+    ok( hsmicon != NULL, "GetClassLong should return non-zero handle\n");
+
+    SetClassLongPtrW(hwnd, GCLP_HICON, 0);
+    ok(!GetClassLongPtrW(hwnd, GCLP_HICONSM), "GetClassLong should return zero handle\n");
+
+    SetClassLongPtrW(hwnd, GCLP_HICON, (LONG_PTR)LoadIconW(NULL, (LPCWSTR)IDI_QUESTION));
+    hsmicon = (HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM);
+    ok(hsmicon != NULL, "GetClassLong should return non-zero handle\n");
+    UnregisterClassW(cls_name, hinst);
+    ok(GetIconInfo(hsmicon, &icinf), "Icon should NOT be destroyed\n");
+
+    DestroyIcon(hsmallnew);
+    DestroyWindow(hwnd);
 }
 
 START_TEST(class)
@@ -978,6 +1047,7 @@ START_TEST(class)
     CreateDialogParamTest(hInstance);
     test_styles();
     test_builtinproc();
+    test_icons();
 
     /* this test unregisters the Button class so it should be executed at the end */
     test_instances();