1bec5f3215e174746a3f3a3d2c4b2e9ec172512a
[reactos.git] / rostests / apitests / user32 / SendMessageTimeout.c
1 /*
2 * PROJECT: ReactOS API tests
3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Test for SendMessageTimeout
5 * PROGRAMMERS: Thomas Faber <thomas.faber@reactos.org>
6 */
7
8 #include <apitest.h>
9 #include <winuser.h>
10 #include "helper.h"
11
12 static DWORD dwThread1;
13 static DWORD dwThread2;
14 static HANDLE hThread1;
15 static HANDLE hThread2;
16 static HWND hWndThread1;
17 static HWND hWndThread2;
18
19 static
20 void
21 TestSendMessageTimeout(
22 _In_ HWND hWnd,
23 _In_ UINT Msg)
24 {
25 LRESULT ret;
26 DWORD_PTR result;
27
28 ret = SendMessageTimeoutW(hWnd, Msg, 0, 0, SMTO_NORMAL, 0, NULL);
29 ok(ret == 0, "ret = %Id\n", ret);
30
31 result = 0x55555555;
32 ret = SendMessageTimeoutW(hWnd, Msg, 0, 0, SMTO_NORMAL, 0, &result);
33 ok(ret == 0, "ret = %Id\n", ret);
34 ok(result == 0, "result = %Iu\n", result);
35
36 ret = SendMessageTimeoutA(hWnd, Msg, 0, 0, SMTO_NORMAL, 0, NULL);
37 ok(ret == 0, "ret = %Id\n", ret);
38
39 result = 0x55555555;
40 ret = SendMessageTimeoutA(hWnd, Msg, 0, 0, SMTO_NORMAL, 0, &result);
41 ok(ret == 0, "ret = %Id\n", ret);
42 ok(result == 0, "result = %Iu\n", result);
43 }
44
45 #define WM_SENDTOOTHERTHREAD (WM_USER + 14)
46
47 #define KILL_THREAD1_FLAG 0x40000000
48 #define KILL_THREAD2_FLAG 0x20000000
49 #define KILL_THREAD_FLAGS (KILL_THREAD1_FLAG | KILL_THREAD2_FLAG)
50
51 static
52 LRESULT
53 CALLBACK
54 WndProc(
55 _In_ HWND hWnd,
56 _In_ UINT message,
57 _In_ WPARAM wParam,
58 _In_ LPARAM lParam)
59 {
60 if (IsDWmMsg(message) || IseKeyMsg(message))
61 return DefWindowProcW(hWnd, message, wParam, lParam);
62
63 if (hWnd == hWndThread1)
64 {
65 RECORD_MESSAGE(1, message, SENT, wParam, lParam);
66 }
67 else if (hWnd == hWndThread2)
68 {
69 RECORD_MESSAGE(2, message, SENT, wParam, lParam);
70 }
71 else
72 {
73 RECORD_MESSAGE(3, message, SENT, wParam, lParam);
74 }
75
76 switch (message)
77 {
78 case WM_SENDTOOTHERTHREAD:
79 if (GetCurrentThreadId() == dwThread1)
80 {
81 if ((wParam & KILL_THREAD2_FLAG) &&
82 (wParam & ~KILL_THREAD_FLAGS) > 10)
83 {
84 TerminateThread(hThread2, 123);
85 }
86 if ((wParam & KILL_THREAD1_FLAG) &&
87 (wParam & ~KILL_THREAD_FLAGS) > 10)
88 {
89 TerminateThread(hThread1, 456);
90 }
91 ok(lParam == dwThread2, "lParam = %Iu, expected %lu\n", lParam, dwThread2);
92 return SendMessage(hWndThread2, WM_SENDTOOTHERTHREAD, wParam + 1, GetCurrentThreadId());
93 }
94 else
95 {
96 ok(lParam == dwThread1, "lParam = %Iu, expected %lu\n", lParam, dwThread1);
97 return SendMessage(hWndThread1, WM_SENDTOOTHERTHREAD, wParam + 1, GetCurrentThreadId());
98 }
99 }
100
101 return DefWindowProcW(hWnd, message, wParam, lParam);
102 }
103
104 static
105 DWORD
106 WINAPI
107 Thread1(
108 _Inout_opt_ PVOID Parameter)
109 {
110 MSG msg;
111
112 hWndThread1 = CreateWindowExW(0, L"SendTest", NULL, 0, 10, 10, 20, 20, NULL, NULL, 0, NULL);
113 ok(hWndThread1 != NULL, "CreateWindow failed\n");
114
115 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
116 {
117 if (!(msg.message > WM_USER || IsDWmMsg(msg.message) || IseKeyMsg(msg.message)))
118 RECORD_MESSAGE(1, msg.message, POST, 0, 0);
119 DispatchMessageA(&msg);
120 }
121
122 ResumeThread(hThread2);
123
124 while (MsgWaitForMultipleObjectsEx(1, &hThread2, FALSE, QS_ALLEVENTS, MWMO_ALERTABLE) != WAIT_OBJECT_0)
125 {
126 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
127 {
128 if (!(msg.message > WM_USER || IsDWmMsg(msg.message) || IseKeyMsg(msg.message)))
129 RECORD_MESSAGE(1, msg.message, POST, 0, 0);
130 DispatchMessageA(&msg);
131 }
132 }
133
134 DestroyWindow(hWndThread1);
135 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
136 {
137 if (!(msg.message > WM_USER || IsDWmMsg(msg.message) || IseKeyMsg(msg.message)))
138 RECORD_MESSAGE(1, msg.message, POST, 0, 0);
139 DispatchMessageA(&msg);
140 }
141
142 return 6;
143 }
144
145 static
146 DWORD
147 WINAPI
148 Thread2(
149 _Inout_opt_ PVOID Parameter)
150 {
151 MSG msg;
152 LRESULT ret;
153 WPARAM wParam;
154
155 hWndThread2 = CreateWindowExW(0, L"SendTest", NULL, 0, 10, 10, 20, 20, NULL, NULL, 0, NULL);
156 ok(hWndThread2 != NULL, "CreateWindow failed\n");
157
158 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
159 {
160 if (!(msg.message > WM_USER || IsDWmMsg(msg.message) || IseKeyMsg(msg.message)))
161 RECORD_MESSAGE(2, msg.message, POST, 0, 0);
162 DispatchMessageA(&msg);
163 }
164
165 wParam = (WPARAM)Parameter;
166 ret = SendMessage(hWndThread1, WM_SENDTOOTHERTHREAD, wParam, dwThread2);
167 ok(ret == 0, "ret = %lu\n", ret);
168
169 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
170 {
171 if (!(msg.message > WM_USER || IsDWmMsg(msg.message) || IseKeyMsg(msg.message)))
172 RECORD_MESSAGE(2, msg.message, POST, 0, 0);
173 DispatchMessageA(&msg);
174 }
175
176 DestroyWindow(hWndThread2);
177 while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
178 {
179 if (!(msg.message > WM_USER || IsDWmMsg(msg.message) || IseKeyMsg(msg.message)))
180 RECORD_MESSAGE(2, msg.message, POST, 0, 0);
181 DispatchMessageA(&msg);
182 }
183
184 return 7;
185 }
186
187 static
188 void
189 TestRecursiveInterThreadMessages(
190 _In_ BOOL KillThread1,
191 _In_ BOOL KillThread2)
192 {
193 PVOID Parameter;
194 HANDLE Handles[2];
195 BOOL Ret;
196 DWORD ExitCode;
197
198 Parameter = (PVOID)((KillThread1 ? KILL_THREAD1_FLAG : 0) |
199 (KillThread2 ? KILL_THREAD2_FLAG : 0));
200 hThread1 = CreateThread(NULL, 0, Thread1, Parameter, CREATE_SUSPENDED, &dwThread1);
201 hThread2 = CreateThread(NULL, 0, Thread2, Parameter, CREATE_SUSPENDED, &dwThread2);
202
203 ResumeThread(hThread1);
204
205 Handles[0] = hThread1;
206 Handles[1] = hThread2;
207 WaitForMultipleObjects(2, Handles, TRUE, INFINITE);
208
209 Ret = GetExitCodeThread(hThread1, &ExitCode);
210 ok(Ret == TRUE, "GetExitCodeThread failed with %lu\n", GetLastError());
211 if (KillThread1)
212 ok(ExitCode == 456, "Thread1 exit code is %lu\n", ExitCode);
213 else
214 ok(ExitCode == 6, "Thread1 exit code is %lu\n", ExitCode);
215
216 Ret = GetExitCodeThread(hThread2, &ExitCode);
217 ok(Ret == TRUE, "GetExitCodeThread failed with %lu\n", GetLastError());
218 if (KillThread2)
219 ok(ExitCode == 123, "Thread2 exit code is %lu\n", ExitCode);
220 else
221 ok(ExitCode == 7, "Thread2 exit code is %lu\n", ExitCode);
222
223 CloseHandle(hThread2);
224 CloseHandle(hThread1);
225
226 //TRACE_CACHE();
227 }
228
229 START_TEST(SendMessageTimeout)
230 {
231 TestSendMessageTimeout(NULL, WM_USER);
232 TestSendMessageTimeout(NULL, WM_PAINT);
233 TestSendMessageTimeout(NULL, WM_GETICON);
234
235 RegisterSimpleClass(WndProc, L"SendTest");
236
237 TestRecursiveInterThreadMessages(FALSE, FALSE);
238 TestRecursiveInterThreadMessages(FALSE, TRUE);
239 TestRecursiveInterThreadMessages(TRUE, FALSE);
240 TestRecursiveInterThreadMessages(TRUE, TRUE);
241 }