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