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