1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
 * PROJECT:         ReactOS api tests
 * LICENSE:         GPL - See COPYING in the top level directory
 * PURPOSE:         Test for mismatch with function prototype in window procedure callback.
 * PROGRAMMERS:
 */

#include "precomp.h"

/* Used wine Redraw test for proof in principle. */

#define WMPAINT_COUNT_THRESHOLD 10

/* Global variables to trigger exit from loop */
static int redrawComplete, WMPAINT_count;

/*
 * Force stack corruption when calling from assumed window procedure callback.
 * Adding (6 and) more will force exception faults and terminate the test program.
 * The test is with five and this is safe for windows.
 *
 * But,,,, ReactOS compiled with GCC can handle this,,,,,,
 */
static LRESULT WINAPI redraw_window_procA(
    HWND hwnd,
    UINT msg,
    WPARAM wparam,
    LPARAM lparam)
{
    switch (msg)
    {
        case WM_PAINT:
            break;
            WMPAINT_count++;<--- Statements following return, break, continue, goto or throw will never be executed.
            trace("Doing WM_PAINT %d/%d\n", WMPAINT_count, WMPAINT_COUNT_THRESHOLD);

            if (WMPAINT_count > WMPAINT_COUNT_THRESHOLD && redrawComplete == 0)
            {
                PAINTSTRUCT ps;

                trace("Calling *Paint()\n");
                BeginPaint(hwnd, &ps);
                EndPaint(hwnd, &ps);
                return 1;
            }

            // This will force one stack corruption "ret" fault with normal window
            // procedure callback.
#ifdef __MINGW32__
            trace("Executing __MINGW32__ stack corruption code\n");
            asm ("movl $0, %eax\n\t"
                 "leave\n\t"
                 "ret");
#elif defined(_M_IX86)
//#ifdef _MSC_VER
            trace("Executing MSVC x86 stack corruption code\n");
            __asm
              {
                 mov eax, 0
                 leave
                 ret
              }
#else
            ok(FALSE, "FIXME: stack corruption code is unimplemented\n");
#endif

            break;
        default:
            trace("Doing empty default: msg = %u\n", msg);
    }

    trace("Calling DefWindowProc()\n");
    return DefWindowProc(hwnd, msg, wparam, lparam);
}

static void test_wndproc(void)
{
    WNDCLASSA cls;
    ATOM clsAtom;
    HWND hwndMain;

    cls.style = CS_DBLCLKS;
    cls.lpfnWndProc = redraw_window_procA;
    cls.cbClsExtra = 0;
    cls.cbWndExtra = 0;
    cls.hInstance = GetModuleHandleA(NULL);
    cls.hIcon = NULL;
    cls.hCursor = LoadCursorA(NULL, IDC_ARROW);
    cls.hbrBackground = GetStockObject(WHITE_BRUSH);
    cls.lpszMenuName = NULL;
    cls.lpszClassName = "RedrawWindowClass";

    clsAtom = RegisterClassA(&cls);
    ok(clsAtom != 0, "RegisterClassA() failed: LastError = %lu\n", GetLastError());

    if (clsAtom == 0)
    {
        skip("No Class atom\n");
        return;
    }

    hwndMain = CreateWindowA(cls.lpszClassName, "Main Window", WS_OVERLAPPEDWINDOW,
                             CW_USEDEFAULT, 0, 100, 100, NULL, NULL, NULL, NULL);

    ok(hwndMain != NULL, "CreateWindowA() failed: LastError = %lu\n", GetLastError());

    ok(WMPAINT_count == 0,
       "Multiple unexpected WM_PAINT calls = %d\n", WMPAINT_count);

    if (hwndMain == NULL)
    {
        skip("No Window\n");
        ok(UnregisterClassA(cls.lpszClassName, cls.hInstance) != 0,
           "UnregisterClassA() failed: LastError = %lu\n", GetLastError());
        return;
    }

    ShowWindow(hwndMain, SW_SHOW);
    ok(WMPAINT_count == 0,
       "Multiple unexpected WM_PAINT calls = %d\n", WMPAINT_count);

    RedrawWindow(hwndMain, NULL, NULL, RDW_UPDATENOW | RDW_ALLCHILDREN);
    ok(WMPAINT_count == 1 || broken(WMPAINT_count == 0), /* sometimes on win9x */
       "Multiple unexpected WM_PAINT calls = %d\n", WMPAINT_count);

    redrawComplete = TRUE;
    ok(WMPAINT_count < WMPAINT_COUNT_THRESHOLD,
       "RedrawWindow (RDW_UPDATENOW) never completed (%d/%d)\n",
       WMPAINT_count, WMPAINT_COUNT_THRESHOLD);

    ok(DestroyWindow(hwndMain) != 0,
       "DestroyWindow() failed: LastError = %lu\n", GetLastError());

    ok(UnregisterClassA(cls.lpszClassName, cls.hInstance) != 0,
       "UnregisterClassA() failed: LastError = %lu\n", GetLastError());
}

START_TEST(WndProc)
{
#ifdef __RUNTIME_CHECKS__
    skip("This test breaks MSVC runtime checks!\n");
    return;
#endif /* __RUNTIME_CHECKS__ */

    test_wndproc();
}