Sync with trunk r63637.
[reactos.git] / win32ss / user / ntuser / focus.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Focus functions
5 * FILE: subsystems/win32/win32k/ntuser/focus.c
6 * PROGRAMER: ReactOS Team
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserFocus);
11
12 PUSER_MESSAGE_QUEUE gpqForeground = NULL;
13 PUSER_MESSAGE_QUEUE gpqForegroundPrev = NULL;
14 PTHREADINFO gptiForeground = NULL;
15 PPROCESSINFO gppiLockSFW = NULL;
16 ULONG guSFWLockCount = 0; // Rule #8, No menus are active. So should be zero.
17 PTHREADINFO ptiLastInput = NULL;
18
19 /*
20 Check locking of a process or one or more menus are active.
21 */
22 BOOL FASTCALL
23 IsFGLocked(VOID)
24 {
25 return (gppiLockSFW || guSFWLockCount);
26 }
27
28 HWND FASTCALL
29 IntGetCaptureWindow(VOID)
30 {
31 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
32 return ( ForegroundQueue ? (ForegroundQueue->spwndCapture ? UserHMGetHandle(ForegroundQueue->spwndCapture) : 0) : 0);
33 }
34
35 HWND FASTCALL
36 IntGetThreadFocusWindow(VOID)
37 {
38 PTHREADINFO pti;
39 PUSER_MESSAGE_QUEUE ThreadQueue;
40
41 pti = PsGetCurrentThreadWin32Thread();
42 ThreadQueue = pti->MessageQueue;
43 if (!ThreadQueue)
44 return NULL;
45 return ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0;
46 }
47
48 BOOL FASTCALL
49 co_IntSendDeactivateMessages(HWND hWndPrev, HWND hWnd)
50 {
51 USER_REFERENCE_ENTRY RefPrev;
52 PWND WndPrev;
53 BOOL Ret = TRUE;
54
55 if (hWndPrev && (WndPrev = ValidateHwndNoErr(hWndPrev)))
56 {
57 UserRefObjectCo(WndPrev, &RefPrev);
58
59 if (co_IntSendMessageNoWait(hWndPrev, WM_NCACTIVATE, FALSE, 0)) //(LPARAM)hWnd))
60 {
61 co_IntSendMessageNoWait(hWndPrev, WM_ACTIVATE,
62 MAKEWPARAM(WA_INACTIVE, WndPrev->style & WS_MINIMIZE),
63 (LPARAM)hWnd);
64
65 if (WndPrev)
66 WndPrev->state &= ~WNDS_ACTIVEFRAME;
67 }
68 else
69 {
70 ERR("Application is keeping itself Active to prevent the change!\n");
71 Ret = FALSE;
72 }
73
74 UserDerefObjectCo(WndPrev);
75 }
76 return Ret;
77 }
78
79 BOOL FASTCALL
80 co_IntMakeWindowActive(PWND Window)
81 {
82 PWND spwndOwner;
83 if (VerifyWnd(Window))
84 { // Set last active for window and it's owner.
85 spwndOwner = Window;
86 while (spwndOwner->spwndOwner)
87 {
88 spwndOwner = spwndOwner->spwndOwner;
89 }
90 spwndOwner->spwndLastActive = Window;
91 return TRUE;
92 }
93 ERR("MakeWindowActive Failed!\n");
94 return FALSE;
95 }
96
97 BOOL FASTCALL
98 co_IntSendActivateMessages(PWND WindowPrev, PWND Window, BOOL MouseActivate, BOOL Async)
99 {
100 USER_REFERENCE_ENTRY Ref, RefPrev;
101 HANDLE OldTID, NewTID;
102 PTHREADINFO pti, ptiOld, ptiNew;
103 BOOL InAAPM = FALSE;
104
105 //ERR("SendActivateMessages\n");
106
107 pti = PsGetCurrentThreadWin32Thread();
108
109 if (Window)
110 {
111 UserRefObjectCo(Window, &Ref);
112
113 if (WindowPrev) UserRefObjectCo(WindowPrev, &RefPrev);
114
115 /* Send palette messages */
116 if (gpsi->PUSIFlags & PUSIF_PALETTEDISPLAY &&
117 //co_IntPostOrSendMessage(UserHMGetHandle(Window), WM_QUERYNEWPALETTE, 0, 0))
118 co_IntSendMessage(UserHMGetHandle(Window), WM_QUERYNEWPALETTE, 0, 0))
119 {
120 UserSendNotifyMessage( HWND_BROADCAST,
121 WM_PALETTEISCHANGING,
122 (WPARAM)UserHMGetHandle(Window),
123 0);
124 }
125 //// Fixes CORE-6434.
126 if (!(Window->style & WS_CHILD))
127 {
128 PWND pwndTemp = co_GetDesktopWindow(Window)->spwndChild;
129
130 while (pwndTemp && !(pwndTemp->style & WS_VISIBLE)) pwndTemp = pwndTemp->spwndNext;
131
132 if (Window != pwndTemp || (WindowPrev && !IntIsWindowVisible(WindowPrev)))
133 {
134 if (!Async || pti->MessageQueue == gpqForeground)
135 {
136 UINT flags = SWP_NOSIZE | SWP_NOMOVE;
137 if (Window == pwndTemp) flags |= SWP_NOACTIVATE;
138 //ERR("co_IntSendActivateMessages SetWindowPos! Async %d pti Q == FGQ %d\n",Async,pti->MessageQueue == gpqForeground);
139 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, flags);
140 }
141 }
142 }
143 ////
144 //// CORE-1161 and CORE-6651
145 if (Window->spwndPrev)
146 {
147 HWND *phwndTopLevel, *phwndCurrent;
148 PWND pwndCurrent, pwndDesktop;
149
150 pwndDesktop = UserGetDesktopWindow();
151 if (Window->spwndParent == pwndDesktop )
152 {
153 phwndTopLevel = IntWinListChildren(pwndDesktop);
154 phwndCurrent = phwndTopLevel;
155 while(*phwndCurrent)
156 {
157 pwndCurrent = UserGetWindowObject(*phwndCurrent);
158
159 if (pwndCurrent && pwndCurrent->spwndOwner == Window )
160 {
161 co_WinPosSetWindowPos(pwndCurrent, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
162 }
163 phwndCurrent++;
164 }
165 ExFreePool(phwndTopLevel);
166 }
167 }
168 }
169 ////
170 OldTID = WindowPrev ? IntGetWndThreadId(WindowPrev) : NULL;
171 NewTID = Window ? IntGetWndThreadId(Window) : NULL;
172 ptiOld = WindowPrev ? WindowPrev->head.pti : NULL;
173 ptiNew = Window ? Window->head.pti : NULL;
174
175 //ERR("SendActivateMessage Old -> %x, New -> %x\n", OldTID, NewTID);
176
177 if (!(pti->TIF_flags & TIF_INACTIVATEAPPMSG) &&
178 (!WindowPrev || OldTID != NewTID) )
179 {
180 PWND cWindow;
181 HWND *List, *phWnd;
182
183 List = IntWinListChildren(UserGetDesktopWindow());
184 if ( List )
185 {
186 if ( OldTID )
187 {
188 ptiOld->TIF_flags |= TIF_INACTIVATEAPPMSG;
189 // Note: Do not set pci flags, this does crash!
190 for (phWnd = List; *phWnd; ++phWnd)
191 {
192 cWindow = ValidateHwndNoErr(*phWnd);
193 if (cWindow && cWindow->head.pti == ptiOld)
194 { // FALSE if the window is being deactivated,
195 // ThreadId that owns the window being activated.
196 //ERR("SendActivateMessage Old\n");
197 co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, FALSE, (LPARAM)NewTID);
198 }
199 }
200 ptiOld->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
201 }
202 if ( NewTID )
203 { //// Prevents a resource crash due to reentrance!
204 InAAPM = TRUE;
205 pti->TIF_flags |= TIF_INACTIVATEAPPMSG;
206 ////
207 for (phWnd = List; *phWnd; ++phWnd)
208 {
209 cWindow = ValidateHwndNoErr(*phWnd);
210 if (cWindow && cWindow->head.pti == ptiNew)
211 { // TRUE if the window is being activated,
212 // ThreadId that owns the window being deactivated.
213 //ERR("SendActivateMessage New\n");
214 co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, TRUE, (LPARAM)OldTID);
215 }
216 }
217 }
218 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
219 }
220 }
221
222 if (Window)
223 {
224 if (WindowPrev)
225 UserDerefObjectCo(WindowPrev); // Now allow the previous window to die.
226
227 if (Window->state & WNDS_ACTIVEFRAME)
228 { // If already active frame do not allow NCPaint.
229 //ERR("SendActivateMessage Is Active Frame!\n");
230 Window->state |= WNDS_NONCPAINT;
231 }
232
233 if (Window->style & WS_MINIMIZE)
234 {
235 TRACE("Widow was minimized\n");
236 }
237
238 co_IntMakeWindowActive(Window);
239
240 co_IntSendMessageNoWait( UserHMGetHandle(Window),
241 WM_NCACTIVATE,
242 (WPARAM)(Window == (gpqForeground ? gpqForeground->spwndActive : NULL)),
243 0); //(LPARAM)hWndPrev);
244
245 co_IntSendMessageNoWait( UserHMGetHandle(Window),
246 WM_ACTIVATE,
247 MAKEWPARAM(MouseActivate ? WA_CLICKACTIVE : WA_ACTIVE, Window->style & WS_MINIMIZE),
248 (LPARAM)(WindowPrev ? UserHMGetHandle(WindowPrev) : 0));
249
250 if (Window->spwndParent == UserGetDesktopWindow() &&
251 Window->spwndOwner == NULL &&
252 (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
253 (Window->ExStyle & WS_EX_APPWINDOW)))
254 {
255 // FIXME lParam; The value is TRUE if the window is in full-screen mode, or FALSE otherwise.
256 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED, (WPARAM) UserHMGetHandle(Window), FALSE);
257 }
258 else
259 {
260 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED, 0, FALSE);
261 }
262
263 Window->state &= ~WNDS_NONCPAINT;
264
265 UserDerefObjectCo(Window);
266 }
267
268 OldTID = WindowPrev ? IntGetWndThreadId(WindowPrev) : NULL;
269 NewTID = Window ? IntGetWndThreadId(Window) : NULL;
270 ptiOld = WindowPrev ? WindowPrev->head.pti : NULL;
271 ptiNew = Window ? Window->head.pti : NULL;
272
273 //ERR("SendActivateMessage WindowPrev -> %x, Old -> %x, New -> %x\n", WindowPrev, OldTID, NewTID);
274
275 if (!(pti->TIF_flags & TIF_INACTIVATEAPPMSG) &&
276 (OldTID != NewTID) )
277 {
278 PWND cWindow;
279 HWND *List, *phWnd;
280
281 List = IntWinListChildren(UserGetDesktopWindow());
282 if ( List )
283 {
284 if ( OldTID )
285 {
286 ptiOld->TIF_flags |= TIF_INACTIVATEAPPMSG;
287 // Note: Do not set pci flags, this does crash!
288 for (phWnd = List; *phWnd; ++phWnd)
289 {
290 cWindow = ValidateHwndNoErr(*phWnd);
291 if (cWindow && cWindow->head.pti == ptiOld)
292 { // FALSE if the window is being deactivated,
293 // ThreadId that owns the window being activated.
294 co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, FALSE, (LPARAM)NewTID);
295 }
296 }
297 ptiOld->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
298 }
299 if ( NewTID )
300 { //// Prevents a resource crash due to reentrance!
301 InAAPM = TRUE;
302 pti->TIF_flags |= TIF_INACTIVATEAPPMSG;
303 ////
304 for (phWnd = List; *phWnd; ++phWnd)
305 {
306 cWindow = ValidateHwndNoErr(*phWnd);
307 if (cWindow && cWindow->head.pti == ptiNew)
308 { // TRUE if the window is being activated,
309 // ThreadId that owns the window being deactivated.
310 co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, TRUE, (LPARAM)OldTID);
311 }
312 }
313 }
314 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
315 }
316 }
317 return InAAPM;
318 }
319
320 VOID FASTCALL
321 IntSendFocusMessages( PTHREADINFO pti, PWND pWnd)
322 {
323 PWND pWndPrev;
324 PUSER_MESSAGE_QUEUE ThreadQueue = pti->MessageQueue; // Queue can change...
325
326 ThreadQueue->QF_flags &= ~QF_FOCUSNULLSINCEACTIVE;
327 if (!pWnd && ThreadQueue->spwndActive)
328 {
329 ThreadQueue->QF_flags |= QF_FOCUSNULLSINCEACTIVE;
330 }
331
332 pWndPrev = ThreadQueue->spwndFocus;
333
334 /* check if the specified window can be set in the input data of a given queue */
335 if (!pWnd || ThreadQueue == pWnd->head.pti->MessageQueue)
336 /* set the current thread focus window */
337 ThreadQueue->spwndFocus = pWnd;
338
339 if (pWnd)
340 {
341 if (pWndPrev)
342 {
343 //co_IntPostOrSendMessage(UserHMGetHandle(pWndPrev), WM_KILLFOCUS, (WPARAM)UserHMGetHandle(pWnd), 0);
344 co_IntSendMessage(UserHMGetHandle(pWndPrev), WM_KILLFOCUS, (WPARAM)UserHMGetHandle(pWnd), 0);
345 }
346 if (ThreadQueue->spwndFocus == pWnd)
347 {
348 IntNotifyWinEvent(EVENT_OBJECT_FOCUS, pWnd, OBJID_CLIENT, CHILDID_SELF, 0);
349 //co_IntPostOrSendMessage(UserHMGetHandle(pWnd), WM_SETFOCUS, (WPARAM)(pWndPrev ? UserHMGetHandle(pWndPrev) : NULL), 0);
350 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SETFOCUS, (WPARAM)(pWndPrev ? UserHMGetHandle(pWndPrev) : NULL), 0);
351 }
352 }
353 else
354 {
355 if (pWndPrev)
356 {
357 IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0);
358 //co_IntPostOrSendMessage(UserHMGetHandle(pWndPrev), WM_KILLFOCUS, 0, 0);
359 co_IntSendMessage(UserHMGetHandle(pWndPrev), WM_KILLFOCUS, 0, 0);
360 }
361 }
362 }
363
364 VOID FASTCALL
365 FindRemoveAsyncMsg(PWND Wnd, WPARAM wParam)
366 {
367 PTHREADINFO pti;
368 PUSER_SENT_MESSAGE Message;
369 PLIST_ENTRY Entry;
370
371 if (!Wnd) return;
372
373 pti = Wnd->head.pti;
374
375 if (!IsListEmpty(&pti->SentMessagesListHead))
376 {
377 // Scan sent queue messages to see if we received async messages.
378 Entry = pti->SentMessagesListHead.Flink;
379 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
380 do
381 {
382 if (IsListEmpty(Entry)) return;
383 if (!Message) return;
384 Entry = Message->ListEntry.Flink;
385
386 if (Message->Msg.message == WM_ASYNC_SETACTIVEWINDOW &&
387 Message->Msg.hwnd == UserHMGetHandle(Wnd) &&
388 Message->Msg.wParam == wParam )
389 {
390 ERR("ASYNC SAW: Found one in the Sent Msg Queue! %p Activate/Deactivate %d\n", Message->Msg.hwnd,!!wParam);
391 RemoveEntryList(&Message->ListEntry); // Purge the entry.
392 ExFreePoolWithTag(Message, TAG_USRMSG);
393 }
394 Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
395 }
396 while (Entry != &pti->SentMessagesListHead);
397 }
398 }
399
400 BOOL FASTCALL
401 ToggleFGActivate(PTHREADINFO pti)
402 {
403 BOOL Ret;
404 PPROCESSINFO ppi = pti->ppi;
405
406 Ret = !!(pti->TIF_flags & TIF_ALLOWFOREGROUNDACTIVATE);
407 if (Ret)
408 {
409 pti->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE;
410 }
411 else
412 Ret = !!(ppi->W32PF_flags & W32PF_ALLOWFOREGROUNDACTIVATE);
413
414 if (Ret)
415 ppi->W32PF_flags &= ~W32PF_ALLOWFOREGROUNDACTIVATE;
416 //ERR("ToggleFGActivate is %d\n",Ret);
417 return Ret;
418 }
419
420 BOOL FASTCALL
421 IsAllowedFGActive(PTHREADINFO pti, PWND Wnd)
422 {
423 // Not allowed if one or more,,
424 if (!ToggleFGActivate(pti) || // bits not set,
425 pti->rpdesk != gpdeskInputDesktop || // not current Desktop,
426 pti->MessageQueue == gpqForeground || // if already the queue foreground,
427 IsFGLocked() || // foreground is locked,
428 Wnd->ExStyle & WS_EX_NOACTIVATE ) // or,,, does not become the foreground window when the user clicks it.
429 {
430 return FALSE;
431 }
432 //ERR("IsAllowedFGActive is TRUE\n");
433 return TRUE;
434 }
435
436 /*
437 Can the system force foreground from one or more conditions.
438 */
439 BOOL FASTCALL
440 CanForceFG(PPROCESSINFO ppi)
441 {
442 if (!ptiLastInput ||
443 ptiLastInput->ppi == ppi ||
444 !gptiForeground ||
445 gptiForeground->ppi == ppi ||
446 ppi->W32PF_flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_SETFOREGROUNDALLOWED) ||
447 gppiInputProvider == ppi ||
448 !gpqForeground
449 ) return TRUE;
450 //ERR("CanForceFG is FALSE\n");
451 return FALSE;
452 }
453
454 /*
455 MSDN:
456 The system restricts which processes can set the foreground window. A process
457 can set the foreground window only if one of the following conditions is true:
458
459 * The process is the foreground process.
460 * The process was started by the foreground process.
461 * The process received the last input event.
462 * There is no foreground process.
463 * The foreground process is being debugged.
464 * The foreground is not locked (see LockSetForegroundWindow).
465 * The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
466 * No menus are active.
467 */
468 static
469 BOOL FASTCALL
470 co_IntSetForegroundAndFocusWindow(
471 _In_ PWND Wnd,
472 _In_ BOOL MouseActivate)
473 {
474 HWND hWnd = Wnd ? UserHMGetHandle(Wnd) : NULL;
475 HWND hWndPrev = NULL;
476 PWND pWndPrev = NULL;
477 PUSER_MESSAGE_QUEUE PrevForegroundQueue;
478 PTHREADINFO pti;
479 BOOL fgRet = FALSE, Ret = FALSE;
480
481 if (Wnd) ASSERT_REFS_CO(Wnd);
482
483 //ERR("SetForegroundAndFocusWindow(%x, %s)\n", hWnd, (MouseActivate ? "TRUE" : "FALSE"));
484
485 PrevForegroundQueue = IntGetFocusMessageQueue(); // Use this active desktop.
486 pti = PsGetCurrentThreadWin32Thread();
487
488 if (PrevForegroundQueue)
489 { // Same Window Q as foreground just do active.
490 if (Wnd && Wnd->head.pti->MessageQueue == PrevForegroundQueue)
491 {
492 //ERR("Same Window Q as foreground just do active.\n");
493 if (pti->MessageQueue == PrevForegroundQueue)
494 { // Same WQ and TQ go active.
495 //ERR("Same WQ and TQ go active.\n");
496 Ret = co_IntSetActiveWindow(Wnd, MouseActivate, TRUE, FALSE);
497 }
498 else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd)
499 { // Same WQ and it is active.
500 //ERR("Same WQ and it is active.\n");
501 Ret = TRUE;
502 }
503 else
504 { // Same WQ as FG but not the same TQ send active.
505 //ERR("Same WQ as FG but not the same TQ send active.\n");
506 co_IntSendMessage(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate );
507 Ret = TRUE;
508 }
509 return Ret;
510 }
511
512 hWndPrev = PrevForegroundQueue->spwndActive ? UserHMGetHandle(PrevForegroundQueue->spwndActive) : 0;
513 pWndPrev = PrevForegroundQueue->spwndActive;
514 }
515
516 if ( (( !IsFGLocked() || pti->ppi == gppiInputProvider ) &&
517 ( CanForceFG(pti->ppi) || pti->TIF_flags & (TIF_SYSTEMTHREAD|TIF_CSRSSTHREAD|TIF_ALLOWFOREGROUNDACTIVATE) )) ||
518 pti->ppi == ppiScrnSaver
519 )
520 {
521
522 //ToggleFGActivate(pti); // win.c line 2662 fail
523 if (Wnd)
524 {
525 IntSetFocusMessageQueue(Wnd->head.pti->MessageQueue);
526 gptiForeground = Wnd->head.pti;
527 //ERR("Set Foreground pti 0x%p Q 0x%p hWnd 0x%p\n",Wnd->head.pti, Wnd->head.pti->MessageQueue,Wnd->head.h);
528 }
529 else
530 {
531 IntSetFocusMessageQueue(NULL);
532 gptiForeground = NULL;
533 //ERR("Set Foreground pti 0x0 Q 0x0 hWnd 0x0\n");
534 }
535 /*
536 Henri Verbeet,
537 What happens is that we get the WM_WINE_SETACTIVEWINDOW message sent by the
538 other thread after we already changed the foreground window back to our own
539 window.
540 */
541 //ERR("SFAFW: 1\n");
542 FindRemoveAsyncMsg(Wnd, 0); // Do this to fix test_SFW todos!
543
544 fgRet = TRUE;
545 }
546
547 // Fix FG Bounce with regedit.
548 if (hWndPrev != hWnd )
549 {
550 if (PrevForegroundQueue &&
551 fgRet &&
552 PrevForegroundQueue->spwndActive)
553 {
554 //ERR("SFGW: Send NULL to 0x%x\n",hWndPrev);
555 if (pti->MessageQueue == PrevForegroundQueue)
556 {
557 //ERR("SFGW: TI same as Prev TI\n");
558 co_IntSetActiveWindow(NULL, FALSE, TRUE, FALSE);
559 }
560 else if (pWndPrev)
561 {
562 //ERR("SFGW Deactivate: TI not same as Prev TI\n");
563 // No real reason to wait here.
564 co_IntSendMessageNoWait(hWndPrev, WM_ASYNC_SETACTIVEWINDOW, 0, 0 );
565 }
566 }
567 }
568
569 if (!Wnd) return FALSE; // Always return false.
570
571 if (pti->MessageQueue == Wnd->head.pti->MessageQueue)
572 {
573 //ERR("Same PQ and WQ go active.\n");
574 Ret = co_IntSetActiveWindow(Wnd, MouseActivate, TRUE, FALSE);
575 }
576 else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd)
577 {
578 //ERR("Same Active and Wnd.\n");
579 Ret = TRUE;
580 }
581 else
582 {
583 //ERR("Activate Not same PQ and WQ and Wnd.\n");
584 co_IntSendMessageNoWait(hWnd, WM_ASYNC_SETACTIVEWINDOW, (WPARAM)Wnd, (LPARAM)MouseActivate );
585 Ret = TRUE;
586 }
587 return Ret && fgRet;
588 }
589
590 /*
591 Revision 7888, activate modal dialog when clicking on a disabled window.
592 */
593 HWND FASTCALL
594 IntFindChildWindowToOwner(PWND Root, PWND Owner)
595 {
596 HWND Ret;
597 PWND Child, OwnerWnd;
598
599 for(Child = Root->spwndChild; Child; Child = Child->spwndNext)
600 {
601 OwnerWnd = Child->spwndOwner;
602 if(!OwnerWnd)
603 continue;
604
605 if(OwnerWnd == Owner)
606 {
607 Ret = Child->head.h;
608 return Ret;
609 }
610 }
611 return NULL;
612 }
613
614 BOOL FASTCALL
615 co_IntMouseActivateWindow(PWND Wnd)
616 {
617 HWND Top;
618 USER_REFERENCE_ENTRY Ref;
619 ASSERT_REFS_CO(Wnd);
620
621 if (Wnd->style & WS_DISABLED)
622 {
623 BOOL Ret;
624 PWND TopWnd;
625 PWND DesktopWindow = UserGetDesktopWindow();
626 if (DesktopWindow)
627 {
628 ERR("Window Diabled\n");
629 Top = IntFindChildWindowToOwner(DesktopWindow, Wnd);
630 if ((TopWnd = ValidateHwndNoErr(Top)))
631 {
632 UserRefObjectCo(TopWnd, &Ref);
633 Ret = co_IntMouseActivateWindow(TopWnd);
634 UserDerefObjectCo(TopWnd);
635
636 return Ret;
637 }
638 }
639 return FALSE;
640 }
641 ERR("Mouse Active\n");
642 co_IntSetForegroundAndFocusWindow(Wnd, TRUE);
643 return TRUE;
644 }
645
646 BOOL FASTCALL
647 co_IntSetActiveWindow(PWND Wnd OPTIONAL, BOOL bMouse, BOOL bFocus, BOOL Async)
648 {
649 PTHREADINFO pti;
650 PUSER_MESSAGE_QUEUE ThreadQueue;
651 PWND pWndChg, WndPrev; // State changes.
652 HWND hWndPrev;
653 HWND hWnd = 0;
654 BOOL InAAPM;
655 CBTACTIVATESTRUCT cbt;
656 //ERR("co_IntSetActiveWindow 1\n");
657 if (Wnd)
658 {
659 ASSERT_REFS_CO(Wnd);
660 hWnd = UserHMGetHandle(Wnd);
661 if ((Wnd->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
662 if (Wnd == UserGetDesktopWindow()) return FALSE;
663 //ERR("co_IntSetActiveWindow 1a hWnd 0x%p\n",hWnd);
664 }
665
666 //ERR("co_IntSetActiveWindow 2\n");
667 pti = PsGetCurrentThreadWin32Thread();
668 ThreadQueue = pti->MessageQueue;
669 ASSERT(ThreadQueue != 0);
670
671 hWndPrev = ThreadQueue->spwndActive ? UserHMGetHandle(ThreadQueue->spwndActive) : NULL;
672
673 pWndChg = ThreadQueue->spwndActive; // Keep to notify of a preemptive switch.
674
675 while (Wnd)
676 {
677 BOOL Ret, DoFG, AllowFG;
678
679 if (Wnd->state & WNDS_BEINGACTIVATED) return TRUE;
680
681 if (ThreadQueue == Wnd->head.pti->MessageQueue)
682 {
683 if (IsAllowedFGActive(pti, Wnd))
684 {
685 DoFG = TRUE;
686 }
687 else
688 {
689 //ERR("co_IntSetActiveWindow 3 Go Out!\n");
690 break;
691 }
692 AllowFG = !pti->cVisWindows; // Nothing is visable.
693 //ERR("co_IntSetActiveWindow 3a DoFG = %d AllowFG = %d\n",DoFG,AllowFG);
694 }
695 else //if (ThreadQueue != Wnd->head.pti->MessageQueue)
696 {
697 //PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue();
698 // Rule 1 & 4, We are foreground so set this FG window or NULL foreground....
699 //if (!ForegroundQueue || ForegroundQueue == ThreadQueue)
700 if (!gpqForeground || gpqForeground == ThreadQueue)
701 {
702 DoFG = TRUE;
703 }
704 else
705 DoFG = FALSE;
706 if (DoFG)
707 {
708 if (pti->TIF_flags & TIF_ALLOWFOREGROUNDACTIVATE || pti->cVisWindows)
709 AllowFG = TRUE;
710 else
711 AllowFG = FALSE;
712 }
713 else
714 AllowFG = FALSE;
715 //ERR("co_IntSetActiveWindow 3b DoFG = %d AllowFG = %d\n",DoFG,AllowFG);
716 }
717 Ret = FALSE;
718 if (DoFG)
719 {
720 pti->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
721 //ERR("co_IntSetActiveWindow 3c FG set\n");
722 Ret = co_IntSetForegroundAndFocusWindow(Wnd, bMouse);
723 if (AllowFG)
724 {
725 pti->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE;
726 }
727 else
728 {
729 pti->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE;
730 }
731 }
732 return Ret;
733 }
734
735 /* Call CBT hook chain */
736 cbt.fMouse = bMouse;
737 cbt.hWndActive = hWndPrev;
738 if (co_HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hWnd, (LPARAM)&cbt))
739 {
740 ERR("SetActiveWindow: WH_CBT Call Hook return!\n");
741 return FALSE;
742 }
743
744 if ( ThreadQueue->spwndActive && ThreadQueue->spwndActive->state & WNDS_DESTROYED )
745 ThreadQueue->spwndActive = NULL;
746 else
747 ThreadQueue->spwndActivePrev = ThreadQueue->spwndActive;
748
749 WndPrev = ThreadQueue->spwndActive; // Keep to save changing active.
750
751 if (WndPrev)
752 {
753 if (ThreadQueue == gpqForeground) gpqForegroundPrev = ThreadQueue;
754 if (!co_IntSendDeactivateMessages(UserHMGetHandle(WndPrev), hWnd)) return FALSE;
755 }
756
757 WndPrev = ThreadQueue->spwndActive; // Again keep to save changing active.
758
759 // While in calling message proc or hook:
760 // Fail if a preemptive switch was made, current active not made previous,
761 // focus window is dead or no longer the same thread queue.
762 if ( ThreadQueue->spwndActivePrev != ThreadQueue->spwndActive ||
763 pWndChg != WndPrev ||
764 (Wnd && !VerifyWnd(Wnd)) ||
765 ThreadQueue != pti->MessageQueue )
766 {
767 ERR("SetActiveWindow: Summery ERROR, active state changed!\n");
768 return FALSE;
769 }
770
771 if (!WndPrev) ThreadQueue->QF_flags &= ~QF_FOCUSNULLSINCEACTIVE;
772
773 if (Wnd) Wnd->state |= WNDS_BEINGACTIVATED;
774
775 IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
776 //// Breaks Atl-Esc/Tab via User32.
777 ////FindRemoveAsyncMsg(Wnd,(WPARAM)Wnd); // Clear out activate ASYNC messages.
778
779 /* check if the specified window can be set in the input data of a given queue */
780 if ( !Wnd || ThreadQueue == Wnd->head.pti->MessageQueue)
781 {
782 /* set the current thread active window */
783 ThreadQueue->spwndActive = Wnd;
784 }
785
786 WndPrev = VerifyWnd(ThreadQueue->spwndActivePrev); // Now should be set but verify it again.
787
788 InAAPM = co_IntSendActivateMessages(WndPrev, Wnd, bMouse, Async);
789
790 /* now change focus if necessary */
791 //// Fixes CORE-6452 allows setting focus on window.
792 if (bFocus && !(ThreadQueue->QF_flags & QF_FOCUSNULLSINCEACTIVE))
793 {
794 /* Do not change focus if the window is no longer active */
795 if (pti->MessageQueue->spwndActive != IntGetNonChildAncestor(pti->MessageQueue->spwndFocus))
796 {
797 PWND pWndSend = pti->MessageQueue->spwndActive;
798 // Clear focus if the active window is minimized.
799 if (pWndSend && pti->MessageQueue->spwndActive->style & WS_MINIMIZE) pWndSend = NULL;
800 // Send focus messages and if so, set the focus.
801 IntSendFocusMessages( pti, pWndSend);
802 }
803 }
804 ////
805 if (InAAPM)
806 {
807 pti->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
808 }
809
810 // FIXME: Used in the menu loop!!!
811 //ThreadQueue->QF_flags |= QF_ACTIVATIONCHANGE;
812
813 //ERR("co_IntSetActiveWindow Exit\n");
814 if (Wnd) Wnd->state &= ~WNDS_BEINGACTIVATED;
815 return (ThreadQueue->spwndActive == Wnd);
816 }
817
818 BOOL FASTCALL
819 UserSetActiveWindow(PWND Wnd)
820 {
821 if (Wnd) // Must have a window!
822 {
823 if ((Wnd->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
824
825 return co_IntSetActiveWindow(Wnd, FALSE, TRUE, FALSE);
826 }
827 /*
828 Yes your eye are not deceiving you~!
829
830 First part of wines Win.c test_SetActiveWindow:
831
832 flush_events( TRUE );
833 ShowWindow(hwnd, SW_HIDE);
834 SetFocus(0);
835 SetActiveWindow(0);
836 check_wnd_state(0, 0, 0, 0); <-- This should pass if ShowWindow does it's job!!! As of 10/28/2012 it does!
837
838 */
839 return FALSE;
840 }
841
842 HWND FASTCALL
843 co_UserSetFocus(PWND Window)
844 {
845 HWND hWndPrev = 0;
846 PWND pwndTop;
847 PTHREADINFO pti;
848 PUSER_MESSAGE_QUEUE ThreadQueue;
849
850 if (Window)
851 ASSERT_REFS_CO(Window);
852
853 pti = PsGetCurrentThreadWin32Thread();
854 ThreadQueue = pti->MessageQueue;
855 ASSERT(ThreadQueue != 0);
856
857 TRACE("Enter SetFocus hWnd 0x%p pti 0x%p\n",Window ? UserHMGetHandle(Window) : 0, pti );
858
859 hWndPrev = ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0;
860
861 if (Window != 0)
862 {
863 if (hWndPrev == UserHMGetHandle(Window))
864 {
865 return hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0; /* Nothing to do */
866 }
867
868 if (Window->head.pti->MessageQueue != ThreadQueue)
869 {
870 ERR("SetFocus Must have the same Q!\n");
871 return 0;
872 }
873
874 /* Check if we can set the focus to this window */
875 //// Fixes wine win test_SetParent both "todo" line 3710 and 3720...
876 for (pwndTop = Window; pwndTop; pwndTop = pwndTop->spwndParent)
877 {
878 if (pwndTop->style & (WS_MINIMIZED|WS_DISABLED)) return 0;
879 if ((pwndTop->style & (WS_POPUP|WS_CHILD)) != WS_CHILD) break;
880 }
881 ////
882 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)Window->head.h, (LPARAM)hWndPrev))
883 {
884 ERR("SetFocus 1 WH_CBT Call Hook return!\n");
885 return 0;
886 }
887
888 /* Activate pwndTop if needed. */
889 if (pwndTop != ThreadQueue->spwndActive)
890 {
891 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue(); // Keep it based on desktop.
892 if (ThreadQueue != ForegroundQueue && IsAllowedFGActive(pti, pwndTop)) // Rule 2 & 3.
893 {
894 //ERR("SetFocus: Set Foreground!\n");
895 if (!(pwndTop->style & WS_VISIBLE))
896 {
897 pti->ppi->W32PF_flags |= W32PF_ALLOWFOREGROUNDACTIVATE;
898 }
899 if (!co_IntSetForegroundAndFocusWindow(pwndTop, FALSE))
900 {
901 ERR("SetFocus: Set Foreground and Focus Failed!\n");
902 return 0;
903 }
904 }
905
906 /* Set Active when it is needed. */
907 if (pwndTop != ThreadQueue->spwndActive)
908 {
909 //ERR("SetFocus: Set Active!\n");
910 if (!co_IntSetActiveWindow(pwndTop, FALSE, FALSE, FALSE))
911 {
912 ERR("SetFocus: Set Active Failed!\n");
913 return 0;
914 }
915 }
916
917 /* Abort if window destroyed */
918 if (Window->state2 & WNDS2_INDESTROY) return 0;
919 /* Do not change focus if the window is no longer active */
920 if (pwndTop != ThreadQueue->spwndActive)
921 {
922 ERR("SetFocus: Top window did not go active!\n");
923 return 0;
924 }
925 }
926
927 // Check again! SetActiveWindow could have set the focus via WM_ACTIVATE.
928 hWndPrev = ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0;
929
930 IntSendFocusMessages( pti, Window);
931
932 TRACE("Focus: %p -> %p\n", hWndPrev, Window->head.h);
933 }
934 else /* NULL hwnd passed in */
935 {
936 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)0, (LPARAM)hWndPrev))
937 {
938 ERR("SetFocus: 2 WH_CBT Call Hook return!\n");
939 return 0;
940 }
941
942 /* set the current thread focus window null */
943 IntSendFocusMessages( pti, NULL);
944 }
945 return hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0;
946 }
947
948 HWND FASTCALL
949 UserGetForegroundWindow(VOID)
950 {
951 PUSER_MESSAGE_QUEUE ForegroundQueue;
952
953 ForegroundQueue = IntGetFocusMessageQueue();
954 return( ForegroundQueue ? (ForegroundQueue->spwndActive ? UserHMGetHandle(ForegroundQueue->spwndActive) : 0) : 0);
955 }
956
957 HWND FASTCALL UserGetActiveWindow(VOID)
958 {
959 PTHREADINFO pti;
960 PUSER_MESSAGE_QUEUE ThreadQueue;
961
962 pti = PsGetCurrentThreadWin32Thread();
963 ThreadQueue = pti->MessageQueue;
964 return( ThreadQueue ? (ThreadQueue->spwndActive ? UserHMGetHandle(ThreadQueue->spwndActive) : 0) : 0);
965 }
966
967 HWND APIENTRY
968 IntGetCapture(VOID)
969 {
970 PTHREADINFO pti;
971 PUSER_MESSAGE_QUEUE ThreadQueue;
972 DECLARE_RETURN(HWND);
973
974 TRACE("Enter IntGetCapture\n");
975
976 pti = PsGetCurrentThreadWin32Thread();
977 ThreadQueue = pti->MessageQueue;
978 RETURN( ThreadQueue ? (ThreadQueue->spwndCapture ? UserHMGetHandle(ThreadQueue->spwndCapture) : 0) : 0);
979
980 CLEANUP:
981 TRACE("Leave IntGetCapture, ret=%p\n", _ret_);
982 END_CLEANUP;
983 }
984
985 HWND FASTCALL
986 co_UserSetCapture(HWND hWnd)
987 {
988 PTHREADINFO pti;
989 PUSER_MESSAGE_QUEUE ThreadQueue;
990 PWND pWnd, Window = NULL;
991 HWND hWndPrev;
992
993 pti = PsGetCurrentThreadWin32Thread();
994 ThreadQueue = pti->MessageQueue;
995
996 if (ThreadQueue->QF_flags & QF_CAPTURELOCKED)
997 return NULL;
998
999 if (hWnd && (Window = UserGetWindowObject(hWnd)))
1000 {
1001 if (Window->head.pti->MessageQueue != ThreadQueue)
1002 {
1003 return NULL;
1004 }
1005 }
1006
1007 hWndPrev = MsqSetStateWindow(pti, MSQ_STATE_CAPTURE, hWnd);
1008
1009 if (hWndPrev)
1010 {
1011 pWnd = UserGetWindowObject(hWndPrev);
1012 if (pWnd)
1013 IntNotifyWinEvent(EVENT_SYSTEM_CAPTUREEND, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1014 }
1015
1016 if (Window)
1017 IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1018
1019 if (hWndPrev && hWndPrev != hWnd)
1020 {
1021 if (ThreadQueue->MenuOwner && Window) ThreadQueue->QF_flags |= QF_CAPTURELOCKED;
1022
1023 //co_IntPostOrSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd);
1024 co_IntSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd);
1025
1026 ThreadQueue->QF_flags &= ~QF_CAPTURELOCKED;
1027 }
1028
1029 ThreadQueue->spwndCapture = Window;
1030
1031 if (hWnd == NULL) // Release mode.
1032 {
1033 MOUSEINPUT mi;
1034 /// These are HACKS!
1035 /* Also remove other windows if not capturing anymore */
1036 MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL);
1037 MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, NULL);
1038 ///
1039 /* Somebody may have missed some mouse movements */
1040 mi.dx = 0;
1041 mi.dy = 0;
1042 mi.mouseData = 0;
1043 mi.dwFlags = MOUSEEVENTF_MOVE;
1044 mi.time = 0;
1045 mi.dwExtraInfo = 0;
1046 UserSendMouseInput(&mi, FALSE);
1047 }
1048 return hWndPrev;
1049 }
1050
1051 /*
1052 API Call
1053 */
1054 BOOL
1055 FASTCALL
1056 IntReleaseCapture(VOID)
1057 {
1058 PTHREADINFO pti;
1059 PUSER_MESSAGE_QUEUE ThreadQueue;
1060
1061 pti = PsGetCurrentThreadWin32Thread();
1062 ThreadQueue = pti->MessageQueue;
1063
1064 // Can not release inside WM_CAPTURECHANGED!!
1065 if (ThreadQueue->QF_flags & QF_CAPTURELOCKED) return FALSE;
1066
1067 co_UserSetCapture(NULL);
1068
1069 return TRUE;
1070 }
1071
1072 /*
1073 API Call
1074 */
1075 BOOL FASTCALL
1076 co_IntSetForegroundWindow(PWND Window)
1077 {
1078 if (Window) ASSERT_REFS_CO(Window);
1079
1080 return co_IntSetForegroundAndFocusWindow(Window, FALSE);
1081 }
1082
1083 /*
1084 API Call
1085 */
1086 BOOL FASTCALL
1087 co_IntSetForegroundWindowMouse(PWND Window)
1088 {
1089 if (Window) ASSERT_REFS_CO(Window);
1090
1091 return co_IntSetForegroundAndFocusWindow(Window, TRUE);
1092 }
1093
1094 /*
1095 API Call
1096 */
1097 BOOL FASTCALL
1098 IntLockSetForegroundWindow(UINT uLockCode)
1099 {
1100 ULONG Err = ERROR_ACCESS_DENIED;
1101 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
1102 switch (uLockCode)
1103 {
1104 case LSFW_LOCK:
1105 if ( CanForceFG(ppi) && !gppiLockSFW )
1106 {
1107 gppiLockSFW = ppi;
1108 return TRUE;
1109 }
1110 break;
1111 case LSFW_UNLOCK:
1112 if ( gppiLockSFW == ppi)
1113 {
1114 gppiLockSFW = NULL;
1115 return TRUE;
1116 }
1117 break;
1118 default:
1119 Err = ERROR_INVALID_PARAMETER;
1120 }
1121 EngSetLastError(Err);
1122 return FALSE;
1123 }
1124
1125 /*
1126 API Call
1127 */
1128 BOOL FASTCALL
1129 IntAllowSetForegroundWindow(DWORD dwProcessId)
1130 {
1131 PPROCESSINFO ppi, ppiCur;
1132 PEPROCESS Process = NULL;
1133
1134 ppi = NULL;
1135 if (dwProcessId != ASFW_ANY)
1136 {
1137 if (!NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)dwProcessId, &Process)))
1138 {
1139 EngSetLastError(ERROR_INVALID_PARAMETER);
1140 return FALSE;
1141 }
1142 ppi = PsGetProcessWin32Process(Process);
1143 if (!ppi)
1144 {
1145 ObDereferenceObject(Process);
1146 return FALSE;
1147 }
1148 }
1149 ppiCur = PsGetCurrentProcessWin32Process();
1150 if (!CanForceFG(ppiCur))
1151 {
1152 if (Process) ObDereferenceObject(Process);
1153 EngSetLastError(ERROR_ACCESS_DENIED);
1154 return FALSE;
1155 }
1156 if (dwProcessId == ASFW_ANY)
1157 { // All processes will be enabled to set the foreground window.
1158 //ERR("ptiLastInput is CLEARED!!\n");
1159 ptiLastInput = NULL;
1160 }
1161 else
1162 { // Rule #3, last input event in force.
1163 ERR("ptiLastInput is SET!!\n");
1164 //ptiLastInput = ppi->ptiList; // See CORE-6384 & CORE-7030.
1165 ObDereferenceObject(Process);
1166 }
1167 return TRUE;
1168 }
1169
1170 /*
1171 * @implemented
1172 */
1173 HWND APIENTRY
1174 NtUserGetForegroundWindow(VOID)
1175 {
1176 DECLARE_RETURN(HWND);
1177
1178 TRACE("Enter NtUserGetForegroundWindow\n");
1179 UserEnterExclusive();
1180
1181 RETURN( UserGetForegroundWindow());
1182
1183 CLEANUP:
1184 TRACE("Leave NtUserGetForegroundWindow, ret=%p\n",_ret_);
1185 UserLeave();
1186 END_CLEANUP;
1187 }
1188
1189 HWND APIENTRY
1190 NtUserSetActiveWindow(HWND hWnd)
1191 {
1192 USER_REFERENCE_ENTRY Ref;
1193 HWND hWndPrev;
1194 PWND Window;
1195 DECLARE_RETURN(HWND);
1196
1197 TRACE("Enter NtUserSetActiveWindow(%p)\n", hWnd);
1198 UserEnterExclusive();
1199
1200 Window = NULL;
1201 if (hWnd)
1202 {
1203 if (!(Window = UserGetWindowObject(hWnd)))
1204 {
1205 ERR("NtUserSetActiveWindow: Invalid handle 0x%p!\n",hWnd);
1206 RETURN( NULL);
1207 }
1208 }
1209
1210 if (!Window ||
1211 Window->head.pti->MessageQueue == gptiCurrent->MessageQueue)
1212 {
1213 hWndPrev = gptiCurrent->MessageQueue->spwndActive ? UserHMGetHandle(gptiCurrent->MessageQueue->spwndActive) : NULL;
1214 if (Window) UserRefObjectCo(Window, &Ref);
1215 UserSetActiveWindow(Window);
1216 if (Window) UserDerefObjectCo(Window);
1217 RETURN( hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0 );
1218 }
1219 RETURN( NULL);
1220
1221 CLEANUP:
1222 TRACE("Leave NtUserSetActiveWindow, ret=%p\n",_ret_);
1223 UserLeave();
1224 END_CLEANUP;
1225 }
1226
1227 /*
1228 * @implemented
1229 */
1230 HWND APIENTRY
1231 NtUserSetCapture(HWND hWnd)
1232 {
1233 DECLARE_RETURN(HWND);
1234
1235 TRACE("Enter NtUserSetCapture(%p)\n", hWnd);
1236 UserEnterExclusive();
1237
1238 RETURN( co_UserSetCapture(hWnd));
1239
1240 CLEANUP:
1241 TRACE("Leave NtUserSetCapture, ret=%p\n", _ret_);
1242 UserLeave();
1243 END_CLEANUP;
1244 }
1245
1246 /*
1247 * @implemented
1248 */
1249 HWND APIENTRY
1250 NtUserSetFocus(HWND hWnd)
1251 {
1252 PWND Window;
1253 USER_REFERENCE_ENTRY Ref;
1254 DECLARE_RETURN(HWND);
1255 HWND ret;
1256
1257 TRACE("Enter NtUserSetFocus(%p)\n", hWnd);
1258 UserEnterExclusive();
1259
1260 if (hWnd)
1261 {
1262 if (!(Window = UserGetWindowObject(hWnd)))
1263 {
1264 ERR("NtUserSetFocus: Invalid handle 0x%p!\n",hWnd);
1265 RETURN(NULL);
1266 }
1267
1268 UserRefObjectCo(Window, &Ref);
1269 ret = co_UserSetFocus(Window);
1270 UserDerefObjectCo(Window);
1271
1272 RETURN(ret);
1273 }
1274 else
1275 {
1276 RETURN( co_UserSetFocus(0));
1277 }
1278
1279 CLEANUP:
1280 TRACE("Leave NtUserSetFocus, ret=%p\n",_ret_);
1281 UserLeave();
1282 END_CLEANUP;
1283 }
1284
1285 /* EOF */