1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:         ReactOS api tests
3c2c66affSColin Finck  * LICENSE:         GPL - See COPYING in the top level directory
4c2c66affSColin Finck  * PURPOSE:         Test for mismatch with function prototype in window procedure callback.
5c2c66affSColin Finck  * PROGRAMMERS:
6c2c66affSColin Finck  */
7c2c66affSColin Finck 
8c39b0fc6SAmine Khaldi #include "precomp.h"
9c2c66affSColin Finck 
10c2c66affSColin Finck /* Used wine Redraw test for proof in principle. */
11c2c66affSColin Finck 
12620d8c01SSerge Gautherie #define WMPAINT_COUNT_THRESHOLD 10
13620d8c01SSerge Gautherie 
14c2c66affSColin Finck /* Global variables to trigger exit from loop */
15c2c66affSColin Finck static int redrawComplete, WMPAINT_count;
16c2c66affSColin Finck 
17c2c66affSColin Finck /*
189a8b5ffcSSerge Gautherie  * Force stack corruption when calling from assumed window procedure callback.
199a8b5ffcSSerge Gautherie  * Adding (6 and) more will force exception faults and terminate the test program.
209a8b5ffcSSerge Gautherie  * The test is with five and this is safe for windows.
219a8b5ffcSSerge Gautherie  *
229a8b5ffcSSerge Gautherie  * But,,,, ReactOS compiled with GCC can handle this,,,,,,
23c2c66affSColin Finck  */
redraw_window_procA(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)249a8b5ffcSSerge Gautherie static LRESULT WINAPI redraw_window_procA(
259a8b5ffcSSerge Gautherie     HWND hwnd,
269a8b5ffcSSerge Gautherie     UINT msg,
279a8b5ffcSSerge Gautherie     WPARAM wparam,
28465745b6STimo Kreuzer     LPARAM lparam)
29c2c66affSColin Finck {
30c2c66affSColin Finck     switch (msg)
31c2c66affSColin Finck     {
32c2c66affSColin Finck         case WM_PAINT:
33465745b6STimo Kreuzer             break;
34c2c66affSColin Finck             WMPAINT_count++;
35620d8c01SSerge Gautherie             trace("Doing WM_PAINT %d/%d\n", WMPAINT_count, WMPAINT_COUNT_THRESHOLD);
369a8b5ffcSSerge Gautherie 
37620d8c01SSerge Gautherie             if (WMPAINT_count > WMPAINT_COUNT_THRESHOLD && redrawComplete == 0)
38c2c66affSColin Finck             {
39c2c66affSColin Finck                 PAINTSTRUCT ps;
409a8b5ffcSSerge Gautherie 
41620d8c01SSerge Gautherie                 trace("Calling *Paint()\n");
42c2c66affSColin Finck                 BeginPaint(hwnd, &ps);
43c2c66affSColin Finck                 EndPaint(hwnd, &ps);
44c2c66affSColin Finck                 return 1;
45c2c66affSColin Finck             }
469a8b5ffcSSerge Gautherie 
479a8b5ffcSSerge Gautherie             // This will force one stack corruption "ret" fault with normal window
489a8b5ffcSSerge Gautherie             // procedure callback.
49c2c66affSColin Finck #ifdef __MINGW32__
50620d8c01SSerge Gautherie             trace("Executing __MINGW32__ stack corruption code\n");
51c2c66affSColin Finck             asm ("movl $0, %eax\n\t"
52c2c66affSColin Finck                  "leave\n\t"
53c2c66affSColin Finck                  "ret");
54c2c66affSColin Finck #elif defined(_M_IX86)
55c2c66affSColin Finck //#ifdef _MSC_VER
56620d8c01SSerge Gautherie             trace("Executing MSVC x86 stack corruption code\n");
57c2c66affSColin Finck             __asm
58c2c66affSColin Finck               {
59c2c66affSColin Finck                  mov eax, 0
60c2c66affSColin Finck                  leave
61c2c66affSColin Finck                  ret
62c2c66affSColin Finck               }
63c2c66affSColin Finck #else
64620d8c01SSerge Gautherie             ok(FALSE, "FIXME: stack corruption code is unimplemented\n");
65c2c66affSColin Finck #endif
66620d8c01SSerge Gautherie 
67620d8c01SSerge Gautherie             break;
68620d8c01SSerge Gautherie         default:
69620d8c01SSerge Gautherie             trace("Doing empty default: msg = %u\n", msg);
70c2c66affSColin Finck     }
719a8b5ffcSSerge Gautherie 
72620d8c01SSerge Gautherie     trace("Calling DefWindowProc()\n");
73c2c66affSColin Finck     return DefWindowProc(hwnd, msg, wparam, lparam);
74c2c66affSColin Finck }
75c2c66affSColin Finck 
test_wndproc(void)76c2c66affSColin Finck static void test_wndproc(void)
77c2c66affSColin Finck {
78c2c66affSColin Finck     WNDCLASSA cls;
79620d8c01SSerge Gautherie     ATOM clsAtom;
80c2c66affSColin Finck     HWND hwndMain;
81c2c66affSColin Finck 
82c2c66affSColin Finck     cls.style = CS_DBLCLKS;
83465745b6STimo Kreuzer     cls.lpfnWndProc = redraw_window_procA;
84c2c66affSColin Finck     cls.cbClsExtra = 0;
85c2c66affSColin Finck     cls.cbWndExtra = 0;
86c5d3ff03SSerge Gautherie     cls.hInstance = GetModuleHandleA(NULL);
87c5d3ff03SSerge Gautherie     cls.hIcon = NULL;
88c5d3ff03SSerge Gautherie     cls.hCursor = LoadCursorA(NULL, IDC_ARROW);
89c2c66affSColin Finck     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
90c2c66affSColin Finck     cls.lpszMenuName = NULL;
91c2c66affSColin Finck     cls.lpszClassName = "RedrawWindowClass";
92c2c66affSColin Finck 
93620d8c01SSerge Gautherie     clsAtom = RegisterClassA(&cls);
94620d8c01SSerge Gautherie     ok(clsAtom != 0, "RegisterClassA() failed: LastError = %lu\n", GetLastError());
95620d8c01SSerge Gautherie 
96620d8c01SSerge Gautherie     if (clsAtom == 0)
97c2c66affSColin Finck     {
98620d8c01SSerge Gautherie         skip("No Class atom\n");
99c2c66affSColin Finck         return;
100c2c66affSColin Finck     }
101c2c66affSColin Finck 
102620d8c01SSerge Gautherie     hwndMain = CreateWindowA(cls.lpszClassName, "Main Window", WS_OVERLAPPEDWINDOW,
103c5d3ff03SSerge Gautherie                              CW_USEDEFAULT, 0, 100, 100, NULL, NULL, NULL, NULL);
104465745b6STimo Kreuzer 
105620d8c01SSerge Gautherie     ok(hwndMain != NULL, "CreateWindowA() failed: LastError = %lu\n", GetLastError());
106c2c66affSColin Finck 
107620d8c01SSerge Gautherie     ok(WMPAINT_count == 0,
108620d8c01SSerge Gautherie        "Multiple unexpected WM_PAINT calls = %d\n", WMPAINT_count);
109620d8c01SSerge Gautherie 
110620d8c01SSerge Gautherie     if (hwndMain == NULL)
111620d8c01SSerge Gautherie     {
112620d8c01SSerge Gautherie         skip("No Window\n");
113620d8c01SSerge Gautherie         ok(UnregisterClassA(cls.lpszClassName, cls.hInstance) != 0,
114620d8c01SSerge Gautherie            "UnregisterClassA() failed: LastError = %lu\n", GetLastError());
115620d8c01SSerge Gautherie         return;
116620d8c01SSerge Gautherie     }
117620d8c01SSerge Gautherie 
118c2c66affSColin Finck     ShowWindow(hwndMain, SW_SHOW);
119620d8c01SSerge Gautherie     ok(WMPAINT_count == 0,
120620d8c01SSerge Gautherie        "Multiple unexpected WM_PAINT calls = %d\n", WMPAINT_count);
121620d8c01SSerge Gautherie 
122c2c66affSColin Finck     RedrawWindow(hwndMain, NULL, NULL, RDW_UPDATENOW | RDW_ALLCHILDREN);
123c2c66affSColin Finck     ok(WMPAINT_count == 1 || broken(WMPAINT_count == 0), /* sometimes on win9x */
124620d8c01SSerge Gautherie        "Multiple unexpected WM_PAINT calls = %d\n", WMPAINT_count);
125c2c66affSColin Finck 
126620d8c01SSerge Gautherie     redrawComplete = TRUE;
127620d8c01SSerge Gautherie     ok(WMPAINT_count < WMPAINT_COUNT_THRESHOLD,
128620d8c01SSerge Gautherie        "RedrawWindow (RDW_UPDATENOW) never completed (%d/%d)\n",
129620d8c01SSerge Gautherie        WMPAINT_count, WMPAINT_COUNT_THRESHOLD);
130620d8c01SSerge Gautherie 
131620d8c01SSerge Gautherie     ok(DestroyWindow(hwndMain) != 0,
132620d8c01SSerge Gautherie        "DestroyWindow() failed: LastError = %lu\n", GetLastError());
133620d8c01SSerge Gautherie 
134620d8c01SSerge Gautherie     ok(UnregisterClassA(cls.lpszClassName, cls.hInstance) != 0,
135620d8c01SSerge Gautherie        "UnregisterClassA() failed: LastError = %lu\n", GetLastError());
136c2c66affSColin Finck }
137c2c66affSColin Finck 
test_get_wndproc(void)138*993eb076SJames Tabor static void test_get_wndproc(void)
139*993eb076SJames Tabor {
140*993eb076SJames Tabor     LONG_PTR ret;
141*993eb076SJames Tabor     SetLastError(0xfeedf00d);
142*993eb076SJames Tabor     ret = GetWindowLongPtrA(GetShellWindow(), GWLP_WNDPROC);
143*993eb076SJames Tabor     ok (ret == 0, "Should return NULL\n");
144*993eb076SJames Tabor     ok (GetLastError() == ERROR_ACCESS_DENIED, "Wrong return error!\n");
145*993eb076SJames Tabor     SetLastError(0xfeedf00d);
146*993eb076SJames Tabor     ret = GetWindowLongPtrW(GetShellWindow(), GWLP_WNDPROC);
147*993eb076SJames Tabor     ok (ret == 0, "Should return NULL\n");
148*993eb076SJames Tabor     ok (GetLastError() == ERROR_ACCESS_DENIED, "Wrong return error!\n");
149*993eb076SJames Tabor     SetLastError(0xfeedf00d);
150*993eb076SJames Tabor     ret = GetWindowLongPtrA(GetShellWindow(), GWLP_WNDPROC);
151*993eb076SJames Tabor     ok (ret == 0, "Should return NULL\n");
152*993eb076SJames Tabor     ok (GetLastError() == ERROR_ACCESS_DENIED, "Wrong return error!\n");
153*993eb076SJames Tabor     SetLastError(0xfeedf00d);
154*993eb076SJames Tabor     ret = GetWindowLongPtrW(GetShellWindow(), GWLP_WNDPROC);
155*993eb076SJames Tabor     ok (ret == 0, "Should return NULL\n");
156*993eb076SJames Tabor     ok (GetLastError() == ERROR_ACCESS_DENIED, "Wrong return error!\n");
157*993eb076SJames Tabor }
158*993eb076SJames Tabor 
START_TEST(WndProc)159c2c66affSColin Finck START_TEST(WndProc)
160c2c66affSColin Finck {
161c2c66affSColin Finck #ifdef __RUNTIME_CHECKS__
162620d8c01SSerge Gautherie     skip("This test breaks MSVC runtime checks!\n");
163c2c66affSColin Finck     return;
164c2c66affSColin Finck #endif /* __RUNTIME_CHECKS__ */
1659a8b5ffcSSerge Gautherie 
166*993eb076SJames Tabor     test_get_wndproc();
167c2c66affSColin Finck     test_wndproc();
168c2c66affSColin Finck }
169