ReactOS 0.4.17-dev-357-ga8f14ff
MessageStateAnalyzer.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS API tests
3 * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
4 * PURPOSE: debugging and analysis of message states
5 * COPYRIGHT: Copyright 2019-2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6 */
7
8#include "precomp.h"
9#include "undocuser.h"
10#include "winxx.h"
11#include <imm.h>
12#include <strsafe.h>
13
14//#define VERBOSE
15
16#define MAX_MSGS 512
17
19static UINT s_cMsgs = 0;
20static CHAR s_prefix[16] = "";
26
27#ifdef VERBOSE
28 #define MSGDUMP_PRINTF printf
29 #define MSGDUMP_PREFIX s_prefix
30 #include "msgdump.h" /* msgdump.h needs MSGDUMP_PRINTF and MSGDUMP_PREFIX */
31#else
32 #define MD_msgdump(hwnd, uMsg, wParam, lParam)
33 #define MD_msgresult(hwnd, uMsg, wParam, lParam, lResult)
34#endif
35
36static void MD_build_prefix(void)
37{
39 INT i = 0;
40
41 if (Flags & ISMEX_CALLBACK)
42 s_prefix[i++] = 'C';
43 if (Flags & ISMEX_NOTIFY)
44 s_prefix[i++] = 'N';
45 if (Flags & ISMEX_REPLIED)
46 s_prefix[i++] = 'R';
47 if (Flags & ISMEX_SEND)
48 s_prefix[i++] = 'S';
49 if (i == 0)
50 s_prefix[i++] = 'P';
51
52 s_prefix[i++] = ':';
53 s_prefix[i++] = ' ';
54 s_prefix[i] = 0;
55}
56
57#define STAGE_1 1
58#define STAGE_2 2
59#define STAGE_3 3
60#define STAGE_4 4
61#define STAGE_5 5
62
63static INT findMessage(INT iMsg, HWND hwnd, UINT uMsg)
64{
65 if (iMsg == -1)
66 iMsg = 0;
67 for (; iMsg < s_cMsgs; ++iMsg)
68 {
69 if (s_Msgs[iMsg].message == uMsg && s_Msgs[iMsg].hwnd == hwnd)
70 return iMsg;
71 }
72 return -1;
73}
74
75typedef struct TEST_ENTRY
76{
77 INT line;
81
82static VOID DoAnalyzeEntries(size_t nCount, PTEST_ENTRY pEntries)
83{
84 size_t i;
85 for (i = 0; i < nCount - 1; ++i)
86 {
87 PTEST_ENTRY entry1 = &pEntries[i];
88 PTEST_ENTRY entry2 = &pEntries[i + 1];
89 ok(entry1->iFound < entry2->iFound,
90 "Line %d: message wrong order (%d >= %d): %s vs %s\n",
91 entry1->line, entry1->iFound, entry2->iFound,
92 entry1->name, entry2->name);
93 }
94}
95
97{
98 size_t i;
99 TEST_ENTRY entries1[] =
100 {
101 { __LINE__, "WM_NCCREATE", findMessage(0, s_hMainWnd, WM_NCCREATE) },
102 { __LINE__, "WM_NCCALCSIZE", findMessage(0, s_hMainWnd, WM_NCCALCSIZE) },
103 { __LINE__, "WM_CREATE", findMessage(0, s_hMainWnd, WM_CREATE) },
104 { __LINE__, "WM_PARENTNOTIFY", findMessage(0, s_hMainWnd, WM_PARENTNOTIFY) },
105 { __LINE__, "WM_WINDOWPOSCHANGING", findMessage(0, s_hMainWnd, WM_WINDOWPOSCHANGING) },
106 { __LINE__, "WM_ACTIVATEAPP", findMessage(0, s_hMainWnd, WM_ACTIVATEAPP) },
107 { __LINE__, "WM_NCACTIVATE", findMessage(0, s_hMainWnd, WM_NCACTIVATE) },
108 { __LINE__, "WM_ACTIVATE", findMessage(0, s_hMainWnd, WM_ACTIVATE) },
109 { __LINE__, "WM_IME_SETCONTEXT", findMessage(0, s_hMainWnd, WM_IME_SETCONTEXT) },
110 { __LINE__, "WM_IME_NOTIFY", findMessage(0, s_hMainWnd, WM_IME_NOTIFY) },
111 { __LINE__, "WM_SETFOCUS", findMessage(0, s_hMainWnd, WM_SETFOCUS) },
112 { __LINE__, "WM_KILLFOCUS", findMessage(0, s_hMainWnd, WM_KILLFOCUS) },
113 };
114 INT iFound1 = entries1[_countof(entries1) - 1].iFound;
115 TEST_ENTRY entries2[] =
116 {
117 { __LINE__, "WM_IME_SETCONTEXT", findMessage(iFound1, s_hMainWnd, WM_IME_SETCONTEXT) },
118 { __LINE__, "WM_IME_SETCONTEXT", findMessage(iFound1, s_hwndEdit, WM_IME_SETCONTEXT) },
119 { __LINE__, "WM_SETFOCUS", findMessage(iFound1, s_hwndEdit, WM_SETFOCUS) },
120 { __LINE__, "WM_SHOWWINDOW", findMessage(iFound1, s_hMainWnd, WM_SHOWWINDOW) },
121 { __LINE__, "WM_WINDOWPOSCHANGING", findMessage(iFound1, s_hMainWnd, WM_WINDOWPOSCHANGING) },
122 { __LINE__, "WM_NCPAINT", findMessage(iFound1, s_hMainWnd, WM_NCPAINT) },
123 { __LINE__, "WM_ERASEBKGND", findMessage(iFound1, s_hMainWnd, WM_ERASEBKGND) },
124 { __LINE__, "WM_WINDOWPOSCHANGED", findMessage(iFound1, s_hMainWnd, WM_WINDOWPOSCHANGED) },
125 { __LINE__, "WM_SIZE", findMessage(iFound1, s_hMainWnd, WM_SIZE) },
126 { __LINE__, "WM_MOVE", findMessage(iFound1, s_hMainWnd, WM_MOVE) },
127 };
128 INT iFound2 = entries2[_countof(entries2) - 1].iFound;
129 TEST_ENTRY entries3[] =
130 {
131 { __LINE__, "WM_IME_KEYDOWN", findMessage(iFound2, s_hwndEdit, WM_IME_KEYDOWN) },
132 { __LINE__, "WM_KEYDOWN", findMessage(iFound2, s_hwndEdit, WM_KEYDOWN) },
133 { __LINE__, "WM_IME_KEYUP", findMessage(iFound2, s_hwndEdit, WM_IME_KEYUP) },
134 { __LINE__, "WM_CHAR", findMessage(iFound2, s_hwndEdit, WM_CHAR) },
135 { __LINE__, "WM_IME_CHAR", findMessage(iFound2, s_hwndEdit, WM_IME_CHAR) },
136 };
137 INT iFound3 = entries3[_countof(entries3) - 1].iFound;
138 TEST_ENTRY entries4[] =
139 {
140 { __LINE__, "WM_IME_NOTIFY", findMessage(iFound3, s_hwndEdit, WM_IME_NOTIFY) },
141 { __LINE__, "WM_IME_NOTIFY", findMessage(iFound3, s_hImeWnd, WM_IME_NOTIFY) },
142 { __LINE__, "WM_IME_SETCONTEXT", findMessage(iFound3, s_hwndEdit, WM_IME_SETCONTEXT) },
143 { __LINE__, "WM_IME_SETCONTEXT", findMessage(iFound3, s_hImeWnd, WM_IME_SETCONTEXT) },
144 };
145 INT iFound4 = entries4[_countof(entries4) - 1].iFound;
146 TEST_ENTRY entries5[] =
147 {
148 { __LINE__, "WM_DESTROY", findMessage(iFound4, s_hMainWnd, WM_DESTROY) },
149 { __LINE__, "WM_DESTROY", findMessage(iFound4, s_hwndEdit, WM_DESTROY) },
150 { __LINE__, "WM_NCDESTROY", findMessage(iFound4, s_hwndEdit, WM_NCDESTROY) },
151 { __LINE__, "WM_NCDESTROY", findMessage(iFound4, s_hMainWnd, WM_NCDESTROY) },
152 };
153 DoAnalyzeEntries(_countof(entries1), entries1);
154 DoAnalyzeEntries(_countof(entries2), entries2);
155 DoAnalyzeEntries(_countof(entries3), entries3);
156 //DoAnalyzeEntries(_countof(entries4), entries4); // No order
157 DoAnalyzeEntries(_countof(entries5), entries5);
158
159 ok(iFound1 < entries2[0].iFound, "%d vs %d\n", iFound1, entries2[0].iFound);
160 ok(iFound2 < entries3[0].iFound, "%d vs %d\n", iFound2, entries3[0].iFound);
161 ok(iFound3 < entries4[0].iFound, "%d vs %d\n", iFound3, entries4[0].iFound);
162 ok(iFound4 < entries5[0].iFound, "%d vs %d\n", iFound4, entries5[0].iFound);
163
164 for (i = 0; i < _countof(entries4); ++i)
165 {
166 ok(entries4[i].iFound != -1, "entries4[%d].iFound was -1\n", i);
167 }
168}
169
170static LRESULT CALLBACK
172{
173 LRESULT ret;
174 MSG msg = { hwnd, uMsg, wParam, lParam };
175
176 /* Build s_prefix */
178
179 /* message dump */
180 MD_msgdump(hwnd, uMsg, wParam, lParam);
181
182 /* Add message */
183 if (s_cMsgs < MAX_MSGS)
184 s_Msgs[s_cMsgs++] = msg;
185
186 /* Do inner task */
188
189 /* message return */
190 StringCbCopyA(s_prefix, sizeof(s_prefix), "R: ");
192
193 return ret;
194}
195
196static LRESULT CALLBACK
198{
199 LRESULT ret;
200 MSG msg = { hwnd, uMsg, wParam, lParam };
201
202 /* Build s_prefix */
204
205 /* message dump */
206 MD_msgdump(hwnd, uMsg, wParam, lParam);
207
208 /* Add message */
209 if (s_cMsgs < MAX_MSGS)
210 s_Msgs[s_cMsgs++] = msg;
211
212 /* Do inner task */
214
215 /* message return */
216 StringCbCopyA(s_prefix, sizeof(s_prefix), "R: ");
218
219 return ret;
220}
221
222static LRESULT CALLBACK
224{
225 switch (uMsg)
226 {
227 case WM_NCCREATE:
229 trace("s_hMainWnd: %p\n", s_hMainWnd);
230 break;
231 case WM_CREATE:
233 0, 0, 100, 20, hwnd, NULL, GetModuleHandleW(NULL), NULL);
234 ok(s_hwndEdit != NULL, "s_hwndEdit was NULL\n");
235 trace("s_hwndEdit: %p\n", s_hwndEdit);
240 break;
241 case WM_COMMAND:
242 switch (LOWORD(wParam))
243 {
244 case STAGE_1:
246 ok(s_hImeWnd != NULL, "s_hImeWnd was NULL\n");
247 trace("s_hImeWnd: %p\n", s_hImeWnd );
251 break;
252 case STAGE_2:
255 break;
256 case STAGE_3:
259 break;
260 case STAGE_4:
263 break;
264 case STAGE_5:
265 PostMessageW(hwnd, WM_CLOSE, 0, 0);
266 break;
267 }
268 break;
269 case WM_DESTROY:
271 break;
272 }
273
274 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
275}
276
277static LRESULT CALLBACK
279{
280 LRESULT ret;
281 MSG msg = { hwnd, uMsg, wParam, lParam };
282
283 /* Build s_prefix */
285
286 /* message dump */
287 MD_msgdump(hwnd, uMsg, wParam, lParam);
288
289 /* Add message */
290 if (s_cMsgs < MAX_MSGS)
291 s_Msgs[s_cMsgs++] = msg;
292
293 /* Do inner task */
295
296 /* message return */
297 StringCbCopyA(s_prefix, sizeof(s_prefix), "R: ");
299
300 return ret;
301}
302
303START_TEST(MessageStateAnalyzer)
304{
305 WNDCLASSW wc;
306 HWND hwnd;
307 MSG msg;
308 static const WCHAR s_szName[] = L"MessageStateAnalyzer";
309
310 /* register window class */
311 ZeroMemory(&wc, sizeof(wc));
317 wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
319 if (!RegisterClassW(&wc))
320 {
321 skip("RegisterClassW failed.\n");
322 return;
323 }
324
325 /* create a window */
329 if (!hwnd)
330 {
331 skip("CreateWindowW failed.\n");
332 return;
333 }
334
335 /* message loop */
336 while (GetMessageW(&msg, NULL, 0, 0))
337 {
340 }
341
343}
static MSG s_Msgs[MAX_MSGS]
static CHAR s_prefix[16]
static VOID DoAnalyzeAllMessages(VOID)
static UINT s_cMsgs
#define MD_msgdump(hwnd, uMsg, wParam, lParam)
static LRESULT CALLBACK ImeWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
static WNDPROC s_fnOldEditWndProc
static void MD_build_prefix(void)
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
static LRESULT CALLBACK InnerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
static HWND s_hMainWnd
#define STAGE_2
static VOID DoAnalyzeEntries(size_t nCount, PTEST_ENTRY pEntries)
static WNDPROC s_fnOldImeWndProc
struct TEST_ENTRY TEST_ENTRY
struct TEST_ENTRY * PTEST_ENTRY
#define STAGE_4
static HWND s_hImeWnd
#define STAGE_3
#define MAX_MSGS
#define MD_msgresult(hwnd, uMsg, wParam, lParam, lResult)
#define STAGE_5
static HWND s_hwndEdit
#define STAGE_1
static INT findMessage(INT iMsg, HWND hwnd, UINT uMsg)
static LRESULT CALLBACK EditWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
#define trace
Definition: atltest.h:70
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
#define START_TEST(x)
Definition: atltest.h:75
#define msg(x)
Definition: auth_time.c:54
static WCHAR s_szName[MAX_PATH]
Definition: find.c:22
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
#define NULL
Definition: types.h:112
#define CALLBACK
Definition: compat.h:35
HMODULE WINAPI GetModuleHandleW(LPCWSTR lpModuleName)
Definition: loader.c:838
return ret
Definition: mutex.c:146
#define L(x)
Definition: resources.c:13
unsigned long DWORD
Definition: ntddk_ex.h:95
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
HWND WINAPI ImmGetDefaultIMEWnd(_In_opt_ HWND hWnd)
Definition: ime.c:441
#define ZeroMemory
Definition: minwinbase.h:31
LONG_PTR LPARAM
Definition: minwindef.h:175
LONG_PTR LRESULT
Definition: minwindef.h:176
UINT_PTR WPARAM
Definition: minwindef.h:174
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
unsigned int UINT
Definition: ndis.h:50
#define LOWORD(l)
Definition: pedump.c:82
#define WS_CHILD
Definition: pedump.c:617
#define WS_OVERLAPPEDWINDOW
Definition: pedump.c:637
short WCHAR
Definition: pedump.c:58
#define WS_VISIBLE
Definition: pedump.c:620
char CHAR
Definition: pedump.c:57
#define _countof(array)
Definition: sndvol32.h:70
STRSAFEAPI StringCbCopyA(STRSAFE_LPSTR pszDest, size_t cbDest, STRSAFE_LPCSTR pszSrc)
Definition: strsafe.h:161
Definition: cmd.c:13
INT line
Definition: cmd.c:14
UINT iFound
LPCSTR name
LPCWSTR lpszClassName
Definition: winuser.h:3293
HBRUSH hbrBackground
Definition: winuser.h:3291
HICON hIcon
Definition: winuser.h:3289
HINSTANCE hInstance
Definition: winuser.h:3288
UINT style
Definition: winuser.h:3284
WNDPROC lpfnWndProc
Definition: winuser.h:3285
HCURSOR hCursor
Definition: winuser.h:3290
Definition: tftpd.h:60
#define GWLP_WNDPROC
Definition: treelist.c:66
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1829
const char * LPCSTR
Definition: typedefs.h:52
int32_t INT
Definition: typedefs.h:58
DWORD WINAPI InSendMessageEx(LPVOID lpReserved)
Definition: message.c:1391
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
#define WM_ERASEBKGND
Definition: winuser.h:1653
#define CS_VREDRAW
Definition: winuser.h:666
#define WM_IME_KEYUP
Definition: winuser.h:1867
#define WM_CLOSE
Definition: winuser.h:1649
BOOL WINAPI TranslateMessage(_In_ const MSG *)
LRESULT WINAPI DefWindowProcW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define WM_IME_NOTIFY
Definition: winuser.h:1858
#define CallWindowProc
Definition: winuser.h:5901
BOOL WINAPI GetMessageW(_Out_ LPMSG, _In_opt_ HWND, _In_ UINT, _In_ UINT)
BOOL WINAPI PostMessageW(_In_opt_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define WM_WINDOWPOSCHANGING
Definition: winuser.h:1689
#define WM_IME_KEYDOWN
Definition: winuser.h:1866
#define WM_CREATE
Definition: winuser.h:1636
__analysis_noreturn void WINAPI PostQuitMessage(_In_ int)
#define WM_SIZE
Definition: winuser.h:1639
#define WM_COMMAND
Definition: winuser.h:1768
#define CS_HREDRAW
Definition: winuser.h:661
ATOM WINAPI RegisterClassW(_In_ CONST WNDCLASSW *)
#define IDC_ARROW
Definition: winuser.h:695
#define WM_SETFOCUS
Definition: winuser.h:1641
#define CS_DBLCLKS
Definition: winuser.h:659
#define WM_NCCREATE
Definition: winuser.h:1711
#define IDI_APPLICATION
Definition: winuser.h:712
#define WM_ACTIVATE
Definition: winuser.h:1640
#define WM_SHOWWINDOW
Definition: winuser.h:1656
#define WM_IME_SETCONTEXT
Definition: winuser.h:1857
#define WM_NCACTIVATE
Definition: winuser.h:1716
#define WM_IME_CHAR
Definition: winuser.h:1862
HWND WINAPI SetFocus(_In_opt_ HWND)
#define LoadIcon
Definition: winuser.h:5979
#define LoadCursor
Definition: winuser.h:5978
#define CreateWindowW(a, b, c, d, e, f, g, h, i, j, k)
Definition: winuser.h:4470
#define WM_CHAR
Definition: winuser.h:1745
#define CW_USEDEFAULT
Definition: winuser.h:225
#define WM_MOVE
Definition: winuser.h:1638
#define WM_NCDESTROY
Definition: winuser.h:1712
LRESULT WINAPI DispatchMessageW(_In_ const MSG *)
#define WM_ACTIVATEAPP
Definition: winuser.h:1660
#define WM_DESTROY
Definition: winuser.h:1637
#define WM_KEYDOWN
Definition: winuser.h:1743
LRESULT(CALLBACK * WNDPROC)(HWND, UINT, WPARAM, LPARAM)
Definition: winuser.h:3014
#define WM_PARENTNOTIFY
Definition: winuser.h:1831
#define SetWindowLongPtrW
Definition: winuser.h:5512
#define WM_NCCALCSIZE
Definition: winuser.h:1713
#define WM_WINDOWPOSCHANGED
Definition: winuser.h:1690
#define WM_KILLFOCUS
Definition: winuser.h:1642
#define WM_NCPAINT
Definition: winuser.h:1715
#define COLOR_3DFACE
Definition: winuser.h:940
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170