Sync with trunk r63502.
[reactos.git] / win32ss / user / ntuser / window.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Windows
5 * FILE: subsystems/win32/win32k/ntuser/window.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserWnd);
11
12 INT gNestedWindowLimit = 50;
13
14 /* HELPER FUNCTIONS ***********************************************************/
15
16 BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam)
17 {
18 WORD Action = LOWORD(wParam);
19 WORD Flags = HIWORD(wParam);
20
21 if (Flags & ~(UISF_HIDEFOCUS | UISF_HIDEACCEL | UISF_ACTIVE))
22 {
23 EngSetLastError(ERROR_INVALID_PARAMETER);
24 return FALSE;
25 }
26
27 switch (Action)
28 {
29 case UIS_INITIALIZE:
30 EngSetLastError(ERROR_INVALID_PARAMETER);
31 return FALSE;
32
33 case UIS_SET:
34 if (Flags & UISF_HIDEFOCUS)
35 Wnd->HideFocus = TRUE;
36 if (Flags & UISF_HIDEACCEL)
37 Wnd->HideAccel = TRUE;
38 break;
39
40 case UIS_CLEAR:
41 if (Flags & UISF_HIDEFOCUS)
42 Wnd->HideFocus = FALSE;
43 if (Flags & UISF_HIDEACCEL)
44 Wnd->HideAccel = FALSE;
45 break;
46 }
47
48 return TRUE;
49 }
50
51 PWND FASTCALL IntGetWindowObject(HWND hWnd)
52 {
53 PWND Window;
54
55 if (!hWnd) return NULL;
56
57 Window = UserGetWindowObject(hWnd);
58 if (Window)
59 Window->head.cLockObj++;
60
61 return Window;
62 }
63
64 PWND FASTCALL VerifyWnd(PWND pWnd)
65 {
66 HWND hWnd;
67 UINT State, State2;
68
69 if (!pWnd) return NULL;
70
71 _SEH2_TRY
72 {
73 hWnd = UserHMGetHandle(pWnd);
74 State = pWnd->state;
75 State2 = pWnd->state2;
76 }
77 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
78 {
79 _SEH2_YIELD(return NULL);
80 }
81 _SEH2_END
82
83 if ( UserObjectInDestroy(hWnd) ||
84 State & WNDS_DESTROYED ||
85 State2 & WNDS2_INDESTROY )
86 return NULL;
87
88 return pWnd;
89 }
90
91 PWND FASTCALL ValidateHwndNoErr(HWND hWnd)
92 {
93 if (hWnd) return (PWND)UserGetObjectNoErr(gHandleTable, hWnd, TYPE_WINDOW);
94 return NULL;
95 }
96
97 /* Temp HACK */
98 PWND FASTCALL UserGetWindowObject(HWND hWnd)
99 {
100 PWND Window;
101
102 if (!hWnd)
103 {
104 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
105 return NULL;
106 }
107
108 Window = (PWND)UserGetObject(gHandleTable, hWnd, TYPE_WINDOW);
109 if (!Window || 0 != (Window->state & WNDS_DESTROYED))
110 {
111 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
112 return NULL;
113 }
114
115 return Window;
116 }
117
118 ULONG FASTCALL
119 IntSetStyle( PWND pwnd, ULONG set_bits, ULONG clear_bits )
120 {
121 ULONG styleOld, styleNew;
122 styleOld = pwnd->style;
123 styleNew = (pwnd->style | set_bits) & ~clear_bits;
124 if (styleNew == styleOld) return styleNew;
125 pwnd->style = styleNew;
126 if ((styleOld ^ styleNew) & WS_VISIBLE) // State Change.
127 {
128 if (styleOld & WS_VISIBLE) pwnd->head.pti->cVisWindows--;
129 if (styleNew & WS_VISIBLE) pwnd->head.pti->cVisWindows++;
130 DceResetActiveDCEs( pwnd );
131 }
132 return styleOld;
133 }
134
135 /*
136 * IntIsWindow
137 *
138 * The function determines whether the specified window handle identifies
139 * an existing window.
140 *
141 * Parameters
142 * hWnd
143 * Handle to the window to test.
144 *
145 * Return Value
146 * If the window handle identifies an existing window, the return value
147 * is TRUE. If the window handle does not identify an existing window,
148 * the return value is FALSE.
149 */
150
151 BOOL FASTCALL
152 IntIsWindow(HWND hWnd)
153 {
154 PWND Window;
155
156 if (!(Window = UserGetWindowObject(hWnd)))
157 {
158 return FALSE;
159 }
160
161 return TRUE;
162 }
163
164 BOOL FASTCALL
165 IntIsWindowVisible(PWND Wnd)
166 {
167 PWND Temp = Wnd;
168 for (;;)
169 {
170 if (!Temp) return TRUE;
171 if (!(Temp->style & WS_VISIBLE)) break;
172 if (Temp->style & WS_MINIMIZE && Temp != Wnd) break;
173 if (Temp->fnid == FNID_DESKTOP) return TRUE;
174 Temp = Temp->spwndParent;
175 }
176 return FALSE;
177 }
178
179 PWND FASTCALL
180 IntGetParent(PWND Wnd)
181 {
182 if (Wnd->style & WS_POPUP)
183 {
184 return Wnd->spwndOwner;
185 }
186 else if (Wnd->style & WS_CHILD)
187 {
188 return Wnd->spwndParent;
189 }
190
191 return NULL;
192 }
193
194 BOOL
195 FASTCALL
196 IntEnableWindow( HWND hWnd, BOOL bEnable )
197 {
198 BOOL Update;
199 PWND pWnd;
200 UINT bIsDisabled;
201
202 if(!(pWnd = UserGetWindowObject(hWnd)))
203 {
204 return FALSE;
205 }
206
207 /* check if updating is needed */
208 bIsDisabled = !!(pWnd->style & WS_DISABLED);
209 Update = bIsDisabled;
210
211 if (bEnable)
212 {
213 IntSetStyle( pWnd, 0, WS_DISABLED );
214 }
215 else
216 {
217 Update = !bIsDisabled;
218
219 co_IntSendMessage( hWnd, WM_CANCELMODE, 0, 0);
220
221 /* Remove keyboard focus from that window if it had focus */
222 if (hWnd == IntGetThreadFocusWindow())
223 {
224 TRACE("IntEnableWindow SF NULL\n");
225 co_UserSetFocus(NULL);
226 }
227 IntSetStyle( pWnd, WS_DISABLED, 0 );
228 }
229
230 if (Update)
231 {
232 IntNotifyWinEvent(EVENT_OBJECT_STATECHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, 0);
233 co_IntSendMessage(hWnd, WM_ENABLE, (LPARAM)bEnable, 0);
234 }
235 // Return nonzero if it was disabled, or zero if it wasn't:
236 return bIsDisabled;
237 }
238
239 /*
240 * IntWinListChildren
241 *
242 * Compile a list of all child window handles from given window.
243 *
244 * Remarks
245 * This function is similar to Wine WIN_ListChildren. The caller
246 * must free the returned list with ExFreePool.
247 */
248
249 HWND* FASTCALL
250 IntWinListChildren(PWND Window)
251 {
252 PWND Child;
253 HWND *List;
254 UINT Index, NumChildren = 0;
255
256 if (!Window) return NULL;
257
258 for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
259 ++NumChildren;
260
261 List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), USERTAG_WINDOWLIST);
262 if(!List)
263 {
264 ERR("Failed to allocate memory for children array\n");
265 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
266 return NULL;
267 }
268 for (Child = Window->spwndChild, Index = 0;
269 Child != NULL;
270 Child = Child->spwndNext, ++Index)
271 List[Index] = Child->head.h;
272 List[Index] = NULL;
273
274 return List;
275 }
276
277 PWND FASTCALL
278 IntGetNonChildAncestor(PWND pWnd)
279 {
280 while(pWnd && (pWnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
281 pWnd = pWnd->spwndParent;
282 return pWnd;
283 }
284
285 BOOL FASTCALL
286 IntIsTopLevelWindow(PWND pWnd)
287 {
288 if ( pWnd->spwndParent &&
289 pWnd->spwndParent == co_GetDesktopWindow(pWnd) ) return TRUE;
290 return FALSE;
291 }
292
293 BOOL FASTCALL
294 IntValidateOwnerDepth(PWND Wnd, PWND Owner)
295 {
296 INT Depth = 1;
297 for (;;)
298 {
299 if ( !Owner ) return gNestedWindowLimit >= Depth;
300 if (Owner == Wnd) break;
301 Owner = Owner->spwndOwner;
302 Depth++;
303 }
304 return FALSE;
305 }
306
307 HWND FASTCALL
308 IntGetWindow(HWND hWnd,
309 UINT uCmd)
310 {
311 PWND Wnd, FoundWnd;
312 HWND Ret = NULL;
313
314 Wnd = ValidateHwndNoErr(hWnd);
315 if (!Wnd)
316 return NULL;
317
318 FoundWnd = NULL;
319 switch (uCmd)
320 {
321 case GW_OWNER:
322 if (Wnd->spwndOwner != NULL)
323 FoundWnd = Wnd->spwndOwner;
324 break;
325
326 case GW_HWNDFIRST:
327 if(Wnd->spwndParent != NULL)
328 {
329 FoundWnd = Wnd->spwndParent;
330 if (FoundWnd->spwndChild != NULL)
331 FoundWnd = FoundWnd->spwndChild;
332 }
333 break;
334 case GW_HWNDNEXT:
335 if (Wnd->spwndNext != NULL)
336 FoundWnd = Wnd->spwndNext;
337 break;
338
339 case GW_HWNDPREV:
340 if (Wnd->spwndPrev != NULL)
341 FoundWnd = Wnd->spwndPrev;
342 break;
343
344 case GW_CHILD:
345 if (Wnd->spwndChild != NULL)
346 FoundWnd = Wnd->spwndChild;
347 break;
348
349 case GW_HWNDLAST:
350 FoundWnd = Wnd;
351 while ( FoundWnd->spwndNext != NULL)
352 FoundWnd = FoundWnd->spwndNext;
353 break;
354
355 default:
356 Wnd = NULL;
357 break;
358 }
359
360 if (FoundWnd != NULL)
361 Ret = UserHMGetHandle(FoundWnd);
362 return Ret;
363 }
364
365 /***********************************************************************
366 * IntSendDestroyMsg
367 */
368 static void IntSendDestroyMsg(HWND hWnd)
369 {
370
371 PWND Window;
372 #if 0 /* FIXME */
373
374 GUITHREADINFO info;
375
376 if (GetGUIThreadInfo(GetCurrentThreadId(), &info))
377 {
378 if (hWnd == info.hwndCaret)
379 {
380 DestroyCaret();
381 }
382 }
383 #endif
384
385 Window = UserGetWindowObject(hWnd);
386 if (Window)
387 {
388 // USER_REFERENCE_ENTRY Ref;
389 // UserRefObjectCo(Window, &Ref);
390
391 if (!Window->spwndOwner && !IntGetParent(Window))
392 {
393 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM) hWnd, 0);
394 }
395
396 // UserDerefObjectCo(Window);
397 }
398
399 /* The window could already be destroyed here */
400
401 /*
402 * Send the WM_DESTROY to the window.
403 */
404
405 co_IntSendMessage(hWnd, WM_DESTROY, 0, 0);
406
407 /*
408 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
409 * make sure that the window still exists when we come back.
410 */
411 #if 0 /* FIXME */
412
413 if (IsWindow(Wnd))
414 {
415 HWND* pWndArray;
416 int i;
417
418 if (!(pWndArray = WIN_ListChildren( hwnd )))
419 return;
420
421 /* start from the end (FIXME: is this needed?) */
422 for (i = 0; pWndArray[i]; i++)
423 ;
424
425 while (--i >= 0)
426 {
427 if (IsWindow( pWndArray[i] ))
428 WIN_SendDestroyMsg( pWndArray[i] );
429 }
430 HeapFree(GetProcessHeap(), 0, pWndArray);
431 }
432 else
433 {
434 TRACE("destroyed itself while in WM_DESTROY!\n");
435 }
436 #endif
437 }
438
439 static VOID
440 UserFreeWindowInfo(PTHREADINFO ti, PWND Wnd)
441 {
442 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
443
444 if (!Wnd) return;
445
446 if (ClientInfo->CallbackWnd.pWnd == DesktopHeapAddressToUser(Wnd))
447 {
448 ClientInfo->CallbackWnd.hWnd = NULL;
449 ClientInfo->CallbackWnd.pWnd = NULL;
450 }
451
452 if (Wnd->strName.Buffer != NULL)
453 {
454 Wnd->strName.Length = 0;
455 Wnd->strName.MaximumLength = 0;
456 DesktopHeapFree(Wnd->head.rpdesk,
457 Wnd->strName.Buffer);
458 Wnd->strName.Buffer = NULL;
459 }
460
461 // DesktopHeapFree(Wnd->head.rpdesk, Wnd);
462 // WindowObject->hWnd = NULL;
463 }
464
465 /***********************************************************************
466 * IntDestroyWindow
467 *
468 * Destroy storage associated to a window. "Internals" p.358
469 *
470 * This is the "functional" DestroyWindows function ei. all stuff
471 * done in CreateWindow is undone here and not in DestroyWindow:-P
472
473 */
474 static LRESULT co_UserFreeWindow(PWND Window,
475 PPROCESSINFO ProcessData,
476 PTHREADINFO ThreadData,
477 BOOLEAN SendMessages)
478 {
479 HWND *Children;
480 HWND *ChildHandle;
481 PWND Child;
482 PMENU Menu;
483 BOOLEAN BelongsToThreadData;
484
485 ASSERT(Window);
486
487 if(Window->state2 & WNDS2_INDESTROY)
488 {
489 TRACE("Tried to call IntDestroyWindow() twice\n");
490 return 0;
491 }
492 Window->state2 |= WNDS2_INDESTROY;
493 Window->style &= ~WS_VISIBLE;
494 Window->head.pti->cVisWindows--;
495
496 IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Window, OBJID_WINDOW, CHILDID_SELF, 0);
497
498 /* remove the window already at this point from the thread window list so we
499 don't get into trouble when destroying the thread windows while we're still
500 in IntDestroyWindow() */
501 RemoveEntryList(&Window->ThreadListEntry);
502
503 BelongsToThreadData = IntWndBelongsToThread(Window, ThreadData);
504
505 IntDeRegisterShellHookWindow(Window->head.h);
506
507 if(SendMessages)
508 {
509 /* Send destroy messages */
510 IntSendDestroyMsg(Window->head.h);
511 }
512
513 /* free child windows */
514 Children = IntWinListChildren(Window);
515 if (Children)
516 {
517 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
518 {
519 if ((Child = IntGetWindowObject(*ChildHandle)))
520 {
521 if(!IntWndBelongsToThread(Child, ThreadData))
522 {
523 /* send WM_DESTROY messages to windows not belonging to the same thread */
524 IntSendDestroyMsg(Child->head.h);
525 }
526 else
527 co_UserFreeWindow(Child, ProcessData, ThreadData, SendMessages);
528
529 UserDereferenceObject(Child);
530 }
531 }
532 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
533 }
534
535 if(SendMessages)
536 {
537 /*
538 * Clear the update region to make sure no WM_PAINT messages will be
539 * generated for this window while processing the WM_NCDESTROY.
540 */
541 co_UserRedrawWindow(Window, NULL, 0,
542 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
543 RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
544 if(BelongsToThreadData)
545 co_IntSendMessage(Window->head.h, WM_NCDESTROY, 0, 0);
546 }
547
548 DestroyTimersForWindow(ThreadData, Window);
549
550 /* Unregister hot keys */
551 UnregisterWindowHotKeys (Window);
552
553 /* flush the message queue */
554 MsqRemoveWindowMessagesFromQueue(Window);
555
556 /* from now on no messages can be sent to this window anymore */
557 Window->state |= WNDS_DESTROYED;
558 Window->fnid |= FNID_FREED;
559
560 /* don't remove the WINDOWSTATUS_DESTROYING bit */
561
562 /* reset shell window handles */
563 if(ThreadData->rpdesk)
564 {
565 if (Window->head.h == ThreadData->rpdesk->rpwinstaParent->ShellWindow)
566 ThreadData->rpdesk->rpwinstaParent->ShellWindow = NULL;
567
568 if (Window->head.h == ThreadData->rpdesk->rpwinstaParent->ShellListView)
569 ThreadData->rpdesk->rpwinstaParent->ShellListView = NULL;
570 }
571
572 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
573
574 #if 0 /* FIXME */
575
576 WinPosCheckInternalPos(Window->head.h);
577 if (Window->head.h == GetCapture())
578 {
579 ReleaseCapture();
580 }
581
582 /* free resources associated with the window */
583 TIMER_RemoveWindowTimers(Window->head.h);
584 #endif
585
586 if ( ((Window->style & (WS_CHILD|WS_POPUP)) != WS_CHILD) &&
587 Window->IDMenu &&
588 (Menu = UserGetMenuObject((HMENU)Window->IDMenu)))
589 {
590 IntDestroyMenuObject(Menu, TRUE, TRUE);
591 Window->IDMenu = 0;
592 }
593
594 if(Window->SystemMenu
595 && (Menu = UserGetMenuObject(Window->SystemMenu)))
596 {
597 IntDestroyMenuObject(Menu, TRUE, TRUE);
598 Window->SystemMenu = (HMENU)0;
599 }
600
601 DceFreeWindowDCE(Window); /* Always do this to catch orphaned DCs */
602 #if 0 /* FIXME */
603
604 WINPROC_FreeProc(Window->winproc, WIN_PROC_WINDOW);
605 CLASS_RemoveWindow(Window->Class);
606 #endif
607
608 IntUnlinkWindow(Window);
609
610 if (Window->PropListItems)
611 {
612 IntRemoveWindowProp(Window);
613 TRACE("Window->PropListItems %d\n",Window->PropListItems);
614 ASSERT(Window->PropListItems==0);
615 }
616
617 UserReferenceObject(Window);
618 UserDeleteObject(Window->head.h, TYPE_WINDOW);
619
620 IntDestroyScrollBars(Window);
621
622 /* dereference the class */
623 IntDereferenceClass(Window->pcls,
624 Window->head.pti->pDeskInfo,
625 Window->head.pti->ppi);
626 Window->pcls = NULL;
627
628 if(Window->hrgnClip)
629 {
630 IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED);
631 GreDeleteObject(Window->hrgnClip);
632 Window->hrgnClip = NULL;
633 }
634 Window->head.pti->cWindows--;
635
636 // ASSERT(Window != NULL);
637 UserFreeWindowInfo(Window->head.pti, Window);
638
639 UserDereferenceObject(Window);
640
641 UserClipboardFreeWindow(Window);
642
643 return 0;
644 }
645
646 //
647 // Same as User32:IntGetWndProc.
648 //
649 WNDPROC FASTCALL
650 IntGetWindowProc(PWND pWnd,
651 BOOL Ansi)
652 {
653 INT i;
654 PCLS Class;
655 WNDPROC gcpd, Ret = 0;
656
657 ASSERT(UserIsEnteredExclusive() == TRUE);
658
659 Class = pWnd->pcls;
660
661 if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
662 {
663 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
664 {
665 if (GETPFNSERVER(i) == pWnd->lpfnWndProc)
666 {
667 if (Ansi)
668 Ret = GETPFNCLIENTA(i);
669 else
670 Ret = GETPFNCLIENTW(i);
671 }
672 }
673 return Ret;
674 }
675
676 if (Class->fnid == FNID_EDIT)
677 Ret = pWnd->lpfnWndProc;
678 else
679 {
680 Ret = pWnd->lpfnWndProc;
681
682 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
683 {
684 if (Ansi)
685 {
686 if (GETPFNCLIENTW(Class->fnid) == pWnd->lpfnWndProc)
687 Ret = GETPFNCLIENTA(Class->fnid);
688 }
689 else
690 {
691 if (GETPFNCLIENTA(Class->fnid) == pWnd->lpfnWndProc)
692 Ret = GETPFNCLIENTW(Class->fnid);
693 }
694 }
695 if ( Ret != pWnd->lpfnWndProc)
696 return Ret;
697 }
698 if ( Ansi == !!(pWnd->state & WNDS_ANSIWINDOWPROC) )
699 return Ret;
700
701 gcpd = (WNDPROC)UserGetCPD(
702 pWnd,
703 (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWindow,
704 (ULONG_PTR)Ret);
705
706 return (gcpd ? gcpd : Ret);
707 }
708
709 static WNDPROC
710 IntSetWindowProc(PWND pWnd,
711 WNDPROC NewWndProc,
712 BOOL Ansi)
713 {
714 INT i;
715 PCALLPROCDATA CallProc;
716 PCLS Class;
717 WNDPROC Ret, chWndProc = NULL;
718
719 // Retrieve previous window proc.
720 Ret = IntGetWindowProc(pWnd, Ansi);
721
722 Class = pWnd->pcls;
723
724 if (IsCallProcHandle(NewWndProc))
725 {
726 CallProc = UserGetObject(gHandleTable, NewWndProc, TYPE_CALLPROC);
727 if (CallProc)
728 { // Reset new WndProc.
729 NewWndProc = CallProc->pfnClientPrevious;
730 // Reset Ansi from CallProc handle. This is expected with wine "deftest".
731 Ansi = !!(CallProc->wType & UserGetCPDU2A);
732 }
733 }
734 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
735 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
736 {
737 if (GETPFNCLIENTW(i) == NewWndProc)
738 {
739 chWndProc = GETPFNSERVER(i);
740 break;
741 }
742 if (GETPFNCLIENTA(i) == NewWndProc)
743 {
744 chWndProc = GETPFNSERVER(i);
745 break;
746 }
747 }
748 // If match, set/reset to Server Side and clear ansi.
749 if (chWndProc)
750 {
751 pWnd->lpfnWndProc = chWndProc;
752 pWnd->Unicode = TRUE;
753 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
754 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
755 }
756 else
757 {
758 pWnd->Unicode = !Ansi;
759 // Handle the state change in here.
760 if (Ansi)
761 pWnd->state |= WNDS_ANSIWINDOWPROC;
762 else
763 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
764
765 if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
766 pWnd->state &= ~WNDS_SERVERSIDEWINDOWPROC;
767
768 if (!NewWndProc) NewWndProc = pWnd->lpfnWndProc;
769
770 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
771 {
772 if (Ansi)
773 {
774 if (GETPFNCLIENTW(Class->fnid) == NewWndProc)
775 chWndProc = GETPFNCLIENTA(Class->fnid);
776 }
777 else
778 {
779 if (GETPFNCLIENTA(Class->fnid) == NewWndProc)
780 chWndProc = GETPFNCLIENTW(Class->fnid);
781 }
782 }
783 // Now set the new window proc.
784 pWnd->lpfnWndProc = (chWndProc ? chWndProc : NewWndProc);
785 }
786 return Ret;
787 }
788
789 static BOOL FASTCALL
790 IntSetMenu(
791 PWND Wnd,
792 HMENU Menu,
793 BOOL *Changed)
794 {
795 PMENU OldMenu, NewMenu = NULL;
796
797 if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
798 {
799 ERR("SetMenu: Invalid handle 0x%p!\n",UserHMGetHandle(Wnd));
800 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
801 return FALSE;
802 }
803
804 *Changed = (Wnd->IDMenu != (UINT) Menu);
805 if (! *Changed)
806 {
807 return TRUE;
808 }
809
810 if (Wnd->IDMenu)
811 {
812 OldMenu = IntGetMenuObject((HMENU) Wnd->IDMenu);
813 ASSERT(NULL == OldMenu || OldMenu->hWnd == Wnd->head.h);
814 }
815 else
816 {
817 OldMenu = NULL;
818 }
819
820 if (NULL != Menu)
821 {
822 NewMenu = IntGetMenuObject(Menu);
823 if (NULL == NewMenu)
824 {
825 if (NULL != OldMenu)
826 {
827 IntReleaseMenuObject(OldMenu);
828 }
829 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
830 return FALSE;
831 }
832 if (NULL != NewMenu->hWnd)
833 {
834 /* Can't use the same menu for two windows */
835 if (NULL != OldMenu)
836 {
837 IntReleaseMenuObject(OldMenu);
838 }
839 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
840 return FALSE;
841 }
842
843 }
844
845 Wnd->IDMenu = (UINT) Menu;
846 if (NULL != NewMenu)
847 {
848 NewMenu->hWnd = Wnd->head.h;
849 IntReleaseMenuObject(NewMenu);
850 }
851 if (NULL != OldMenu)
852 {
853 OldMenu->hWnd = NULL;
854 IntReleaseMenuObject(OldMenu);
855 }
856
857 return TRUE;
858 }
859
860
861 /* INTERNAL ******************************************************************/
862
863
864 VOID FASTCALL
865 co_DestroyThreadWindows(struct _ETHREAD *Thread)
866 {
867 PTHREADINFO WThread;
868 PLIST_ENTRY Current;
869 PWND Wnd;
870 USER_REFERENCE_ENTRY Ref;
871 WThread = (PTHREADINFO)Thread->Tcb.Win32Thread;
872
873 while (!IsListEmpty(&WThread->WindowListHead))
874 {
875 Current = WThread->WindowListHead.Flink;
876 Wnd = CONTAINING_RECORD(Current, WND, ThreadListEntry);
877
878 TRACE("thread cleanup: while destroy wnds, wnd=%p\n", Wnd);
879
880 /* Window removes itself from the list */
881
882 /*
883 * FIXME: It is critical that the window removes itself! If now, we will loop
884 * here forever...
885 */
886
887 //ASSERT(co_UserDestroyWindow(Wnd));
888
889 UserRefObjectCo(Wnd, &Ref); // FIXME: Temp HACK??
890 if (!co_UserDestroyWindow(Wnd))
891 {
892 ERR("Unable to destroy window %p at thread cleanup... This is _VERY_ bad!\n", Wnd);
893 }
894 UserDerefObjectCo(Wnd); // FIXME: Temp HACK??
895 }
896 }
897
898 BOOL FASTCALL
899 IntIsChildWindow(PWND Parent, PWND BaseWindow)
900 {
901 PWND Window;
902
903 Window = BaseWindow;
904 while (Window && ((Window->style & (WS_POPUP|WS_CHILD)) == WS_CHILD))
905 {
906 if (Window == Parent)
907 {
908 return(TRUE);
909 }
910
911 Window = Window->spwndParent;
912 }
913
914 return(FALSE);
915 }
916
917 /*
918 Link the window into siblings list
919 children and parent are kept in place.
920 */
921 VOID FASTCALL
922 IntLinkWindow(
923 PWND Wnd,
924 PWND WndInsertAfter /* set to NULL if top sibling */
925 )
926 {
927 if ((Wnd->spwndPrev = WndInsertAfter))
928 {
929 /* link after WndInsertAfter */
930 if ((Wnd->spwndNext = WndInsertAfter->spwndNext))
931 Wnd->spwndNext->spwndPrev = Wnd;
932
933 Wnd->spwndPrev->spwndNext = Wnd;
934 }
935 else
936 {
937 /* link at top */
938 if ((Wnd->spwndNext = Wnd->spwndParent->spwndChild))
939 Wnd->spwndNext->spwndPrev = Wnd;
940
941 Wnd->spwndParent->spwndChild = Wnd;
942 }
943 }
944
945 /*
946 Note: Wnd->spwndParent can be null if it is the desktop.
947 */
948 VOID FASTCALL IntLinkHwnd(PWND Wnd, HWND hWndPrev)
949 {
950 if (hWndPrev == HWND_NOTOPMOST)
951 {
952 if (!(Wnd->ExStyle & WS_EX_TOPMOST) &&
953 (Wnd->ExStyle2 & WS_EX2_LINKED)) return; /* nothing to do */
954 Wnd->ExStyle &= ~WS_EX_TOPMOST;
955 hWndPrev = HWND_TOP; /* fallback to the HWND_TOP case */
956 }
957
958 IntUnlinkWindow(Wnd); /* unlink it from the previous location */
959
960 if (hWndPrev == HWND_BOTTOM)
961 {
962 /* Link in the bottom of the list */
963 PWND WndInsertAfter;
964
965 WndInsertAfter = Wnd->spwndParent->spwndChild;
966 while( WndInsertAfter && WndInsertAfter->spwndNext)
967 WndInsertAfter = WndInsertAfter->spwndNext;
968
969 IntLinkWindow(Wnd, WndInsertAfter);
970 Wnd->ExStyle &= ~WS_EX_TOPMOST;
971 }
972 else if (hWndPrev == HWND_TOPMOST)
973 {
974 /* Link in the top of the list */
975 IntLinkWindow(Wnd, NULL);
976
977 Wnd->ExStyle |= WS_EX_TOPMOST;
978 }
979 else if (hWndPrev == HWND_TOP)
980 {
981 /* Link it after the last topmost window */
982 PWND WndInsertBefore;
983
984 WndInsertBefore = Wnd->spwndParent->spwndChild;
985
986 if (!(Wnd->ExStyle & WS_EX_TOPMOST)) /* put it above the first non-topmost window */
987 {
988 while (WndInsertBefore != NULL && WndInsertBefore->spwndNext != NULL)
989 {
990 if (!(WndInsertBefore->ExStyle & WS_EX_TOPMOST)) break;
991 if (WndInsertBefore == Wnd->spwndOwner) /* keep it above owner */
992 {
993 Wnd->ExStyle |= WS_EX_TOPMOST;
994 break;
995 }
996 WndInsertBefore = WndInsertBefore->spwndNext;
997 }
998 }
999
1000 IntLinkWindow(Wnd, WndInsertBefore ? WndInsertBefore->spwndPrev : NULL);
1001 }
1002 else
1003 {
1004 /* Link it after hWndPrev */
1005 PWND WndInsertAfter;
1006
1007 WndInsertAfter = UserGetWindowObject(hWndPrev);
1008 /* Are we called with an erroneous handle */
1009 if(WndInsertAfter == NULL)
1010 {
1011 /* Link in a default position */
1012 IntLinkHwnd(Wnd, HWND_TOP);
1013 return;
1014 }
1015
1016 IntLinkWindow(Wnd, WndInsertAfter);
1017
1018 /* Fix the WS_EX_TOPMOST flag */
1019 if (!(WndInsertAfter->ExStyle & WS_EX_TOPMOST))
1020 {
1021 Wnd->ExStyle &= ~WS_EX_TOPMOST;
1022 }
1023 else
1024 {
1025 if(WndInsertAfter->spwndNext &&
1026 WndInsertAfter->spwndNext->ExStyle & WS_EX_TOPMOST)
1027 {
1028 Wnd->ExStyle |= WS_EX_TOPMOST;
1029 }
1030 }
1031 }
1032 Wnd->ExStyle2 |= WS_EX2_LINKED;
1033 }
1034
1035 VOID FASTCALL
1036 IntProcessOwnerSwap(PWND Wnd, PWND WndNewOwner, PWND WndOldOwner)
1037 {
1038 if (WndOldOwner)
1039 {
1040 if (Wnd->head.pti != WndOldOwner->head.pti)
1041 {
1042 if (!WndNewOwner ||
1043 Wnd->head.pti == WndNewOwner->head.pti ||
1044 WndOldOwner->head.pti != WndNewOwner->head.pti )
1045 {
1046 //ERR("ProcessOwnerSwap Old out.\n");
1047 UserAttachThreadInput(Wnd->head.pti, WndOldOwner->head.pti, FALSE);
1048 }
1049 }
1050 }
1051 if (WndNewOwner)
1052 {
1053 if (Wnd->head.pti != WndNewOwner->head.pti)
1054 {
1055 if (!WndOldOwner ||
1056 WndOldOwner->head.pti != WndNewOwner->head.pti )
1057 {
1058 //ERR("ProcessOwnerSwap New in.\n");
1059 UserAttachThreadInput(Wnd->head.pti, WndNewOwner->head.pti, TRUE);
1060 }
1061 }
1062 }
1063 // FIXME: System Tray checks.
1064 }
1065
1066 HWND FASTCALL
1067 IntSetOwner(HWND hWnd, HWND hWndNewOwner)
1068 {
1069 PWND Wnd, WndOldOwner, WndNewOwner;
1070 HWND ret;
1071
1072 Wnd = IntGetWindowObject(hWnd);
1073 if(!Wnd)
1074 return NULL;
1075
1076 WndOldOwner = Wnd->spwndOwner;
1077
1078 ret = WndOldOwner ? UserHMGetHandle(WndOldOwner) : 0;
1079 WndNewOwner = UserGetWindowObject(hWndNewOwner);
1080
1081 if (!WndNewOwner && hWndNewOwner)
1082 {
1083 EngSetLastError(ERROR_INVALID_PARAMETER);
1084 ret = NULL;
1085 goto Error;
1086 }
1087
1088 /* if parent belongs to a different thread and the window isn't */
1089 /* top-level, attach the two threads */
1090 IntProcessOwnerSwap(Wnd, WndNewOwner, WndOldOwner);
1091
1092 if (IntValidateOwnerDepth(Wnd, WndNewOwner))
1093 {
1094 if (WndNewOwner)
1095 {
1096 Wnd->spwndOwner= WndNewOwner;
1097 }
1098 else
1099 {
1100 Wnd->spwndOwner = NULL;
1101 }
1102 }
1103 else
1104 {
1105 IntProcessOwnerSwap(Wnd, WndOldOwner, WndNewOwner);
1106 EngSetLastError(ERROR_INVALID_PARAMETER);
1107 ret = NULL;
1108 }
1109 Error:
1110 UserDereferenceObject(Wnd);
1111 return ret;
1112 }
1113
1114 PWND FASTCALL
1115 co_IntSetParent(PWND Wnd, PWND WndNewParent)
1116 {
1117 PWND WndOldParent, pWndExam;
1118 BOOL WasVisible;
1119 POINT pt;
1120 int swFlags = SWP_NOSIZE|SWP_NOZORDER;
1121
1122 ASSERT(Wnd);
1123 ASSERT(WndNewParent);
1124 ASSERT_REFS_CO(Wnd);
1125 ASSERT_REFS_CO(WndNewParent);
1126
1127 if (Wnd == Wnd->head.rpdesk->spwndMessage)
1128 {
1129 EngSetLastError(ERROR_ACCESS_DENIED);
1130 return( NULL);
1131 }
1132
1133 /* Some applications try to set a child as a parent */
1134 if (IntIsChildWindow(Wnd, WndNewParent))
1135 {
1136 TRACE("IntSetParent try to set a child as a parent.\n");
1137 EngSetLastError( ERROR_INVALID_PARAMETER );
1138 return NULL;
1139 }
1140
1141 pWndExam = WndNewParent; // Load parent Window to examine.
1142 // Now test for set parent to parent hit.
1143 while (pWndExam)
1144 {
1145 if (Wnd == pWndExam)
1146 {
1147 TRACE("IntSetParent Failed Test for set parent to parent!\n");
1148 EngSetLastError(ERROR_INVALID_PARAMETER);
1149 return NULL;
1150 }
1151 pWndExam = pWndExam->spwndParent;
1152 }
1153
1154 /*
1155 * Windows hides the window first, then shows it again
1156 * including the WM_SHOWWINDOW messages and all
1157 */
1158 WasVisible = co_WinPosShowWindow(Wnd, SW_HIDE);
1159
1160 /* Window must belong to current process */
1161 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
1162 {
1163 ERR("IntSetParent Window must belong to current process!\n");
1164 return NULL;
1165 }
1166
1167 WndOldParent = Wnd->spwndParent;
1168
1169 if ( WndOldParent &&
1170 WndOldParent->ExStyle & WS_EX_LAYOUTRTL)
1171 pt.x = Wnd->rcWindow.right;
1172 else
1173 pt.x = Wnd->rcWindow.left;
1174 pt.y = Wnd->rcWindow.top;
1175
1176 IntScreenToClient(WndOldParent, &pt);
1177
1178 if (WndOldParent) UserReferenceObject(WndOldParent); /* Caller must deref */
1179
1180 if (WndNewParent != WndOldParent)
1181 {
1182 /* Unlink the window from the siblings list */
1183 IntUnlinkWindow(Wnd);
1184 Wnd->ExStyle2 &= ~WS_EX2_LINKED;
1185
1186 /* Set the new parent */
1187 Wnd->spwndParent = WndNewParent;
1188
1189 if ( Wnd->style & WS_CHILD &&
1190 Wnd->spwndOwner &&
1191 Wnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1192 {
1193 ERR("SetParent Top Most from Pop up!\n");
1194 Wnd->ExStyle |= WS_EX_TOPMOST;
1195 }
1196
1197 /* Link the window with its new siblings */
1198 IntLinkHwnd( Wnd,
1199 ((0 == (Wnd->ExStyle & WS_EX_TOPMOST) &&
1200 WndNewParent == UserGetDesktopWindow() ) ? HWND_TOP : HWND_TOPMOST ) );
1201
1202 }
1203
1204 if ( WndNewParent == co_GetDesktopWindow(Wnd) &&
1205 !(Wnd->style & WS_CLIPSIBLINGS) )
1206 {
1207 Wnd->style |= WS_CLIPSIBLINGS;
1208 DceResetActiveDCEs(Wnd);
1209 }
1210
1211 /* if parent belongs to a different thread and the window isn't */
1212 /* top-level, attach the two threads */
1213 if ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1214 {
1215 if ( Wnd->spwndParent != co_GetDesktopWindow(Wnd))
1216 {
1217 if (Wnd->head.pti != WndOldParent->head.pti)
1218 {
1219 //ERR("SetParent Old out.\n");
1220 UserAttachThreadInput(Wnd->head.pti, WndOldParent->head.pti, FALSE);
1221 }
1222 }
1223 if ( WndNewParent != co_GetDesktopWindow(Wnd))
1224 {
1225 if (Wnd->head.pti != WndNewParent->head.pti)
1226 {
1227 //ERR("SetParent New in.\n");
1228 UserAttachThreadInput(Wnd->head.pti, WndNewParent->head.pti, TRUE);
1229 }
1230 }
1231 }
1232
1233 if (WndOldParent == UserGetMessageWindow() || WndNewParent == UserGetMessageWindow())
1234 swFlags |= SWP_NOACTIVATE;
1235
1236 IntNotifyWinEvent(EVENT_OBJECT_PARENTCHANGE, Wnd ,OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1237 /*
1238 * SetParent additionally needs to make hwnd the top window
1239 * in the z-order and send the expected WM_WINDOWPOSCHANGING and
1240 * WM_WINDOWPOSCHANGED notification messages.
1241 */
1242 //ERR("IntSetParent SetWindowPos 1\n");
1243 co_WinPosSetWindowPos( Wnd,
1244 (0 == (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
1245 pt.x, pt.y, 0, 0, swFlags);
1246 //ERR("IntSetParent SetWindowPos 2 X %d Y %d\n",pt.x, pt.y);
1247 if (WasVisible) co_WinPosShowWindow(Wnd, SW_SHOWNORMAL);
1248
1249 return WndOldParent;
1250 }
1251
1252 HWND FASTCALL
1253 co_UserSetParent(HWND hWndChild, HWND hWndNewParent)
1254 {
1255 PWND Wnd = NULL, WndParent = NULL, WndOldParent;
1256 HWND hWndOldParent = NULL;
1257 USER_REFERENCE_ENTRY Ref, ParentRef;
1258
1259 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
1260 {
1261 EngSetLastError(ERROR_INVALID_PARAMETER);
1262 return( NULL);
1263 }
1264
1265 if (hWndChild == IntGetDesktopWindow())
1266 {
1267 ERR("UserSetParent Access Denied!\n");
1268 EngSetLastError(ERROR_ACCESS_DENIED);
1269 return( NULL);
1270 }
1271
1272 if (hWndNewParent)
1273 {
1274 if (!(WndParent = UserGetWindowObject(hWndNewParent)))
1275 {
1276 ERR("UserSetParent Bad New Parent!\n");
1277 return( NULL);
1278 }
1279 }
1280 else
1281 {
1282 if (!(WndParent = UserGetWindowObject(IntGetDesktopWindow())))
1283 {
1284 return( NULL);
1285 }
1286 }
1287
1288 if (!(Wnd = UserGetWindowObject(hWndChild)))
1289 {
1290 ERR("UserSetParent Bad Child!\n");
1291 return( NULL);
1292 }
1293
1294 UserRefObjectCo(Wnd, &Ref);
1295 UserRefObjectCo(WndParent, &ParentRef);
1296 //ERR("Enter co_IntSetParent\n");
1297 WndOldParent = co_IntSetParent(Wnd, WndParent);
1298 //ERR("Leave co_IntSetParent\n");
1299 UserDerefObjectCo(WndParent);
1300 UserDerefObjectCo(Wnd);
1301
1302 if (WndOldParent)
1303 {
1304 hWndOldParent = WndOldParent->head.h;
1305 UserDereferenceObject(WndOldParent);
1306 }
1307
1308 return( hWndOldParent);
1309 }
1310
1311 /* Unlink the window from siblings. children and parent are kept in place. */
1312 VOID FASTCALL
1313 IntUnlinkWindow(PWND Wnd)
1314 {
1315 if (Wnd->spwndNext)
1316 Wnd->spwndNext->spwndPrev = Wnd->spwndPrev;
1317
1318 if (Wnd->spwndPrev)
1319 Wnd->spwndPrev->spwndNext = Wnd->spwndNext;
1320
1321 if (Wnd->spwndParent && Wnd->spwndParent->spwndChild == Wnd)
1322 Wnd->spwndParent->spwndChild = Wnd->spwndNext;
1323
1324 Wnd->spwndPrev = Wnd->spwndNext = NULL;
1325 }
1326
1327 /* FUNCTIONS *****************************************************************/
1328
1329 /*
1330 * As best as I can figure, this function is used by EnumWindows,
1331 * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
1332 *
1333 * It's supposed to build a list of HWNDs to return to the caller.
1334 * We can figure out what kind of list by what parameters are
1335 * passed to us.
1336 */
1337 /*
1338 * @implemented
1339 */
1340 NTSTATUS
1341 APIENTRY
1342 NtUserBuildHwndList(
1343 HDESK hDesktop,
1344 HWND hwndParent,
1345 BOOLEAN bChildren,
1346 ULONG dwThreadId,
1347 ULONG lParam,
1348 HWND* pWnd,
1349 ULONG* pBufSize)
1350 {
1351 NTSTATUS Status;
1352 ULONG dwCount = 0;
1353
1354 if (pBufSize == 0)
1355 return ERROR_INVALID_PARAMETER;
1356
1357 if (hwndParent || !dwThreadId)
1358 {
1359 PDESKTOP Desktop;
1360 PWND Parent, Window;
1361
1362 if(!hwndParent)
1363 {
1364 if(hDesktop == NULL && !(Desktop = IntGetActiveDesktop()))
1365 {
1366 return ERROR_INVALID_HANDLE;
1367 }
1368
1369 if(hDesktop)
1370 {
1371 Status = IntValidateDesktopHandle(hDesktop,
1372 UserMode,
1373 0,
1374 &Desktop);
1375 if(!NT_SUCCESS(Status))
1376 {
1377 return ERROR_INVALID_HANDLE;
1378 }
1379 }
1380 hwndParent = Desktop->DesktopWindow;
1381 }
1382 else
1383 {
1384 hDesktop = 0;
1385 }
1386
1387 if((Parent = UserGetWindowObject(hwndParent)) &&
1388 (Window = Parent->spwndChild))
1389 {
1390 BOOL bGoDown = TRUE;
1391
1392 Status = STATUS_SUCCESS;
1393 while(TRUE)
1394 {
1395 if (bGoDown)
1396 {
1397 if(dwCount++ < *pBufSize && pWnd)
1398 {
1399 _SEH2_TRY
1400 {
1401 ProbeForWrite(pWnd, sizeof(HWND), 1);
1402 *pWnd = Window->head.h;
1403 pWnd++;
1404 }
1405 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1406 {
1407 Status = _SEH2_GetExceptionCode();
1408 }
1409 _SEH2_END
1410 if(!NT_SUCCESS(Status))
1411 {
1412 SetLastNtError(Status);
1413 break;
1414 }
1415 }
1416 if (Window->spwndChild && bChildren)
1417 {
1418 Window = Window->spwndChild;
1419 continue;
1420 }
1421 bGoDown = FALSE;
1422 }
1423 if (Window->spwndNext)
1424 {
1425 Window = Window->spwndNext;
1426 bGoDown = TRUE;
1427 continue;
1428 }
1429 Window = Window->spwndParent;
1430 if (Window == Parent)
1431 {
1432 break;
1433 }
1434 }
1435 }
1436
1437 if(hDesktop)
1438 {
1439 ObDereferenceObject(Desktop);
1440 }
1441 }
1442 else // Build EnumThreadWindows list!
1443 {
1444 PETHREAD Thread;
1445 PTHREADINFO W32Thread;
1446 PLIST_ENTRY Current;
1447 PWND Window;
1448
1449 Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
1450 if (!NT_SUCCESS(Status))
1451 {
1452 ERR("Thread Id is not valid!\n");
1453 return ERROR_INVALID_PARAMETER;
1454 }
1455 if (!(W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread))
1456 {
1457 ObDereferenceObject(Thread);
1458 ERR("Thread is not initialized!\n");
1459 return ERROR_INVALID_PARAMETER;
1460 }
1461
1462 Current = W32Thread->WindowListHead.Flink;
1463 while (Current != &(W32Thread->WindowListHead))
1464 {
1465 Window = CONTAINING_RECORD(Current, WND, ThreadListEntry);
1466 ASSERT(Window);
1467
1468 if (dwCount < *pBufSize && pWnd)
1469 {
1470 _SEH2_TRY
1471 {
1472 ProbeForWrite(pWnd, sizeof(HWND), 1);
1473 *pWnd = Window->head.h;
1474 pWnd++;
1475 }
1476 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1477 {
1478 Status = _SEH2_GetExceptionCode();
1479 }
1480 _SEH2_END
1481 if (!NT_SUCCESS(Status))
1482 {
1483 ERR("Failure to build window list!\n");
1484 SetLastNtError(Status);
1485 break;
1486 }
1487 }
1488 dwCount++;
1489 Current = Window->ThreadListEntry.Flink;
1490 }
1491
1492 ObDereferenceObject(Thread);
1493 }
1494
1495 *pBufSize = dwCount;
1496 return STATUS_SUCCESS;
1497 }
1498
1499 static void IntSendParentNotify( PWND pWindow, UINT msg )
1500 {
1501 if ( (pWindow->style & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
1502 !(pWindow->style & WS_EX_NOPARENTNOTIFY))
1503 {
1504 if (pWindow->spwndParent && pWindow->spwndParent != UserGetDesktopWindow())
1505 {
1506 USER_REFERENCE_ENTRY Ref;
1507 UserRefObjectCo(pWindow->spwndParent, &Ref);
1508 co_IntSendMessage( pWindow->spwndParent->head.h,
1509 WM_PARENTNOTIFY,
1510 MAKEWPARAM( msg, pWindow->IDMenu),
1511 (LPARAM)pWindow->head.h );
1512 UserDerefObjectCo(pWindow->spwndParent);
1513 }
1514 }
1515 }
1516
1517 void FASTCALL
1518 IntFixWindowCoordinates(CREATESTRUCTW* Cs, PWND ParentWindow, DWORD* dwShowMode)
1519 {
1520 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1521
1522 /* default positioning for overlapped windows */
1523 if(!(Cs->style & (WS_POPUP | WS_CHILD)))
1524 {
1525 PMONITOR pMonitor;
1526 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
1527
1528 pMonitor = UserGetPrimaryMonitor();
1529
1530 /* Check if we don't have a monitor attached yet */
1531 if(pMonitor == NULL)
1532 {
1533 Cs->x = Cs->y = 0;
1534 Cs->cx = 800;
1535 Cs->cy = 600;
1536 return;
1537 }
1538
1539 ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
1540
1541 if (IS_DEFAULT(Cs->x))
1542 {
1543 if (!IS_DEFAULT(Cs->y)) *dwShowMode = Cs->y;
1544
1545 if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
1546 {
1547 Cs->x = ProcessParams->StartingX;
1548 Cs->y = ProcessParams->StartingY;
1549 }
1550 else
1551 {
1552 Cs->x = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CXSIZE) + UserGetSystemMetrics(SM_CXFRAME));
1553 Cs->y = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CYSIZE) + UserGetSystemMetrics(SM_CYFRAME));
1554 if (Cs->x > ((pMonitor->rcWork.right - pMonitor->rcWork.left) / 4) ||
1555 Cs->y > ((pMonitor->rcWork.bottom - pMonitor->rcWork.top) / 4))
1556 {
1557 /* reset counter and position */
1558 Cs->x = 0;
1559 Cs->y = 0;
1560 pMonitor->cWndStack = 0;
1561 }
1562 pMonitor->cWndStack++;
1563 }
1564 }
1565
1566 if (IS_DEFAULT(Cs->cx))
1567 {
1568 if (ProcessParams->WindowFlags & STARTF_USEPOSITION)
1569 {
1570 Cs->cx = ProcessParams->CountX;
1571 Cs->cy = ProcessParams->CountY;
1572 }
1573 else
1574 {
1575 Cs->cx = (pMonitor->rcWork.right - pMonitor->rcWork.left) * 3 / 4;
1576 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1577 }
1578 }
1579 /* neither x nor cx are default. Check the y values .
1580 * In the trace we see Outlook and Outlook Express using
1581 * cy set to CW_USEDEFAULT when opening the address book.
1582 */
1583 else if (IS_DEFAULT(Cs->cy))
1584 {
1585 TRACE("Strange use of CW_USEDEFAULT in nHeight\n");
1586 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1587 }
1588 }
1589 else
1590 {
1591 /* if CW_USEDEFAULT is set for non-overlapped windows, both values are set to zero */
1592 if(IS_DEFAULT(Cs->x))
1593 {
1594 Cs->x = 0;
1595 Cs->y = 0;
1596 }
1597 if(IS_DEFAULT(Cs->cx))
1598 {
1599 Cs->cx = 0;
1600 Cs->cy = 0;
1601 }
1602 }
1603
1604 #undef IS_DEFAULT
1605 }
1606
1607 /* Allocates and initializes a window */
1608 PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
1609 PLARGE_STRING WindowName,
1610 PCLS Class,
1611 PWND ParentWindow,
1612 PWND OwnerWindow,
1613 PVOID acbiBuffer,
1614 PDESKTOP pdeskCreated)
1615 {
1616 PWND pWnd = NULL;
1617 HWND hWnd;
1618 PTHREADINFO pti = NULL;
1619 BOOL MenuChanged;
1620 BOOL bUnicodeWindow;
1621
1622 pti = pdeskCreated ? gptiDesktopThread : GetW32ThreadInfo();
1623
1624 if (!(Cs->dwExStyle & WS_EX_LAYOUTRTL))
1625 { // Need both here for wine win.c test_CreateWindow.
1626 //if (Cs->hwndParent && ParentWindow)
1627 if (ParentWindow) // It breaks more tests..... WIP.
1628 {
1629 if ( (Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD &&
1630 ParentWindow->ExStyle & WS_EX_LAYOUTRTL &&
1631 !(ParentWindow->ExStyle & WS_EX_NOINHERITLAYOUT) )
1632 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1633 }
1634 else
1635 { /*
1636 * Note from MSDN <http://msdn.microsoft.com/en-us/library/aa913269.aspx>:
1637 *
1638 * Dialog boxes and message boxes do not inherit layout, so you must
1639 * set the layout explicitly.
1640 */
1641 if ( Class->fnid != FNID_DIALOG )
1642 {
1643 if (pti->ppi->dwLayout & LAYOUT_RTL)
1644 {
1645 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1646 }
1647 }
1648 }
1649 }
1650
1651 /* Automatically add WS_EX_WINDOWEDGE */
1652 if ((Cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1653 ((!(Cs->dwExStyle & WS_EX_STATICEDGE)) &&
1654 (Cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1655 Cs->dwExStyle |= WS_EX_WINDOWEDGE;
1656 else
1657 Cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1658
1659 /* Is it a unicode window? */
1660 bUnicodeWindow =!(Cs->dwExStyle & WS_EX_SETANSICREATOR);
1661 Cs->dwExStyle &= ~WS_EX_SETANSICREATOR;
1662
1663 /* Allocate the new window */
1664 pWnd = (PWND) UserCreateObject( gHandleTable,
1665 pdeskCreated ? pdeskCreated : pti->rpdesk,
1666 pti,
1667 (PHANDLE)&hWnd,
1668 TYPE_WINDOW,
1669 sizeof(WND) + Class->cbwndExtra);
1670
1671 if (!pWnd)
1672 {
1673 goto AllocError;
1674 }
1675
1676 TRACE("Created window object with handle %p\n", hWnd);
1677
1678 if (pdeskCreated && pdeskCreated->DesktopWindow == NULL )
1679 { /* HACK: Helper for win32csr/desktopbg.c */
1680 /* If there is no desktop window yet, we must be creating it */
1681 TRACE("CreateWindow setting desktop.\n");
1682 pdeskCreated->DesktopWindow = hWnd;
1683 pdeskCreated->pDeskInfo->spwnd = pWnd;
1684 }
1685
1686 /*
1687 * Fill out the structure describing it.
1688 */
1689 /* Remember, pWnd->head is setup in object.c ... */
1690 pWnd->spwndParent = ParentWindow;
1691 pWnd->spwndOwner = OwnerWindow;
1692 pWnd->fnid = 0;
1693 pWnd->spwndLastActive = pWnd;
1694 pWnd->state2 |= WNDS2_WIN40COMPAT; // FIXME!!!
1695 pWnd->pcls = Class;
1696 pWnd->hModule = Cs->hInstance;
1697 pWnd->style = Cs->style & ~WS_VISIBLE;
1698 pWnd->ExStyle = Cs->dwExStyle;
1699 pWnd->cbwndExtra = pWnd->pcls->cbwndExtra;
1700 pWnd->pActCtx = acbiBuffer;
1701 pWnd->InternalPos.MaxPos.x = pWnd->InternalPos.MaxPos.y = -1;
1702 pWnd->InternalPos.IconPos.x = pWnd->InternalPos.IconPos.y = -1;
1703
1704 if (pWnd->spwndParent != NULL && Cs->hwndParent != 0)
1705 {
1706 pWnd->HideFocus = pWnd->spwndParent->HideFocus;
1707 pWnd->HideAccel = pWnd->spwndParent->HideAccel;
1708 }
1709
1710 pWnd->head.pti->cWindows++;
1711
1712 if (Class->hIcon && !Class->hIconSm)
1713 {
1714 Class->hIconSmIntern = co_IntCopyImage( Class->hIcon, IMAGE_ICON,
1715 UserGetSystemMetrics( SM_CXSMICON ),
1716 UserGetSystemMetrics( SM_CYSMICON ), 0 );
1717 TRACE("IntCreateWindow hIconSmIntern %p\n",Class->hIconSmIntern);
1718 Class->CSF_flags |= CSF_CACHEDSMICON;
1719 }
1720
1721 if (pWnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
1722 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
1723
1724 /* BugBoy Comments: Comment below say that System classes are always created
1725 as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
1726 sets the window to ansi as verified by testing with IsUnicodeWindow API.
1727
1728 No where can I see in code or through testing does the window change back
1729 to ANSI after being created as UNICODE in ROS. I didnt do more testing to
1730 see what problems this would cause. */
1731
1732 // Set WndProc from Class.
1733 pWnd->lpfnWndProc = pWnd->pcls->lpfnWndProc;
1734
1735 // GetWindowProc, test for non server side default classes and set WndProc.
1736 if ( pWnd->pcls->fnid <= FNID_GHOST && pWnd->pcls->fnid >= FNID_BUTTON )
1737 {
1738 if (bUnicodeWindow)
1739 {
1740 if (GETPFNCLIENTA(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1741 pWnd->lpfnWndProc = GETPFNCLIENTW(pWnd->pcls->fnid);
1742 }
1743 else
1744 {
1745 if (GETPFNCLIENTW(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1746 pWnd->lpfnWndProc = GETPFNCLIENTA(pWnd->pcls->fnid);
1747 }
1748 }
1749
1750 // If not an Unicode caller, set Ansi creator bit.
1751 if (!bUnicodeWindow) pWnd->state |= WNDS_ANSICREATOR;
1752
1753 // Clone Class Ansi/Unicode proc type.
1754 if (pWnd->pcls->CSF_flags & CSF_ANSIPROC)
1755 {
1756 pWnd->state |= WNDS_ANSIWINDOWPROC;
1757 pWnd->Unicode = FALSE;
1758 }
1759 else
1760 { /*
1761 * It seems there can be both an Ansi creator and Unicode Class Window
1762 * WndProc, unless the following overriding conditions occur:
1763 */
1764 if ( !bUnicodeWindow &&
1765 ( Class->atomClassName == gpsi->atomSysClass[ICLS_BUTTON] ||
1766 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX] ||
1767 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOLBOX] ||
1768 Class->atomClassName == gpsi->atomSysClass[ICLS_DIALOG] ||
1769 Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT] ||
1770 Class->atomClassName == gpsi->atomSysClass[ICLS_IME] ||
1771 Class->atomClassName == gpsi->atomSysClass[ICLS_LISTBOX] ||
1772 Class->atomClassName == gpsi->atomSysClass[ICLS_MDICLIENT] ||
1773 Class->atomClassName == gpsi->atomSysClass[ICLS_STATIC] ) )
1774 { // Override Class and set the window Ansi WndProc.
1775 pWnd->state |= WNDS_ANSIWINDOWPROC;
1776 pWnd->Unicode = FALSE;
1777 }
1778 else
1779 { // Set the window Unicode WndProc.
1780 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
1781 pWnd->Unicode = TRUE;
1782 }
1783 }
1784
1785 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
1786 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
1787 Dont understand why it does this. */
1788 if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT])
1789 {
1790 PCALLPROCDATA CallProc;
1791 CallProc = CreateCallProc(NULL, pWnd->lpfnWndProc, pWnd->Unicode , pWnd->head.pti->ppi);
1792
1793 if (!CallProc)
1794 {
1795 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1796 ERR("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %p\n", hWnd);
1797 }
1798 else
1799 {
1800 UserAddCallProcToClass(pWnd->pcls, CallProc);
1801 }
1802 }
1803
1804 InitializeListHead(&pWnd->PropListHead);
1805
1806 if ( WindowName->Buffer != NULL && WindowName->Length > 0 )
1807 {
1808 pWnd->strName.Buffer = DesktopHeapAlloc(pWnd->head.rpdesk,
1809 WindowName->Length + sizeof(UNICODE_NULL));
1810 if (pWnd->strName.Buffer == NULL)
1811 {
1812 goto AllocError;
1813 }
1814
1815 RtlCopyMemory(pWnd->strName.Buffer, WindowName->Buffer, WindowName->Length);
1816 pWnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
1817 pWnd->strName.Length = WindowName->Length;
1818 pWnd->strName.MaximumLength = WindowName->Length + sizeof(UNICODE_NULL);
1819 }
1820
1821 /* Correct the window style. */
1822 if ((pWnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1823 {
1824 pWnd->style |= WS_CLIPSIBLINGS;
1825 if (!(pWnd->style & WS_POPUP))
1826 {
1827 pWnd->style |= WS_CAPTION;
1828 }
1829 }
1830
1831 /* WS_EX_WINDOWEDGE depends on some other styles */
1832 if (pWnd->ExStyle & WS_EX_DLGMODALFRAME)
1833 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1834 else if (pWnd->style & (WS_DLGFRAME | WS_THICKFRAME))
1835 {
1836 if (!((pWnd->ExStyle & WS_EX_STATICEDGE) &&
1837 (pWnd->style & (WS_CHILD | WS_POPUP))))
1838 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1839 }
1840 else
1841 pWnd->ExStyle &= ~WS_EX_WINDOWEDGE;
1842
1843 if (!(pWnd->style & (WS_CHILD | WS_POPUP)))
1844 pWnd->state |= WNDS_SENDSIZEMOVEMSGS;
1845
1846 /* Set the window menu */
1847 if ((Cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1848 {
1849 if (Cs->hMenu)
1850 {
1851 IntSetMenu(pWnd, Cs->hMenu, &MenuChanged);
1852 }
1853 else if (pWnd->pcls->lpszMenuName) // Take it from the parent.
1854 {
1855 UNICODE_STRING MenuName;
1856 HMENU hMenu;
1857
1858 if (IS_INTRESOURCE(pWnd->pcls->lpszMenuName))
1859 {
1860 MenuName.Length = 0;
1861 MenuName.MaximumLength = 0;
1862 MenuName.Buffer = pWnd->pcls->lpszMenuName;
1863 }
1864 else
1865 {
1866 RtlInitUnicodeString( &MenuName, pWnd->pcls->lpszMenuName);
1867 }
1868 hMenu = co_IntCallLoadMenu( pWnd->pcls->hModule, &MenuName);
1869 if (hMenu) IntSetMenu(pWnd, hMenu, &MenuChanged);
1870 }
1871 }
1872 else // Not a child
1873 pWnd->IDMenu = (UINT) Cs->hMenu;
1874
1875
1876 if ( ParentWindow &&
1877 ParentWindow != ParentWindow->head.rpdesk->spwndMessage &&
1878 ParentWindow != ParentWindow->head.rpdesk->pDeskInfo->spwnd )
1879 {
1880 PWND Owner = IntGetNonChildAncestor(ParentWindow);
1881
1882 if (!IntValidateOwnerDepth(pWnd, Owner))
1883 {
1884 EngSetLastError(ERROR_INVALID_PARAMETER);
1885 goto Error;
1886 }
1887 if ( pWnd->spwndOwner &&
1888 pWnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1889 {
1890 pWnd->ExStyle |= WS_EX_TOPMOST;
1891 }
1892 if ( pWnd->spwndOwner &&
1893 Class->atomClassName != gpsi->atomSysClass[ICLS_IME] &&
1894 pti != pWnd->spwndOwner->head.pti)
1895 {
1896 //ERR("CreateWindow Owner in.\n");
1897 UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE);
1898 }
1899 }
1900
1901 /* Insert the window into the thread's window list. */
1902 InsertTailList (&pti->WindowListHead, &pWnd->ThreadListEntry);
1903
1904 /* Handle "CS_CLASSDC", it is tested first. */
1905 if ( (pWnd->pcls->style & CS_CLASSDC) && !(pWnd->pcls->pdce) )
1906 { /* One DCE per class to have CLASS. */
1907 pWnd->pcls->pdce = DceAllocDCE( pWnd, DCE_CLASS_DC );
1908 }
1909 else if ( pWnd->pcls->style & CS_OWNDC)
1910 { /* Allocate a DCE for this window. */
1911 DceAllocDCE(pWnd, DCE_WINDOW_DC);
1912 }
1913
1914 return pWnd;
1915
1916 AllocError:
1917 ERR("IntCreateWindow Allocation Error.\n");
1918 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1919 Error:
1920 if(pWnd)
1921 UserDereferenceObject(pWnd);
1922 return NULL;
1923 }
1924
1925 /*
1926 * @implemented
1927 */
1928 PWND FASTCALL
1929 co_UserCreateWindowEx(CREATESTRUCTW* Cs,
1930 PUNICODE_STRING ClassName,
1931 PLARGE_STRING WindowName,
1932 PVOID acbiBuffer)
1933 {
1934 ULONG style;
1935 PWND Window = NULL, ParentWindow = NULL, OwnerWindow;
1936 HWND hWnd, hWndParent, hWndOwner, hwndInsertAfter;
1937 PWINSTATION_OBJECT WinSta;
1938 PCLS Class = NULL;
1939 SIZE Size;
1940 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
1941 CBT_CREATEWNDW * pCbtCreate;
1942 LRESULT Result;
1943 USER_REFERENCE_ENTRY ParentRef, Ref;
1944 PTHREADINFO pti;
1945 DWORD dwShowMode = SW_SHOW;
1946 CREATESTRUCTW *pCsw = NULL;
1947 PVOID pszClass = NULL, pszName = NULL;
1948 PWND ret = NULL;
1949
1950 /* Get the current window station and reference it */
1951 pti = GetW32ThreadInfo();
1952 if (pti == NULL || pti->rpdesk == NULL)
1953 {
1954 ERR("Thread is not attached to a desktop! Cannot create window!\n");
1955 return NULL; // There is nothing to cleanup.
1956 }
1957 WinSta = pti->rpdesk->rpwinstaParent;
1958 ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
1959
1960 pCsw = NULL;
1961 pCbtCreate = NULL;
1962
1963 /* Get the class and reference it */
1964 Class = IntGetAndReferenceClass(ClassName, Cs->hInstance, FALSE);
1965 if(!Class)
1966 {
1967 ERR("Failed to find class %wZ\n", ClassName);
1968 goto cleanup;
1969 }
1970
1971 /* Now find the parent and the owner window */
1972 hWndParent = pti->rpdesk->pDeskInfo->spwnd->head.h;
1973 hWndOwner = NULL;
1974
1975 if (Cs->hwndParent == HWND_MESSAGE)
1976 {
1977 Cs->hwndParent = hWndParent = pti->rpdesk->spwndMessage->head.h;
1978 }
1979 else if (Cs->hwndParent)
1980 {
1981 if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1982 hWndOwner = Cs->hwndParent;
1983 else
1984 hWndParent = Cs->hwndParent;
1985 }
1986 else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1987 {
1988 ERR("Cannot create a child window without a parrent!\n");
1989 EngSetLastError(ERROR_TLW_WITH_WSCHILD);
1990 goto cleanup; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1991 }
1992
1993 ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
1994 OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
1995
1996 /* FIXME: Is this correct? */
1997 if(OwnerWindow)
1998 OwnerWindow = UserGetAncestor(OwnerWindow, GA_ROOT);
1999
2000 /* Fix the position and the size of the window */
2001 if (ParentWindow)
2002 {
2003 UserRefObjectCo(ParentWindow, &ParentRef);
2004 IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode);
2005 }
2006
2007 /* Allocate and initialize the new window */
2008 Window = IntCreateWindow(Cs,
2009 WindowName,
2010 Class,
2011 ParentWindow,
2012 OwnerWindow,
2013 acbiBuffer,
2014 NULL);
2015 if(!Window)
2016 {
2017 ERR("IntCreateWindow failed!\n");
2018 goto cleanup;
2019 }
2020
2021 hWnd = UserHMGetHandle(Window);
2022 hwndInsertAfter = HWND_TOP;
2023
2024 UserRefObjectCo(Window, &Ref);
2025 UserDereferenceObject(Window);
2026 ObDereferenceObject(WinSta);
2027
2028 //// Check for a hook to eliminate overhead. ////
2029 if ( ISITHOOKED(WH_CBT) || (pti->rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)) )
2030 {
2031 // Allocate the calling structures Justin Case this goes Global.
2032 pCsw = ExAllocatePoolWithTag(NonPagedPool, sizeof(CREATESTRUCTW), TAG_HOOK);
2033 pCbtCreate = ExAllocatePoolWithTag(NonPagedPool, sizeof(CBT_CREATEWNDW), TAG_HOOK);
2034 if (!pCsw || !pCbtCreate)
2035 {
2036 ERR("UserHeapAlloc() failed!\n");
2037 goto cleanup;
2038 }
2039
2040 /* Fill the new CREATESTRUCTW */
2041 RtlCopyMemory(pCsw, Cs, sizeof(CREATESTRUCTW));
2042 pCsw->style = Window->style; /* HCBT_CREATEWND needs the real window style */
2043
2044 // Based on the assumption this is from "unicode source" user32, ReactOS, answer is yes.
2045 if (!IS_ATOM(ClassName->Buffer))
2046 {
2047 if (Window->state & WNDS_ANSICREATOR)
2048 {
2049 ANSI_STRING AnsiString;
2050 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(ClassName)+sizeof(CHAR);
2051 pszClass = UserHeapAlloc(AnsiString.MaximumLength);
2052 if (!pszClass)
2053 {
2054 ERR("UserHeapAlloc() failed!\n");
2055 goto cleanup;
2056 }
2057 RtlZeroMemory(pszClass, AnsiString.MaximumLength);
2058 AnsiString.Buffer = (PCHAR)pszClass;
2059 RtlUnicodeStringToAnsiString(&AnsiString, ClassName, FALSE);
2060 }
2061 else
2062 {
2063 UNICODE_STRING UnicodeString;
2064 UnicodeString.MaximumLength = ClassName->Length + sizeof(UNICODE_NULL);
2065 pszClass = UserHeapAlloc(UnicodeString.MaximumLength);
2066 if (!pszClass)
2067 {
2068 ERR("UserHeapAlloc() failed!\n");
2069 goto cleanup;
2070 }
2071 RtlZeroMemory(pszClass, UnicodeString.MaximumLength);
2072 UnicodeString.Buffer = (PWSTR)pszClass;
2073 RtlCopyUnicodeString(&UnicodeString, ClassName);
2074 }
2075 pCsw->lpszClass = UserHeapAddressToUser(pszClass);
2076 }
2077 if (WindowName->Length)
2078 {
2079 UNICODE_STRING Name;
2080 Name.Buffer = WindowName->Buffer;
2081 Name.Length = (USHORT)min(WindowName->Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2082 Name.MaximumLength = (USHORT)min(WindowName->MaximumLength, MAXUSHORT);
2083
2084 if (Window->state & WNDS_ANSICREATOR)
2085 {
2086 ANSI_STRING AnsiString;
2087 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(&Name) + sizeof(CHAR);
2088 pszName = UserHeapAlloc(AnsiString.MaximumLength);
2089 if (!pszName)
2090 {
2091 ERR("UserHeapAlloc() failed!\n");
2092 goto cleanup;
2093 }
2094 RtlZeroMemory(pszName, AnsiString.MaximumLength);
2095 AnsiString.Buffer = (PCHAR)pszName;
2096 RtlUnicodeStringToAnsiString(&AnsiString, &Name, FALSE);
2097 }
2098 else
2099 {
2100 UNICODE_STRING UnicodeString;
2101 UnicodeString.MaximumLength = Name.Length + sizeof(UNICODE_NULL);
2102 pszName = UserHeapAlloc(UnicodeString.MaximumLength);
2103 if (!pszName)
2104 {
2105 ERR("UserHeapAlloc() failed!\n");
2106 goto cleanup;
2107 }
2108 RtlZeroMemory(pszName, UnicodeString.MaximumLength);
2109 UnicodeString.Buffer = (PWSTR)pszName;
2110 RtlCopyUnicodeString(&UnicodeString, &Name);
2111 }
2112 pCsw->lpszName = UserHeapAddressToUser(pszName);
2113 }
2114
2115 pCbtCreate->lpcs = pCsw;
2116 pCbtCreate->hwndInsertAfter = hwndInsertAfter;
2117
2118 //// Call the WH_CBT hook ////
2119 Result = co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) pCbtCreate);
2120 if (Result != 0)
2121 {
2122 ERR("WH_CBT HCBT_CREATEWND hook failed! 0x%x\n", Result);
2123 goto cleanup;
2124 }
2125 // Write back changes.
2126 Cs->cx = pCsw->cx;
2127 Cs->cy = pCsw->cy;
2128 Cs->x = pCsw->x;
2129 Cs->y = pCsw->y;
2130 hwndInsertAfter = pCbtCreate->hwndInsertAfter;
2131 }
2132
2133 /* NCCREATE and WM_NCCALCSIZE need the original values */
2134 Cs->lpszName = (LPCWSTR) WindowName;
2135 Cs->lpszClass = (LPCWSTR) ClassName;
2136
2137 if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2138 {
2139 if (ParentWindow != co_GetDesktopWindow(Window))
2140 {
2141 Cs->x += ParentWindow->rcClient.left;
2142 Cs->y += ParentWindow->rcClient.top;
2143 }
2144 }
2145
2146 /* Send the WM_GETMINMAXINFO message */
2147 Size.cx = Cs->cx;
2148 Size.cy = Cs->cy;
2149
2150 if ((Cs->style & WS_THICKFRAME) || !(Cs->style & (WS_POPUP | WS_CHILD)))
2151 {
2152 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
2153 if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
2154 if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
2155 if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
2156 if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
2157 }
2158
2159 Window->rcWindow.left = Cs->x;
2160 Window->rcWindow.top = Cs->y;
2161 Window->rcWindow.right = Cs->x + Size.cx;
2162 Window->rcWindow.bottom = Cs->y + Size.cy;
2163 /*
2164 if (0 != (Window->style & WS_CHILD) && ParentWindow)
2165 {
2166 ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
2167 RECTL_vOffsetRect(&Window->rcWindow,
2168 ParentWindow->rcClient.left,
2169 ParentWindow->rcClient.top);
2170 }
2171 */
2172 /* correct child window coordinates if mirroring on parent is enabled */
2173 if (ParentWindow != NULL)
2174 {
2175 if ( ((Cs->style & WS_CHILD) == WS_CHILD) &&
2176 ((ParentWindow->ExStyle & WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL))
2177 {
2178 Window->rcWindow.right = ParentWindow->rcClient.right - (Window->rcWindow.left - ParentWindow->rcClient.left);
2179 Window->rcWindow.left = Window->rcWindow.right - Size.cx;
2180 }
2181 }
2182
2183 Window->rcClient = Window->rcWindow;
2184
2185 /* Link the window */
2186 if (NULL != ParentWindow)
2187 {
2188 /* Link the window into the siblings list */
2189 if ((Cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2190 IntLinkHwnd(Window, HWND_BOTTOM);
2191 else
2192 IntLinkHwnd(Window, hwndInsertAfter);
2193 }
2194
2195 if (!(Window->state2 & WNDS2_WIN31COMPAT))
2196 {
2197 if (Class->style & CS_PARENTDC && !(ParentWindow->style & WS_CLIPCHILDREN))
2198 Window->style &= ~(WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
2199 }
2200
2201 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2202 {
2203 if ( !IntIsTopLevelWindow(Window) )
2204 {
2205 if (pti != Window->spwndParent->head.pti)
2206 {
2207 //ERR("CreateWindow Parent in.\n");
2208 UserAttachThreadInput(pti, Window->spwndParent->head.pti, TRUE);
2209 }
2210 }
2211 }
2212
2213 /* Send the NCCREATE message */
2214 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_NCCREATE, 0, (LPARAM) Cs);
2215 if (!Result)
2216 {
2217 ERR("co_UserCreateWindowEx(): NCCREATE message failed\n");
2218 goto cleanup;
2219 }
2220
2221 /* Send the WM_NCCALCSIZE message */
2222 {
2223 // RECT rc;
2224 MaxPos.x = Window->rcWindow.left;
2225 MaxPos.y = Window->rcWindow.top;
2226
2227 Result = co_WinPosGetNonClientSize(Window, &Window->rcWindow, &Window->rcClient);
2228 //rc = Window->rcWindow;
2229 //Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM)&rc);
2230 //Window->rcClient = rc;
2231
2232 RECTL_vOffsetRect(&Window->rcWindow, MaxPos.x - Window->rcWindow.left,
2233 MaxPos.y - Window->rcWindow.top);
2234 }
2235
2236 /* Send the WM_CREATE message. */
2237 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_CREATE, 0, (LPARAM) Cs);
2238 if (Result == (LRESULT)-1)
2239 {
2240 ERR("co_UserCreateWindowEx(): WM_CREATE message failed\n");
2241 goto cleanup;
2242 }
2243
2244 /* Send the EVENT_OBJECT_CREATE event */
2245 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2246
2247 /* By setting the flag below it can be examined to determine if the window
2248 was created successfully and a valid pwnd was passed back to caller since
2249 from here the function has to succeed. */
2250 Window->state2 |= WNDS2_WMCREATEMSGPROCESSED;
2251
2252 /* Send the WM_SIZE and WM_MOVE messages. */
2253 if (!(Window->state & WNDS_SENDSIZEMOVEMSGS))
2254 {
2255 co_WinPosSendSizeMove(Window);
2256 }
2257
2258 /* Show or maybe minimize or maximize the window. */
2259
2260 style = IntSetStyle( Window, 0, WS_MAXIMIZE | WS_MINIMIZE );
2261 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2262 {
2263 RECTL NewPos;
2264 UINT SwFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
2265
2266 SwFlag = co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2267 SwFlag |= SWP_NOZORDER|SWP_FRAMECHANGED; /* Frame always gets changed */
2268 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || UserGetActiveWindow()) SwFlag |= SWP_NOACTIVATE;
2269 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2270 NewPos.right, NewPos.bottom, SwFlag);
2271 }
2272
2273 /* Send the WM_PARENTNOTIFY message */
2274 IntSendParentNotify(Window, WM_CREATE);
2275
2276 /* Notify the shell that a new window was created */
2277 if (Window->spwndParent == UserGetDesktopWindow() &&
2278 Window->spwndOwner == NULL &&
2279 (Window->style & WS_VISIBLE) &&
2280 (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
2281 (Window->ExStyle & WS_EX_APPWINDOW)))
2282 {
2283 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0);
2284 }
2285
2286 /* Initialize and show the window's scrollbars */
2287 if (Window->style & WS_VSCROLL)
2288 {
2289 co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE);
2290 }
2291 if (Window->style & WS_HSCROLL)
2292 {
2293 co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE);
2294 }
2295
2296 /* Show the new window */
2297 if (Cs->style & WS_VISIBLE)
2298 {
2299 if (Window->style & WS_MAXIMIZE)
2300 dwShowMode = SW_SHOW;
2301 else if (Window->style & WS_MINIMIZE)
2302 dwShowMode = SW_SHOWMINIMIZED;
2303
2304 co_WinPosShowWindow(Window, dwShowMode);
2305
2306 if (Window->ExStyle & WS_EX_MDICHILD)
2307 {
2308 ASSERT(ParentWindow);
2309 if(!ParentWindow)
2310 goto cleanup;
2311 co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0);
2312 /* ShowWindow won't activate child windows */
2313 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2314 }
2315 }
2316
2317 TRACE("co_UserCreateWindowEx(): Created window %p\n", hWnd);
2318 ret = Window;
2319
2320 cleanup:
2321 if (!ret)
2322 {
2323 TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2324 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2325 if (Window)
2326 co_UserDestroyWindow(Window);
2327 else if (Class)
2328 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2329 }
2330
2331 if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
2332 if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
2333 if (pszName) UserHeapFree(pszName);
2334 if (pszClass) UserHeapFree(pszClass);
2335
2336 if (Window)
2337 {
2338 UserDerefObjectCo(Window);
2339 }
2340 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2341
2342 return ret;
2343 }
2344
2345 NTSTATUS
2346 NTAPI
2347 ProbeAndCaptureLargeString(
2348 OUT PLARGE_STRING plstrSafe,
2349 IN PLARGE_STRING plstrUnsafe)
2350 {
2351 LARGE_STRING lstrTemp;
2352 PVOID pvBuffer = NULL;
2353
2354 _SEH2_TRY
2355 {
2356 /* Probe and copy the string */
2357 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2358 lstrTemp = *plstrUnsafe;
2359 }
2360 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2361 {
2362 /* Fail */
2363 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2364 }
2365 _SEH2_END
2366
2367 if (lstrTemp.Length != 0)
2368 {
2369 /* Allocate a buffer from paged pool */
2370 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2371 if (!pvBuffer)
2372 {
2373 return STATUS_NO_MEMORY;
2374 }
2375
2376 _SEH2_TRY
2377 {
2378 /* Probe and copy the buffer */
2379 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2380 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2381 }
2382 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2383 {
2384 /* Cleanup and fail */
2385 ExFreePoolWithTag(pvBuffer, TAG_STRING);
2386 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2387 }
2388 _SEH2_END
2389 }
2390
2391 /* Set the output string */
2392 plstrSafe->Buffer = pvBuffer;
2393 plstrSafe->Length = lstrTemp.Length;
2394 plstrSafe->MaximumLength = lstrTemp.Length;
2395
2396 return STATUS_SUCCESS;
2397 }
2398
2399 /**
2400 * \todo Allow passing plstrClassName as ANSI.
2401 */
2402 HWND
2403 NTAPI
2404 NtUserCreateWindowEx(
2405 DWORD dwExStyle,
2406 PLARGE_STRING plstrClassName,
2407 PLARGE_STRING plstrClsVersion,
2408 PLARGE_STRING plstrWindowName,
2409 DWORD dwStyle,
2410 int x,
2411 int y,
2412 int nWidth,
2413 int nHeight,
2414 HWND hWndParent,
2415 HMENU hMenu,
2416 HINSTANCE hInstance,
2417 LPVOID lpParam,
2418 DWORD dwFlags,
2419 PVOID acbiBuffer)
2420 {
2421 NTSTATUS Status;
2422 LARGE_STRING lstrWindowName;
2423 LARGE_STRING lstrClassName;
2424 UNICODE_STRING ustrClassName;
2425 CREATESTRUCTW Cs;
2426 HWND hwnd = NULL;
2427 PWND pwnd;
2428
2429 lstrWindowName.Buffer = NULL;
2430 lstrClassName.Buffer = NULL;
2431
2432 ASSERT(plstrWindowName);
2433
2434 if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2435 {
2436 /* check hMenu is valid handle */
2437 if (hMenu && !ValidateHandle(hMenu, TYPE_MENU))
2438 {
2439 /* error is set in ValidateHandle */
2440 return NULL;
2441 }
2442 }
2443
2444 /* Copy the window name to kernel mode */
2445 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2446 if (!NT_SUCCESS(Status))
2447 {
2448 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2449 SetLastNtError(Status);
2450 return NULL;
2451 }
2452
2453 plstrWindowName = &lstrWindowName;
2454
2455 /* Check if the class is an atom */
2456 if (IS_ATOM(plstrClassName))
2457 {
2458 /* It is, pass the atom in the UNICODE_STRING */
2459 ustrClassName.Buffer = (PVOID)plstrClassName;
2460 ustrClassName.Length = 0;
2461 ustrClassName.MaximumLength = 0;
2462 }
2463 else
2464 {
2465 /* It's not, capture the class name */
2466 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2467 if (!NT_SUCCESS(Status))
2468 {
2469 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2470 /* Set last error, cleanup and return */
2471 SetLastNtError(Status);
2472 goto cleanup;
2473 }
2474
2475 /* We pass it on as a UNICODE_STRING */
2476 ustrClassName.Buffer = lstrClassName.Buffer;
2477 ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2478 ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
2479 }
2480
2481 /* Fill the CREATESTRUCTW */
2482 /* we will keep here the original parameters */
2483 Cs.style = dwStyle;
2484 Cs.lpCreateParams = lpParam;
2485 Cs.hInstance = hInstance;
2486 Cs.hMenu = hMenu;
2487 Cs.hwndParent = hWndParent;
2488 Cs.cx = nWidth;
2489 Cs.cy = nHeight;
2490 Cs.x = x;
2491 Cs.y = y;
2492 Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
2493 if (IS_ATOM(plstrClassName))
2494 Cs.lpszClass = (LPCWSTR) plstrClassName;
2495 else
2496 Cs.lpszClass = (LPCWSTR) plstrClassName->Buffer;
2497 Cs.dwExStyle = dwExStyle;
2498
2499 UserEnterExclusive();
2500
2501 /* Call the internal function */
2502 pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName, acbiBuffer);
2503
2504 if(!pwnd)
2505 {
2506 ERR("co_UserCreateWindowEx failed!\n");
2507 }
2508 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2509
2510 UserLeave();
2511
2512 cleanup:
2513 if (lstrWindowName.Buffer)
2514 {
2515 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2516 }
2517 if (lstrClassName.Buffer)
2518 {
2519 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2520 }
2521
2522 return hwnd;
2523 }
2524
2525
2526 BOOLEAN FASTCALL co_UserDestroyWindow(PWND Window)
2527 {
2528 HWND hWnd;
2529 PWND pwndTemp;
2530 PTHREADINFO ti;
2531 MSG msg;
2532
2533 ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
2534
2535 hWnd = Window->head.h;
2536 ti = PsGetCurrentThreadWin32Thread();
2537
2538 TRACE("co_UserDestroyWindow \n");
2539
2540 /* Check for owner thread */
2541 if ( Window->head.pti != PsGetCurrentThreadWin32Thread())
2542 {
2543 /* Check if we are destroying the desktop window */
2544 if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
2545 {
2546 EngSetLastError(ERROR_ACCESS_DENIED);
2547 return FALSE;
2548 }
2549 }
2550
2551 /* If window was created successfully and it is hooked */
2552 if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
2553 {
2554 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0))
2555 {
2556 ERR("Destroy Window WH_CBT Call Hook return!\n");
2557 return FALSE;
2558 }
2559 }
2560
2561 if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
2562 {
2563 if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2564 {
2565 if (Window->spwndOwner)
2566 {
2567 //ERR("DestroyWindow Owner out.\n");
2568 UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2569 }
2570 }
2571 }
2572
2573 /* Inform the parent */
2574 if (Window->style & WS_CHILD)
2575 {
2576 IntSendParentNotify(Window, WM_DESTROY);
2577 }
2578
2579 /* Look whether the focus is within the tree of windows we will
2580 * be destroying.
2581 */
2582 if (!co_WinPosShowWindow(Window, SW_HIDE))
2583 { // Rule #1.
2584 if (ti->MessageQueue->spwndActive == Window && ti->MessageQueue == IntGetFocusMessageQueue())
2585 {
2586 co_WinPosActivateOtherWindow(Window);
2587 }
2588 }
2589
2590 // Adjust last active.
2591 if ((pwndTemp = Window->spwndOwner))
2592 {
2593 while (pwndTemp->spwndOwner)
2594 pwndTemp = pwndTemp->spwndOwner;
2595
2596 if (pwndTemp->spwndLastActive == Window)
2597 pwndTemp->spwndLastActive = Window->spwndOwner;
2598 }
2599
2600 if (Window->spwndParent && IntIsWindow(Window->head.h))
2601 {
2602 if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
2603 {
2604 if (!IntIsTopLevelWindow(Window))
2605 {
2606 //ERR("DestroyWindow Parent out.\n");
2607 UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2608 }
2609 }
2610 }
2611
2612 if (Window->head.pti->MessageQueue->spwndActive == Window)
2613 Window->head.pti->MessageQueue->spwndActive = NULL;
2614 if (Window->head.pti->MessageQueue->spwndFocus == Window)
2615 Window->head.pti->MessageQueue->spwndFocus = NULL;
2616 if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
2617 Window->head.pti->MessageQueue->spwndActivePrev = NULL;
2618 if (Window->head.pti->MessageQueue->spwndCapture == Window)
2619 Window->head.pti->MessageQueue->spwndCapture = NULL;
2620
2621 /*
2622 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2623 */
2624
2625 if ((ti != NULL) && (ti->pDeskInfo != NULL))
2626 {
2627 if (ti->pDeskInfo->hShellWindow == hWnd)
2628 {
2629 ERR("Destroying the ShellWindow!\n");
2630 ti->pDeskInfo->hShellWindow = NULL;
2631 }
2632 }
2633
2634 IntEngWindowChanged(Window, WOC_DELETE);
2635
2636 if (!IntIsWindow(Window->head.h))
2637 {
2638 return TRUE;
2639 }
2640
2641 /* Recursively destroy owned windows */
2642
2643 if (! (Window->style & WS_CHILD))
2644 {
2645 for (;;)
2646 {
2647 BOOL GotOne = FALSE;
2648 HWND *Children;
2649 HWND *ChildHandle;
2650 PWND Child, Desktop;
2651
2652 Desktop = IntIsDesktopWindow(Window) ? Window :
2653 UserGetWindowObject(IntGetDesktopWindow());
2654 Children = IntWinListChildren(Desktop);
2655
2656 if (Children)
2657 {
2658 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2659 {
2660 Child = UserGetWindowObject(*ChildHandle);
2661 if (Child == NULL)
2662 continue;
2663 if (Child->spwndOwner != Window)
2664 {
2665 continue;
2666 }
2667
2668 if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
2669 {
2670 USER_REFERENCE_ENTRY ChildRef;
2671 UserRefObjectCo(Child, &ChildRef); // Temp HACK?
2672 co_UserDestroyWindow(Child);
2673 UserDerefObjectCo(Child); // Temp HACK?
2674
2675 GotOne = TRUE;
2676 continue;
2677 }
2678
2679 if (Child->spwndOwner != NULL)
2680 {
2681 Child->spwndOwner = NULL;
2682 }
2683
2684 }
2685 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
2686 }
2687 if (! GotOne)
2688 {
2689 break;
2690 }
2691 }
2692 }
2693
2694 /* Generate mouse move message for the next window */
2695 msg.message = WM_MOUSEMOVE;
2696 msg.wParam = UserGetMouseButtonsState();
2697 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2698 msg.pt = gpsi->ptCursor;
2699 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2700
2701 if (!IntIsWindow(Window->head.h))
2702 {
2703 return TRUE;
2704 }
2705
2706 /* Destroy the window storage */
2707 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2708
2709 return TRUE;
2710 }
2711
2712
2713 /*
2714 * @implemented
2715 */
2716 BOOLEAN APIENTRY
2717 NtUserDestroyWindow(HWND Wnd)
2718 {
2719 PWND Window;
2720 DECLARE_RETURN(BOOLEAN);
2721 BOOLEAN ret;
2722 USER_REFERENCE_ENTRY Ref;
2723
2724 TRACE("Enter NtUserDestroyWindow\n");
2725 UserEnterExclusive();
2726
2727 if (!(Window = UserGetWindowObject(Wnd)))
2728 {
2729 RETURN(FALSE);
2730 }
2731
2732 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
2733 ret = co_UserDestroyWindow(Window);
2734 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
2735
2736 RETURN(ret);
2737
2738 CLEANUP:
2739 TRACE("Leave NtUserDestroyWindow, ret=%u\n", _ret_);
2740 UserLeave();
2741 END_CLEANUP;
2742 }
2743
2744
2745 static HWND FASTCALL
2746 IntFindWindow(PWND Parent,
2747 PWND ChildAfter,
2748 RTL_ATOM ClassAtom,
2749 PUNICODE_STRING WindowName)
2750 {
2751 BOOL CheckWindowName;
2752 HWND *List, *phWnd;
2753 HWND Ret = NULL;
2754 UNICODE_STRING CurrentWindowName;
2755
2756 ASSERT(Parent);
2757
2758 CheckWindowName = WindowName->Buffer != 0;
2759
2760 if((List = IntWinListChildren(Parent)))
2761 {
2762 phWnd = List;
2763 if(ChildAfter)
2764 {
2765 /* skip handles before and including ChildAfter */
2766 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2767 ;
2768 }
2769
2770 /* search children */
2771 while(*phWnd)
2772 {
2773 PWND Child;
2774 if(!(Child = UserGetWindowObject(*(phWnd++))))
2775 {
2776 continue;
2777 }
2778
2779 /* Do not send WM_GETTEXT messages in the kernel mode version!
2780 The user mode version however calls GetWindowText() which will
2781 send WM_GETTEXT messages to windows belonging to its processes */
2782 if (!ClassAtom || Child->pcls->atomClassName == ClassAtom)
2783 {
2784 // FIXME: LARGE_STRING truncated
2785 CurrentWindowName.Buffer = Child->strName.Buffer;
2786 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
2787 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
2788 if(!CheckWindowName ||
2789 (Child->strName.Length < 0xFFFF &&
2790 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
2791 {
2792 Ret = Child->head.h;
2793 break;
2794 }
2795 }
2796 }
2797 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2798 }
2799
2800 return Ret;
2801 }
2802
2803 /*
2804 * FUNCTION:
2805 * Searches a window's children for a window with the specified
2806 * class and name
2807 * ARGUMENTS:
2808 * hwndParent = The window whose childs are to be searched.
2809 * NULL = desktop
2810 * HWND_MESSAGE = message-only windows
2811 *
2812 * hwndChildAfter = Search starts after this child window.
2813 * NULL = start from beginning
2814 *
2815 * ucClassName = Class name to search for
2816 * Reguired parameter.
2817 *
2818 * ucWindowName = Window name
2819 * ->Buffer == NULL = don't care
2820 *
2821 * RETURNS:
2822 * The HWND of the window if it was found, otherwise NULL
2823 */
2824 /*
2825 * @implemented
2826 */
2827 HWND APIENTRY
2828 NtUserFindWindowEx(HWND hwndParent,
2829 HWND hwndChildAfter,
2830 PUNICODE_STRING ucClassName,
2831 PUNICODE_STRING ucWindowName,
2832 DWORD dwUnknown)
2833 {
2834 PWND Parent, ChildAfter;
2835 UNICODE_STRING ClassName = {0}, WindowName = {0};
2836 HWND Desktop, Ret = NULL;
2837 BOOL DoMessageWnd = FALSE;
2838 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2839 DECLARE_RETURN(HWND);
2840
2841 TRACE("Enter NtUserFindWindowEx\n");
2842 UserEnterShared();
2843
2844 if (ucClassName != NULL || ucWindowName != NULL)
2845 {
2846 _SEH2_TRY
2847 {
2848 if (ucClassName != NULL)
2849 {
2850 ClassName = ProbeForReadUnicodeString(ucClassName);
2851 if (ClassName.Length != 0)
2852 {
2853 ProbeForRead(ClassName.Buffer,
2854 ClassName.Length,
2855 sizeof(WCHAR));
2856 }
2857 else if (!IS_ATOM(ClassName.Buffer))
2858 {
2859 EngSetLastError(ERROR_INVALID_PARAMETER);
2860 _SEH2_LEAVE;
2861 }
2862
2863 if (!IntGetAtomFromStringOrAtom(&ClassName,
2864 &ClassAtom))
2865 {
2866 _SEH2_LEAVE;
2867 }
2868 }
2869
2870 if (ucWindowName != NULL)
2871 {
2872 WindowName = ProbeForReadUnicodeString(ucWindowName);
2873 if (WindowName.Length != 0)
2874 {
2875 ProbeForRead(WindowName.Buffer,
2876 WindowName.Length,
2877 sizeof(WCHAR));
2878 }
2879 }
2880 }
2881 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2882 {
2883 SetLastNtError(_SEH2_GetExceptionCode());
2884 _SEH2_YIELD(RETURN(NULL));
2885 }
2886 _SEH2_END;
2887
2888 if (ucClassName != NULL)
2889 {
2890 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
2891 !IS_ATOM(ClassName.Buffer))
2892 {
2893 EngSetLastError(ERROR_INVALID_PARAMETER);
2894 RETURN(NULL);
2895 }
2896 else if (ClassAtom == (RTL_ATOM)0)
2897 {
2898 /* LastError code was set by IntGetAtomFromStringOrAtom */
2899 RETURN(NULL);
2900 }
2901 }
2902 }
2903
2904 Desktop = IntGetCurrentThreadDesktopWindow();
2905
2906 if(hwndParent == NULL)
2907 {
2908 hwndParent = Desktop;
2909 DoMessageWnd = TRUE;
2910 }
2911 else if(hwndParent == HWND_MESSAGE)
2912 {
2913 hwndParent = IntGetMessageWindow();
2914 }
2915
2916 if(!(Parent = UserGetWindowObject(hwndParent)))
2917 {
2918 RETURN( NULL);
2919 }
2920
2921 ChildAfter = NULL;
2922 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
2923 {
2924 RETURN( NULL);
2925 }
2926
2927 _SEH2_TRY
2928 {
2929 if(Parent->head.h == Desktop)
2930 {
2931 HWND *List, *phWnd;
2932 PWND TopLevelWindow;
2933 BOOLEAN CheckWindowName;
2934 BOOLEAN WindowMatches;
2935 BOOLEAN ClassMatches;
2936
2937 /* windows searches through all top-level windows if the parent is the desktop
2938 window */
2939
2940 if((List = IntWinListChildren(Parent)))
2941 {
2942 phWnd = List;
2943
2944 if(ChildAfter)
2945 {
2946 /* skip handles before and including ChildAfter */
2947 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2948 ;
2949 }
2950
2951 CheckWindowName = WindowName.Buffer != 0;
2952
2953 /* search children */
2954 while(*phWnd)
2955 {
2956 UNICODE_STRING ustr;
2957
2958 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
2959 {
2960 continue;
2961 }
2962
2963 /* Do not send WM_GETTEXT messages in the kernel mode version!
2964 The user mode version however calls GetWindowText() which will
2965 send WM_GETTEXT messages to windows belonging to its processes */
2966 ustr.Buffer = TopLevelWindow->strName.Buffer;
2967 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
2968 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
2969 WindowMatches = !CheckWindowName ||
2970 (TopLevelWindow->strName.Length < 0xFFFF &&
2971 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
2972 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
2973 ClassAtom == TopLevelWindow->pcls->atomClassName;
2974
2975 if (WindowMatches && ClassMatches)
2976 {
2977 Ret = TopLevelWindow->head.h;
2978 break;
2979 }
2980
2981 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
2982 {
2983 /* window returns the handle of the top-level window, in case it found
2984 the child window */
2985 Ret = TopLevelWindow->head.h;
2986 break;
2987 }
2988
2989 }
2990 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2991 }
2992 }
2993 else
2994 {
2995 ERR("FindWindowEx: Not Desktop Parent!\n");
2996 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
2997 }
2998
2999 if (Ret == NULL && DoMessageWnd)
3000 {
3001 PWND MsgWindows;
3002
3003 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3004 {
3005 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3006 }
3007 }
3008 }
3009 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3010 {
3011 SetLastNtError(_SEH2_GetExceptionCode());
3012 Ret = NULL;
3013 }
3014 _SEH2_END;
3015
3016 RETURN( Ret);
3017
3018 CLEANUP:
3019 TRACE("Leave NtUserFindWindowEx, ret %p\n", _ret_);
3020 UserLeave();
3021 END_CLEANUP;
3022 }
3023
3024
3025 /*
3026 * @implemented
3027 */
3028 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
3029 {
3030 PWND WndAncestor, Parent;
3031
3032 if (Wnd->head.h == IntGetDesktopWindow())
3033 {
3034 return NULL;
3035 }
3036
3037 switch (Type)
3038 {
3039 case GA_PARENT:
3040 {
3041 WndAncestor = Wnd->spwndParent;
3042 break;
3043 }
3044
3045 case GA_ROOT:
3046 {
3047 WndAncestor = Wnd;
3048 Parent = NULL;
3049
3050 for(;;)
3051 {
3052 if(!(Parent = WndAncestor->spwndParent))
3053 {
3054 break;
3055 }
3056 if(IntIsDesktopWindow(Parent))
3057 {
3058 break;
3059 }
3060
3061 WndAncestor = Parent;
3062 }
3063 break;
3064 }
3065
3066 case GA_ROOTOWNER:
3067 {
3068 WndAncestor = Wnd;
3069
3070 for (;;)
3071 {
3072 Parent = IntGetParent(WndAncestor);
3073
3074 if (!Parent)
3075 {
3076 break;
3077 }
3078
3079 WndAncestor = Parent;
3080 }
3081 break;
3082 }
3083
3084 default:
3085 {
3086 return NULL;
3087 }
3088 }
3089
3090 return WndAncestor;
3091 }
3092
3093 /*
3094 * @implemented
3095 */
3096 HWND APIENTRY
3097 NtUserGetAncestor(HWND hWnd, UINT Type)
3098 {
3099 PWND Window, Ancestor;
3100 DECLARE_RETURN(HWND);
3101
3102 TRACE("Enter NtUserGetAncestor\n");
3103 UserEnterExclusive();
3104
3105 if (!(Window = UserGetWindowObject(hWnd)))
3106 {
3107 RETURN(NULL);
3108 }
3109
3110 Ancestor = UserGetAncestor(Window, Type);
3111 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3112
3113 RETURN(Ancestor ? Ancestor->head.h : NULL);
3114
3115 CLEANUP:
3116 TRACE("Leave NtUserGetAncestor, ret=%p\n", _ret_);
3117 UserLeave();
3118 END_CLEANUP;
3119 }
3120
3121 ////
3122 //// ReactOS work around! Keep it the sames as in Combo.c and Controls.h
3123 ////
3124 /* combo state struct */
3125 typedef struct
3126 {
3127 HWND self;
3128 HWND owner;
3129 UINT dwStyle;
3130 HWND hWndEdit;
3131 HWND hWndLBox;
3132 UINT wState;
3133 HFONT hFont;
3134 RECT textRect;
3135 RECT buttonRect;
3136 RECT droppedRect;
3137 INT droppedIndex;
3138 INT fixedOwnerDrawHeight;
3139 INT droppedWidth; /* last two are not used unless set */
3140 INT editHeight; /* explicitly */
3141 LONG UIState;
3142 } HEADCOMBO,*LPHEADCOMBO;
3143
3144 // Window Extra data container.
3145 typedef struct _WND2CBOX
3146 {
3147 WND;
3148 LPHEADCOMBO pCBox;
3149 } WND2CBOX, *PWND2CBOX;
3150
3151 #define CBF_BUTTONDOWN 0x0002
3152 ////
3153 ////
3154 ////
3155 BOOL
3156 APIENTRY
3157 NtUserGetComboBoxInfo(
3158 HWND hWnd,
3159 PCOMBOBOXINFO pcbi)
3160 {
3161 PWND Wnd;
3162 PPROCESSINFO ppi;
3163 BOOL NotSameppi = FALSE;
3164 BOOL Ret = TRUE;
3165 DECLARE_RETURN(BOOL);
3166
3167 TRACE("Enter NtUserGetComboBoxInfo\n");
3168 UserEnterShared();
3169
3170 if (!(Wnd = UserGetWindowObject(hWnd)))
3171 {
3172 RETURN( FALSE );
3173 }
3174 _SEH2_TRY
3175 {
3176 if(pcbi)
3177 {
3178 ProbeForWrite(pcbi,
3179 sizeof(COMBOBOXINFO),
3180 1);
3181 }
3182 }
3183 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3184 {
3185 SetLastNtError(_SEH2_GetExceptionCode());
3186 _SEH2_YIELD(RETURN(FALSE));
3187 }
3188 _SEH2_END;
3189
3190 if (pcbi->cbSize < sizeof(COMBOBOXINFO))
3191 {
3192 EngSetLastError(ERROR_INVALID_PARAMETER);
3193 RETURN(FALSE);
3194 }
3195
3196 // Pass the user pointer, it was already probed.
3197 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_COMBOBOX]) && Wnd->fnid != FNID_COMBOBOX)
3198 {
3199 RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3200 }
3201
3202 ppi = PsGetCurrentProcessWin32Process();
3203 NotSameppi = ppi != Wnd->head.pti->ppi;
3204 if (NotSameppi)
3205 {
3206 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3207 }
3208
3209 _SEH2_TRY
3210 {
3211 LPHEADCOMBO lphc = ((PWND2CBOX)Wnd)->pCBox;
3212 pcbi->rcItem = lphc->textRect;
3213 pcbi->rcButton = lphc->buttonRect;
3214 pcbi->stateButton = 0;
3215 if (lphc->wState & CBF_BUTTONDOWN)
3216 pcbi->stateButton |= STATE_SYSTEM_PRESSED;
3217 if (RECTL_bIsEmptyRect(&lphc->buttonRect))
3218 pcbi->stateButton |= STATE_SYSTEM_INVISIBLE;
3219 pcbi->hwndCombo = lphc->self;
3220 pcbi->hwndItem = lphc->hWndEdit;
3221 pcbi->hwndList = lphc->hWndLBox;
3222 }
3223 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3224 {
3225 Ret = FALSE;
3226 SetLastNtError(_SEH2_GetExceptionCode());
3227 }
3228 _SEH2_END;
3229
3230 RETURN( Ret);
3231
3232 CLEANUP:
3233 if (NotSameppi) KeDetachProcess();
3234 TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3235 UserLeave();
3236 END_CLEANUP;
3237 }
3238
3239 ////
3240 //// ReactOS work around! Keep it the sames as in Listbox.c
3241 ////
3242 /* Listbox structure */
3243 typedef struct
3244 {
3245 HWND self; /* Our own window handle */
3246 HWND owner; /* Owner window to send notifications to */
3247 UINT style; /* Window style */
3248 INT width; /* Window width */
3249 INT height; /* Window height */
3250 VOID *items; /* Array of items */
3251 INT nb_items; /* Number of items */
3252 INT top_item; /* Top visible item */
3253 INT selected_item; /* Selected item */
3254 INT focus_item; /* Item that has the focus */
3255 INT anchor_item; /* Anchor item for extended selection */
3256 INT item_height; /* Default item height */
3257 INT page_size; /* Items per listbox page */
3258 INT column_width; /* Column width for multi-column listboxes */
3259 } LB_DESCR;
3260
3261 // Window Extra data container.
3262 typedef struct _WND2LB
3263 {
3264 WND;
3265 LB_DESCR * pLBiv;
3266 } WND2LB, *PWND2LB;
3267 ////
3268 ////
3269 ////
3270 DWORD
3271 APIENTRY
3272 NtUserGetListBoxInfo(
3273 HWND hWnd)
3274 {
3275 PWND Wnd;
3276 PPROCESSINFO ppi;
3277 BOOL NotSameppi = FALSE;
3278 DWORD Ret = 0;
3279 DECLARE_RETURN(DWORD);
3280
3281 TRACE("Enter NtUserGetListBoxInfo\n");
3282 UserEnterShared();
3283
3284 if (!(Wnd = UserGetWindowObject(hWnd)))
3285 {
3286 RETURN( 0 );
3287 }
3288
3289 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && Wnd->fnid != FNID_LISTBOX)
3290 {
3291 RETURN( (DWORD) co_IntSendMessage( Wnd->head.h, LB_GETLISTBOXINFO, 0, 0 ));
3292 }
3293
3294 // wine lisbox:test_GetListBoxInfo lb_getlistboxinfo = 0, should not send a message!
3295 ppi = PsGetCurrentProcessWin32Process();
3296 NotSameppi = ppi != Wnd->head.pti->ppi;
3297 if (NotSameppi)
3298 {
3299 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3300 }
3301
3302 _SEH2_TRY
3303 {
3304 LB_DESCR *descr = ((PWND2LB)Wnd)->pLBiv;
3305 // See Controls ListBox.c:LB_GETLISTBOXINFO must match...
3306 if (descr->style & LBS_MULTICOLUMN) //// ReactOS
3307 Ret = descr->page_size * descr->column_width;
3308 else
3309 Ret = descr->page_size;
3310 }
3311 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3312 {
3313 Ret = 0;
3314 SetLastNtError(_SEH2_GetExceptionCode());
3315 }
3316 _SEH2_END;
3317
3318 RETURN( Ret);
3319
3320 CLEANUP:
3321 if (NotSameppi) KeDetachProcess();
3322 TRACE("Leave NtUserGetListBoxInfo, ret=%lu\n", _ret_);
3323 UserLeave();
3324 END_CLEANUP;
3325 }
3326
3327 /*
3328 * NtUserSetParent
3329 *
3330 * The NtUserSetParent function changes the parent window of the specified
3331 * child window.
3332 *
3333 * Remarks
3334 * The new parent window and the child window must belong to the same
3335 * application. If the window identified by the hWndChild parameter is
3336 * visible, the system performs the appropriate redrawing and repainting.
3337 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3338 * or WS_POPUP window styles of the window whose parent is being changed.
3339 *
3340 * Status
3341 * @implemented
3342 */
3343
3344 HWND APIENTRY
3345 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3346 {
3347 DECLARE_RETURN(HWND);
3348
3349 TRACE("Enter NtUserSetParent\n");
3350 UserEnterExclusive();
3351
3352 /*
3353 Check Parent first from user space, set it here.
3354 */
3355 if (!hWndNewParent)
3356 {
3357 hWndNewParent = IntGetDesktopWindow();
3358 }
3359 else if (hWndNewParent == HWND_MESSAGE)
3360 {
3361 hWndNewParent = IntGetMessageWindow();
3362 }
3363
3364 RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3365
3366 CLEANUP:
3367 TRACE("Leave NtUserSetParent, ret=%p\n", _ret_);
3368 UserLeave();
3369 END_CLEANUP;
3370 }
3371
3372 /*
3373 * UserGetShellWindow
3374 *
3375 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3376 *
3377 * Status
3378 * @implemented
3379 */
3380 HWND FASTCALL UserGetShellWindow(VOID)
3381 {
3382 PWINSTATION_OBJECT WinStaObject;
3383 HWND Ret;
3384
3385 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3386 KernelMode,
3387 0,