1 /*
2  * PROJECT:         ReactOS api tests
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * PURPOSE:         Test for mismatch with function prototype in window procedure callback.
5  * PROGRAMMERS:
6  */
7 
8 #include "precomp.h"
9 
10 /* Used wine Redraw test for proof in principle. */
11 
12 #define WMPAINT_COUNT_THRESHOLD 10
13 
14 /* Global variables to trigger exit from loop */
15 static int redrawComplete, WMPAINT_count;
16 
17 /*
18  * Force stack corruption when calling from assumed window procedure callback.
19  * Adding (6 and) more will force exception faults and terminate the test program.
20  * The test is with five and this is safe for windows.
21  *
22  * But,,,, ReactOS compiled with GCC can handle this,,,,,,
23  */
24 static LRESULT WINAPI redraw_window_procA(
25     HWND hwnd,
26     UINT msg,
27     WPARAM wparam,
28     LPARAM lparam)
29 {
30     switch (msg)
31     {
32         case WM_PAINT:
33             break;
34             WMPAINT_count++;
35             trace("Doing WM_PAINT %d/%d\n", WMPAINT_count, WMPAINT_COUNT_THRESHOLD);
36 
37             if (WMPAINT_count > WMPAINT_COUNT_THRESHOLD && redrawComplete == 0)
38             {
39                 PAINTSTRUCT ps;
40 
41                 trace("Calling *Paint()\n");
42                 BeginPaint(hwnd, &ps);
43                 EndPaint(hwnd, &ps);
44                 return 1;
45             }
46 
47             // This will force one stack corruption "ret" fault with normal window
48             // procedure callback.
49 #ifdef __MINGW32__
50             trace("Executing __MINGW32__ stack corruption code\n");
51             asm ("movl $0, %eax\n\t"
52                  "leave\n\t"
53                  "ret");
54 #elif defined(_M_IX86)
55 //#ifdef _MSC_VER
56             trace("Executing MSVC x86 stack corruption code\n");
57             __asm
58               {
59                  mov eax, 0
60                  leave
61                  ret
62               }
63 #else
64             ok(FALSE, "FIXME: stack corruption code is unimplemented\n");
65 #endif
66 
67             break;
68         default:
69             trace("Doing empty default: msg = %u\n", msg);
70     }
71 
72     trace("Calling DefWindowProc()\n");
73     return DefWindowProc(hwnd, msg, wparam, lparam);
74 }
75 
76 static void test_wndproc(void)
77 {
78     WNDCLASSA cls;
79     ATOM clsAtom;
80     HWND hwndMain;
81 
82     cls.style = CS_DBLCLKS;
83     cls.lpfnWndProc = redraw_window_procA;
84     cls.cbClsExtra = 0;
85     cls.cbWndExtra = 0;
86     cls.hInstance = GetModuleHandleA(NULL);
87     cls.hIcon = NULL;
88     cls.hCursor = LoadCursorA(NULL, IDC_ARROW);
89     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
90     cls.lpszMenuName = NULL;
91     cls.lpszClassName = "RedrawWindowClass";
92 
93     clsAtom = RegisterClassA(&cls);
94     ok(clsAtom != 0, "RegisterClassA() failed: LastError = %lu\n", GetLastError());
95 
96     if (clsAtom == 0)
97     {
98         skip("No Class atom\n");
99         return;
100     }
101 
102     hwndMain = CreateWindowA(cls.lpszClassName, "Main Window", WS_OVERLAPPEDWINDOW,
103                              CW_USEDEFAULT, 0, 100, 100, NULL, NULL, NULL, NULL);
104 
105     ok(hwndMain != NULL, "CreateWindowA() failed: LastError = %lu\n", GetLastError());
106 
107     ok(WMPAINT_count == 0,
108        "Multiple unexpected WM_PAINT calls = %d\n", WMPAINT_count);
109 
110     if (hwndMain == NULL)
111     {
112         skip("No Window\n");
113         ok(UnregisterClassA(cls.lpszClassName, cls.hInstance) != 0,
114            "UnregisterClassA() failed: LastError = %lu\n", GetLastError());
115         return;
116     }
117 
118     ShowWindow(hwndMain, SW_SHOW);
119     ok(WMPAINT_count == 0,
120        "Multiple unexpected WM_PAINT calls = %d\n", WMPAINT_count);
121 
122     RedrawWindow(hwndMain, NULL, NULL, RDW_UPDATENOW | RDW_ALLCHILDREN);
123     ok(WMPAINT_count == 1 || broken(WMPAINT_count == 0), /* sometimes on win9x */
124        "Multiple unexpected WM_PAINT calls = %d\n", WMPAINT_count);
125 
126     redrawComplete = TRUE;
127     ok(WMPAINT_count < WMPAINT_COUNT_THRESHOLD,
128        "RedrawWindow (RDW_UPDATENOW) never completed (%d/%d)\n",
129        WMPAINT_count, WMPAINT_COUNT_THRESHOLD);
130 
131     ok(DestroyWindow(hwndMain) != 0,
132        "DestroyWindow() failed: LastError = %lu\n", GetLastError());
133 
134     ok(UnregisterClassA(cls.lpszClassName, cls.hInstance) != 0,
135        "UnregisterClassA() failed: LastError = %lu\n", GetLastError());
136 }
137 
138 static void test_get_wndproc(void)
139 {
140     LONG_PTR ret;
141     SetLastError(0xfeedf00d);
142     ret = GetWindowLongPtrA(GetShellWindow(), GWLP_WNDPROC);
143     ok (ret == 0, "Should return NULL\n");
144     ok (GetLastError() == ERROR_ACCESS_DENIED, "Wrong return error!\n");
145     SetLastError(0xfeedf00d);
146     ret = GetWindowLongPtrW(GetShellWindow(), GWLP_WNDPROC);
147     ok (ret == 0, "Should return NULL\n");
148     ok (GetLastError() == ERROR_ACCESS_DENIED, "Wrong return error!\n");
149     SetLastError(0xfeedf00d);
150     ret = GetWindowLongPtrA(GetShellWindow(), GWLP_WNDPROC);
151     ok (ret == 0, "Should return NULL\n");
152     ok (GetLastError() == ERROR_ACCESS_DENIED, "Wrong return error!\n");
153     SetLastError(0xfeedf00d);
154     ret = GetWindowLongPtrW(GetShellWindow(), GWLP_WNDPROC);
155     ok (ret == 0, "Should return NULL\n");
156     ok (GetLastError() == ERROR_ACCESS_DENIED, "Wrong return error!\n");
157 }
158 
159 START_TEST(WndProc)
160 {
161 #ifdef __RUNTIME_CHECKS__
162     skip("This test breaks MSVC runtime checks!\n");
163     return;
164 #endif /* __RUNTIME_CHECKS__ */
165 
166     test_get_wndproc();
167     test_wndproc();
168 }
169