ReactOS 0.4.15-dev-7968-g24a56f8
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 MAX_MSGS 512
15
17static UINT s_cMsgs = 0;
18static CHAR s_prefix[16] = "";
24
25static void MsgDumpPrintf(LPCSTR fmt, ...)
26{
27 static char s_szText[1024];
28 va_list va;
29 va_start(va, fmt);
30 StringCbVPrintfA(s_szText, sizeof(s_szText), fmt, va);
31 trace("%s", s_szText);
32 va_end(va);
33}
34#define MSGDUMP_TPRINTF MsgDumpPrintf
35#define MSGDUMP_PREFIX s_prefix
36#include "msgdump.h" /* msgdump.h needs MSGDUMP_TPRINTF and MSGDUMP_PREFIX */
37
38static void MD_build_prefix(void)
39{
41 INT i = 0;
42
43 if (Flags & ISMEX_CALLBACK)
44 s_prefix[i++] = 'C';
45 if (Flags & ISMEX_NOTIFY)
46 s_prefix[i++] = 'N';
47 if (Flags & ISMEX_REPLIED)
48 s_prefix[i++] = 'R';
49 if (Flags & ISMEX_SEND)
50 s_prefix[i++] = 'S';
51 if (i == 0)
52 s_prefix[i++] = 'P';
53
54 s_prefix[i++] = ':';
55 s_prefix[i++] = ' ';
56 s_prefix[i] = 0;
57}
58
59#define STAGE_1 1
60#define STAGE_2 2
61#define STAGE_3 3
62#define STAGE_4 4
63#define STAGE_5 5
64
65static INT findMessage(INT iMsg, HWND hwnd, UINT uMsg)
66{
67 if (iMsg == -1)
68 iMsg = 0;
69 for (; iMsg < s_cMsgs; ++iMsg)
70 {
71 if (s_Msgs[iMsg].message == uMsg && s_Msgs[iMsg].hwnd == hwnd)
72 return iMsg;
73 }
74 return -1;
75}
76
77typedef struct TEST_ENTRY
78{
79 INT line;
83
84static VOID DoAnalyzeEntries(size_t nCount, PTEST_ENTRY pEntries)
85{
86 size_t i;
87 for (i = 0; i < nCount - 1; ++i)
88 {
89 PTEST_ENTRY entry1 = &pEntries[i];
90 PTEST_ENTRY entry2 = &pEntries[i + 1];
91 ok(entry1->iFound < entry2->iFound,
92 "Line %d: message wrong order (%d >= %d): %s vs %s\n",
93 entry1->line, entry1->iFound, entry2->iFound,
94 entry1->name, entry2->name);
95 }
96}
97
99{
100 size_t i;
101 TEST_ENTRY entries1[] =
102 {
103 { __LINE__, "WM_NCCREATE", findMessage(0, s_hMainWnd, WM_NCCREATE) },
104 { __LINE__, "WM_NCCALCSIZE", findMessage(0, s_hMainWnd, WM_NCCALCSIZE) },
105 { __LINE__, "WM_CREATE", findMessage(0, s_hMainWnd, WM_CREATE) },
106 { __LINE__, "WM_PARENTNOTIFY", findMessage(0, s_hMainWnd, WM_PARENTNOTIFY) },
107 { __LINE__, "WM_WINDOWPOSCHANGING", findMessage(0, s_hMainWnd, WM_WINDOWPOSCHANGING) },
108 { __LINE__, "WM_ACTIVATEAPP", findMessage(0, s_hMainWnd, WM_ACTIVATEAPP) },
109 { __LINE__, "WM_NCACTIVATE", findMessage(0, s_hMainWnd, WM_NCACTIVATE) },
110 { __LINE__, "WM_ACTIVATE", findMessage(0, s_hMainWnd, WM_ACTIVATE) },
111 { __LINE__, "WM_IME_SETCONTEXT", findMessage(0, s_hMainWnd, WM_IME_SETCONTEXT) },
112 { __LINE__, "WM_IME_NOTIFY", findMessage(0, s_hMainWnd, WM_IME_NOTIFY) },
113 { __LINE__, "WM_SETFOCUS", findMessage(0, s_hMainWnd, WM_SETFOCUS) },
114 { __LINE__, "WM_KILLFOCUS", findMessage(0, s_hMainWnd, WM_KILLFOCUS) },
115 };
116 INT iFound1 = entries1[_countof(entries1) - 1].iFound;
117 TEST_ENTRY entries2[] =
118 {
119 { __LINE__, "WM_IME_SETCONTEXT", findMessage(iFound1, s_hMainWnd, WM_IME_SETCONTEXT) },
120 { __LINE__, "WM_IME_SETCONTEXT", findMessage(iFound1, s_hwndEdit, WM_IME_SETCONTEXT) },
121 { __LINE__, "WM_SETFOCUS", findMessage(iFound1, s_hwndEdit, WM_SETFOCUS) },
122 { __LINE__, "WM_SHOWWINDOW", findMessage(iFound1, s_hMainWnd, WM_SHOWWINDOW) },
123 { __LINE__, "WM_WINDOWPOSCHANGING", findMessage(iFound1, s_hMainWnd, WM_WINDOWPOSCHANGING) },
124 { __LINE__, "WM_NCPAINT", findMessage(iFound1, s_hMainWnd, WM_NCPAINT) },
125 { __LINE__, "WM_ERASEBKGND", findMessage(iFound1, s_hMainWnd, WM_ERASEBKGND) },
126 { __LINE__, "WM_WINDOWPOSCHANGED", findMessage(iFound1, s_hMainWnd, WM_WINDOWPOSCHANGED) },
127 { __LINE__, "WM_SIZE", findMessage(iFound1, s_hMainWnd, WM_SIZE) },
128 { __LINE__, "WM_MOVE", findMessage(iFound1, s_hMainWnd, WM_MOVE) },
129 };
130 INT iFound2 = entries2[_countof(entries2) - 1].iFound;
131 TEST_ENTRY entries3[] =
132 {
133 { __LINE__, "WM_IME_KEYDOWN", findMessage(iFound2, s_hwndEdit, WM_IME_KEYDOWN) },
134 { __LINE__, "WM_KEYDOWN", findMessage(iFound2, s_hwndEdit, WM_KEYDOWN) },
135 { __LINE__, "WM_IME_KEYUP", findMessage(iFound2, s_hwndEdit, WM_IME_KEYUP) },
136 { __LINE__, "WM_CHAR", findMessage(iFound2, s_hwndEdit, WM_CHAR) },
137 { __LINE__, "WM_IME_CHAR", findMessage(iFound2, s_hwndEdit, WM_IME_CHAR) },
138 };
139 INT iFound3 = entries3[_countof(entries3) - 1].iFound;
140 TEST_ENTRY entries4[] =
141 {
142 { __LINE__, "WM_IME_NOTIFY", findMessage(iFound3, s_hwndEdit, WM_IME_NOTIFY) },
143 { __LINE__, "WM_IME_NOTIFY", findMessage(iFound3, s_hImeWnd, WM_IME_NOTIFY) },
144 { __LINE__, "WM_IME_SETCONTEXT", findMessage(iFound3, s_hwndEdit, WM_IME_SETCONTEXT) },
145 { __LINE__, "WM_IME_SETCONTEXT", findMessage(iFound3, s_hImeWnd, WM_IME_SETCONTEXT) },
146 };
147 INT iFound4 = entries4[_countof(entries4) - 1].iFound;
148 TEST_ENTRY entries5[] =
149 {
150 { __LINE__, "WM_DESTROY", findMessage(iFound4, s_hMainWnd, WM_DESTROY) },
151 { __LINE__, "WM_DESTROY", findMessage(iFound4, s_hwndEdit, WM_DESTROY) },
152 { __LINE__, "WM_NCDESTROY", findMessage(iFound4, s_hwndEdit, WM_NCDESTROY) },
153 { __LINE__, "WM_NCDESTROY", findMessage(iFound4, s_hMainWnd, WM_NCDESTROY) },
154 };
155 DoAnalyzeEntries(_countof(entries1), entries1);
156 DoAnalyzeEntries(_countof(entries2), entries2);
157 DoAnalyzeEntries(_countof(entries3), entries3);
158 //DoAnalyzeEntries(_countof(entries4), entries4); // No order
159 DoAnalyzeEntries(_countof(entries5), entries5);
160
161 ok(iFound1 < entries2[0].iFound, "%d vs %d\n", iFound1, entries2[0].iFound);
162 ok(iFound2 < entries3[0].iFound, "%d vs %d\n", iFound2, entries3[0].iFound);
163 ok(iFound3 < entries4[0].iFound, "%d vs %d\n", iFound3, entries4[0].iFound);
164 ok(iFound4 < entries5[0].iFound, "%d vs %d\n", iFound4, entries5[0].iFound);
165
166 for (i = 0; i < _countof(entries4); ++i)
167 {
168 ok(entries4[i].iFound != -1, "entries4[%d].iFound was -1\n", i);
169 }
170}
171
172static LRESULT CALLBACK
174{
175 LRESULT ret;
176 MSG msg = { hwnd, uMsg, wParam, lParam };
177
178 /* Build s_prefix */
180
181 /* message dump */
182 MD_msgdump(hwnd, uMsg, wParam, lParam);
183
184 /* Add message */
185 if (s_cMsgs < MAX_MSGS)
186 s_Msgs[s_cMsgs++] = msg;
187
188 /* Do inner task */
190
191 /* message return */
192 StringCbCopyA(s_prefix, sizeof(s_prefix), "R: ");
194
195 return ret;
196}
197
198static LRESULT CALLBACK
200{
201 LRESULT ret;
202 MSG msg = { hwnd, uMsg, wParam, lParam };
203
204 /* Build s_prefix */
206
207 /* message dump */
208 MD_msgdump(hwnd, uMsg, wParam, lParam);
209
210 /* Add message */
211 if (s_cMsgs < MAX_MSGS)
212 s_Msgs[s_cMsgs++] = msg;
213
214 /* Do inner task */
216
217 /* message return */
218 StringCbCopyA(s_prefix, sizeof(s_prefix), "R: ");
220
221 return ret;
222}
223
224static LRESULT CALLBACK
226{
227 switch (uMsg)
228 {
229 case WM_NCCREATE:
231 trace("s_hMainWnd: %p\n", s_hMainWnd);
232 break;
233 case WM_CREATE:
235 0, 0, 100, 20, hwnd, NULL, GetModuleHandleW(NULL), NULL);
236 ok(s_hwndEdit != NULL, "s_hwndEdit was NULL\n");
237 trace("s_hwndEdit: %p\n", s_hwndEdit);
242 break;
243 case WM_COMMAND:
244 switch (LOWORD(wParam))
245 {
246 case STAGE_1:
248 ok(s_hImeWnd != NULL, "s_hImeWnd was NULL\n");
249 trace("s_hImeWnd: %p\n", s_hImeWnd );
253 break;
254 case STAGE_2:
257 break;
258 case STAGE_3:
261 break;
262 case STAGE_4:
265 break;
266 case STAGE_5:
267 PostMessageW(hwnd, WM_CLOSE, 0, 0);
268 break;
269 }
270 break;
271 case WM_DESTROY:
273 break;
274 }
275
276 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
277}
278
279static LRESULT CALLBACK
281{
282 LRESULT ret;
283 MSG msg = { hwnd, uMsg, wParam, lParam };
284
285 /* Build s_prefix */
287
288 /* message dump */
289 MD_msgdump(hwnd, uMsg, wParam, lParam);
290
291 /* Add message */
292 if (s_cMsgs < MAX_MSGS)
293 s_Msgs[s_cMsgs++] = msg;
294
295 /* Do inner task */
297
298 /* message return */
299 StringCbCopyA(s_prefix, sizeof(s_prefix), "R: ");
301
302 return ret;
303}
304
305START_TEST(MessageStateAnalyzer)
306{
307 WNDCLASSW wc;
308 HWND hwnd;
309 MSG msg;
310 static const WCHAR s_szName[] = L"MessageStateAnalyzer";
311
312 /* register window class */
313 ZeroMemory(&wc, sizeof(wc));
319 wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
321 if (!RegisterClassW(&wc))
322 {
323 skip("RegisterClassW failed.\n");
324 return;
325 }
326
327 /* create a window */
331 if (!hwnd)
332 {
333 skip("CreateWindowW failed.\n");
334 return;
335 }
336
337 /* message loop */
338 while (GetMessageW(&msg, NULL, 0, 0))
339 {
342 }
343
345}
static MSG s_Msgs[MAX_MSGS]
static CHAR s_prefix[16]
static VOID DoAnalyzeAllMessages(VOID)
static UINT s_cMsgs
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
static void MsgDumpPrintf(LPCSTR fmt,...)
#define STAGE_3
#define MAX_MSGS
#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)
char * va_list
Definition: acmsvcex.h:78
#define va_end(ap)
Definition: acmsvcex.h:90
#define va_start(ap, A)
Definition: acmsvcex.h:91
#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:34
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
#define NULL
Definition: types.h:112
#define CALLBACK
Definition: compat.h:35
HWND WINAPI ImmGetDefaultIMEWnd(HWND hWnd)
Definition: ime.c:890
HMODULE WINAPI GetModuleHandleW(LPCWSTR lpModuleName)
Definition: loader.c:838
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
static __inline LRESULT MSGDUMP_API MD_msgdump(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: msgdump.h:4655
static __inline LRESULT MSGDUMP_API MD_msgresult(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT lResult)
Definition: msgdump.h:5368
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
unsigned int UINT
Definition: ndis.h:50
#define L(x)
Definition: ntvdm.h:50
#define LOWORD(l)
Definition: pedump.c:82
#define WS_CHILD
Definition: pedump.c:617
#define WS_OVERLAPPEDWINDOW
Definition: pedump.c:637
#define WS_VISIBLE
Definition: pedump.c:620
#define _countof(array)
Definition: sndvol32.h:68
STRSAFEAPI StringCbVPrintfA(STRSAFE_LPSTR pszDest, size_t cbDest, STRSAFE_LPCSTR pszFormat, va_list argList)
Definition: strsafe.h:502
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:3185
HBRUSH hbrBackground
Definition: winuser.h:3183
HICON hIcon
Definition: winuser.h:3181
HINSTANCE hInstance
Definition: winuser.h:3180
UINT style
Definition: winuser.h:3176
WNDPROC lpfnWndProc
Definition: winuser.h:3177
HCURSOR hCursor
Definition: winuser.h:3182
Definition: dsound.c:943
Definition: tftpd.h:60
#define GWLP_WNDPROC
Definition: treelist.c:66
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1829
int32_t INT
Definition: typedefs.h:58
int ret
DWORD WINAPI InSendMessageEx(LPVOID lpReserved)
Definition: message.c:1391
#define ZeroMemory
Definition: winbase.h:1712
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
LONG_PTR LPARAM
Definition: windef.h:208
LONG_PTR LRESULT
Definition: windef.h:209
UINT_PTR WPARAM
Definition: windef.h:207
#define WM_ERASEBKGND
Definition: winuser.h:1625
#define CS_VREDRAW
Definition: winuser.h:658
#define WM_IME_KEYUP
Definition: winuser.h:1839
#define WM_CLOSE
Definition: winuser.h:1621
BOOL WINAPI TranslateMessage(_In_ const MSG *)
LRESULT WINAPI DefWindowProcW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define WM_IME_NOTIFY
Definition: winuser.h:1830
#define CallWindowProc
Definition: winuser.h:5735
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:1661
#define WM_IME_KEYDOWN
Definition: winuser.h:1838
#define WM_CREATE
Definition: winuser.h:1608
__analysis_noreturn void WINAPI PostQuitMessage(_In_ int)
#define WM_SIZE
Definition: winuser.h:1611
#define WM_COMMAND
Definition: winuser.h:1740
#define CS_HREDRAW
Definition: winuser.h:653
ATOM WINAPI RegisterClassW(_In_ CONST WNDCLASSW *)
#define IDC_ARROW
Definition: winuser.h:687
#define WM_SETFOCUS
Definition: winuser.h:1613
#define CS_DBLCLKS
Definition: winuser.h:651
#define WM_NCCREATE
Definition: winuser.h:1683
#define IDI_APPLICATION
Definition: winuser.h:704
#define WM_ACTIVATE
Definition: winuser.h:1612
#define WM_SHOWWINDOW
Definition: winuser.h:1628
#define WM_IME_SETCONTEXT
Definition: winuser.h:1829
#define WM_NCACTIVATE
Definition: winuser.h:1688
#define WM_IME_CHAR
Definition: winuser.h:1834
HWND WINAPI SetFocus(_In_opt_ HWND)
#define LoadIcon
Definition: winuser.h:5813
#define LoadCursor
Definition: winuser.h:5812
#define CreateWindowW(a, b, c, d, e, f, g, h, i, j, k)
Definition: winuser.h:4316
#define WM_CHAR
Definition: winuser.h:1717
#define CW_USEDEFAULT
Definition: winuser.h:225
#define WM_MOVE
Definition: winuser.h:1610
#define WM_NCDESTROY
Definition: winuser.h:1684
LRESULT WINAPI DispatchMessageW(_In_ const MSG *)
#define WM_ACTIVATEAPP
Definition: winuser.h:1632
#define WM_DESTROY
Definition: winuser.h:1609
#define WM_KEYDOWN
Definition: winuser.h:1715
LRESULT(CALLBACK * WNDPROC)(HWND, UINT, WPARAM, LPARAM)
Definition: winuser.h:2906
#define WM_PARENTNOTIFY
Definition: winuser.h:1803
#define SetWindowLongPtrW
Definition: winuser.h:5346
#define WM_NCCALCSIZE
Definition: winuser.h:1685
#define WM_WINDOWPOSCHANGED
Definition: winuser.h:1662
#define WM_KILLFOCUS
Definition: winuser.h:1614
#define WM_NCPAINT
Definition: winuser.h:1687
#define COLOR_3DFACE
Definition: winuser.h:929
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
const char * LPCSTR
Definition: xmlstorage.h:183
__wchar_t WCHAR
Definition: xmlstorage.h:180
char CHAR
Definition: xmlstorage.h:175