- Rewrite NtUserCreateDesktop and move the desktop thread completely in win32k like...
[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, otWindow);
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, otWindow);
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 IntDereferenceMessageQueue(Window->head.pti->MessageQueue);
501
502 /* from now on no messages can be sent to this window anymore */
503 Window->state |= WNDS_DESTROYED;
504 Window->fnid |= FNID_FREED;
505
506 /* don't remove the WINDOWSTATUS_DESTROYING bit */
507
508 /* reset shell window handles */
509 if(ThreadData->rpdesk)
510 {
511 if (Window->head.h == ThreadData->rpdesk->rpwinstaParent->ShellWindow)
512 ThreadData->rpdesk->rpwinstaParent->ShellWindow = NULL;
513
514 if (Window->head.h == ThreadData->rpdesk->rpwinstaParent->ShellListView)
515 ThreadData->rpdesk->rpwinstaParent->ShellListView = NULL;
516 }
517
518 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
519
520 #if 0 /* FIXME */
521
522 WinPosCheckInternalPos(Window->head.h);
523 if (Window->head.h == GetCapture())
524 {
525 ReleaseCapture();
526 }
527
528 /* free resources associated with the window */
529 TIMER_RemoveWindowTimers(Window->head.h);
530 #endif
531
532 if ( ((Window->style & (WS_CHILD|WS_POPUP)) != WS_CHILD) &&
533 Window->IDMenu &&
534 (Menu = UserGetMenuObject((HMENU)Window->IDMenu)))
535 {
536 IntDestroyMenuObject(Menu, TRUE, TRUE);
537 Window->IDMenu = 0;
538 }
539
540 if(Window->SystemMenu
541 && (Menu = UserGetMenuObject(Window->SystemMenu)))
542 {
543 IntDestroyMenuObject(Menu, TRUE, TRUE);
544 Window->SystemMenu = (HMENU)0;
545 }
546
547 DceFreeWindowDCE(Window); /* Always do this to catch orphaned DCs */
548 #if 0 /* FIXME */
549
550 WINPROC_FreeProc(Window->winproc, WIN_PROC_WINDOW);
551 CLASS_RemoveWindow(Window->Class);
552 #endif
553
554 IntUnlinkWindow(Window);
555
556 UserReferenceObject(Window);
557 UserDeleteObject(Window->head.h, otWindow);
558
559 IntDestroyScrollBars(Window);
560
561 /* dereference the class */
562 IntDereferenceClass(Window->pcls,
563 Window->head.pti->pDeskInfo,
564 Window->head.pti->ppi);
565 Window->pcls = NULL;
566
567 if(Window->hrgnClip)
568 {
569 IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED);
570 GreDeleteObject(Window->hrgnClip);
571 Window->hrgnClip = NULL;
572 }
573
574 // ASSERT(Window != NULL);
575 UserFreeWindowInfo(Window->head.pti, Window);
576
577 UserDereferenceObject(Window);
578
579 UserClipboardFreeWindow(Window);
580
581 return 0;
582 }
583
584 //
585 // Same as User32:IntGetWndProc.
586 //
587 WNDPROC FASTCALL
588 IntGetWindowProc(PWND pWnd,
589 BOOL Ansi)
590 {
591 INT i;
592 PCLS Class;
593 WNDPROC gcpd, Ret = 0;
594
595 ASSERT(UserIsEnteredExclusive() == TRUE);
596
597 Class = pWnd->pcls;
598
599 if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
600 {
601 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
602 {
603 if (GETPFNSERVER(i) == pWnd->lpfnWndProc)
604 {
605 if (Ansi)
606 Ret = GETPFNCLIENTA(i);
607 else
608 Ret = GETPFNCLIENTW(i);
609 }
610 }
611 return Ret;
612 }
613
614 if (Class->fnid == FNID_EDIT)
615 Ret = pWnd->lpfnWndProc;
616 else
617 {
618 Ret = pWnd->lpfnWndProc;
619
620 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
621 {
622 if (Ansi)
623 {
624 if (GETPFNCLIENTW(Class->fnid) == pWnd->lpfnWndProc)
625 Ret = GETPFNCLIENTA(Class->fnid);
626 }
627 else
628 {
629 if (GETPFNCLIENTA(Class->fnid) == pWnd->lpfnWndProc)
630 Ret = GETPFNCLIENTW(Class->fnid);
631 }
632 }
633 if ( Ret != pWnd->lpfnWndProc)
634 return Ret;
635 }
636 if ( Ansi == !!(pWnd->state & WNDS_ANSIWINDOWPROC) )
637 return Ret;
638
639 gcpd = (WNDPROC)UserGetCPD(
640 pWnd,
641 (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWindow,
642 (ULONG_PTR)Ret);
643
644 return (gcpd ? gcpd : Ret);
645 }
646
647 static WNDPROC
648 IntSetWindowProc(PWND pWnd,
649 WNDPROC NewWndProc,
650 BOOL Ansi)
651 {
652 INT i;
653 PCALLPROCDATA CallProc;
654 PCLS Class;
655 WNDPROC Ret, chWndProc = NULL;
656
657 // Retrieve previous window proc.
658 Ret = IntGetWindowProc(pWnd, Ansi);
659
660 Class = pWnd->pcls;
661
662 if (IsCallProcHandle(NewWndProc))
663 {
664 CallProc = UserGetObject(gHandleTable, NewWndProc, otCallProc);
665 if (CallProc)
666 { // Reset new WndProc.
667 NewWndProc = CallProc->pfnClientPrevious;
668 // Reset Ansi from CallProc handle. This is expected with wine "deftest".
669 Ansi = !!(CallProc->wType & UserGetCPDU2A);
670 }
671 }
672 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
673 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
674 {
675 if (GETPFNCLIENTW(i) == NewWndProc)
676 {
677 chWndProc = GETPFNSERVER(i);
678 break;
679 }
680 if (GETPFNCLIENTA(i) == NewWndProc)
681 {
682 chWndProc = GETPFNSERVER(i);
683 break;
684 }
685 }
686 // If match, set/reset to Server Side and clear ansi.
687 if (chWndProc)
688 {
689 pWnd->lpfnWndProc = chWndProc;
690 pWnd->Unicode = TRUE;
691 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
692 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
693 }
694 else
695 {
696 pWnd->Unicode = !Ansi;
697 // Handle the state change in here.
698 if (Ansi)
699 pWnd->state |= WNDS_ANSIWINDOWPROC;
700 else
701 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
702
703 if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
704 pWnd->state &= ~WNDS_SERVERSIDEWINDOWPROC;
705
706 if (!NewWndProc) NewWndProc = pWnd->lpfnWndProc;
707
708 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
709 {
710 if (Ansi)
711 {
712 if (GETPFNCLIENTW(Class->fnid) == NewWndProc)
713 chWndProc = GETPFNCLIENTA(Class->fnid);
714 }
715 else
716 {
717 if (GETPFNCLIENTA(Class->fnid) == NewWndProc)
718 chWndProc = GETPFNCLIENTW(Class->fnid);
719 }
720 }
721 // Now set the new window proc.
722 pWnd->lpfnWndProc = (chWndProc ? chWndProc : NewWndProc);
723 }
724 return Ret;
725 }
726
727 static BOOL FASTCALL
728 IntSetMenu(
729 PWND Wnd,
730 HMENU Menu,
731 BOOL *Changed)
732 {
733 PMENU_OBJECT OldMenu, NewMenu = NULL;
734
735 if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
736 {
737 ERR("SetMenu: Invalid handle 0x%p!\n",UserHMGetHandle(Wnd));
738 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
739 return FALSE;
740 }
741
742 *Changed = (Wnd->IDMenu != (UINT) Menu);
743 if (! *Changed)
744 {
745 return TRUE;
746 }
747
748 if (Wnd->IDMenu)
749 {
750 OldMenu = IntGetMenuObject((HMENU) Wnd->IDMenu);
751 ASSERT(NULL == OldMenu || OldMenu->MenuInfo.Wnd == Wnd->head.h);
752 }
753 else
754 {
755 OldMenu = NULL;
756 }
757
758 if (NULL != Menu)
759 {
760 NewMenu = IntGetMenuObject(Menu);
761 if (NULL == NewMenu)
762 {
763 if (NULL != OldMenu)
764 {
765 IntReleaseMenuObject(OldMenu);
766 }
767 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
768 return FALSE;
769 }
770 if (NULL != NewMenu->MenuInfo.Wnd)
771 {
772 /* Can't use the same menu for two windows */
773 if (NULL != OldMenu)
774 {
775 IntReleaseMenuObject(OldMenu);
776 }
777 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
778 return FALSE;
779 }
780
781 }
782
783 Wnd->IDMenu = (UINT) Menu;
784 if (NULL != NewMenu)
785 {
786 NewMenu->MenuInfo.Wnd = Wnd->head.h;
787 IntReleaseMenuObject(NewMenu);
788 }
789 if (NULL != OldMenu)
790 {
791 OldMenu->MenuInfo.Wnd = NULL;
792 IntReleaseMenuObject(OldMenu);
793 }
794
795 return TRUE;
796 }
797
798
799 /* INTERNAL ******************************************************************/
800
801
802 VOID FASTCALL
803 co_DestroyThreadWindows(struct _ETHREAD *Thread)
804 {
805 PTHREADINFO WThread;
806 PLIST_ENTRY Current;
807 PWND Wnd;
808 USER_REFERENCE_ENTRY Ref;
809 WThread = (PTHREADINFO)Thread->Tcb.Win32Thread;
810
811 while (!IsListEmpty(&WThread->WindowListHead))
812 {
813 Current = WThread->WindowListHead.Flink;
814 Wnd = CONTAINING_RECORD(Current, WND, ThreadListEntry);
815
816 TRACE("thread cleanup: while destroy wnds, wnd=0x%x\n",Wnd);
817
818 /* Window removes itself from the list */
819
820 /*
821 * FIXME: It is critical that the window removes itself! If now, we will loop
822 * here forever...
823 */
824
825 //ASSERT(co_UserDestroyWindow(Wnd));
826
827 UserRefObjectCo(Wnd, &Ref); // FIXME: Temp HACK??
828 if (!co_UserDestroyWindow(Wnd))
829 {
830 ERR("Unable to destroy window 0x%x at thread cleanup... This is _VERY_ bad!\n", Wnd);
831 }
832 UserDerefObjectCo(Wnd); // FIXME: Temp HACK??
833 }
834 }
835
836 PMENU_OBJECT FASTCALL
837 IntGetSystemMenu(PWND Window, BOOL bRevert, BOOL RetMenu)
838 {
839 PMENU_OBJECT Menu, NewMenu = NULL, SysMenu = NULL, ret = NULL;
840 PTHREADINFO W32Thread;
841 HMENU hNewMenu, hSysMenu;
842 ROSMENUITEMINFO ItemInfo;
843
844 if(bRevert)
845 {
846 W32Thread = PsGetCurrentThreadWin32Thread();
847
848 if(!W32Thread->rpdesk)
849 return NULL;
850
851 if(Window->SystemMenu)
852 {
853 Menu = UserGetMenuObject(Window->SystemMenu);
854 if(Menu)
855 {
856 IntDestroyMenuObject(Menu, TRUE, TRUE);
857 Window->SystemMenu = (HMENU)0;
858 }
859 }
860
861 if(W32Thread->rpdesk->rpwinstaParent->SystemMenuTemplate)
862 {
863 /* Clone system menu */
864 Menu = UserGetMenuObject(W32Thread->rpdesk->rpwinstaParent->SystemMenuTemplate);
865 if(!Menu)
866 return NULL;
867
868 NewMenu = IntCloneMenu(Menu);
869 if(NewMenu)
870 {
871 Window->SystemMenu = NewMenu->MenuInfo.Self;
872 NewMenu->MenuInfo.Flags |= MF_SYSMENU;
873 NewMenu->MenuInfo.Wnd = Window->head.h;
874 ret = NewMenu;
875 //IntReleaseMenuObject(NewMenu);
876 }
877 }
878 else
879 {
880 hSysMenu = UserCreateMenu(FALSE);
881 if (NULL == hSysMenu)
882 {
883 return NULL;
884 }
885 SysMenu = IntGetMenuObject(hSysMenu);
886 if (NULL == SysMenu)
887 {
888 UserDestroyMenu(hSysMenu);
889 return NULL;
890 }
891 SysMenu->MenuInfo.Flags |= MF_SYSMENU;
892 SysMenu->MenuInfo.Wnd = Window->head.h;
893 hNewMenu = co_IntLoadSysMenuTemplate();
894 if(!hNewMenu)
895 {
896 IntReleaseMenuObject(SysMenu);
897 UserDestroyMenu(hSysMenu);
898 return NULL;
899 }
900 Menu = IntGetMenuObject(hNewMenu);
901 if(!Menu)
902 {
903 IntReleaseMenuObject(SysMenu);
904 UserDestroyMenu(hSysMenu);
905 return NULL;
906 }
907
908 NewMenu = IntCloneMenu(Menu);
909 if(NewMenu)
910 {
911 NewMenu->MenuInfo.Flags |= MF_SYSMENU | MF_POPUP;
912 IntReleaseMenuObject(NewMenu);
913 UserSetMenuDefaultItem(NewMenu, SC_CLOSE, FALSE);
914
915 ItemInfo.cbSize = sizeof(MENUITEMINFOW);
916 ItemInfo.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_SUBMENU;
917 ItemInfo.fType = MF_POPUP;
918 ItemInfo.fState = MFS_ENABLED;
919 ItemInfo.dwTypeData = NULL;
920 ItemInfo.cch = 0;
921 ItemInfo.hSubMenu = NewMenu->MenuInfo.Self;
922 IntInsertMenuItem(SysMenu, (UINT) -1, TRUE, &ItemInfo);
923
924 Window->SystemMenu = SysMenu->MenuInfo.Self;
925
926 ret = SysMenu;
927 }
928 IntDestroyMenuObject(Menu, FALSE, TRUE);
929 }
930 if(RetMenu)
931 return ret;
932 else
933 return NULL;
934 }
935 else
936 {
937 if(Window->SystemMenu)
938 return IntGetMenuObject((HMENU)Window->SystemMenu);
939 else
940 return NULL;
941 }
942 }
943
944
945 BOOL FASTCALL
946 IntIsChildWindow(PWND Parent, PWND BaseWindow)
947 {
948 PWND Window;
949
950 Window = BaseWindow;
951 while (Window && ((Window->style & (WS_POPUP|WS_CHILD)) == WS_CHILD))
952 {
953 if (Window == Parent)
954 {
955 return(TRUE);
956 }
957
958 Window = Window->spwndParent;
959 }
960
961 return(FALSE);
962 }
963
964 /*
965 Link the window into siblings list
966 children and parent are kept in place.
967 */
968 VOID FASTCALL
969 IntLinkWindow(
970 PWND Wnd,
971 PWND WndInsertAfter /* set to NULL if top sibling */
972 )
973 {
974 if ((Wnd->spwndPrev = WndInsertAfter))
975 {
976 /* link after WndInsertAfter */
977 if ((Wnd->spwndNext = WndInsertAfter->spwndNext))
978 Wnd->spwndNext->spwndPrev = Wnd;
979
980 Wnd->spwndPrev->spwndNext = Wnd;
981 }
982 else
983 {
984 /* link at top */
985 if ((Wnd->spwndNext = Wnd->spwndParent->spwndChild))
986 Wnd->spwndNext->spwndPrev = Wnd;
987
988 Wnd->spwndParent->spwndChild = Wnd;
989 }
990 }
991
992 /*
993 Note: Wnd->spwndParent can be null if it is the desktop.
994 */
995 VOID FASTCALL IntLinkHwnd(PWND Wnd, HWND hWndPrev)
996 {
997 if (hWndPrev == HWND_NOTOPMOST)
998 {
999 if (!(Wnd->ExStyle & WS_EX_TOPMOST) &&
1000 (Wnd->ExStyle2 & WS_EX2_LINKED)) return; /* nothing to do */
1001 Wnd->ExStyle &= ~WS_EX_TOPMOST;
1002 hWndPrev = HWND_TOP; /* fallback to the HWND_TOP case */
1003 }
1004
1005 IntUnlinkWindow(Wnd); /* unlink it from the previous location */
1006
1007 if (hWndPrev == HWND_BOTTOM)
1008 {
1009 /* Link in the bottom of the list */
1010 PWND WndInsertAfter;
1011
1012 WndInsertAfter = Wnd->spwndParent->spwndChild;
1013 while( WndInsertAfter && WndInsertAfter->spwndNext)
1014 WndInsertAfter = WndInsertAfter->spwndNext;
1015
1016 IntLinkWindow(Wnd, WndInsertAfter);
1017 Wnd->ExStyle &= ~WS_EX_TOPMOST;
1018 }
1019 else if (hWndPrev == HWND_TOPMOST)
1020 {
1021 /* Link in the top of the list */
1022 IntLinkWindow(Wnd, NULL);
1023
1024 Wnd->ExStyle |= WS_EX_TOPMOST;
1025 }
1026 else if (hWndPrev == HWND_TOP)
1027 {
1028 /* Link it after the last topmost window */
1029 PWND WndInsertBefore;
1030
1031 WndInsertBefore = Wnd->spwndParent->spwndChild;
1032
1033 if (!(Wnd->ExStyle & WS_EX_TOPMOST)) /* put it above the first non-topmost window */
1034 {
1035 while (WndInsertBefore != NULL && WndInsertBefore->spwndNext != NULL)
1036 {
1037 if (!(WndInsertBefore->ExStyle & WS_EX_TOPMOST)) break;
1038 if (WndInsertBefore == Wnd->spwndOwner) /* keep it above owner */
1039 {
1040 Wnd->ExStyle |= WS_EX_TOPMOST;
1041 break;
1042 }
1043 WndInsertBefore = WndInsertBefore->spwndNext;
1044 }
1045 }
1046
1047 IntLinkWindow(Wnd, WndInsertBefore ? WndInsertBefore->spwndPrev : NULL);
1048 }
1049 else
1050 {
1051 /* Link it after hWndPrev */
1052 PWND WndInsertAfter;
1053
1054 WndInsertAfter = UserGetWindowObject(hWndPrev);
1055 /* Are we called with an erroneous handle */
1056 if(WndInsertAfter == NULL)
1057 {
1058 /* Link in a default position */
1059 IntLinkHwnd(Wnd, HWND_TOP);
1060 return;
1061 }
1062
1063 IntLinkWindow(Wnd, WndInsertAfter);
1064
1065 /* Fix the WS_EX_TOPMOST flag */
1066 if (!(WndInsertAfter->ExStyle & WS_EX_TOPMOST))
1067 {
1068 Wnd->ExStyle &= ~WS_EX_TOPMOST;
1069 }
1070 else
1071 {
1072 if(WndInsertAfter->spwndNext &&
1073 WndInsertAfter->spwndNext->ExStyle & WS_EX_TOPMOST)
1074 {
1075 Wnd->ExStyle |= WS_EX_TOPMOST;
1076 }
1077 }
1078 }
1079 Wnd->ExStyle2 |= WS_EX2_LINKED;
1080 }
1081
1082 VOID FASTCALL
1083 IntProcessOwnerSwap(PWND Wnd, PWND WndNewOwner, PWND WndOldOwner)
1084 {
1085 if (WndOldOwner)
1086 {
1087 if (Wnd->head.pti != WndOldOwner->head.pti)
1088 {
1089 if (!WndNewOwner ||
1090 Wnd->head.pti == WndNewOwner->head.pti ||
1091 WndOldOwner->head.pti != WndNewOwner->head.pti )
1092 {
1093 ERR("ProcessOwnerSwap Old out.\n");
1094 //UserAttachThreadInput(Wnd->head.pti, WndOldOwner->head.pti, FALSE);
1095 }
1096 }
1097 }
1098 if (WndNewOwner)
1099 {
1100 if (Wnd->head.pti != WndNewOwner->head.pti)
1101 {
1102 if (!WndOldOwner ||
1103 WndOldOwner->head.pti != WndNewOwner->head.pti )
1104 {
1105 ERR("ProcessOwnerSwap New in.\n");
1106 //UserAttachThreadInput(Wnd->head.pti, WndNewOwner->head.pti, TRUE);
1107 }
1108 }
1109 }
1110 // FIXME: System Tray checks.
1111 }
1112
1113 HWND FASTCALL
1114 IntSetOwner(HWND hWnd, HWND hWndNewOwner)
1115 {
1116 PWND Wnd, WndOldOwner, WndNewOwner;
1117 HWND ret;
1118
1119 Wnd = IntGetWindowObject(hWnd);
1120 if(!Wnd)
1121 return NULL;
1122
1123 WndOldOwner = Wnd->spwndOwner;
1124
1125 ret = WndOldOwner ? UserHMGetHandle(WndOldOwner) : 0;
1126 WndNewOwner = UserGetWindowObject(hWndNewOwner);
1127
1128 if (!WndNewOwner && hWndNewOwner)
1129 {
1130 EngSetLastError(ERROR_INVALID_PARAMETER);
1131 ret = NULL;
1132 goto Error;
1133 }
1134
1135 IntProcessOwnerSwap(Wnd, WndNewOwner, WndOldOwner);
1136
1137 if (IntValidateOwnerDepth(Wnd, WndNewOwner))
1138 {
1139 if (WndNewOwner)
1140 {
1141 Wnd->spwndOwner= WndNewOwner;
1142 }
1143 else
1144 {
1145 Wnd->spwndOwner = NULL;
1146 }
1147 }
1148 else
1149 {
1150 IntProcessOwnerSwap(Wnd, WndOldOwner, WndNewOwner);
1151 EngSetLastError(ERROR_INVALID_PARAMETER);
1152 ret = NULL;
1153 }
1154 Error:
1155 UserDereferenceObject(Wnd);
1156 return ret;
1157 }
1158
1159 PWND FASTCALL
1160 co_IntSetParent(PWND Wnd, PWND WndNewParent)
1161 {
1162 PWND WndOldParent, pWndExam;
1163 BOOL WasVisible;
1164 POINT pt;
1165 int swFlags = SWP_NOSIZE|SWP_NOZORDER;
1166
1167 ASSERT(Wnd);
1168 ASSERT(WndNewParent);
1169 ASSERT_REFS_CO(Wnd);
1170 ASSERT_REFS_CO(WndNewParent);
1171
1172 if (Wnd == Wnd->head.rpdesk->spwndMessage)
1173 {
1174 EngSetLastError(ERROR_ACCESS_DENIED);
1175 return( NULL);
1176 }
1177
1178 /* Some applications try to set a child as a parent */
1179 if (IntIsChildWindow(Wnd, WndNewParent))
1180 {
1181 EngSetLastError( ERROR_INVALID_PARAMETER );
1182 return NULL;
1183 }
1184
1185 pWndExam = WndNewParent; // Load parent Window to examine.
1186 // Now test for set parent to parent hit.
1187 while (pWndExam)
1188 {
1189 if (Wnd == pWndExam)
1190 {
1191 EngSetLastError(ERROR_INVALID_PARAMETER);
1192 return NULL;
1193 }
1194 pWndExam = pWndExam->spwndParent;
1195 }
1196
1197 /*
1198 * Windows hides the window first, then shows it again
1199 * including the WM_SHOWWINDOW messages and all
1200 */
1201 WasVisible = co_WinPosShowWindow(Wnd, SW_HIDE);
1202
1203 /* Window must belong to current process */
1204 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
1205 return NULL;
1206
1207 WndOldParent = Wnd->spwndParent;
1208
1209 if ( WndOldParent &&
1210 WndOldParent->ExStyle & WS_EX_LAYOUTRTL)
1211 pt.x = Wnd->rcWindow.right;
1212 else
1213 pt.x = Wnd->rcWindow.left;
1214 pt.y = Wnd->rcWindow.top;
1215
1216 if (WndOldParent) UserReferenceObject(WndOldParent); /* Caller must deref */
1217
1218 if (WndNewParent != WndOldParent)
1219 {
1220 /* Unlink the window from the siblings list */
1221 IntUnlinkWindow(Wnd);
1222 Wnd->ExStyle2 &= ~WS_EX2_LINKED;
1223
1224 /* Set the new parent */
1225 Wnd->spwndParent = WndNewParent;
1226
1227 if ( Wnd->style & WS_CHILD &&
1228 Wnd->spwndOwner &&
1229 Wnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1230 {
1231 ERR("SetParent Top Most from Pop up!\n");
1232 Wnd->ExStyle |= WS_EX_TOPMOST;
1233 }
1234
1235 /* Link the window with its new siblings */
1236 IntLinkHwnd( Wnd,
1237 ((0 == (Wnd->ExStyle & WS_EX_TOPMOST) &&
1238 WndNewParent == UserGetDesktopWindow() ) ? HWND_TOP : HWND_TOPMOST ) );
1239
1240 }
1241
1242 if ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1243 {
1244 if ( Wnd->spwndParent != co_GetDesktopWindow(Wnd))
1245 {
1246 if (Wnd->head.pti != WndOldParent->head.pti)
1247 {
1248 ERR("SetParent Old out.\n");
1249 //UserAttachThreadInput(Wnd->head.pti, WndOldParent->head.pti, FALSE);
1250 }
1251 }
1252 if ( WndNewParent != co_GetDesktopWindow(Wnd))
1253 {
1254 if (Wnd->head.pti != WndNewParent->head.pti)
1255 {
1256 ERR("SetParent New in.\n");
1257 //UserAttachThreadInput(Wnd->head.pti, WndNewParent->head.pti, TRUE);
1258 }
1259 }
1260 }
1261
1262 if (WndOldParent == UserGetMessageWindow() || WndNewParent == UserGetMessageWindow())
1263 swFlags |= SWP_NOACTIVATE;
1264
1265 IntNotifyWinEvent(EVENT_OBJECT_PARENTCHANGE, Wnd ,OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1266 /*
1267 * SetParent additionally needs to make hwnd the top window
1268 * in the z-order and send the expected WM_WINDOWPOSCHANGING and
1269 * WM_WINDOWPOSCHANGED notification messages.
1270 */
1271 co_WinPosSetWindowPos( Wnd,
1272 (0 == (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
1273 pt.x, pt.y, 0, 0, swFlags);
1274
1275 if (WasVisible) co_WinPosShowWindow(Wnd, SW_SHOWNORMAL);
1276
1277 return WndOldParent;
1278 }
1279
1280 HWND FASTCALL
1281 co_UserSetParent(HWND hWndChild, HWND hWndNewParent)
1282 {
1283 PWND Wnd = NULL, WndParent = NULL, WndOldParent;
1284 HWND hWndOldParent = NULL;
1285 USER_REFERENCE_ENTRY Ref, ParentRef;
1286
1287 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
1288 {
1289 EngSetLastError(ERROR_INVALID_PARAMETER);
1290 return( NULL);
1291 }
1292
1293 if (hWndChild == IntGetDesktopWindow())
1294 {
1295 EngSetLastError(ERROR_ACCESS_DENIED);
1296 return( NULL);
1297 }
1298
1299 if (hWndNewParent)
1300 {
1301 if (!(WndParent = UserGetWindowObject(hWndNewParent)))
1302 {
1303 return( NULL);
1304 }
1305 }
1306 else
1307 {
1308 if (!(WndParent = UserGetWindowObject(IntGetDesktopWindow())))
1309 {
1310 return( NULL);
1311 }
1312 }
1313
1314 if (!(Wnd = UserGetWindowObject(hWndChild)))
1315 {
1316 return( NULL);
1317 }
1318
1319 UserRefObjectCo(Wnd, &Ref);
1320 UserRefObjectCo(WndParent, &ParentRef);
1321 //ERR("Enter co_IntSetParent\n");
1322 WndOldParent = co_IntSetParent(Wnd, WndParent);
1323 //ERR("Leave co_IntSetParent\n");
1324 UserDerefObjectCo(WndParent);
1325 UserDerefObjectCo(Wnd);
1326
1327 if (WndOldParent)
1328 {
1329 hWndOldParent = WndOldParent->head.h;
1330 UserDereferenceObject(WndOldParent);
1331 }
1332
1333 return( hWndOldParent);
1334 }
1335
1336 BOOL FASTCALL
1337 IntSetSystemMenu(PWND Window, PMENU_OBJECT Menu)
1338 {
1339 PMENU_OBJECT OldMenu;
1340 if(Window->SystemMenu)
1341 {
1342 OldMenu = IntGetMenuObject(Window->SystemMenu);
1343 if(OldMenu)
1344 {
1345 OldMenu->MenuInfo.Flags &= ~ MF_SYSMENU;
1346 IntReleaseMenuObject(OldMenu);
1347 }
1348 }
1349
1350 if(Menu)
1351 {
1352 /* FIXME: Check window style, propably return FALSE? */
1353 Window->SystemMenu = Menu->MenuInfo.Self;
1354 Menu->MenuInfo.Flags |= MF_SYSMENU;
1355 }
1356 else
1357 Window->SystemMenu = (HMENU)0;
1358
1359 return TRUE;
1360 }
1361
1362 /* Unlink the window from siblings. children and parent are kept in place. */
1363 VOID FASTCALL
1364 IntUnlinkWindow(PWND Wnd)
1365 {
1366 if (Wnd->spwndNext)
1367 Wnd->spwndNext->spwndPrev = Wnd->spwndPrev;
1368
1369 if (Wnd->spwndPrev)
1370 Wnd->spwndPrev->spwndNext = Wnd->spwndNext;
1371
1372 if (Wnd->spwndParent && Wnd->spwndParent->spwndChild == Wnd)
1373 Wnd->spwndParent->spwndChild = Wnd->spwndNext;
1374
1375 Wnd->spwndPrev = Wnd->spwndNext = NULL;
1376 }
1377
1378 /* FUNCTIONS *****************************************************************/
1379
1380 /*
1381 * As best as I can figure, this function is used by EnumWindows,
1382 * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
1383 *
1384 * It's supposed to build a list of HWNDs to return to the caller.
1385 * We can figure out what kind of list by what parameters are
1386 * passed to us.
1387 */
1388 /*
1389 * @implemented
1390 */
1391 NTSTATUS
1392 APIENTRY
1393 NtUserBuildHwndList(
1394 HDESK hDesktop,
1395 HWND hwndParent,
1396 BOOLEAN bChildren,
1397 ULONG dwThreadId,
1398 ULONG lParam,
1399 HWND* pWnd,
1400 ULONG* pBufSize)
1401 {
1402 NTSTATUS Status;
1403 ULONG dwCount = 0;
1404
1405 if (pBufSize == 0)
1406 return ERROR_INVALID_PARAMETER;
1407
1408 if (hwndParent || !dwThreadId)
1409 {
1410 PDESKTOP Desktop;
1411 PWND Parent, Window;
1412
1413 if(!hwndParent)
1414 {
1415 if(hDesktop == NULL && !(Desktop = IntGetActiveDesktop()))
1416 {
1417 return ERROR_INVALID_HANDLE;
1418 }
1419
1420 if(hDesktop)
1421 {
1422 Status = IntValidateDesktopHandle(hDesktop,
1423 UserMode,
1424 0,
1425 &Desktop);
1426 if(!NT_SUCCESS(Status))
1427 {
1428 return ERROR_INVALID_HANDLE;
1429 }
1430 }
1431 hwndParent = Desktop->DesktopWindow;
1432 }
1433 else
1434 {
1435 hDesktop = 0;
1436 }
1437
1438 if((Parent = UserGetWindowObject(hwndParent)) &&
1439 (Window = Parent->spwndChild))
1440 {
1441 BOOL bGoDown = TRUE;
1442
1443 Status = STATUS_SUCCESS;
1444 while(TRUE)
1445 {
1446 if (bGoDown)
1447 {
1448 if(dwCount++ < *pBufSize && pWnd)
1449 {
1450 _SEH2_TRY
1451 {
1452 ProbeForWrite(pWnd, sizeof(HWND), 1);
1453 *pWnd = Window->head.h;
1454 pWnd++;
1455 }
1456 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1457 {
1458 Status = _SEH2_GetExceptionCode();
1459 }
1460 _SEH2_END
1461 if(!NT_SUCCESS(Status))
1462 {
1463 SetLastNtError(Status);
1464 break;
1465 }
1466 }
1467 if (Window->spwndChild && bChildren)
1468 {
1469 Window = Window->spwndChild;
1470 continue;
1471 }
1472 bGoDown = FALSE;
1473 }
1474 if (Window->spwndNext)
1475 {
1476 Window = Window->spwndNext;
1477 bGoDown = TRUE;
1478 continue;
1479 }
1480 Window = Window->spwndParent;
1481 if (Window == Parent)
1482 {
1483 break;
1484 }
1485 }
1486 }
1487
1488 if(hDesktop)
1489 {
1490 ObDereferenceObject(Desktop);
1491 }
1492 }
1493 else // Build EnumThreadWindows list!
1494 {
1495 PETHREAD Thread;
1496 PTHREADINFO W32Thread;
1497 PLIST_ENTRY Current;
1498 PWND Window;
1499
1500 Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
1501 if (!NT_SUCCESS(Status))
1502 {
1503 ERR("Thread Id is not valid!\n");
1504 return ERROR_INVALID_PARAMETER;
1505 }
1506 if (!(W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread))
1507 {
1508 ObDereferenceObject(Thread);
1509 ERR("Thread is not initialized!\n");
1510 return ERROR_INVALID_PARAMETER;
1511 }
1512
1513 Current = W32Thread->WindowListHead.Flink;
1514 while (Current != &(W32Thread->WindowListHead))
1515 {
1516 Window = CONTAINING_RECORD(Current, WND, ThreadListEntry);
1517 ASSERT(Window);
1518
1519 if (dwCount < *pBufSize && pWnd)
1520 {
1521 _SEH2_TRY
1522 {
1523 ProbeForWrite(pWnd, sizeof(HWND), 1);
1524 *pWnd = Window->head.h;
1525 pWnd++;
1526 }
1527 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1528 {
1529 Status = _SEH2_GetExceptionCode();
1530 }
1531 _SEH2_END
1532 if (!NT_SUCCESS(Status))
1533 {
1534 ERR("Failure to build window list!\n");
1535 SetLastNtError(Status);
1536 break;
1537 }
1538 }
1539 dwCount++;
1540 Current = Window->ThreadListEntry.Flink;
1541 }
1542
1543 ObDereferenceObject(Thread);
1544 }
1545
1546 *pBufSize = dwCount;
1547 return STATUS_SUCCESS;
1548 }
1549
1550 static void IntSendParentNotify( PWND pWindow, UINT msg )
1551 {
1552 if ( (pWindow->style & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
1553 !(pWindow->style & WS_EX_NOPARENTNOTIFY))
1554 {
1555 if (pWindow->spwndParent && pWindow->spwndParent != UserGetDesktopWindow())
1556 {
1557 USER_REFERENCE_ENTRY Ref;
1558 UserRefObjectCo(pWindow->spwndParent, &Ref);
1559 co_IntSendMessage( pWindow->spwndParent->head.h,
1560 WM_PARENTNOTIFY,
1561 MAKEWPARAM( msg, pWindow->IDMenu),
1562 (LPARAM)pWindow->head.h );
1563 UserDerefObjectCo(pWindow->spwndParent);
1564 }
1565 }
1566 }
1567
1568 void FASTCALL
1569 IntFixWindowCoordinates(CREATESTRUCTW* Cs, PWND ParentWindow, DWORD* dwShowMode)
1570 {
1571 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1572
1573 /* default positioning for overlapped windows */
1574 if(!(Cs->style & (WS_POPUP | WS_CHILD)))
1575 {
1576 PMONITOR pMonitor;
1577 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
1578
1579 pMonitor = UserGetPrimaryMonitor();
1580
1581 /* Check if we don't have a monitor attached yet */
1582 if(pMonitor == NULL)
1583 {
1584 Cs->x = Cs->y = 0;
1585 Cs->cx = 800;
1586 Cs->cy = 600;
1587 return;
1588 }
1589
1590 ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
1591
1592 if (IS_DEFAULT(Cs->x))
1593 {
1594 if (!IS_DEFAULT(Cs->y)) *dwShowMode = Cs->y;
1595
1596 if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
1597 {
1598 Cs->x = ProcessParams->StartingX;
1599 Cs->y = ProcessParams->StartingY;
1600 }
1601 else
1602 {
1603 Cs->x = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CXSIZE) + UserGetSystemMetrics(SM_CXFRAME));
1604 Cs->y = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CYSIZE) + UserGetSystemMetrics(SM_CYFRAME));
1605 if (Cs->x > ((pMonitor->rcWork.right - pMonitor->rcWork.left) / 4) ||
1606 Cs->y > ((pMonitor->rcWork.bottom - pMonitor->rcWork.top) / 4))
1607 {
1608 /* reset counter and position */
1609 Cs->x = 0;
1610 Cs->y = 0;
1611 pMonitor->cWndStack = 0;
1612 }
1613 pMonitor->cWndStack++;
1614 }
1615 }
1616
1617 if (IS_DEFAULT(Cs->cx))
1618 {
1619 if (ProcessParams->WindowFlags & STARTF_USEPOSITION)
1620 {
1621 Cs->cx = ProcessParams->CountX;
1622 Cs->cy = ProcessParams->CountY;
1623 }
1624 else
1625 {
1626 Cs->cx = (pMonitor->rcWork.right - pMonitor->rcWork.left) * 3 / 4;
1627 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1628 }
1629 }
1630 /* neither x nor cx are default. Check the y values .
1631 * In the trace we see Outlook and Outlook Express using
1632 * cy set to CW_USEDEFAULT when opening the address book.
1633 */
1634 else if (IS_DEFAULT(Cs->cy))
1635 {
1636 TRACE("Strange use of CW_USEDEFAULT in nHeight\n");
1637 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1638 }
1639 }
1640 else
1641 {
1642 /* if CW_USEDEFAULT is set for non-overlapped windows, both values are set to zero */
1643 if(IS_DEFAULT(Cs->x))
1644 {
1645 Cs->x = 0;
1646 Cs->y = 0;
1647 }
1648 if(IS_DEFAULT(Cs->cx))
1649 {
1650 Cs->cx = 0;
1651 Cs->cy = 0;
1652 }
1653 }
1654
1655 #undef IS_DEFAULT
1656 }
1657
1658 /* Allocates and initializes a window */
1659 PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
1660 PLARGE_STRING WindowName,
1661 PCLS Class,
1662 PWND ParentWindow,
1663 PWND OwnerWindow,
1664 PVOID acbiBuffer,
1665 PDESKTOP pdeskCreated)
1666 {
1667 PWND pWnd = NULL;
1668 HWND hWnd;
1669 PTHREADINFO pti = NULL;
1670 PMENU_OBJECT SystemMenu;
1671 BOOL MenuChanged;
1672 BOOL bUnicodeWindow;
1673
1674 pti = pdeskCreated ? gptiDesktopThread : GetW32ThreadInfo();
1675
1676 if (!(Cs->dwExStyle & WS_EX_LAYOUTRTL))
1677 {
1678 if (ParentWindow)
1679 {
1680 if ( (Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD &&
1681 ParentWindow->ExStyle & WS_EX_LAYOUTRTL &&
1682 !(ParentWindow->ExStyle & WS_EX_NOINHERITLAYOUT) )
1683 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1684 }
1685 else
1686 { /*
1687 * Note from MSDN <http://msdn.microsoft.com/en-us/library/aa913269.aspx>:
1688 *
1689 * Dialog boxes and message boxes do not inherit layout, so you must
1690 * set the layout explicitly.
1691 */
1692 if ( Class->fnid != FNID_DIALOG )
1693 {
1694 if (pti->ppi->dwLayout & LAYOUT_RTL)
1695 {
1696 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1697 }
1698 }
1699 }
1700 }
1701
1702 /* Automatically add WS_EX_WINDOWEDGE */
1703 if ((Cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1704 ((!(Cs->dwExStyle & WS_EX_STATICEDGE)) &&
1705 (Cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1706 Cs->dwExStyle |= WS_EX_WINDOWEDGE;
1707 else
1708 Cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1709
1710 /* Is it a unicode window? */
1711 bUnicodeWindow =!(Cs->dwExStyle & WS_EX_SETANSICREATOR);
1712 Cs->dwExStyle &= ~WS_EX_SETANSICREATOR;
1713
1714 /* Allocate the new window */
1715 pWnd = (PWND) UserCreateObject( gHandleTable,
1716 pdeskCreated ? pdeskCreated : pti->rpdesk,
1717 pti,
1718 (PHANDLE)&hWnd,
1719 otWindow,
1720 sizeof(WND) + Class->cbwndExtra);
1721
1722 if (!pWnd)
1723 {
1724 goto AllocError;
1725 }
1726
1727 TRACE("Created window object with handle %X\n", hWnd);
1728
1729 if (pdeskCreated && pdeskCreated->DesktopWindow == NULL )
1730 { /* HACK: Helper for win32csr/desktopbg.c */
1731 /* If there is no desktop window yet, we must be creating it */
1732 TRACE("CreateWindow setting desktop.\n");
1733 pdeskCreated->DesktopWindow = hWnd;
1734 pdeskCreated->pDeskInfo->spwnd = pWnd;
1735 }
1736
1737 /*
1738 * Fill out the structure describing it.
1739 */
1740 /* Remember, pWnd->head is setup in object.c ... */
1741 pWnd->spwndParent = ParentWindow;
1742 pWnd->spwndOwner = OwnerWindow;
1743 pWnd->fnid = 0;
1744 pWnd->spwndLastActive = pWnd;
1745 pWnd->state2 |= WNDS2_WIN40COMPAT; // FIXME!!!
1746 pWnd->pcls = Class;
1747 pWnd->hModule = Cs->hInstance;
1748 pWnd->style = Cs->style & ~WS_VISIBLE;
1749 pWnd->ExStyle = Cs->dwExStyle;
1750 pWnd->cbwndExtra = pWnd->pcls->cbwndExtra;
1751 pWnd->pActCtx = acbiBuffer;
1752 pWnd->InternalPos.MaxPos.x = pWnd->InternalPos.MaxPos.y = -1;
1753 pWnd->InternalPos.IconPos.x = pWnd->InternalPos.IconPos.y = -1;
1754
1755 IntReferenceMessageQueue(pWnd->head.pti->MessageQueue);
1756 if (pWnd->spwndParent != NULL && Cs->hwndParent != 0)
1757 {
1758 pWnd->HideFocus = pWnd->spwndParent->HideFocus;
1759 pWnd->HideAccel = pWnd->spwndParent->HideAccel;
1760 }
1761
1762 if (pWnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
1763 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
1764
1765 /* BugBoy Comments: Comment below say that System classes are always created
1766 as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
1767 sets the window to ansi as verified by testing with IsUnicodeWindow API.
1768
1769 No where can I see in code or through testing does the window change back
1770 to ANSI after being created as UNICODE in ROS. I didnt do more testing to
1771 see what problems this would cause. */
1772
1773 // Set WndProc from Class.
1774 pWnd->lpfnWndProc = pWnd->pcls->lpfnWndProc;
1775
1776 // GetWindowProc, test for non server side default classes and set WndProc.
1777 if ( pWnd->pcls->fnid <= FNID_GHOST && pWnd->pcls->fnid >= FNID_BUTTON )
1778 {
1779 if (bUnicodeWindow)
1780 {
1781 if (GETPFNCLIENTA(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1782 pWnd->lpfnWndProc = GETPFNCLIENTW(pWnd->pcls->fnid);
1783 }
1784 else
1785 {
1786 if (GETPFNCLIENTW(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1787 pWnd->lpfnWndProc = GETPFNCLIENTA(pWnd->pcls->fnid);
1788 }
1789 }
1790
1791 // If not an Unicode caller, set Ansi creator bit.
1792 if (!bUnicodeWindow) pWnd->state |= WNDS_ANSICREATOR;
1793
1794 // Clone Class Ansi/Unicode proc type.
1795 if (pWnd->pcls->CSF_flags & CSF_ANSIPROC)
1796 {
1797 pWnd->state |= WNDS_ANSIWINDOWPROC;
1798 pWnd->Unicode = FALSE;
1799 }
1800 else
1801 { /*
1802 * It seems there can be both an Ansi creator and Unicode Class Window
1803 * WndProc, unless the following overriding conditions occur:
1804 */
1805 if ( !bUnicodeWindow &&
1806 ( Class->atomClassName == gpsi->atomSysClass[ICLS_BUTTON] ||
1807 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX] ||
1808 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOLBOX] ||
1809 Class->atomClassName == gpsi->atomSysClass[ICLS_DIALOG] ||
1810 Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT] ||
1811 Class->atomClassName == gpsi->atomSysClass[ICLS_IME] ||
1812 Class->atomClassName == gpsi->atomSysClass[ICLS_LISTBOX] ||
1813 Class->atomClassName == gpsi->atomSysClass[ICLS_MDICLIENT] ||
1814 Class->atomClassName == gpsi->atomSysClass[ICLS_STATIC] ) )
1815 { // Override Class and set the window Ansi WndProc.
1816 pWnd->state |= WNDS_ANSIWINDOWPROC;
1817 pWnd->Unicode = FALSE;
1818 }
1819 else
1820 { // Set the window Unicode WndProc.
1821 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
1822 pWnd->Unicode = TRUE;
1823 }
1824 }
1825
1826 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
1827 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
1828 Dont understand why it does this. */
1829 if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT])
1830 {
1831 PCALLPROCDATA CallProc;
1832 CallProc = CreateCallProc(NULL, pWnd->lpfnWndProc, pWnd->Unicode , pWnd->head.pti->ppi);
1833
1834 if (!CallProc)
1835 {
1836 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1837 ERR("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %x\n",hWnd);
1838 }
1839 else
1840 {
1841 UserAddCallProcToClass(pWnd->pcls, CallProc);
1842 }
1843 }
1844
1845 InitializeListHead(&pWnd->PropListHead);
1846
1847 if ( WindowName->Buffer != NULL && WindowName->Length > 0 )
1848 {
1849 pWnd->strName.Buffer = DesktopHeapAlloc(pWnd->head.rpdesk,
1850 WindowName->Length + sizeof(UNICODE_NULL));
1851 if (pWnd->strName.Buffer == NULL)
1852 {
1853 goto AllocError;
1854 }
1855
1856 RtlCopyMemory(pWnd->strName.Buffer, WindowName->Buffer, WindowName->Length);
1857 pWnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
1858 pWnd->strName.Length = WindowName->Length;
1859 pWnd->strName.MaximumLength = WindowName->Length + sizeof(UNICODE_NULL);
1860 }
1861
1862 /* Correct the window style. */
1863 if ((pWnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1864 {
1865 pWnd->style |= WS_CLIPSIBLINGS;
1866 if (!(pWnd->style & WS_POPUP))
1867 {
1868 pWnd->style |= WS_CAPTION;
1869 }
1870 }
1871
1872 /* WS_EX_WINDOWEDGE depends on some other styles */
1873 if (pWnd->ExStyle & WS_EX_DLGMODALFRAME)
1874 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1875 else if (pWnd->style & (WS_DLGFRAME | WS_THICKFRAME))
1876 {
1877 if (!((pWnd->ExStyle & WS_EX_STATICEDGE) &&
1878 (pWnd->style & (WS_CHILD | WS_POPUP))))
1879 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1880 }
1881 else
1882 pWnd->ExStyle &= ~WS_EX_WINDOWEDGE;
1883
1884 if (!(pWnd->style & (WS_CHILD | WS_POPUP)))
1885 pWnd->state |= WNDS_SENDSIZEMOVEMSGS;
1886
1887 /* Create system menu */
1888 if ((Cs->style & WS_SYSMENU)) // && (dwStyle & WS_CAPTION) == WS_CAPTION)
1889 {
1890 SystemMenu = IntGetSystemMenu(pWnd, TRUE, TRUE);
1891 if(SystemMenu)
1892 {
1893 pWnd->SystemMenu = SystemMenu->MenuInfo.Self;
1894 IntReleaseMenuObject(SystemMenu);
1895 }
1896 }
1897
1898 /* Set the window menu */
1899 if ((Cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1900 {
1901 if (Cs->hMenu)
1902 IntSetMenu(pWnd, Cs->hMenu, &MenuChanged);
1903 else if (pWnd->pcls->lpszMenuName) // Take it from the parent.
1904 {
1905 UNICODE_STRING MenuName;
1906 HMENU hMenu;
1907
1908 if (IS_INTRESOURCE(pWnd->pcls->lpszMenuName))
1909 {
1910 MenuName.Length = 0;
1911 MenuName.MaximumLength = 0;
1912 MenuName.Buffer = pWnd->pcls->lpszMenuName;
1913 }
1914 else
1915 {
1916 RtlInitUnicodeString( &MenuName, pWnd->pcls->lpszMenuName);
1917 }
1918 hMenu = co_IntCallLoadMenu( pWnd->pcls->hModule, &MenuName);
1919 if (hMenu) IntSetMenu(pWnd, hMenu, &MenuChanged);
1920 }
1921 }
1922 else // Not a child
1923 pWnd->IDMenu = (UINT) Cs->hMenu;
1924
1925
1926 if ( ParentWindow &&
1927 ParentWindow != ParentWindow->head.rpdesk->spwndMessage &&
1928 ParentWindow != ParentWindow->head.rpdesk->pDeskInfo->spwnd )
1929 {
1930 PWND Owner = IntGetNonChildAncestor(ParentWindow);
1931
1932 if (!IntValidateOwnerDepth(pWnd, Owner))
1933 {
1934 EngSetLastError(ERROR_INVALID_PARAMETER);
1935 goto Error;
1936 }
1937 if ( pWnd->spwndOwner &&
1938 pWnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1939 {
1940 pWnd->ExStyle |= WS_EX_TOPMOST;
1941 }
1942 if ( pWnd->spwndOwner &&
1943 Class->atomClassName != gpsi->atomSysClass[ICLS_IME] &&
1944 pti != pWnd->spwndOwner->head.pti)
1945 {
1946 ERR("CreateWindow Owner in.\n");
1947 //UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE);
1948 }
1949 }
1950
1951 /* Insert the window into the thread's window list. */
1952 InsertTailList (&pti->WindowListHead, &pWnd->ThreadListEntry);
1953
1954 /* Handle "CS_CLASSDC", it is tested first. */
1955 if ( (pWnd->pcls->style & CS_CLASSDC) && !(pWnd->pcls->pdce) )
1956 { /* One DCE per class to have CLASS. */
1957 pWnd->pcls->pdce = DceAllocDCE( pWnd, DCE_CLASS_DC );
1958 }
1959 else if ( pWnd->pcls->style & CS_OWNDC)
1960 { /* Allocate a DCE for this window. */
1961 DceAllocDCE(pWnd, DCE_WINDOW_DC);
1962 }
1963
1964 return pWnd;
1965
1966 AllocError:
1967 ERR("IntCreateWindow Allocation Error.\n");
1968 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1969 Error:
1970 if(pWnd)
1971 UserDereferenceObject(pWnd);
1972 return NULL;
1973 }
1974
1975 /*
1976 * @implemented
1977 */
1978 PWND FASTCALL
1979 co_UserCreateWindowEx(CREATESTRUCTW* Cs,
1980 PUNICODE_STRING ClassName,
1981 PLARGE_STRING WindowName,
1982 PVOID acbiBuffer)
1983 {
1984 ULONG style;
1985 PWND Window = NULL, ParentWindow = NULL, OwnerWindow;
1986 HWND hWnd, hWndParent, hWndOwner, hwndInsertAfter;
1987 PWINSTATION_OBJECT WinSta;
1988 PCLS Class = NULL;
1989 SIZE Size;
1990 POINT MaxPos;
1991 CBT_CREATEWNDW * pCbtCreate;
1992 LRESULT Result;
1993 USER_REFERENCE_ENTRY ParentRef, Ref;
1994 PTHREADINFO pti;
1995 DWORD dwShowMode = SW_SHOW;
1996 CREATESTRUCTW *pCsw = NULL;
1997 PVOID pszClass = NULL, pszName = NULL;
1998 PWND ret = NULL;
1999
2000 /* Get the current window station and reference it */
2001 pti = GetW32ThreadInfo();
2002 if (pti == NULL || pti->rpdesk == NULL)
2003 {
2004 ERR("Thread is not attached to a desktop! Cannot create window!\n");
2005 return NULL; // There is nothing to cleanup.
2006 }
2007 WinSta = pti->rpdesk->rpwinstaParent;
2008 ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
2009
2010 pCsw = NULL;
2011 pCbtCreate = NULL;
2012
2013 /* Get the class and reference it */
2014 Class = IntGetAndReferenceClass(ClassName, Cs->hInstance, FALSE);
2015 if(!Class)
2016 {
2017 ERR("Failed to find class %wZ\n", ClassName);
2018 goto cleanup;
2019 }
2020
2021 /* Now find the parent and the owner window */
2022 hWndParent = IntGetDesktopWindow();
2023 hWndOwner = NULL;
2024
2025 if (Cs->hwndParent == HWND_MESSAGE)
2026 {
2027 Cs->hwndParent = hWndParent = IntGetMessageWindow();
2028 }
2029 else if (Cs->hwndParent)
2030 {
2031 if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
2032 hWndOwner = Cs->hwndParent;
2033 else
2034 hWndParent = Cs->hwndParent;
2035 }
2036 else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2037 {
2038 ERR("Cannot create a child window without a parrent!\n");
2039 EngSetLastError(ERROR_TLW_WITH_WSCHILD);
2040 goto cleanup; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
2041 }
2042
2043 ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
2044 OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
2045
2046 /* FIXME: Is this correct? */
2047 if(OwnerWindow)
2048 OwnerWindow = UserGetAncestor(OwnerWindow, GA_ROOT);
2049
2050 /* Fix the position and the size of the window */
2051 if (ParentWindow)
2052 {
2053 UserRefObjectCo(ParentWindow, &ParentRef);
2054 IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode);
2055 }
2056
2057 /* Allocate and initialize the new window */
2058 Window = IntCreateWindow(Cs,
2059 WindowName,
2060 Class,
2061 ParentWindow,
2062 OwnerWindow,
2063 acbiBuffer,
2064 NULL);
2065 if(!Window)
2066 {
2067 ERR("IntCreateWindow failed!\n");
2068 goto cleanup;
2069 }
2070
2071 hWnd = UserHMGetHandle(Window);
2072 hwndInsertAfter = HWND_TOP;
2073
2074 UserRefObjectCo(Window, &Ref);
2075 UserDereferenceObject(Window);
2076 ObDereferenceObject(WinSta);
2077
2078 //// Check for a hook to eliminate overhead. ////
2079 if ( ISITHOOKED(WH_CBT) || (pti->rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)) )
2080 {
2081 // Allocate the calling structures Justin Case this goes Global.
2082 pCsw = ExAllocatePoolWithTag(NonPagedPool, sizeof(CREATESTRUCTW), TAG_HOOK);
2083 pCbtCreate = ExAllocatePoolWithTag(NonPagedPool, sizeof(CBT_CREATEWNDW), TAG_HOOK);
2084 if (!pCsw || !pCbtCreate)
2085 {
2086 ERR("UserHeapAlloc() failed!\n");
2087 goto cleanup;
2088 }
2089
2090 /* Fill the new CREATESTRUCTW */
2091 RtlCopyMemory(pCsw, Cs, sizeof(CREATESTRUCTW));
2092 pCsw->style = Window->style; /* HCBT_CREATEWND needs the real window style */
2093
2094 // Based on the assumption this is from "unicode source" user32, ReactOS, answer is yes.
2095 if (!IS_ATOM(ClassName->Buffer))
2096 {
2097 if (Window->state & WNDS_ANSICREATOR)
2098 {
2099 ANSI_STRING AnsiString;
2100 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(ClassName)+sizeof(CHAR);
2101 pszClass = UserHeapAlloc(AnsiString.MaximumLength);
2102 if (!pszClass)
2103 {
2104 ERR("UserHeapAlloc() failed!\n");
2105 goto cleanup;
2106 }
2107 RtlZeroMemory(pszClass, AnsiString.MaximumLength);
2108 AnsiString.Buffer = (PCHAR)pszClass;
2109 RtlUnicodeStringToAnsiString(&AnsiString, ClassName, FALSE);
2110 }
2111 else
2112 {
2113 UNICODE_STRING UnicodeString;
2114 UnicodeString.MaximumLength = ClassName->Length + sizeof(UNICODE_NULL);
2115 pszClass = UserHeapAlloc(UnicodeString.MaximumLength);
2116 if (!pszClass)
2117 {
2118 ERR("UserHeapAlloc() failed!\n");
2119 goto cleanup;
2120 }
2121 RtlZeroMemory(pszClass, UnicodeString.MaximumLength);
2122 UnicodeString.Buffer = (PWSTR)pszClass;
2123 RtlCopyUnicodeString(&UnicodeString, ClassName);
2124 }
2125 pCsw->lpszClass = UserHeapAddressToUser(pszClass);
2126 }
2127 if (WindowName->Length)
2128 {
2129 UNICODE_STRING Name;
2130 Name.Buffer = WindowName->Buffer;
2131 Name.Length = (USHORT)min(WindowName->Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2132 Name.MaximumLength = (USHORT)min(WindowName->MaximumLength, MAXUSHORT);
2133
2134 if (Window->state & WNDS_ANSICREATOR)
2135 {
2136 ANSI_STRING AnsiString;
2137 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(&Name) + sizeof(CHAR);
2138 pszName = UserHeapAlloc(AnsiString.MaximumLength);
2139 if (!pszName)
2140 {
2141 ERR("UserHeapAlloc() failed!\n");
2142 goto cleanup;
2143 }
2144 RtlZeroMemory(pszName, AnsiString.MaximumLength);
2145 AnsiString.Buffer = (PCHAR)pszName;
2146 RtlUnicodeStringToAnsiString(&AnsiString, &Name, FALSE);
2147 }
2148 else
2149 {
2150 UNICODE_STRING UnicodeString;
2151 UnicodeString.MaximumLength = Name.Length + sizeof(UNICODE_NULL);
2152 pszName = UserHeapAlloc(UnicodeString.MaximumLength);
2153 if (!pszName)
2154 {
2155 ERR("UserHeapAlloc() failed!\n");
2156 goto cleanup;
2157 }
2158 RtlZeroMemory(pszName, UnicodeString.MaximumLength);
2159 UnicodeString.Buffer = (PWSTR)pszName;
2160 RtlCopyUnicodeString(&UnicodeString, &Name);
2161 }
2162 pCsw->lpszName = UserHeapAddressToUser(pszName);
2163 }
2164
2165 pCbtCreate->lpcs = pCsw;
2166 pCbtCreate->hwndInsertAfter = hwndInsertAfter;
2167
2168 //// Call the WH_CBT hook ////
2169 Result = co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) pCbtCreate);
2170 if (Result != 0)
2171 {
2172 ERR("WH_CBT HCBT_CREATEWND hook failed! 0x%x\n", Result);
2173 goto cleanup;
2174 }
2175 // Write back changes.
2176 Cs->cx = pCsw->cx;
2177 Cs->cy = pCsw->cy;
2178 Cs->x = pCsw->x;
2179 Cs->y = pCsw->y;
2180 hwndInsertAfter = pCbtCreate->hwndInsertAfter;
2181 }
2182
2183 /* NCCREATE and WM_NCCALCSIZE need the original values */
2184 Cs->lpszName = (LPCWSTR) WindowName;
2185 Cs->lpszClass = (LPCWSTR) ClassName;
2186
2187 /* Send the WM_GETMINMAXINFO message */
2188 Size.cx = Cs->cx;
2189 Size.cy = Cs->cy;
2190
2191 if ((Cs->style & WS_THICKFRAME) || !(Cs->style & (WS_POPUP | WS_CHILD)))
2192 {
2193 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
2194
2195 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
2196 if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
2197 if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
2198 if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
2199 if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
2200 }
2201
2202 Window->rcWindow.left = Cs->x;
2203 Window->rcWindow.top = Cs->y;
2204 Window->rcWindow.right = Cs->x + Size.cx;
2205 Window->rcWindow.bottom = Cs->y + Size.cy;
2206 if (0 != (Window->style & WS_CHILD) && ParentWindow)
2207 {
2208 // ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
2209 RECTL_vOffsetRect(&Window->rcWindow,
2210 ParentWindow->rcClient.left,
2211 ParentWindow->rcClient.top);
2212 }
2213 Window->rcClient = Window->rcWindow;
2214
2215 /* Link the window */
2216 if (NULL != ParentWindow)
2217 {
2218 /* Link the window into the siblings list */
2219 if ((Cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2220 IntLinkHwnd(Window, HWND_BOTTOM);
2221 else
2222 IntLinkHwnd(Window, hwndInsertAfter);
2223 }
2224
2225 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2226 {
2227 if ( !IntIsTopLevelWindow(Window) )
2228 {
2229 if (pti != Window->spwndParent->head.pti)
2230 {
2231 ERR("CreateWindow Parent in.\n");
2232 //UserAttachThreadInput(pti, Window->spwndParent->head.pti, TRUE);
2233 }
2234 }
2235 }
2236
2237 /* Send the NCCREATE message */
2238 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_NCCREATE, 0, (LPARAM) Cs);
2239 if (!Result)
2240 {
2241 ERR("co_UserCreateWindowEx(): NCCREATE message failed\n");
2242 goto cleanup;
2243 }
2244
2245 /* Send the WM_NCCALCSIZE message */
2246 MaxPos.x = Window->rcWindow.left;
2247 MaxPos.y = Window->rcWindow.top;
2248
2249 Result = co_WinPosGetNonClientSize(Window, &Window->rcWindow, &Window->rcClient);
2250
2251 RECTL_vOffsetRect(&Window->rcWindow, MaxPos.x - Window->rcWindow.left,
2252 MaxPos.y - Window->rcWindow.top);
2253
2254
2255 /* Send the WM_CREATE message. */
2256 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_CREATE, 0, (LPARAM) Cs);
2257 if (Result == (LRESULT)-1)
2258 {
2259 ERR("co_UserCreateWindowEx(): WM_CREATE message failed\n");
2260 goto cleanup;
2261 }
2262
2263 /* Send the EVENT_OBJECT_CREATE event */
2264 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2265
2266 /* By setting the flag below it can be examined to determine if the window
2267 was created successfully and a valid pwnd was passed back to caller since
2268 from here the function has to succeed. */
2269 Window->state2 |= WNDS2_WMCREATEMSGPROCESSED;
2270
2271 /* Send the WM_SIZE and WM_MOVE messages. */
2272 if (!(Window->state & WNDS_SENDSIZEMOVEMSGS))
2273 {
2274 co_WinPosSendSizeMove(Window);
2275 }
2276
2277 /* Show or maybe minimize or maximize the window. */
2278
2279 style = IntSetStyle( Window, 0, WS_MAXIMIZE | WS_MINIMIZE );
2280 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2281 {
2282 RECTL NewPos;
2283 UINT SwFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
2284
2285 SwFlag = co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2286 SwFlag |= SWP_NOZORDER|SWP_FRAMECHANGED; /* Frame always gets changed */
2287 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || UserGetActiveWindow()) SwFlag |= SWP_NOACTIVATE;
2288 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2289 NewPos.right, NewPos.bottom, SwFlag);
2290 }
2291
2292 /* Send the WM_PARENTNOTIFY message */
2293 IntSendParentNotify(Window, WM_CREATE);
2294
2295 /* Notify the shell that a new window was created */
2296 if ((!hWndParent) && (!hWndOwner))
2297 {
2298 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0);
2299 }
2300
2301 /* Initialize and show the window's scrollbars */
2302 if (Window->style & WS_VSCROLL)
2303 {
2304 co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE);
2305 }
2306 if (Window->style & WS_HSCROLL)
2307 {
2308 co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE);
2309 }
2310
2311 /* Show the new window */
2312 if (Cs->style & WS_VISIBLE)
2313 {
2314 if (Window->style & WS_MAXIMIZE)
2315 dwShowMode = SW_SHOW;
2316 else if (Window->style & WS_MINIMIZE)
2317 dwShowMode = SW_SHOWMINIMIZED;
2318
2319 co_WinPosShowWindow(Window, dwShowMode);
2320
2321 if (Window->ExStyle & WS_EX_MDICHILD)
2322 {
2323 ASSERT(ParentWindow);
2324 if(!ParentWindow)
2325 goto cleanup;
2326 co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0);
2327 /* ShowWindow won't activate child windows */
2328 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2329 }
2330 }
2331
2332 TRACE("co_UserCreateWindowEx(): Created window %X\n", hWnd);
2333 ret = Window;
2334
2335 cleanup:
2336 if (!ret)
2337 {
2338 TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2339 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2340 if (Window)
2341 co_UserDestroyWindow(Window);
2342 else if (Class)
2343 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2344 }
2345
2346 if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
2347 if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
2348 if (pszName) UserHeapFree(pszName);
2349 if (pszClass) UserHeapFree(pszClass);
2350
2351 if (Window)
2352 {
2353 UserDerefObjectCo(Window);
2354 }
2355 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2356
2357 return ret;
2358 }
2359
2360 NTSTATUS
2361 NTAPI
2362 ProbeAndCaptureLargeString(
2363 OUT PLARGE_STRING plstrSafe,
2364 IN PLARGE_STRING plstrUnsafe)
2365 {
2366 LARGE_STRING lstrTemp;
2367 PVOID pvBuffer = NULL;
2368
2369 _SEH2_TRY
2370 {
2371 /* Probe and copy the string */
2372 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2373 lstrTemp = *plstrUnsafe;
2374 }
2375 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2376 {
2377 /* Fail */
2378 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2379 }
2380 _SEH2_END
2381
2382 if (lstrTemp.Length != 0)
2383 {
2384 /* Allocate a buffer from paged pool */
2385 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2386 if (!pvBuffer)
2387 {
2388 return STATUS_NO_MEMORY;
2389 }
2390
2391 _SEH2_TRY
2392 {
2393 /* Probe and copy the buffer */
2394 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2395 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2396 }
2397 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2398 {
2399 /* Cleanup and fail */
2400 ExFreePoolWithTag(pvBuffer, TAG_STRING);
2401 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2402 }
2403 _SEH2_END
2404 }
2405
2406 /* Set the output string */
2407 plstrSafe->Buffer = pvBuffer;
2408 plstrSafe->Length = lstrTemp.Length;
2409 plstrSafe->MaximumLength = lstrTemp.Length;
2410
2411 return STATUS_SUCCESS;
2412 }
2413
2414 /**
2415 * \todo Allow passing plstrClassName as ANSI.
2416 */
2417 HWND
2418 NTAPI
2419 NtUserCreateWindowEx(
2420 DWORD dwExStyle,
2421 PLARGE_STRING plstrClassName,
2422 PLARGE_STRING plstrClsVersion,
2423 PLARGE_STRING plstrWindowName,
2424 DWORD dwStyle,
2425 int x,
2426 int y,
2427 int nWidth,
2428 int nHeight,
2429 HWND hWndParent,
2430 HMENU hMenu,
2431 HINSTANCE hInstance,
2432 LPVOID lpParam,
2433 DWORD dwFlags,
2434 PVOID acbiBuffer)
2435 {
2436 NTSTATUS Status;
2437 LARGE_STRING lstrWindowName;
2438 LARGE_STRING lstrClassName;
2439 UNICODE_STRING ustrClassName;
2440 CREATESTRUCTW Cs;
2441 HWND hwnd = NULL;
2442 PWND pwnd;
2443
2444 lstrWindowName.Buffer = NULL;
2445 lstrClassName.Buffer = NULL;
2446
2447 ASSERT(plstrWindowName);
2448
2449 /* Copy the window name to kernel mode */
2450 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2451 if (!NT_SUCCESS(Status))
2452 {
2453 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2454 SetLastNtError(Status);
2455 return NULL;
2456 }
2457
2458 plstrWindowName = &lstrWindowName;
2459
2460 /* Check if the class is an atom */
2461 if (IS_ATOM(plstrClassName))
2462 {
2463 /* It is, pass the atom in the UNICODE_STRING */
2464 ustrClassName.Buffer = (PVOID)plstrClassName;
2465 ustrClassName.Length = 0;
2466 ustrClassName.MaximumLength = 0;
2467 }
2468 else
2469 {
2470 /* It's not, capture the class name */
2471 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2472 if (!NT_SUCCESS(Status))
2473 {
2474 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2475 /* Set last error, cleanup and return */
2476 SetLastNtError(Status);
2477 goto cleanup;
2478 }
2479
2480 /* We pass it on as a UNICODE_STRING */
2481 ustrClassName.Buffer = lstrClassName.Buffer;
2482 ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2483 ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
2484 }
2485
2486 /* Fill the CREATESTRUCTW */
2487 /* we will keep here the original parameters */
2488 Cs.style = dwStyle;
2489 Cs.lpCreateParams = lpParam;
2490 Cs.hInstance = hInstance;
2491 Cs.hMenu = hMenu;
2492 Cs.hwndParent = hWndParent;
2493 Cs.cx = nWidth;
2494 Cs.cy = nHeight;
2495 Cs.x = x;
2496 Cs.y = y;
2497 Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
2498 if (IS_ATOM(plstrClassName))
2499 Cs.lpszClass = (LPCWSTR) plstrClassName;
2500 else
2501 Cs.lpszClass = (LPCWSTR) plstrClassName->Buffer;
2502 Cs.dwExStyle = dwExStyle;
2503
2504 UserEnterExclusive();
2505
2506 /* Call the internal function */
2507 pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName, acbiBuffer, NULL);
2508
2509 if(!pwnd)
2510 {
2511 ERR("co_UserCreateWindowEx failed!\n");
2512 }
2513 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2514
2515 UserLeave();
2516
2517 cleanup:
2518 if (lstrWindowName.Buffer)
2519 {
2520 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2521 }
2522 if (lstrClassName.Buffer)
2523 {
2524 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2525 }
2526
2527 return hwnd;
2528 }
2529
2530
2531 BOOLEAN FASTCALL co_UserDestroyWindow(PWND Window)
2532 {
2533 HWND hWnd;
2534 PWND pwndTemp;
2535 PTHREADINFO ti;
2536 MSG msg;
2537
2538 ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
2539
2540 hWnd = Window->head.h;
2541 ti = PsGetCurrentThreadWin32Thread();
2542
2543 TRACE("co_UserDestroyWindow \n");
2544
2545 /* Check for owner thread */
2546 if ( Window->head.pti != PsGetCurrentThreadWin32Thread())
2547 {
2548 /* Check if we are destroying the desktop window */
2549 if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
2550 {
2551 EngSetLastError(ERROR_ACCESS_DENIED);
2552 return FALSE;
2553 }
2554 }
2555
2556 /* If window was created successfully and it is hooked */
2557 if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
2558 {
2559 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0))
2560 {
2561 ERR("Destroy Window WH_CBT Call Hook return!\n");
2562 return FALSE;
2563 }
2564 }
2565
2566 if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
2567 {
2568 if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2569 {
2570 if (Window->spwndOwner)
2571 {
2572 ERR("DestroyWindow Owner out.\n");
2573 //UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2574 }
2575 }
2576 }
2577
2578 /* Inform the parent */
2579 if (Window->style & WS_CHILD)
2580 {
2581 IntSendParentNotify(Window, WM_DESTROY);
2582 }
2583
2584 /* Look whether the focus is within the tree of windows we will
2585 * be destroying.
2586 */
2587 if (!co_WinPosShowWindow(Window, SW_HIDE))
2588 { // Rule #1.
2589 if (ti->MessageQueue->spwndActive == Window && ti->MessageQueue == IntGetFocusMessageQueue())
2590 {
2591 co_WinPosActivateOtherWindow(Window);
2592 }
2593 }
2594
2595 // Adjust last active.
2596 if ((pwndTemp = Window->spwndOwner))
2597 {
2598 while (pwndTemp->spwndOwner)
2599 pwndTemp = pwndTemp->spwndOwner;
2600
2601 if (pwndTemp->spwndLastActive == Window)
2602 pwndTemp->spwndLastActive = Window->spwndOwner;
2603 }
2604
2605 if (Window->spwndParent && IntIsWindow(Window->head.h))
2606 {
2607 if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
2608 {
2609 if (!IntIsTopLevelWindow(Window))
2610 {
2611 ERR("DestroyWindow Parent out.\n");
2612 //UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2613 }
2614 }
2615 }
2616
2617 if (Window->head.pti->MessageQueue->spwndActive == Window)
2618 Window->head.pti->MessageQueue->spwndActive = NULL;
2619 if (Window->head.pti->MessageQueue->spwndFocus == Window)
2620 Window->head.pti->MessageQueue->spwndFocus = NULL;
2621 if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
2622 Window->head.pti->MessageQueue->spwndActivePrev = NULL;
2623 if (Window->head.pti->MessageQueue->spwndCapture == Window)
2624 Window->head.pti->MessageQueue->spwndCapture = NULL;
2625
2626 /*
2627 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2628 */
2629
2630 if ((ti != NULL) & (ti->pDeskInfo != NULL))
2631 {
2632 if (ti->pDeskInfo->hShellWindow == hWnd)
2633 {
2634 ERR("Destroying the ShellWindow!\n");
2635 ti->pDeskInfo->hShellWindow = NULL;
2636 }
2637 }
2638
2639 IntEngWindowChanged(Window, WOC_DELETE);
2640
2641 if (!IntIsWindow(Window->head.h))
2642 {
2643 return TRUE;
2644 }
2645
2646 /* Recursively destroy owned windows */
2647
2648 if (! (Window->style & WS_CHILD))
2649 {
2650 for (;;)
2651 {
2652 BOOL GotOne = FALSE;
2653 HWND *Children;
2654 HWND *ChildHandle;
2655 PWND Child, Desktop;
2656
2657 Desktop = IntIsDesktopWindow(Window) ? Window :
2658 UserGetWindowObject(IntGetDesktopWindow());
2659 Children = IntWinListChildren(Desktop);
2660
2661 if (Children)
2662 {
2663 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2664 {
2665 Child = UserGetWindowObject(*ChildHandle);
2666 if (Child == NULL)
2667 continue;
2668 if (Child->spwndOwner != Window)
2669 {
2670 continue;
2671 }
2672
2673 if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
2674 {
2675 USER_REFERENCE_ENTRY ChildRef;
2676 UserRefObjectCo(Child, &ChildRef); // Temp HACK?
2677 co_UserDestroyWindow(Child);
2678 UserDerefObjectCo(Child); // Temp HACK?
2679
2680 GotOne = TRUE;
2681 continue;
2682 }
2683
2684 if (Child->spwndOwner != NULL)
2685 {
2686 Child->spwndOwner = NULL;
2687 }
2688
2689 }
2690 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
2691 }
2692 if (! GotOne)
2693 {
2694 break;
2695 }
2696 }
2697 }
2698
2699 /* Generate mouse move message for the next window */
2700 msg.message = WM_MOUSEMOVE;
2701 msg.wParam = UserGetMouseButtonsState();
2702 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2703 msg.pt = gpsi->ptCursor;
2704 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2705
2706 if (!IntIsWindow(Window->head.h))
2707 {
2708 return TRUE;
2709 }
2710
2711 /* Destroy the window storage */
2712 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2713
2714 return TRUE;
2715 }
2716
2717
2718 /*
2719 * @implemented
2720 */
2721 BOOLEAN APIENTRY
2722 NtUserDestroyWindow(HWND Wnd)
2723 {
2724 PWND Window;
2725 DECLARE_RETURN(BOOLEAN);
2726 BOOLEAN ret;
2727 USER_REFERENCE_ENTRY Ref;
2728
2729 TRACE("Enter NtUserDestroyWindow\n");
2730 UserEnterExclusive();
2731
2732 if (!(Window = UserGetWindowObject(Wnd)))
2733 {
2734 RETURN(FALSE);
2735 }
2736
2737 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
2738 ret = co_UserDestroyWindow(Window);
2739 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
2740
2741 RETURN(ret);
2742
2743 CLEANUP:
2744 TRACE("Leave NtUserDestroyWindow, ret=%i\n",_ret_);
2745 UserLeave();
2746 END_CLEANUP;
2747 }
2748
2749
2750 static HWND FASTCALL
2751 IntFindWindow(PWND Parent,
2752 PWND ChildAfter,
2753 RTL_ATOM ClassAtom,
2754 PUNICODE_STRING WindowName)
2755 {
2756 BOOL CheckWindowName;
2757 HWND *List, *phWnd;
2758 HWND Ret = NULL;
2759 UNICODE_STRING CurrentWindowName;
2760
2761 ASSERT(Parent);
2762
2763 CheckWindowName = WindowName->Buffer != 0;
2764
2765 if((List = IntWinListChildren(Parent)))
2766 {
2767 phWnd = List;
2768 if(ChildAfter)
2769 {
2770 /* skip handles before and including ChildAfter */
2771 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2772 ;
2773 }
2774
2775 /* search children */
2776 while(*phWnd)
2777 {
2778 PWND Child;
2779 if(!(Child = UserGetWindowObject(*(phWnd++))))
2780 {
2781 continue;
2782 }
2783
2784 /* Do not send WM_GETTEXT messages in the kernel mode version!
2785 The user mode version however calls GetWindowText() which will
2786 send WM_GETTEXT messages to windows belonging to its processes */
2787 if (!ClassAtom || Child->pcls->atomClassName == ClassAtom)
2788 {
2789 // FIXME: LARGE_STRING truncated
2790 CurrentWindowName.Buffer = Child->strName.Buffer;
2791 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
2792 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
2793 if(!CheckWindowName ||
2794 (Child->strName.Length < 0xFFFF &&
2795 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
2796 {
2797 Ret = Child->head.h;
2798 break;
2799 }
2800 }
2801 }
2802 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2803 }
2804
2805 return Ret;
2806 }
2807
2808 /*
2809 * FUNCTION:
2810 * Searches a window's children for a window with the specified
2811 * class and name
2812 * ARGUMENTS:
2813 * hwndParent = The window whose childs are to be searched.
2814 * NULL = desktop
2815 * HWND_MESSAGE = message-only windows
2816 *
2817 * hwndChildAfter = Search starts after this child window.
2818 * NULL = start from beginning
2819 *
2820 * ucClassName = Class name to search for
2821 * Reguired parameter.
2822 *
2823 * ucWindowName = Window name
2824 * ->Buffer == NULL = don't care
2825 *
2826 * RETURNS:
2827 * The HWND of the window if it was found, otherwise NULL
2828 */
2829 /*
2830 * @implemented
2831 */
2832 HWND APIENTRY
2833 NtUserFindWindowEx(HWND hwndParent,
2834 HWND hwndChildAfter,
2835 PUNICODE_STRING ucClassName,
2836 PUNICODE_STRING ucWindowName,
2837 DWORD dwUnknown)
2838 {
2839 PWND Parent, ChildAfter;
2840 UNICODE_STRING ClassName = {0}, WindowName = {0};
2841 HWND Desktop, Ret = NULL;
2842 BOOL DoMessageWnd = FALSE;
2843 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2844 DECLARE_RETURN(HWND);
2845
2846 TRACE("Enter NtUserFindWindowEx\n");
2847 UserEnterShared();
2848
2849 if (ucClassName != NULL || ucWindowName != NULL)
2850 {
2851 _SEH2_TRY
2852 {
2853 if (ucClassName != NULL)
2854 {
2855 ClassName = ProbeForReadUnicodeString(ucClassName);
2856 if (ClassName.Length != 0)
2857 {
2858 ProbeForRead(ClassName.Buffer,
2859 ClassName.Length,
2860 sizeof(WCHAR));
2861 }
2862 else if (!IS_ATOM(ClassName.Buffer))
2863 {
2864 EngSetLastError(ERROR_INVALID_PARAMETER);
2865 _SEH2_LEAVE;
2866 }
2867
2868 if (!IntGetAtomFromStringOrAtom(&ClassName,
2869 &ClassAtom))
2870 {
2871 _SEH2_LEAVE;
2872 }
2873 }
2874
2875 if (ucWindowName != NULL)
2876 {
2877 WindowName = ProbeForReadUnicodeString(ucWindowName);
2878 if (WindowName.Length != 0)
2879 {
2880 ProbeForRead(WindowName.Buffer,
2881 WindowName.Length,
2882 sizeof(WCHAR));
2883 }
2884 }
2885 }
2886 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2887 {
2888 SetLastNtError(_SEH2_GetExceptionCode());
2889 _SEH2_YIELD(RETURN(NULL));
2890 }
2891 _SEH2_END;
2892
2893 if (ucClassName != NULL)
2894 {
2895 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
2896 !IS_ATOM(ClassName.Buffer))
2897 {
2898 EngSetLastError(ERROR_INVALID_PARAMETER);
2899 RETURN(NULL);
2900 }
2901 else if (ClassAtom == (RTL_ATOM)0)
2902 {
2903 /* LastError code was set by IntGetAtomFromStringOrAtom */
2904 RETURN(NULL);
2905 }
2906 }
2907 }
2908
2909 Desktop = IntGetCurrentThreadDesktopWindow();
2910
2911 if(hwndParent == NULL)
2912 {
2913 hwndParent = Desktop;
2914 DoMessageWnd = TRUE;
2915 }
2916 else if(hwndParent == HWND_MESSAGE)
2917 {
2918 hwndParent = IntGetMessageWindow();
2919 }
2920
2921 if(!(Parent = UserGetWindowObject(hwndParent)))
2922 {
2923 RETURN( NULL);
2924 }
2925
2926 ChildAfter = NULL;
2927 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
2928 {
2929 RETURN( NULL);
2930 }
2931
2932 _SEH2_TRY
2933 {
2934 if(Parent->head.h == Desktop)
2935 {
2936 HWND *List, *phWnd;
2937 PWND TopLevelWindow;
2938 BOOLEAN CheckWindowName;
2939 BOOLEAN WindowMatches;
2940 BOOLEAN ClassMatches;
2941
2942 /* windows searches through all top-level windows if the parent is the desktop
2943 window */
2944
2945 if((List = IntWinListChildren(Parent)))
2946 {
2947 phWnd = List;
2948
2949 if(ChildAfter)
2950 {
2951 /* skip handles before and including ChildAfter */
2952 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2953 ;
2954 }
2955
2956 CheckWindowName = WindowName.Buffer != 0;
2957
2958 /* search children */
2959 while(*phWnd)
2960 {
2961 UNICODE_STRING ustr;
2962
2963 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
2964 {
2965 continue;
2966 }
2967
2968 /* Do not send WM_GETTEXT messages in the kernel mode version!
2969 The user mode version however calls GetWindowText() which will
2970 send WM_GETTEXT messages to windows belonging to its processes */
2971 ustr.Buffer = TopLevelWindow->strName.Buffer;
2972 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
2973 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
2974 WindowMatches = !CheckWindowName ||
2975 (TopLevelWindow->strName.Length < 0xFFFF &&
2976 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
2977 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
2978 ClassAtom == TopLevelWindow->pcls->atomClassName;
2979
2980 if (WindowMatches && ClassMatches)
2981 {
2982 Ret = TopLevelWindow->head.h;
2983 break;
2984 }
2985
2986 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
2987 {
2988 /* window returns the handle of the top-level window, in case it found
2989 the child window */
2990 Ret = TopLevelWindow->head.h;
2991 break;
2992 }
2993
2994 }
2995 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2996 }
2997 }
2998 else
2999 {
3000 ERR("FindWindowEx: Not Desktop Parent!\n");
3001 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
3002 }
3003
3004 if (Ret == NULL && DoMessageWnd)
3005 {
3006 PWND MsgWindows;
3007
3008 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3009 {
3010 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3011 }
3012 }
3013 }
3014 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3015 {
3016 SetLastNtError(_SEH2_GetExceptionCode());
3017 Ret = NULL;
3018 }
3019 _SEH2_END;
3020
3021 RETURN( Ret);
3022
3023 CLEANUP:
3024 TRACE("Leave NtUserFindWindowEx, ret %i\n",_ret_);
3025 UserLeave();
3026 END_CLEANUP;
3027 }
3028
3029
3030 /*
3031 * @implemented
3032 */
3033 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
3034 {
3035 PWND WndAncestor, Parent;
3036
3037 if (Wnd->head.h == IntGetDesktopWindow())
3038 {
3039 return NULL;
3040 }
3041
3042 switch (Type)
3043 {
3044 case GA_PARENT:
3045 {
3046 WndAncestor = Wnd->spwndParent;
3047 break;
3048 }
3049
3050 case GA_ROOT:
3051 {
3052 WndAncestor = Wnd;
3053 Parent = NULL;
3054
3055 for(;;)
3056 {
3057 if(!(Parent = WndAncestor->spwndParent))
3058 {
3059 break;
3060 }
3061 if(IntIsDesktopWindow(Parent))
3062 {
3063 break;
3064 }
3065
3066 WndAncestor = Parent;
3067 }
3068 break;
3069 }
3070
3071 case GA_ROOTOWNER:
3072 {
3073 WndAncestor = Wnd;
3074
3075 for (;;)
3076 {
3077 PWND Parent;
3078
3079 Parent = IntGetParent(WndAncestor);
3080
3081 if (!Parent)
3082 {
3083 break;
3084 }
3085
3086 WndAncestor = Parent;
3087 }
3088 break;
3089 }
3090
3091 default:
3092 {
3093 return NULL;
3094 }
3095 }
3096
3097 return WndAncestor;
3098 }
3099
3100 /*
3101 * @implemented
3102 */
3103 HWND APIENTRY
3104 NtUserGetAncestor(HWND hWnd, UINT Type)
3105 {
3106 PWND Window, Ancestor;
3107 DECLARE_RETURN(HWND);
3108
3109 TRACE("Enter NtUserGetAncestor\n");
3110 UserEnterExclusive();
3111
3112 if (!(Window = UserGetWindowObject(hWnd)))
3113 {
3114 RETURN(NULL);
3115 }
3116
3117 Ancestor = UserGetAncestor(Window, Type);
3118 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3119
3120 RETURN(Ancestor ? Ancestor->head.h : NULL);
3121
3122 CLEANUP:
3123 TRACE("Leave NtUserGetAncestor, ret=%i\n",_ret_);
3124 UserLeave();
3125 END_CLEANUP;
3126 }
3127
3128
3129 BOOL
3130 APIENTRY
3131 NtUserGetComboBoxInfo(
3132 HWND hWnd,
3133 PCOMBOBOXINFO pcbi)
3134 {
3135 PWND Wnd;
3136 DECLARE_RETURN(BOOL);
3137
3138 TRACE("Enter NtUserGetComboBoxInfo\n");
3139 UserEnterShared();
3140
3141 if (!(Wnd = UserGetWindowObject(hWnd)))
3142 {
3143 RETURN( FALSE );
3144 }
3145 _SEH2_TRY
3146 {
3147 if(pcbi)
3148 {
3149 ProbeForWrite(pcbi,
3150 sizeof(COMBOBOXINFO),
3151 1);
3152 }
3153 }
3154 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3155 {
3156 SetLastNtError(_SEH2_GetExceptionCode());
3157 _SEH2_YIELD(RETURN(FALSE));
3158 }
3159 _SEH2_END;
3160
3161 // Pass the user pointer, it was already probed.
3162 RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3163
3164 CLEANUP:
3165 TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3166 UserLeave();
3167 END_CLEANUP;
3168 }
3169
3170
3171 DWORD
3172 APIENTRY
3173 NtUserGetListBoxInfo(
3174 HWND hWnd)
3175 {
3176 PWND Wnd;
3177 DECLARE_RETURN(DWORD);
3178
3179 TRACE("Enter NtUserGetListBoxInfo\n");
3180 UserEnterShared();
3181
3182 if (!(Wnd = UserGetWindowObject(hWnd)))
3183 {
3184 RETURN( 0 );
3185 }
3186
3187 RETURN( (DWORD) co_IntSendMessage( Wnd->head.h, LB_GETLISTBOXINFO, 0, 0 ));
3188
3189 CLEANUP:
3190 TRACE("Leave NtUserGetListBoxInfo, ret=%i\n",_ret_);
3191 UserLeave();
3192 END_CLEANUP;
3193 }
3194
3195 /*
3196 * NtUserSetParent
3197 *
3198 * The NtUserSetParent function changes the parent window of the specified
3199 * child window.
3200 *
3201 * Remarks
3202 * The new parent window and the child window must belong to the same
3203 * application. If the window identified by the hWndChild parameter is
3204 * visible, the system performs the appropriate redrawing and repainting.
3205 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3206 * or WS_POPUP window styles of the window whose parent is being changed.
3207 *
3208 * Status
3209 * @implemented
3210 */
3211
3212 HWND APIENTRY
3213 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3214 {
3215 DECLARE_RETURN(HWND);
3216
3217 TRACE("Enter NtUserSetParent\n");
3218 UserEnterExclusive();
3219
3220 /*
3221 Check Parent first from user space, set it here.
3222 */
3223 if (!hWndNewParent)
3224 {
3225 hWndNewParent = IntGetDesktopWindow();
3226 }
3227 else if (hWndNewParent == HWND_MESSAGE)
3228 {
3229 hWndNewParent = IntGetMessageWindow();
3230 }
3231
3232 RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3233
3234 CLEANUP:
3235 TRACE("Leave NtUserSetParent, ret=%i\n",_ret_);
3236 UserLeave();
3237 END_CLEANUP;
3238 }
3239
3240 /*
3241 * UserGetShellWindow
3242 *
3243 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3244 *
3245 * Status
3246 * @implemented
3247 */
3248 HWND FASTCALL UserGetShellWindow(VOID)
3249 {
3250 PWINSTATION_OBJECT WinStaObject;
3251 HWND Ret;
3252
3253 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3254 KernelMode,
3255 0,
3256 &WinStaObject);
3257
3258 if (!NT_SUCCESS(Status))
3259 {
3260 SetLastNtError(Status);
3261 return( (HWND)0);
3262 }
3263
3264 Ret = (HWND)WinStaObject->ShellWindow;
3265
3266 ObDereferenceObject(WinStaObject);
3267 return( Ret);
3268 }
3269
3270 /*
3271 * NtUserSetShellWindowEx
3272 *
3273 * This is undocumented function to set global shell window. The global
3274 * shell window has special handling of window position.
3275 *
3276 * Status
3277 * @implemented
3278 */
3279 BOOL APIENTRY
3280 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3281 {
3282 PWINSTATION_OBJECT WinStaObject;
3283 PWND WndShell, WndListView;
3284 DECLARE_RETURN(BOOL);
3285 USER_REFERENCE_ENTRY Ref;
3286 NTSTATUS Status;
3287 PTHREADINFO ti;
3288
3289 TRACE("Enter NtUserSetShellWindowEx\n");
3290 UserEnterExclusive();
3291
3292 if (!(WndShell = UserGetWindowObject(hwndShell)))
3293 {
3294 RETURN(FALSE);
3295 }
3296
3297 if(!(WndListView = UserGetWindowObject(hwndListView)))
3298 {
3299 RETURN(FALSE);
3300 }
3301
3302 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3303 KernelMode,
3304 0,
3305 &WinStaObject);
3306
3307 if (!NT_SUCCESS(Status))
3308 {
3309 SetLastNtError(Status);
3310 RETURN( FALSE);
3311 }
3312
3313 /*
3314 * Test if we are permitted to change the shell window.
3315 */
3316 if (WinStaObject->ShellWindow)
3317 {
3318 ObDereferenceObject(WinStaObject);
3319 RETURN( FALSE);
3320 }
3321
3322 /*
3323 * Move shell window into background.
3324 */
3325 if (hwndListView && hwndListView != hwndShell)
3326 {
3327 /*
3328 * Disabled for now to get Explorer working.
3329 * -- Filip, 01/nov/2003
3330 */
3331 #if 0
3332 co_WinPosSetWindowPos(WndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3333 #endif
3334
3335 if (WndListView->ExStyle & WS_EX_TOPMOST)
3336 {
3337 ObDereferenceObject(WinStaObject);
3338 RETURN( FALSE);
3339 }
3340 }
3341
3342 if (WndShell->ExStyle & WS_EX_TOPMOST)
3343 {
3344 ObDereferenceObject(WinStaObject);
3345 RETURN( FALSE);
3346 }
3347
3348 UserRefObjectCo(WndShell, &Ref);
3349 co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3350
3351 WinStaObject->ShellWindow = hwndShell;
3352 WinStaObject->ShellListView = hwndListView;
3353
3354 ti = GetW32ThreadInfo();
3355 if (ti->pDeskInfo)
3356 {
3357 ti->pDeskInfo->hShellWindow = hwndShell;
3358 ti->pDeskInfo->ppiShellProcess = ti->ppi;
3359 }
3360
3361 UserDerefObjectCo(WndShell);
3362
3363 ObDereferenceObject(WinStaObject);
3364 RETURN( TRUE);
3365
3366 CLEANUP:
3367 TRACE("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3368 UserLeave();
3369 END_CLEANUP;
3370 }
3371
3372 /*
3373 * NtUserGetSystemMenu
3374 *
3375 * The NtUserGetSystemMenu function allows the application to access the
3376 * window menu (also known as the system menu or the control menu) for
3377 * copying and modifying.
3378 *
3379 * Parameters
3380 * hWnd
3381 * Handle to the window that will own a copy of the window menu.
3382 * bRevert
3383 * Specifies the action to be taken. If this parameter is FALSE,
3384 * NtUserGetSystemMenu returns a handle to the copy of the window menu
3385 * currently in use. The copy is initially identical to the window menu
3386 * but it can be modified.
3387 * If this parameter is TRUE, GetSystemMenu resets the window menu back
3388 * to the default state. The previous window menu, if any, is destroyed.
3389 *
3390 * Return Value
3391 * If the bRevert parameter is FALSE, the return value is a handle to a
3392 * copy of the window menu. If the bRevert parameter is TRUE, the return
3393 * value is NULL.
3394 *
3395 * Status
3396 * @implemented
3397 */
3398
3399 HMENU APIENTRY
3400 NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
3401 {
3402 PWND Window;
3403 PMENU_OBJECT Menu;
3404 DECLARE_RETURN(HMENU);
3405
3406 TRACE("Enter NtUserGetSystemMenu\n");
3407 UserEnterShared();
3408
3409 if (!(Window = UserGetWindowObject(hWnd)))
3410 {
3411 RETURN(NULL);
3412 }
3413
3414 if (!(Menu = IntGetSystemMenu(Window, bRevert, FALSE)))
3415 {
3416 RETURN(NULL);
3417 }
3418
3419 RETURN(Menu->MenuInfo.Self);
3420
3421 CLEANUP:
3422 TRACE("Leave NtUserGetSystemMenu, ret=%i\n",_ret_);
3423 UserLeave();
3424 END_CLEANUP;
3425 }
3426
3427 /*
3428 * NtUserSetSystemMenu
3429 *
3430 * Status
3431 * @implemented
3432 */
3433
3434 BOOL APIENTRY
3435 NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
3436 {
3437 BOOL Result = FALSE;
3438 PWND Window;
3439 PMENU_OBJECT Menu;
3440 DECLARE_RETURN(BOOL);
3441
3442 TRACE("Enter NtUserSetSystemMenu\n");
3443 UserEnterExclusive();
3444
3445 if (!(Window = UserGetWindowObject(hWnd)))
3446 {
3447 RETURN( FALSE);
3448 }
3449
3450 if (hMenu)
3451 {
3452 /*
3453 * Assign new menu handle.
3454 */
3455 if (!(Menu = UserGetMenuObject(hMenu)))
3456 {
3457 RETURN( FALSE);
3458 }
3459
3460 Result = IntSetSystemMenu(Window, Menu);
3461 }
3462
3463 RETURN( Result);
3464
3465 CLEANUP:
3466 TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_);
3467 UserLeave();
3468 END_CLEANUP;
3469 }
3470
3471 // Fixes wine Win test_window_styles and todo tests...
3472 static BOOL FASTCALL
3473 IntCheckFrameEdge(ULONG Style, ULONG ExStyle)
3474 {
3475 if (ExStyle & WS_EX_DLGMODALFRAME)
3476 return TRUE;
3477 else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME)))
3478 return TRUE;
3479 else
3480 return FALSE;
3481 }
3482
3483 LONG FASTCALL
3484 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3485 {
3486 PWND Window, Parent;
3487 PWINSTATION_OBJECT WindowStation;
3488 LONG OldValue;
3489 STYLESTRUCT Style;
3490
3491 if (!(Window = UserGetWindowObject(hWnd)))
3492 {
3493 return( 0);
3494 }
3495
3496 if ((INT)Index >= 0)
3497 {
3498 if ((Index + sizeof(LONG)) > Window->cbwndExtra)
3499 {
3500 EngSetLastError(ERROR_INVALID_INDEX);
3501 return( 0);
3502 }
3503
3504 OldValue = *((LONG *)((PCHAR)(Window + 1) + Index));
3505 /*
3506 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3507 {
3508 OldValue = (LONG)IntSetWindowProc( Wnd,
3509 (WNDPROC)NewValue,
3510 Ansi);
3511 if (!OldValue) return 0;
3512 }
3513 */
3514 *((LONG *)((PCHAR)(Window + 1) + Index)) = NewValue;
3515 }
3516 else
3517 {
3518 switch (Index)
3519 {
3520 case GWL_EXSTYLE:
3521 OldValue = (LONG) Window->ExStyle;
3522 Style.styleOld = OldValue;
3523 Style.styleNew = NewValue;
3524
3525 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3526
3527 /*
3528 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3529 */
3530 WindowStation = Window->head.pti->rpdesk->rpwinstaParent;
3531 if(WindowStation)
3532 {
3533 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3534 Style.styleNew &= ~WS_EX_TOPMOST;
3535 }
3536 /* WS_EX_WINDOWEDGE depends on some other styles */
3537 if (IntCheckFrameEdge(Window->style, NewValue))
3538 Style.styleNew |= WS_EX_WINDOWEDGE;
3539 else
3540 Style.styleNew &= ~WS_EX_WINDOWEDGE;
3541
3542 Window->ExStyle = (DWORD)Style.styleNew;
3543 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3544 break;
3545
3546 case GWL_STYLE:
3547 OldValue = (LONG) Window->style;
3548 Style.styleOld = OldValue;
3549 Style.styleNew = NewValue;
3550 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3551
3552 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
3553 if (Window->spwndParent == UserGetDesktopWindow()) Style.styleNew |= WS_CLIPSIBLINGS;
3554 /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */
3555 if (IntCheckFrameEdge(NewValue, Window->ExStyle))
3556 Window->ExStyle |= WS_EX_WINDOWEDGE;
3557 else
3558 Window->ExStyle &= ~WS_EX_WINDOWEDGE;
3559
3560 Window->style = (DWORD)Style.styleNew;
3561 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3562 break;
3563
3564 case GWL_WNDPROC:
3565 {
3566 if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
3567 Window->fnid & FNID_FREED)
3568 {
3569 EngSetLastError(ERROR_ACCESS_DENIED);
3570 return( 0);
3571 }
3572 OldValue = (LONG)IntSetWindowProc(Window,
3573 (WNDPROC)NewValue,
3574 Ansi);
3575 break;
3576 }
3577
3578 case GWL_HINSTANCE:
3579 OldValue = (LONG) Window->hModule;
3580 Window->hModule = (HINSTANCE) NewValue;
3581 break;
3582
3583 case GWL_HWNDPARENT:
3584 Parent = Window->spwndParent;
3585 if (Parent && (Parent->head.h == IntGetDesktopWindow()))
3586 OldValue = (LONG) IntSetOwner(Window->head.h, (HWND) NewValue);
3587 else
3588 OldValue = (LONG) co_UserSetParent(Window->head.h, (HWND) NewValue);
3589 break;
3590
3591 case GWL_ID:
3592 OldValue = (LONG) Window->IDMenu;
3593 Window->IDMenu = (UINT) NewValue;
3594 break;
3595
3596 case GWL_USERDATA:
3597 OldValue = Window->dwUserData;
3598 Window->dwUserData = NewValue;
3599 break;
3600
3601 default:
3602 ERR("NtUserSetWindowLong(): Unsupported index %d\n", Index);
3603 EngSetLastError(ERROR_INVALID_INDEX);
3604 OldValue = 0;
3605 break;
3606 }
3607 }
3608
3609 return( OldValue);
3610 }
3611
3612 /*
3613 * NtUserSetWindowLong
3614 *
3615 * The NtUserSetWindowLong function changes an attribute of the specified
3616 * window. The function also sets the 32-bit (long) value at the specified
3617 * offset into the extra window memory.
3618 *
3619 * Status
3620 * @implemented
3621 */
3622
3623 LONG APIENTRY
3624 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3625 {
3626 DECLARE_RETURN(LONG);
3627
3628 TRACE("Enter NtUserSetWindowLong\n");
3629 UserEnterExclusive();
3630
3631 if (hWnd == IntGetDesktopWindow())
3632 {
3633 EngSetLastError(STATUS_ACCESS_DENIED);
3634 RETURN( 0);
3635 }
3636
3637 RETURN( co_UserSetWindowLong(hWnd, Index, NewValue, Ansi));
3638
3639 CLEANUP:
3640 TRACE("Leave NtUserSetWindowLong, ret=%i\n",_ret_);
3641 UserLeave();
3642 END_CLEANUP;
3643 }
3644
3645 /*
3646 * NtUserSetWindowWord
3647 *
3648 * Legacy function similar to NtUserSetWindowLong.
3649 *
3650 * Status
3651 * @implemented
3652 */
3653
3654 WORD APIENTRY
3655 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
3656 {
3657 PWND Window;
3658 WORD OldValue;
3659 DECLARE_RETURN(WORD);
3660
3661 TRACE("Enter NtUserSetWindowWord\n");
3662 UserEnterExclusive();
3663
3664 if (hWnd == IntGetDesktopWindow())
3665 {
3666 EngSetLastError(STATUS_ACCESS_DENIED);
3667 RETURN( 0);
3668 }
3669
3670 if (!(Window = UserGetWindowObject(hWnd)))
3671 {
3672 RETURN( 0);
3673 }
3674
3675 switch (Index)
3676 {
3677 case GWL_ID:
3678 case GWL_HINSTANCE:
3679 case GWL_HWNDPARENT:
3680 RETURN( (WORD)co_UserSetWindowLong(UserHMGetHandle(Window), Index, (UINT)NewValue, TRUE));
3681 default:
3682 if (Index < 0)
3683 {
3684 EngSetLastError(ERROR_INVALID_INDEX);
3685 RETURN( 0);
3686 }
3687 }
3688
3689 if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD)))
3690 {
3691 EngSetLastError(ERROR_INVALID_PARAMETER);
3692 RETURN( 0);
3693 }
3694
3695 OldValue = *((WORD *)((PCHAR)(Window + 1) + Index));
3696 *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue;
3697
3698 RETURN( OldValue);
3699
3700 CLEANUP:
3701 TRACE("Leave NtUserSetWindowWord, ret=%i\n",_ret_);
3702 UserLeave();
3703 END_CLEANUP;
3704 }
3705
3706 /*
3707 QueryWindow based on KJK::Hyperion and James Tabor.
3708
3709 0 = QWUniqueProcessId
3710 1 = QWUniqueThreadId
3711 2 = QWActiveWindow
3712 3 = QWFocusWindow
3713 4 = QWIsHung Implements IsHungAppWindow found
3714 by KJK::Hyperion.
3715
3716 9 = QWKillWindow When I called this with hWnd ==
3717 DesktopWindow, it shutdown the system
3718 and rebooted.
3719 */
3720 /*
3721 * @implemented
3722 */
3723 DWORD APIENTRY
3724 NtUserQueryWindow(HWND hWnd, DWORD Index)
3725 {
3726 PWND pWnd;
3727 DWORD Result;
3728 DECLARE_RETURN(UINT);
3729
3730 TRACE("Enter NtUserQueryWindow\n");
3731 UserEnterShared();
3732
3733 if (!(pWnd = UserGetWindowObject(hWnd)))
3734 {
3735 RETURN( 0);
3736 }
3737
3738 switch(Index)
3739 {
3740 case QUERY_WINDOW_UNIQUE_PROCESS_ID:
3741 Result = (DWORD)IntGetWndProcessId(pWnd);
3742 break;
3743
3744 case QUERY_WINDOW_UNIQUE_THREAD_ID:
3745 Result = (DWORD)IntGetWndThreadId(pWnd);
3746 break;
3747
3748 case QUERY_WINDOW_ACTIVE:
3749 Result = (DWORD)(pWnd->head.pti->MessageQueue->spwndActive ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndActive) : 0);
3750 break;
3751
3752 case QUERY_WINDOW_FOCUS:
3753 Result = (DWORD)(pWnd->head.pti->MessageQueue->spwndFocus ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndFocus) : 0);
3754 break;
3755
3756 case QUERY_WINDOW_ISHUNG:
3757 Result = (DWORD)MsqIsHung(pWnd->head.pti->MessageQueue);
3758 break;
3759
3760 case QUERY_WINDOW_REAL_ID:
3761 Result = (DWORD)pWnd->head.pti->pEThread->Cid.UniqueProcess;
3762 break;
3763
3764 case QUERY_WINDOW_FOREGROUND:
3765 Result = (pWnd->head.pti->MessageQueue == gpqForeground);
3766 break;
3767
3768 default:
3769 Result = (DWORD)NULL;
3770 break;
3771 }
3772
3773 RETURN( Result);
3774
3775 CLEANUP:
3776 TRACE("Leave NtUserQueryWindow, ret=%i\n",_ret_);
3777 UserLeave();
3778 END_CLEANUP;
3779 }
3780
3781
3782 /*
3783 * @implemented
3784 */
3785 UINT APIENTRY
3786 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
3787 {
3788 UNICODE_STRING SafeMessageName;
3789 NTSTATUS Status;
3790 UINT Ret;
3791 DECLARE_RETURN(UINT);
3792
3793 TRACE("Enter NtUserRegisterWindowMessage\n");
3794 UserEnterExclusive();
3795
3796 if(MessageNameUnsafe == NULL)
3797 {
3798 EngSetLastError(ERROR_INVALID_PARAMETER);
3799 RETURN( 0);
3800 }
3801
3802 Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
3803 if(!NT_SUCCESS(Status))
3804 {
3805 SetLastNtError(Status);
3806 RETURN( 0);
3807 }
3808
3809 Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
3810 if (SafeMessageName.Buffer)
3811 ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING);
3812 RETURN( Ret);
3813
3814 CLEANUP:
3815 TRACE("Leave NtUserRegisterWindowMessage, ret=%i\n",_ret_);
3816 UserLeave();
3817 END_CLEANUP;
3818 }
3819
3820
3821 /*
3822 * @implemented
3823 */
3824 BOOL APIENTRY
3825 NtUserSetMenu(
3826 HWND hWnd,
3827 HMENU Menu,
3828 BOOL Repaint)
3829 {
3830 PWND Window;
3831 BOOL Changed;
3832 DECLARE_RETURN(BOOL);
3833
3834 TRACE("Enter NtUserSetMenu\n");
3835 UserEnterExclusive();
3836
3837 if (!(Window = UserGetWindowObject(hWnd)))
3838 {
3839 RETURN( FALSE);
3840 }
3841
3842 if (! IntSetMenu(Window, Menu, &Changed))
3843 {
3844 RETURN( FALSE);
3845 }
3846
3847 if (Changed && Repaint)
3848 {
3849 USER_REFERENCE_ENTRY Ref;
3850
3851 UserRefObjectCo(Window, &Ref);
3852 co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3853 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
3854
3855 UserDerefObjectCo(Window);
3856 }
3857
3858 RETURN( TRUE);
3859
3860 CLEANUP:
3861 TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_);
3862 UserLeave();
3863 END_CLEANUP;
3864 }
3865
3866 /*
3867 * @implemented
3868 */
3869 BOOL APIENTRY
3870 NtUserSetWindowFNID(HWND hWnd,
3871 WORD fnID)
3872 {
3873 PWND Wnd;
3874 DECLARE_RETURN(BOOL);
3875
3876 TRACE("Enter NtUserSetWindowFNID\n");
3877 UserEnterExclusive();
3878
3879 if (!(Wnd = UserGetWindowObject(hWnd)))
3880 {
3881 RETURN( FALSE);
3882 }
3883
3884 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
3885 {
3886 EngSetLastError(ERROR_ACCESS_DENIED);
3887 RETURN( FALSE);
3888 }
3889
3890 // From user land we only set these.
3891 if (fnID != FNID_DESTROY)
3892 { // Hacked so we can mark desktop~!
3893 if ( (/*(fnID < FNID_BUTTON)*/ (fnID < FNID_FIRST) && (fnID > FNID_GHOST)) ||
3894 Wnd->fnid != 0 )
3895 {
3896 EngSetLastError(ERROR_INVALID_PARAMETER);
3897 RETURN( FALSE);
3898 }
3899 }
3900
3901 Wnd->fnid |= fnID;
3902 RETURN( TRUE);
3903
3904 CLEANUP:
3905 TRACE("Leave NtUserSetWindowFNID\n");
3906 UserLeave();
3907 END_CLEANUP;
3908 }
3909
3910 /*
3911 * NtUserDefSetText
3912 *
3913 * Undocumented function that is called from DefWindowProc to set
3914 * window text.
3915 *
3916 * Status
3917 * @implemented
3918 */
3919 BOOL APIENTRY
3920 NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText)
3921 {
3922 PWND Wnd;
3923 LARGE_STRING SafeText;
3924 UNICODE_STRING UnicodeString;
3925 BOOL Ret = TRUE;
3926
3927 TRACE("Enter NtUserDefSetText\n");
3928
3929 if (WindowText != NULL)
3930 {
3931 _SEH2_TRY
3932 {
3933 SafeText = ProbeForReadLargeString(WindowText);
3934 }
3935 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3936 {
3937 Ret = FALSE;
3938 SetLastNtError(_SEH2_GetExceptionCode());
3939 }
3940 _SEH2_END;
3941
3942 if (!Ret)
3943 return FALSE;
3944 }
3945 else
3946 return TRUE;
3947
3948 UserEnterExclusive();
3949
3950 if(!(Wnd = UserGetWindowObject(hWnd)))
3951 {
3952 UserLeave();
3953 return FALSE;
3954 }
3955
3956 // ReactOS uses Unicode and not mixed. Up/Down converting will take time.
3957 // Brought to you by: The Wine Project! Dysfunctional Thought Processes!
3958 // Now we know what the bAnsi is for.
3959 RtlInitUnicodeString(&UnicodeString, NULL);
3960 if (SafeText.Buffer)
3961 {
3962 _SEH2_TRY
3963 {
3964 if (SafeText.bAnsi)
3965 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR));
3966 else
3967 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR));
3968 Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText);
3969 }
3970 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3971 {
3972 Ret = FALSE;
3973 SetLastNtError(_SEH2_GetExceptionCode());
3974 }
3975 _SEH2_END;
3976 if (!Ret) goto Exit;
3977 }
3978
3979 if (UnicodeString.Length != 0)
3980 {
3981 if (Wnd->strName.MaximumLength > 0 &&
3982 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
3983 {
3984 ASSERT(Wnd->strName.Buffer != NULL);
3985
3986 Wnd->strName.Length = UnicodeString.Length;
3987 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
3988 RtlCopyMemory(Wnd->strName.Buffer,
3989 UnicodeString.Buffer,
3990 UnicodeString.Length);
3991 }
3992 else
3993 {
3994 PWCHAR buf;
3995 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
3996 buf = Wnd->strName.Buffer;
3997 Wnd->strName.Buffer = NULL;
3998 if (buf != NULL)
3999 {
4000 DesktopHeapFree(Wnd->head.rpdesk, buf);
4001 }
4002
4003 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4004 UnicodeString.Length + sizeof(UNICODE_NULL));
4005 if (Wnd->strName.Buffer != NULL)
4006 {
4007 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4008 RtlCopyMemory(Wnd->strName.Buffer,
4009 UnicodeString.Buffer,
4010 UnicodeString.Length);
4011 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4012 Wnd->strName.Length = UnicodeString.Length;
4013 }
4014 else
4015 {
4016 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4017 Ret = FALSE;
4018 goto Exit;
4019 }
4020 }
4021 }
4022 else
4023 {
4024 Wnd->strName.Length = 0;
4025 if (Wnd->strName.Buffer != NULL)
4026 Wnd->strName.Buffer[0] = L'\0';
4027 }
4028
4029 // FIXME: HAX! Windows does not do this in here!
4030 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4031 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4032 /* Send shell notifications */
4033 if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4034 {
4035 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) hWnd, FALSE); // FIXME Flashing?
4036 }
4037
4038 Ret = TRUE;
4039 Exit:
4040 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4041 TRACE("Leave NtUserDefSetText, ret=%i\n", Ret);
4042 UserLeave();
4043 return Ret;
4044 }
4045
4046 /*
4047 * NtUserInternalGetWindowText
4048 *
4049 * Status
4050 * @implemented
4051 */
4052
4053 INT APIENTRY
4054 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount)
4055 {
4056 PWND Wnd;
4057 NTSTATUS Status;
4058 INT Result;
4059 DECLARE_RETURN(INT);
4060
4061 TRACE("Enter NtUserInternalGetWindowText\n");
4062 UserEnterShared();
4063
4064 if(lpString && (nMaxCount <= 1))
4065 {
4066 EngSetLastError(ERROR_INVALID_PARAMETER);
4067 RETURN( 0);
4068 }
4069
4070 if(!(Wnd = UserGetWindowObject(hWnd)))
4071 {
4072 RETURN( 0);
4073 }
4074
4075 Result = Wnd->strName.Length / sizeof(WCHAR);
4076 if(lpString)
4077 {
4078 const WCHAR Terminator = L'\0';
4079 INT Copy;
4080 WCHAR *Buffer = (WCHAR*)lpString;
4081
4082 Copy = min(nMaxCount - 1, Result);
4083 if(Copy > 0)
4084 {
4085 Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR));
4086 if(!NT_SUCCESS(Status))
4087 {
4088 SetLastNtError(Status);
4089 RETURN( 0);
4090 }
4091 Buffer += Copy;
4092 }
4093
4094 Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
4095 if(!NT_SUCCESS(Status))
4096 {
4097 SetLastNtError(Status);
4098 RETURN( 0);
4099 }
4100
4101 Result = Copy;
4102 }
4103
4104 RETURN( Result);
4105
4106 CLEANUP:
4107 TRACE("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_);
4108 UserLeave();
4109 END_CLEANUP;
4110 }
4111
4112 /*
4113 API Call
4114 */
4115 BOOL
4116 FASTCALL
4117 IntShowOwnedPopups(PWND OwnerWnd, BOOL fShow )
4118 {
4119 int count = 0;
4120 PWND pWnd;
4121 HWND *win_array;
4122
4123 // ASSERT(OwnerWnd);
4124
4125 TRACE("Enter ShowOwnedPopups Show: %s\n", (fShow ? "TRUE" : "FALSE"));
4126 win_array = IntWinListChildren(OwnerWnd);
4127
4128 if (!win_array)
4129 return TRUE;
4130
4131 while (win_array[count])
4132 count++;
4133 while (--count >= 0)
4134 {
4135 if (!(pWnd = ValidateHwndNoErr( win_array[count] )))
4136 continue;
4137 if (pWnd->spwndOwner != OwnerWnd)
4138 continue;
4139
4140 if (fShow)
4141 {
4142 if (pWnd->state & WNDS_HIDDENPOPUP)
4143 {
4144 /* In Windows, ShowOwnedPopups(TRUE) generates
4145 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
4146 * regardless of the state of the owner
4147 */
4148 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
4149 continue;
4150 }
4151 }
4152 else
4153 {
4154 if (pWnd->style & WS_VISIBLE)
4155 {
4156 /* In Windows, ShowOwnedPopups(FALSE) generates
4157 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
4158 * regardless of the state of the owner
4159 */
4160 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
4161 continue;
4162 }
4163 }
4164
4165 }
4166 ExFreePoolWithTag(win_array, USERTAG_WINDOWLIST);
4167 TRACE("Leave ShowOwnedPopups\n");
4168 return TRUE;
4169 }
4170
4171 /* EOF */