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     DWORD ExtraData,
30     DWORD ExtraData1,
31     DWORD ExtraData2,
32     DWORD ExtraData3)
33 {
34     switch (msg)
35     {
36         case WM_PAINT:
37             WMPAINT_count++;
38             trace("Doing WM_PAINT %d/%d\n", WMPAINT_count, WMPAINT_COUNT_THRESHOLD);
39 
40             if (WMPAINT_count > WMPAINT_COUNT_THRESHOLD && redrawComplete == 0)
41             {
42                 PAINTSTRUCT ps;
43 
44                 trace("Calling *Paint()\n");
45                 BeginPaint(hwnd, &ps);
46                 EndPaint(hwnd, &ps);
47                 return 1;
48             }
49 
50             // This will force one stack corruption "ret" fault with normal window
51             // procedure callback.
52 #ifdef __MINGW32__
53             trace("Executing __MINGW32__ stack corruption code\n");
54             asm ("movl $0, %eax\n\t"
55                  "leave\n\t"
56                  "ret");
57 #elif defined(_M_IX86)
58 //#ifdef _MSC_VER
59             trace("Executing MSVC x86 stack corruption code\n");
60             __asm
61               {
62                  mov eax, 0
63                  leave
64                  ret
65               }
66 #else
67             ok(FALSE, "FIXME: stack corruption code is unimplemented\n");
68 #endif
69 
70             break;
71         default:
72             trace("Doing empty default: msg = %u\n", msg);
73     }
74 
75     trace("Calling DefWindowProc()\n");
76     return DefWindowProc(hwnd, msg, wparam, lparam);
77 }
78 
79 static void test_wndproc(void)
80 {
81     WNDCLASSA cls;
82     ATOM clsAtom;
83     HWND hwndMain;
84 
85     cls.style = CS_DBLCLKS;
86     cls.lpfnWndProc = (WNDPROC)redraw_window_procA;
87     cls.cbClsExtra = 0;
88     cls.cbWndExtra = 0;
89     cls.hInstance = GetModuleHandleA(NULL);
90     cls.hIcon = NULL;
91     cls.hCursor = LoadCursorA(NULL, IDC_ARROW);
92     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
93     cls.lpszMenuName = NULL;
94     cls.lpszClassName = "RedrawWindowClass";
95 
96     clsAtom = RegisterClassA(&cls);
97     ok(clsAtom != 0, "RegisterClassA() failed: LastError = %lu\n", GetLastError());
98 
99     if (clsAtom == 0)
100     {
101         skip("No Class atom\n");
102         return;
103     }
104 
105     hwndMain = CreateWindowA(cls.lpszClassName, "Main Window", WS_OVERLAPPEDWINDOW,
106                              CW_USEDEFAULT, 0, 100, 100, NULL, NULL, NULL, NULL);
107     ok(hwndMain != NULL, "CreateWindowA() failed: LastError = %lu\n", GetLastError());
108 
109     ok(WMPAINT_count == 0,
110        "Multiple unexpected WM_PAINT calls = %d\n", WMPAINT_count);
111 
112     if (hwndMain == NULL)
113     {
114         skip("No Window\n");
115         ok(UnregisterClassA(cls.lpszClassName, cls.hInstance) != 0,
116            "UnregisterClassA() failed: LastError = %lu\n", GetLastError());
117         return;
118     }
119 
120     ShowWindow(hwndMain, SW_SHOW);
121     ok(WMPAINT_count == 0,
122        "Multiple unexpected WM_PAINT calls = %d\n", WMPAINT_count);
123 
124     RedrawWindow(hwndMain, NULL, NULL, RDW_UPDATENOW | RDW_ALLCHILDREN);
125     ok(WMPAINT_count == 1 || broken(WMPAINT_count == 0), /* sometimes on win9x */
126        "Multiple unexpected WM_PAINT calls = %d\n", WMPAINT_count);
127 
128     redrawComplete = TRUE;
129     ok(WMPAINT_count < WMPAINT_COUNT_THRESHOLD,
130        "RedrawWindow (RDW_UPDATENOW) never completed (%d/%d)\n",
131        WMPAINT_count, WMPAINT_COUNT_THRESHOLD);
132 
133     ok(DestroyWindow(hwndMain) != 0,
134        "DestroyWindow() failed: LastError = %lu\n", GetLastError());
135 
136     ok(UnregisterClassA(cls.lpszClassName, cls.hInstance) != 0,
137        "UnregisterClassA() failed: LastError = %lu\n", GetLastError());
138 }
139 
140 START_TEST(WndProc)
141 {
142 #ifdef __RUNTIME_CHECKS__
143     skip("This test breaks MSVC runtime checks!\n");
144     return;
145 #endif /* __RUNTIME_CHECKS__ */
146 
147     test_wndproc();
148 }
149