79f517f8548bdca830b3030dc16773658e9a8b32
[reactos.git] / rostests / apitests / user32 / AttachThreadInput.c
1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPL - See COPYING in the top level directory
4 * PURPOSE: Test for AttachThreadInput
5 * PROGRAMMERS: Giannis Adamopoulos
6 */
7
8 #include <windows.h>
9 #include <stdio.h>
10 #include <wine/test.h>
11 #include "helper.h"
12 #include <undocuser.h>
13
14 #define DESKTOP_ALL_ACCESS 0x01ff
15
16 typedef struct {
17 DWORD tid;
18 HANDLE hThread;
19 HWND hWnd;
20 WCHAR* Desktop;
21 HANDLE StartEvent;
22 HANDLE QueueStatusEvent;
23 DWORD LastQueueStatus;
24
25 MSG_CACHE cache;
26 } THREAD_DATA;
27
28 DWORD tidMouseMove;
29 THREAD_DATA data[6];
30 HHOOK hMouseHookLL = NULL;
31 HHOOK hKbdHookLL = NULL;
32
33
34 #define EXPECT_FOREGROUND(expected) ok(GetForegroundWindow() == expected, \
35 "Expected hwnd%d at the foreground, got hwnd%d\n", \
36 get_iwnd(expected), get_iwnd(GetForegroundWindow()));
37
38 #define EXPECT_ACTIVE(expected) ok(GetActiveWindow() == expected, \
39 "Expected hwnd%d to be active, got hwnd%d\n", \
40 get_iwnd(expected), get_iwnd(GetActiveWindow()));
41
42 /*
43 * Helper functions
44 */
45
46 static int get_iwnd(HWND hWnd)
47 {
48 if(hWnd == data[0].hWnd) return 0;
49 else if(hWnd == data[1].hWnd) return 1;
50 else if(hWnd == data[2].hWnd) return 2;
51 else if(hWnd == data[3].hWnd) return 3;
52 else if(hWnd == data[4].hWnd) return 4;
53 else return -1;
54 }
55
56 LRESULT CALLBACK TestProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
57 {
58 int iwnd = get_iwnd(hWnd);
59
60 if(iwnd >= 0 && message > 0 && message < WM_APP && message != WM_TIMER)
61 record_message(&data[iwnd].cache, iwnd, message, SENT, wParam,0);
62
63 return DefWindowProc(hWnd, message, wParam, lParam);
64 }
65
66 static void FlushMessages()
67 {
68 MSG msg;
69 LRESULT res;
70
71 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
72 {
73 int iwnd = get_iwnd(msg.hwnd);
74 if( iwnd >= 0 && msg.message > 0 && msg.message < WM_APP && msg.message != WM_TIMER)
75 record_message(&data[0].cache, iwnd, msg.message, POST, msg.wParam,0);
76 DispatchMessageA( &msg );
77 }
78
79 /* Use SendMessage to sync with the other queues */
80 res = SendMessageTimeout(data[1].hWnd, WM_APP, 0,0, SMTO_NORMAL, 1000, NULL);
81 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n");
82 res = SendMessageTimeout(data[2].hWnd, WM_APP, 0,0, SMTO_NORMAL, 1000, NULL);
83 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n");
84 res = SendMessageTimeout(data[3].hWnd, WM_APP, 0,0, SMTO_NORMAL, 1000, NULL);
85 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n");
86 res = SendMessageTimeout(data[4].hWnd, WM_APP, 0,0, SMTO_NORMAL, 1000, NULL);
87 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n");
88 }
89
90 static DWORD WINAPI thread_proc(void *param)
91 {
92 THREAD_DATA* current_data = (THREAD_DATA*)param;
93 MSG msg;
94 HDESK hdesk = NULL;
95 int iwnd;
96
97 if(current_data->Desktop)
98 {
99 hdesk = CreateDesktopW(current_data->Desktop, NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
100 SetThreadDesktop(hdesk);
101 }
102
103 /* create test window */
104 current_data->hWnd = CreateWindowW(L"TestClass", L"test", WS_OVERLAPPEDWINDOW,
105 100, 100, 500, 500, NULL, NULL, 0, NULL);
106 SetEvent( current_data->StartEvent );
107
108 iwnd = get_iwnd(current_data->hWnd);
109
110 /* Use MsgWaitForMultipleObjects to let the thread process apcs */
111 while( GetMessage(&msg, 0,0,0) )
112 {
113 if(msg.message > 0 && msg.message < WM_APP && msg.message != WM_TIMER )
114 record_message(&data[iwnd].cache, iwnd, msg.message, POST, msg.wParam,0);
115 DispatchMessage(&msg);
116 }
117
118 if(hdesk)
119 CloseDesktop(hdesk);
120
121 return 0;
122 }
123
124 BOOL CreateTestThread(int i, WCHAR* Desktop)
125 {
126 DWORD ret;
127
128 data[i].StartEvent = CreateEventW(NULL, 0, 0, NULL);
129 data[i].Desktop = Desktop;
130 data[i].hThread = CreateThread(NULL, 0, thread_proc, &data[i], 0, &data[i].tid);
131 if(!data[i].hThread) goto fail;
132 ret = WaitForSingleObject(data[i].StartEvent, 1000);
133 CloseHandle(data[i].StartEvent);
134 if(ret == WAIT_TIMEOUT)
135 {
136 fail:
137 win_skip("child thread failed to initialize\n");
138 return FALSE;
139 }
140 return TRUE;
141 }
142
143 static LRESULT CALLBACK MouseLLHookProc(int nCode, WPARAM wParam, LPARAM lParam)
144 {
145 LRESULT ret;
146 MSLLHOOKSTRUCT* params = (MSLLHOOKSTRUCT*) lParam;
147
148 ret = CallNextHookEx(hMouseHookLL, nCode, wParam, lParam);
149
150 if((params->flags & LLKHF_INJECTED) == 0)
151 return TRUE;
152
153 return ret;
154 }
155
156 LRESULT CALLBACK KbdLLHookProc(int nCode, WPARAM wParam, LPARAM lParam)
157 {
158 LRESULT ret;
159 KBDLLHOOKSTRUCT* params = (KBDLLHOOKSTRUCT*) lParam;
160
161 ret = CallNextHookEx(hMouseHookLL, nCode, wParam, lParam);
162
163 if((params->flags & LLKHF_INJECTED) == 0)
164 return TRUE;
165
166 return ret;
167 }
168
169 BOOLEAN InitThreads()
170 {
171 /* Create a LL hook that drops any physical keyboard and mouse action
172 and prevent the user from interfering with the test results */
173 if(!IsDebuggerPresent())
174 {
175 hMouseHookLL = SetWindowsHookExW(WH_MOUSE_LL, MouseLLHookProc, GetModuleHandleW( NULL ), 0);
176 ok(hMouseHookLL!=NULL,"failed to set hook\n");
177 hKbdHookLL = SetWindowsHookExW(WH_KEYBOARD_LL, KbdLLHookProc, GetModuleHandleW( NULL ), 0);
178 ok(hKbdHookLL!=NULL,"failed to set hook\n");
179 }
180
181 /* create test clases */
182 RegisterSimpleClass(TestProc, L"TestClass");
183
184 memset(&data[0], 0, sizeof(data[0]));
185
186 data[0].tid = GetCurrentThreadId();
187
188 /* create test window */
189 data[0].hWnd = CreateWindowW(L"TestClass", L"test", WS_OVERLAPPEDWINDOW,
190 100, 100, 500, 500, NULL, NULL, 0, NULL);
191 if(!data[0].hWnd)
192 {
193 win_skip("CreateWindowW failed\n");
194 return FALSE;
195 }
196
197 /* create thread1(same desktop) */
198 if(!CreateTestThread(1, NULL)) return FALSE;
199
200 /* create thread2(same desktop) */
201 if(!CreateTestThread(2, NULL)) return FALSE;
202
203 /* ugly ros hack to bypass desktop crapiness */
204 if(!CreateTestThread(6, L"ThreadTestDesktop")) return FALSE;
205
206 /* create thread3(different desktop) */
207 if(!CreateTestThread(3, L"ThreadTestDesktop")) return FALSE;
208
209 /* create thread4(different desktop) */
210 if(!CreateTestThread(4, L"ThreadTestDesktop")) return FALSE;
211
212 return TRUE;
213 }
214
215 static void cleanup_attachments()
216 {
217 int i,j;
218 BOOL ret;
219
220 for(i = 0; i< 4; i++);
221 {
222 for(j = 0; j< 4; j++);
223 {
224 ret = AttachThreadInput(data[i].tid,data[j].tid, FALSE);
225 ok(ret==0, "expected AttachThreadInput to fail\n");
226 }
227 }
228 }
229
230
231
232
233 /*
234 * The actual tests
235 */
236
237 void Test_SimpleParameters()
238 {
239 BOOL ret;
240 /* FIXME: acording to msdn xp doesn't set last error but vista+ does*/
241
242 /* test wrong thread */
243 ret = AttachThreadInput( 0, 1, TRUE);
244 ok(ret==0, "expected AttachThreadInput to fail\n");
245
246 /* test same thread */
247 ret = AttachThreadInput( data[1].tid, data[1].tid, TRUE);
248 ok(ret==0, "expected AttachThreadInput to fail\n");
249
250 /* try to attach to a thread on another desktop*/
251 ret = AttachThreadInput( data[2].tid,data[3].tid, TRUE);
252 ok(ret==0, "expected AttachThreadInput to fail\n");
253 if(ret == 1 )
254 AttachThreadInput( data[2].tid,data[3].tid, FALSE);
255
256 /* test other desktop to this */
257 ret = AttachThreadInput( data[3].tid,data[2].tid, TRUE);
258 ok(ret==0, "expected AttachThreadInput to fail\n");
259 if(ret == 1 )
260 AttachThreadInput( data[3].tid,data[2].tid, FALSE);
261
262 /* attach two threads that are both in ThreadTestDesktop */
263 {
264 /* Attach thread 3 and 4 */
265 ret = AttachThreadInput( data[3].tid,data[4].tid, TRUE);
266 ok(ret==1, "expected AttachThreadInput to succeed\n");
267
268 /* cleanup previous attachment */
269 ret = AttachThreadInput( data[3].tid,data[4].tid, FALSE);
270 ok(ret==1, "expected AttachThreadInput to succeed\n");
271 }
272
273 {
274 /* Attach thread 1 and 2 */
275 ret = AttachThreadInput( data[1].tid,data[2].tid, TRUE);
276 ok(ret==1, "expected AttachThreadInput to succeed\n");
277
278 /* attach already attached*/
279 ret = AttachThreadInput( data[1].tid,data[2].tid, TRUE);
280 ok(ret==1, "expected AttachThreadInput to succeed\n");
281
282 /* attach in the opposite order */
283 ret = AttachThreadInput( data[2].tid,data[1].tid, TRUE);
284 ok(ret==1, "expected AttachThreadInput to succeed\n");
285
286 /* Now try to detach 0 from 1 */
287 ret = AttachThreadInput( data[0].tid,data[1].tid, FALSE);
288 ok(ret==0, "expected AttachThreadInput to fail\n");
289
290 /* also try to detach 3 from 2 */
291 ret = AttachThreadInput( data[3].tid,data[2].tid, FALSE);
292 ok(ret==0, "expected AttachThreadInput to fail\n");
293
294 /* cleanup previous attachment */
295 ret = AttachThreadInput( data[1].tid,data[2].tid, FALSE);
296 ok(ret==1, "expected AttachThreadInput to succeed\n");
297
298 ret = AttachThreadInput( data[2].tid,data[1].tid, FALSE);
299 ok(ret==1, "expected AttachThreadInput to succeed\n");
300
301 ret = AttachThreadInput( data[1].tid,data[2].tid, FALSE);
302 ok(ret==1, "expected AttachThreadInput to succeed\n");
303 }
304
305 /* test triple attach */
306 {
307 ret = AttachThreadInput( data[0].tid, data[1].tid, TRUE);
308 ok(ret==1, "expected AttachThreadInput to succeed\n");
309 ret = AttachThreadInput( data[1].tid, data[2].tid, TRUE);
310 ok(ret==1, "expected AttachThreadInput to succeed\n");
311
312 /* try to detach 2 and 0 */
313 ret = AttachThreadInput( data[0].tid, data[2].tid, FALSE);
314 ok(ret==0, "expected AttachThreadInput to fail\n");
315 ret = AttachThreadInput( data[2].tid, data[0].tid, FALSE);
316 ok(ret==0, "expected AttachThreadInput to fail\n");
317
318 /* try to to attach 0 to 2. it works! */
319 ret = AttachThreadInput( data[0].tid, data[2].tid, TRUE);
320 ok(ret==1, "expected AttachThreadInput to succeed\n");
321
322 ret = AttachThreadInput( data[0].tid, data[2].tid, FALSE);
323 ok(ret==1, "expected AttachThreadInput to succeed\n");
324
325 /* detach in inverse order */
326 ret = AttachThreadInput( data[0].tid, data[1].tid, FALSE);
327 ok(ret==1, "expected AttachThreadInput to succeed\n");
328 ret = AttachThreadInput( data[1].tid, data[2].tid, FALSE);
329 ok(ret==1, "expected AttachThreadInput to succeed\n");
330 }
331
332 /* test detaching in thread cleanup */
333 {
334 ret = AttachThreadInput( data[0].tid, data[1].tid, TRUE);
335 ok(ret==1, "expected AttachThreadInput to succeed\n");
336 ret = AttachThreadInput( data[0].tid, data[1].tid, TRUE);
337 ok(ret==1, "expected AttachThreadInput to succeed\n");
338 ret = AttachThreadInput( data[1].tid, data[2].tid, TRUE);
339 ok(ret==1, "expected AttachThreadInput to succeed\n");
340 ret = AttachThreadInput( data[1].tid, data[2].tid, TRUE);
341 ok(ret==1, "expected AttachThreadInput to succeed\n");
342
343 TerminateThread(data[1].hThread, 0);
344
345 ret = AttachThreadInput( data[0].tid, data[1].tid, FALSE);
346 ok(ret==0, "expected AttachThreadInput to fail\n");
347 ret = AttachThreadInput( data[1].tid, data[2].tid, FALSE);
348 ok(ret==0, "expected AttachThreadInput to fail\n");
349
350 /* Create Thread1 again */
351 CreateTestThread(1, NULL);
352 }
353
354 }
355
356 void Test_Focus() //Focus Active Capture Foreground Capture
357 {
358 BOOL ret;
359
360 /* Window 1 is in the foreground */
361 SetForegroundWindow(data[1].hWnd);
362 SetActiveWindow(data[0].hWnd);
363 FlushMessages();
364
365 EXPECT_FOREGROUND(data[1].hWnd);
366 EXPECT_ACTIVE(data[0].hWnd);
367
368 /* attach thread 0 to 1 */
369 {
370 ret = AttachThreadInput( data[0].tid, data[1].tid , TRUE);
371 ok(ret==1, "expected AttachThreadInput to succeed\n");
372 FlushMessages();
373
374 EXPECT_FOREGROUND(data[1].hWnd);
375 EXPECT_ACTIVE(data[1].hWnd);
376
377 ret = AttachThreadInput( data[0].tid, data[1].tid , FALSE);
378 ok(ret==1, "expected AttachThreadInput to succeed\n");
379 }
380
381 EXPECT_FOREGROUND(data[1].hWnd);
382 EXPECT_ACTIVE(0);
383
384 SetForegroundWindow(data[1].hWnd);
385 SetActiveWindow(data[0].hWnd);
386 FlushMessages();
387
388 EXPECT_FOREGROUND(data[1].hWnd);
389 EXPECT_ACTIVE(data[0].hWnd);
390
391 /* attach thread 1 to 0 */
392 {
393 ret = AttachThreadInput( data[1].tid, data[0].tid , TRUE);
394 ok(ret==1, "expected AttachThreadInput to succeed\n");
395 FlushMessages();
396
397 EXPECT_FOREGROUND(data[1].hWnd);
398 EXPECT_ACTIVE(data[1].hWnd);
399
400 ret = AttachThreadInput( data[1].tid, data[0].tid , FALSE);
401 ok(ret==1, "expected AttachThreadInput to succeed\n");
402 }
403
404 /* Window 0 is in the foreground */
405 SetForegroundWindow(data[0].hWnd);
406 SetActiveWindow(data[1].hWnd);
407 FlushMessages();
408
409 EXPECT_FOREGROUND(data[0].hWnd);
410 EXPECT_ACTIVE(data[0].hWnd);
411
412 /* attach thread 0 to 1 */
413 {
414 ret = AttachThreadInput( data[0].tid, data[1].tid , TRUE);
415 ok(ret==1, "expected AttachThreadInput to succeed\n");
416 FlushMessages();
417
418 EXPECT_FOREGROUND(data[0].hWnd);
419 EXPECT_ACTIVE(data[0].hWnd);
420
421 SetForegroundWindow(data[0].hWnd);
422 SetActiveWindow(data[1].hWnd);
423 FlushMessages();
424
425 EXPECT_FOREGROUND(data[1].hWnd);
426 EXPECT_ACTIVE(data[1].hWnd);
427
428 ret = AttachThreadInput( data[0].tid, data[1].tid , FALSE);
429 ok(ret==1, "expected AttachThreadInput to succeed\n");
430 }
431
432 EXPECT_FOREGROUND(data[1].hWnd);
433 EXPECT_ACTIVE(0);
434
435 SetForegroundWindow(data[0].hWnd);
436 SetActiveWindow(data[1].hWnd);
437 FlushMessages();
438
439 EXPECT_FOREGROUND(data[0].hWnd);
440 EXPECT_ACTIVE(data[0].hWnd);
441
442 /* attach thread 1 to 0 */
443 {
444 ret = AttachThreadInput( data[1].tid, data[0].tid , TRUE);
445 ok(ret==1, "expected AttachThreadInput to succeed\n");
446 FlushMessages();
447
448 EXPECT_FOREGROUND(data[0].hWnd);
449 EXPECT_ACTIVE(data[0].hWnd);
450
451 SetForegroundWindow(data[0].hWnd);
452 SetActiveWindow(data[1].hWnd);
453 FlushMessages();
454
455 EXPECT_FOREGROUND(data[1].hWnd);
456 EXPECT_ACTIVE(data[1].hWnd);
457
458 ret = AttachThreadInput( data[1].tid, data[0].tid , FALSE);
459 ok(ret==1, "expected AttachThreadInput to succeed\n");
460 }
461 }
462
463 /* test some functions like PostMessage and SendMessage that shouldn't be affected */
464 void Test_UnaffectedMessages()
465 {
466 BOOL ret;
467 LRESULT res;
468
469 EMPTY_CACHE_(&data[0].cache);
470 EMPTY_CACHE_(&data[1].cache);
471
472 /* test that messages posted before and after attachment are unaffected
473 and that we don't receive a meassage from a window we shouldn't */
474 PostMessage(data[0].hWnd, WM_USER, 0,0);
475 PostMessage(data[1].hWnd, WM_USER, 1,0);
476
477 {
478 MSG_ENTRY Thread0_chain[]={
479 {0,WM_USER, POST, 0, 0},
480 {0,WM_USER, POST, 2, 0},
481 {0,0}};
482 MSG_ENTRY Thread1_chain[]={
483 {1,WM_USER, POST, 1, 0},
484 {1,WM_USER, POST, 3, 0},
485 {0,0}};
486
487 ret = AttachThreadInput( data[1].tid, data[0].tid , TRUE);
488 ok(ret==1, "expected AttachThreadInput to succeed\n");
489
490 PostMessage(data[0].hWnd, WM_USER, 2,0);
491 PostMessage(data[1].hWnd, WM_USER, 3,0);
492
493 FlushMessages();
494 Sleep(100);
495
496 COMPARE_CACHE_(&data[0].cache, Thread0_chain);
497 COMPARE_CACHE_(&data[1].cache, Thread1_chain);
498
499 ret = AttachThreadInput( data[1].tid, data[0].tid , FALSE);
500 ok(ret==1, "expected AttachThreadInput to succeed\n");
501 }
502
503 /* test messages send to the wrong thread */
504 res = SendMessageTimeout(data[0].hWnd, WM_USER, 0,0, SMTO_NORMAL, 1000, NULL);
505 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n");
506 res = SendMessageTimeout(data[1].hWnd, WM_USER, 1,0, SMTO_NORMAL, 1000, NULL);
507 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n");
508
509 {
510 MSG_ENTRY Thread0_chain[]={
511 {0,WM_USER, SENT, 0, 0},
512 {0,WM_USER, SENT, 2, 0},
513 {0,0}};
514 MSG_ENTRY Thread1_chain[]={
515 {1,WM_USER, SENT, 1, 0},
516 {1,WM_USER, SENT, 3, 0},
517 {1,WM_MOUSEMOVE, SENT, 0, 0},
518 {0,0}};
519
520 ret = AttachThreadInput( data[2].tid, data[1].tid , TRUE);
521 ok(ret==1, "expected AttachThreadInput to succeed\n");
522
523 res = SendMessageTimeout(data[0].hWnd, WM_USER, 2,0, SMTO_NORMAL, 1000, NULL);
524 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n");
525 res = SendMessageTimeout(data[1].hWnd, WM_USER, 3,0, SMTO_NORMAL, 1000, NULL);
526 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n");
527
528 /* Try to send a fake input message */
529 res = SendMessageTimeout(data[1].hWnd, WM_MOUSEMOVE, 0,0, SMTO_NORMAL, 1000, NULL);
530 ok (res != ERROR_TIMEOUT, "SendMessageTimeout timed out\n");
531
532 COMPARE_CACHE_(&data[0].cache, Thread0_chain);
533 COMPARE_CACHE_(&data[1].cache, Thread1_chain);
534
535 ret = AttachThreadInput( data[2].tid, data[1].tid , FALSE);
536 ok(ret==1, "expected AttachThreadInput to succeed\n");
537 }
538
539 /* todo: test keyboard layout that shouldn't be affected */
540 }
541
542 void Test_SendInput()
543 {
544 MSG_ENTRY Thread1_chain[]={
545 {1,WM_KEYDOWN, POST, VK_SHIFT, 0},
546 {1,WM_KEYUP, POST, VK_SHIFT, 0},
547 {0,0}};
548 MSG_ENTRY Thread0_chain[]={
549 {0,WM_KEYDOWN, POST, VK_SHIFT, 0},
550 {0,WM_KEYUP, POST, VK_SHIFT, 0},
551 {0,0}};
552
553 BOOL ret;
554
555 /* First try sending input without attaching. It will go to the foreground */
556 {
557 SetForegroundWindow(data[1].hWnd);
558 SetActiveWindow(data[0].hWnd);
559
560 ok(GetForegroundWindow() == data[1].hWnd, "wrong foreground\n");
561 ok(GetActiveWindow() == data[0].hWnd, "wrong active\n");
562
563 FlushMessages();
564 EMPTY_CACHE_(&data[0].cache);
565 EMPTY_CACHE_(&data[1].cache);
566
567 keybd_event(VK_SHIFT, 0,0,0);
568 keybd_event(VK_SHIFT, 0,KEYEVENTF_KEYUP,0);
569 Sleep(100);
570 FlushMessages();
571
572 COMPARE_CACHE_(&data[0].cache, empty_chain);
573 COMPARE_CACHE_(&data[1].cache, Thread1_chain);
574 }
575
576 /* Next attach and send input. It will go to the same thread as before */
577 {
578 ret = AttachThreadInput( data[1].tid, data[0].tid , TRUE);
579 ok(ret==1, "expected AttachThreadInput to succeed\n");
580
581 FlushMessages();
582 EMPTY_CACHE_(&data[0].cache);
583 EMPTY_CACHE_(&data[1].cache);
584
585 keybd_event(VK_SHIFT, 0,0,0);
586 keybd_event(VK_SHIFT, 0,KEYEVENTF_KEYUP,0);
587 Sleep(100);
588 FlushMessages();
589
590 COMPARE_CACHE_(&data[0].cache, empty_chain);
591 COMPARE_CACHE_(&data[1].cache, Thread1_chain);
592 }
593
594 /* Now set foregroung and active again. Input will go to thread 0 */
595 {
596 SetForegroundWindow(data[1].hWnd);
597 SetActiveWindow(data[0].hWnd);
598
599 FlushMessages();
600 EMPTY_CACHE_(&data[0].cache);
601 EMPTY_CACHE_(&data[1].cache);
602
603 keybd_event(VK_SHIFT, 0,0,0);
604 keybd_event(VK_SHIFT, 0,KEYEVENTF_KEYUP,0);
605 Sleep(100);
606 FlushMessages();
607
608 COMPARE_CACHE_(&data[0].cache, Thread0_chain);
609 COMPARE_CACHE_(&data[1].cache, empty_chain);
610
611 ret = AttachThreadInput( data[1].tid, data[0].tid , FALSE);
612 ok(ret==1, "expected AttachThreadInput to succeed\n");
613 }
614
615 /* Attach in the opposite order and send input */
616 {
617 ret = AttachThreadInput( data[0].tid, data[1].tid , TRUE);
618 ok(ret==1, "expected AttachThreadInput to succeed\n");
619
620 FlushMessages();
621 EMPTY_CACHE_(&data[0].cache);
622 EMPTY_CACHE_(&data[1].cache);
623
624 keybd_event(VK_SHIFT, 0,0,0);
625 keybd_event(VK_SHIFT, 0,KEYEVENTF_KEYUP,0);
626 Sleep(100);
627 FlushMessages();
628
629 COMPARE_CACHE_(&data[0].cache, Thread0_chain);
630 COMPARE_CACHE_(&data[1].cache, empty_chain);
631 }
632
633 /* Now set foregroung and active again. Input will go to thread 0 */
634 {
635 SetForegroundWindow(data[1].hWnd);
636 SetActiveWindow(data[0].hWnd);
637
638 FlushMessages();
639 EMPTY_CACHE_(&data[0].cache);
640 EMPTY_CACHE_(&data[1].cache);
641
642 keybd_event(VK_SHIFT, 0,0,0);
643 keybd_event(VK_SHIFT, 0,KEYEVENTF_KEYUP,0);
644 Sleep(100);
645 FlushMessages();
646
647 COMPARE_CACHE_(&data[0].cache, Thread0_chain);
648 COMPARE_CACHE_(&data[1].cache, empty_chain);
649
650 ret = AttachThreadInput( data[0].tid, data[1].tid , FALSE);
651 ok(ret==1, "expected AttachThreadInput to succeed\n");
652 }
653 }
654
655 START_TEST(AttachThreadInput)
656 {
657 if(!InitThreads())
658 return;
659
660 win_skip("skip Test_SimpleParameters that crash ros\n");
661 //Test_SimpleParameters();
662 //cleanup_attachments();
663 Test_Focus();
664 cleanup_attachments();
665 Test_UnaffectedMessages();
666 cleanup_attachments();
667 Test_SendInput();
668 cleanup_attachments();
669
670 if(hMouseHookLL)
671 UnhookWindowsHookEx(hMouseHookLL);
672 if(hKbdHookLL)
673 UnhookWindowsHookEx(hKbdHookLL);
674
675 /* Stop all threads and exit gratefully */
676 PostThreadMessage(data[1].tid, WM_QUIT,0,0);
677 PostThreadMessage(data[2].tid, WM_QUIT,0,0);
678 PostThreadMessage(data[3].tid, WM_QUIT,0,0);
679 PostThreadMessage(data[4].tid, WM_QUIT,0,0);
680 }
681