[NtUser]
[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 ExFreePool(Children);
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 {
1666 PWND pWnd = NULL;
1667 HWND hWnd;
1668 PTHREADINFO pti = NULL;
1669 PMENU_OBJECT SystemMenu;
1670 BOOL MenuChanged;
1671 BOOL bUnicodeWindow;
1672
1673 pti = PsGetCurrentThreadWin32Thread();
1674
1675 if (!(Cs->dwExStyle & WS_EX_LAYOUTRTL))
1676 {
1677 if (ParentWindow)
1678 {
1679 if ( (Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD &&
1680 ParentWindow->ExStyle & WS_EX_LAYOUTRTL &&
1681 !(ParentWindow->ExStyle & WS_EX_NOINHERITLAYOUT) )
1682 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1683 }
1684 else
1685 { /*
1686 * Note from MSDN <http://msdn.microsoft.com/en-us/library/aa913269.aspx>:
1687 *
1688 * Dialog boxes and message boxes do not inherit layout, so you must
1689 * set the layout explicitly.
1690 */
1691 if ( Class->fnid != FNID_DIALOG )
1692 {
1693 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
1694 if (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 pti->rpdesk,
1717 (PHANDLE)&hWnd,
1718 otWindow,
1719 sizeof(WND) + Class->cbwndExtra);
1720
1721 if (!pWnd)
1722 {
1723 goto AllocError;
1724 }
1725
1726 TRACE("Created object with handle %X\n", hWnd);
1727
1728 if (NULL == pti->rpdesk->DesktopWindow)
1729 { /* HACK: Helper for win32csr/desktopbg.c */
1730 /* If there is no desktop window yet, we must be creating it */
1731 TRACE("CreateWindow setting desktop.\n");
1732 pti->rpdesk->DesktopWindow = hWnd;
1733 pti->rpdesk->pDeskInfo->spwnd = pWnd;
1734 }
1735
1736 /*
1737 * Fill out the structure describing it.
1738 */
1739 /* Remember, pWnd->head is setup in object.c ... */
1740 pWnd->spwndParent = ParentWindow;
1741 pWnd->spwndOwner = OwnerWindow;
1742 pWnd->fnid = 0;
1743 pWnd->spwndLastActive = pWnd;
1744 pWnd->state2 |= WNDS2_WIN40COMPAT; // FIXME!!!
1745 pWnd->pcls = Class;
1746 pWnd->hModule = Cs->hInstance;
1747 pWnd->style = Cs->style & ~WS_VISIBLE;
1748 pWnd->ExStyle = Cs->dwExStyle;
1749 pWnd->cbwndExtra = pWnd->pcls->cbwndExtra;
1750 pWnd->pActCtx = acbiBuffer;
1751 pWnd->InternalPos.MaxPos.x = pWnd->InternalPos.MaxPos.y = -1;
1752 pWnd->InternalPos.IconPos.x = pWnd->InternalPos.IconPos.y = -1;
1753
1754 IntReferenceMessageQueue(pWnd->head.pti->MessageQueue);
1755 if (pWnd->spwndParent != NULL && Cs->hwndParent != 0)
1756 {
1757 pWnd->HideFocus = pWnd->spwndParent->HideFocus;
1758 pWnd->HideAccel = pWnd->spwndParent->HideAccel;
1759 }
1760
1761 if (pWnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
1762 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
1763
1764 /* BugBoy Comments: Comment below say that System classes are always created
1765 as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
1766 sets the window to ansi as verified by testing with IsUnicodeWindow API.
1767
1768 No where can I see in code or through testing does the window change back
1769 to ANSI after being created as UNICODE in ROS. I didnt do more testing to
1770 see what problems this would cause. */
1771
1772 // Set WndProc from Class.
1773 pWnd->lpfnWndProc = pWnd->pcls->lpfnWndProc;
1774
1775 // GetWindowProc, test for non server side default classes and set WndProc.
1776 if ( pWnd->pcls->fnid <= FNID_GHOST && pWnd->pcls->fnid >= FNID_BUTTON )
1777 {
1778 if (bUnicodeWindow)
1779 {
1780 if (GETPFNCLIENTA(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1781 pWnd->lpfnWndProc = GETPFNCLIENTW(pWnd->pcls->fnid);
1782 }
1783 else
1784 {
1785 if (GETPFNCLIENTW(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1786 pWnd->lpfnWndProc = GETPFNCLIENTA(pWnd->pcls->fnid);
1787 }
1788 }
1789
1790 // If not an Unicode caller, set Ansi creator bit.
1791 if (!bUnicodeWindow) pWnd->state |= WNDS_ANSICREATOR;
1792
1793 // Clone Class Ansi/Unicode proc type.
1794 if (pWnd->pcls->CSF_flags & CSF_ANSIPROC)
1795 {
1796 pWnd->state |= WNDS_ANSIWINDOWPROC;
1797 pWnd->Unicode = FALSE;
1798 }
1799 else
1800 { /*
1801 * It seems there can be both an Ansi creator and Unicode Class Window
1802 * WndProc, unless the following overriding conditions occur:
1803 */
1804 if ( !bUnicodeWindow &&
1805 ( Class->atomClassName == gpsi->atomSysClass[ICLS_BUTTON] ||
1806 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX] ||
1807 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOLBOX] ||
1808 Class->atomClassName == gpsi->atomSysClass[ICLS_DIALOG] ||
1809 Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT] ||
1810 Class->atomClassName == gpsi->atomSysClass[ICLS_IME] ||
1811 Class->atomClassName == gpsi->atomSysClass[ICLS_LISTBOX] ||
1812 Class->atomClassName == gpsi->atomSysClass[ICLS_MDICLIENT] ||
1813 Class->atomClassName == gpsi->atomSysClass[ICLS_STATIC] ) )
1814 { // Override Class and set the window Ansi WndProc.
1815 pWnd->state |= WNDS_ANSIWINDOWPROC;
1816 pWnd->Unicode = FALSE;
1817 }
1818 else
1819 { // Set the window Unicode WndProc.
1820 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
1821 pWnd->Unicode = TRUE;
1822 }
1823 }
1824
1825 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
1826 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
1827 Dont understand why it does this. */
1828 if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT])
1829 {
1830 PCALLPROCDATA CallProc;
1831 CallProc = CreateCallProc(NULL, pWnd->lpfnWndProc, pWnd->Unicode , pWnd->head.pti->ppi);
1832
1833 if (!CallProc)
1834 {
1835 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1836 ERR("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %x\n",hWnd);
1837 }
1838 else
1839 {
1840 UserAddCallProcToClass(pWnd->pcls, CallProc);
1841 }
1842 }
1843
1844 InitializeListHead(&pWnd->PropListHead);
1845
1846 if ( WindowName->Buffer != NULL && WindowName->Length > 0 )
1847 {
1848 pWnd->strName.Buffer = DesktopHeapAlloc(pWnd->head.rpdesk,
1849 WindowName->Length + sizeof(UNICODE_NULL));
1850 if (pWnd->strName.Buffer == NULL)
1851 {
1852 goto AllocError;
1853 }
1854
1855 RtlCopyMemory(pWnd->strName.Buffer, WindowName->Buffer, WindowName->Length);
1856 pWnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
1857 pWnd->strName.Length = WindowName->Length;
1858 pWnd->strName.MaximumLength = WindowName->Length + sizeof(UNICODE_NULL);
1859 }
1860
1861 /* Correct the window style. */
1862 if ((pWnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1863 {
1864 pWnd->style |= WS_CLIPSIBLINGS;
1865 if (!(pWnd->style & WS_POPUP))
1866 {
1867 pWnd->style |= WS_CAPTION;
1868 }
1869 }
1870
1871 /* WS_EX_WINDOWEDGE depends on some other styles */
1872 if (pWnd->ExStyle & WS_EX_DLGMODALFRAME)
1873 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1874 else if (pWnd->style & (WS_DLGFRAME | WS_THICKFRAME))
1875 {
1876 if (!((pWnd->ExStyle & WS_EX_STATICEDGE) &&
1877 (pWnd->style & (WS_CHILD | WS_POPUP))))
1878 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1879 }
1880 else
1881 pWnd->ExStyle &= ~WS_EX_WINDOWEDGE;
1882
1883 if (!(pWnd->style & (WS_CHILD | WS_POPUP)))
1884 pWnd->state |= WNDS_SENDSIZEMOVEMSGS;
1885
1886 /* Create system menu */
1887 if ((Cs->style & WS_SYSMENU)) // && (dwStyle & WS_CAPTION) == WS_CAPTION)
1888 {
1889 SystemMenu = IntGetSystemMenu(pWnd, TRUE, TRUE);
1890 if(SystemMenu)
1891 {
1892 pWnd->SystemMenu = SystemMenu->MenuInfo.Self;
1893 IntReleaseMenuObject(SystemMenu);
1894 }
1895 }
1896
1897 /* Set the window menu */
1898 if ((Cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1899 {
1900 if (Cs->hMenu)
1901 IntSetMenu(pWnd, Cs->hMenu, &MenuChanged);
1902 else if (pWnd->pcls->lpszMenuName) // Take it from the parent.
1903 {
1904 UNICODE_STRING MenuName;
1905 HMENU hMenu;
1906
1907 if (IS_INTRESOURCE(pWnd->pcls->lpszMenuName))
1908 {
1909 MenuName.Length = 0;
1910 MenuName.MaximumLength = 0;
1911 MenuName.Buffer = pWnd->pcls->lpszMenuName;
1912 }
1913 else
1914 {
1915 RtlInitUnicodeString( &MenuName, pWnd->pcls->lpszMenuName);
1916 }
1917 hMenu = co_IntCallLoadMenu( pWnd->pcls->hModule, &MenuName);
1918 if (hMenu) IntSetMenu(pWnd, hMenu, &MenuChanged);
1919 }
1920 }
1921 else // Not a child
1922 pWnd->IDMenu = (UINT) Cs->hMenu;
1923
1924
1925 if ( ParentWindow &&
1926 ParentWindow != ParentWindow->head.rpdesk->spwndMessage &&
1927 ParentWindow != ParentWindow->head.rpdesk->pDeskInfo->spwnd )
1928 {
1929 PWND Owner = IntGetNonChildAncestor(ParentWindow);
1930
1931 if (!IntValidateOwnerDepth(pWnd, Owner))
1932 {
1933 EngSetLastError(ERROR_INVALID_PARAMETER);
1934 goto Error;
1935 }
1936 if ( pWnd->spwndOwner &&
1937 pWnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1938 {
1939 pWnd->ExStyle |= WS_EX_TOPMOST;
1940 }
1941 if ( pWnd->spwndOwner &&
1942 Class->atomClassName != gpsi->atomSysClass[ICLS_IME] &&
1943 pti != pWnd->spwndOwner->head.pti)
1944 {
1945 ERR("CreateWindow Owner in.\n");
1946 //UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE);
1947 }
1948 }
1949
1950 /* Insert the window into the thread's window list. */
1951 InsertTailList (&pti->WindowListHead, &pWnd->ThreadListEntry);
1952
1953 /* Handle "CS_CLASSDC", it is tested first. */
1954 if ( (pWnd->pcls->style & CS_CLASSDC) && !(pWnd->pcls->pdce) )
1955 { /* One DCE per class to have CLASS. */
1956 pWnd->pcls->pdce = DceAllocDCE( pWnd, DCE_CLASS_DC );
1957 }
1958 else if ( pWnd->pcls->style & CS_OWNDC)
1959 { /* Allocate a DCE for this window. */
1960 DceAllocDCE(pWnd, DCE_WINDOW_DC);
1961 }
1962
1963 return pWnd;
1964
1965 AllocError:
1966 ERR("IntCreateWindow Allocation Error.\n");
1967 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1968 Error:
1969 if(pWnd)
1970 UserDereferenceObject(pWnd);
1971 return NULL;
1972 }
1973
1974 /*
1975 * @implemented
1976 */
1977 PWND FASTCALL
1978 co_UserCreateWindowEx(CREATESTRUCTW* Cs,
1979 PUNICODE_STRING ClassName,
1980 PLARGE_STRING WindowName,
1981 PVOID acbiBuffer)
1982 {
1983 ULONG style;
1984 PWND Window = NULL, ParentWindow = NULL, OwnerWindow;
1985 HWND hWnd, hWndParent, hWndOwner, hwndInsertAfter;
1986 PWINSTATION_OBJECT WinSta;
1987 PCLS Class = NULL;
1988 SIZE Size;
1989 POINT MaxPos;
1990 CBT_CREATEWNDW * pCbtCreate;
1991 LRESULT Result;
1992 USER_REFERENCE_ENTRY ParentRef, Ref;
1993 PTHREADINFO pti;
1994 DWORD dwShowMode = SW_SHOW;
1995 CREATESTRUCTW *pCsw = NULL;
1996 PVOID pszClass = NULL, pszName = NULL;
1997 PWND ret = NULL;
1998
1999 /* Get the current window station and reference it */
2000 pti = GetW32ThreadInfo();
2001 if (pti == NULL || pti->rpdesk == NULL)
2002 {
2003 ERR("Thread is not attached to a desktop! Cannot create window!\n");
2004 return NULL; // There is nothing to cleanup.
2005 }
2006 WinSta = pti->rpdesk->rpwinstaParent;
2007 ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
2008
2009 pCsw = NULL;
2010 pCbtCreate = NULL;
2011
2012 /* Get the class and reference it */
2013 Class = IntGetAndReferenceClass(ClassName, Cs->hInstance);
2014 if(!Class)
2015 {
2016 ERR("Failed to find class %wZ\n", ClassName);
2017 goto cleanup;
2018 }
2019
2020 /* Now find the parent and the owner window */
2021 hWndParent = IntGetDesktopWindow();
2022 hWndOwner = NULL;
2023
2024 if (Cs->hwndParent == HWND_MESSAGE)
2025 {
2026 Cs->hwndParent = hWndParent = IntGetMessageWindow();
2027 }
2028 else if (Cs->hwndParent)
2029 {
2030 if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
2031 hWndOwner = Cs->hwndParent;
2032 else
2033 hWndParent = Cs->hwndParent;
2034 }
2035 else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2036 {
2037 ERR("Cannot create a child window without a parrent!\n");
2038 EngSetLastError(ERROR_TLW_WITH_WSCHILD);
2039 goto cleanup; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
2040 }
2041
2042 ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
2043 OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
2044
2045 /* FIXME: Is this correct? */
2046 if(OwnerWindow)
2047 OwnerWindow = UserGetAncestor(OwnerWindow, GA_ROOT);
2048
2049 /* Fix the position and the size of the window */
2050 if (ParentWindow)
2051 {
2052 UserRefObjectCo(ParentWindow, &ParentRef);
2053 IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode);
2054 }
2055
2056 /* Allocate and initialize the new window */
2057 Window = IntCreateWindow(Cs,
2058 WindowName,
2059 Class,
2060 ParentWindow,
2061 OwnerWindow,
2062 acbiBuffer);
2063 if(!Window)
2064 {
2065 ERR("IntCreateWindow failed!\n");
2066 goto cleanup;
2067 }
2068
2069 hWnd = UserHMGetHandle(Window);
2070 hwndInsertAfter = HWND_TOP;
2071
2072 UserRefObjectCo(Window, &Ref);
2073 UserDereferenceObject(Window);
2074 ObDereferenceObject(WinSta);
2075
2076 //// Check for a hook to eliminate overhead. ////
2077 if ( ISITHOOKED(WH_CBT) || (pti->rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)) )
2078 {
2079 // Allocate the calling structures Justin Case this goes Global.
2080 pCsw = ExAllocatePoolWithTag(NonPagedPool, sizeof(CREATESTRUCTW), TAG_HOOK);
2081 pCbtCreate = ExAllocatePoolWithTag(NonPagedPool, sizeof(CBT_CREATEWNDW), TAG_HOOK);
2082 if (!pCsw || !pCbtCreate)
2083 {
2084 ERR("UserHeapAlloc() failed!\n");
2085 goto cleanup;
2086 }
2087
2088 /* Fill the new CREATESTRUCTW */
2089 RtlCopyMemory(pCsw, Cs, sizeof(CREATESTRUCTW));
2090 pCsw->style = Window->style; /* HCBT_CREATEWND needs the real window style */
2091
2092 // Based on the assumption this is from "unicode source" user32, ReactOS, answer is yes.
2093 if (!IS_ATOM(ClassName->Buffer))
2094 {
2095 if (Window->state & WNDS_ANSICREATOR)
2096 {
2097 ANSI_STRING AnsiString;
2098 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(ClassName)+sizeof(CHAR);
2099 pszClass = UserHeapAlloc(AnsiString.MaximumLength);
2100 if (!pszClass)
2101 {
2102 ERR("UserHeapAlloc() failed!\n");
2103 goto cleanup;
2104 }
2105 RtlZeroMemory(pszClass, AnsiString.MaximumLength);
2106 AnsiString.Buffer = (PCHAR)pszClass;
2107 RtlUnicodeStringToAnsiString(&AnsiString, ClassName, FALSE);
2108 }
2109 else
2110 {
2111 UNICODE_STRING UnicodeString;
2112 UnicodeString.MaximumLength = ClassName->Length + sizeof(UNICODE_NULL);
2113 pszClass = UserHeapAlloc(UnicodeString.MaximumLength);
2114 if (!pszClass)
2115 {
2116 ERR("UserHeapAlloc() failed!\n");
2117 goto cleanup;
2118 }
2119 RtlZeroMemory(pszClass, UnicodeString.MaximumLength);
2120 UnicodeString.Buffer = (PWSTR)pszClass;
2121 RtlCopyUnicodeString(&UnicodeString, ClassName);
2122 }
2123 pCsw->lpszClass = UserHeapAddressToUser(pszClass);
2124 }
2125 if (WindowName->Length)
2126 {
2127 UNICODE_STRING Name;
2128 Name.Buffer = WindowName->Buffer;
2129 Name.Length = (USHORT)min(WindowName->Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2130 Name.MaximumLength = (USHORT)min(WindowName->MaximumLength, MAXUSHORT);
2131
2132 if (Window->state & WNDS_ANSICREATOR)
2133 {
2134 ANSI_STRING AnsiString;
2135 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(&Name) + sizeof(CHAR);
2136 pszName = UserHeapAlloc(AnsiString.MaximumLength);
2137 if (!pszName)
2138 {
2139 ERR("UserHeapAlloc() failed!\n");
2140 goto cleanup;
2141 }
2142 RtlZeroMemory(pszName, AnsiString.MaximumLength);
2143 AnsiString.Buffer = (PCHAR)pszName;
2144 RtlUnicodeStringToAnsiString(&AnsiString, &Name, FALSE);
2145 }
2146 else
2147 {
2148 UNICODE_STRING UnicodeString;
2149 UnicodeString.MaximumLength = Name.Length + sizeof(UNICODE_NULL);
2150 pszName = UserHeapAlloc(UnicodeString.MaximumLength);
2151 if (!pszName)
2152 {
2153 ERR("UserHeapAlloc() failed!\n");
2154 goto cleanup;
2155 }
2156 RtlZeroMemory(pszName, UnicodeString.MaximumLength);
2157 UnicodeString.Buffer = (PWSTR)pszName;
2158 RtlCopyUnicodeString(&UnicodeString, &Name);
2159 }
2160 pCsw->lpszName = UserHeapAddressToUser(pszName);
2161 }
2162
2163 pCbtCreate->lpcs = pCsw;
2164 pCbtCreate->hwndInsertAfter = hwndInsertAfter;
2165
2166 //// Call the WH_CBT hook ////
2167 Result = co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) pCbtCreate);
2168 if (Result != 0)
2169 {
2170 ERR("WH_CBT HCBT_CREATEWND hook failed! 0x%x\n", Result);
2171 goto cleanup;
2172 }
2173 // Write back changes.
2174 Cs->cx = pCsw->cx;
2175 Cs->cy = pCsw->cy;
2176 Cs->x = pCsw->x;
2177 Cs->y = pCsw->y;
2178 hwndInsertAfter = pCbtCreate->hwndInsertAfter;
2179 }
2180
2181 /* NCCREATE and WM_NCCALCSIZE need the original values */
2182 Cs->lpszName = (LPCWSTR) WindowName;
2183 Cs->lpszClass = (LPCWSTR) ClassName;
2184
2185 /* Send the WM_GETMINMAXINFO message */
2186 Size.cx = Cs->cx;
2187 Size.cy = Cs->cy;
2188
2189 if ((Cs->style & WS_THICKFRAME) || !(Cs->style & (WS_POPUP | WS_CHILD)))
2190 {
2191 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
2192
2193 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
2194 if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
2195 if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
2196 if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
2197 if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
2198 }
2199
2200 Window->rcWindow.left = Cs->x;
2201 Window->rcWindow.top = Cs->y;
2202 Window->rcWindow.right = Cs->x + Size.cx;
2203 Window->rcWindow.bottom = Cs->y + Size.cy;
2204 if (0 != (Window->style & WS_CHILD) && ParentWindow)
2205 {
2206 // ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
2207 RECTL_vOffsetRect(&Window->rcWindow,
2208 ParentWindow->rcClient.left,
2209 ParentWindow->rcClient.top);
2210 }
2211 Window->rcClient = Window->rcWindow;
2212
2213 /* Link the window */
2214 if (NULL != ParentWindow)
2215 {
2216 /* Link the window into the siblings list */
2217 if ((Cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2218 IntLinkHwnd(Window, HWND_BOTTOM);
2219 else
2220 IntLinkHwnd(Window, hwndInsertAfter);
2221 }
2222
2223 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2224 {
2225 if ( !IntIsTopLevelWindow(Window) )
2226 {
2227 if (pti != Window->spwndParent->head.pti)
2228 {
2229 ERR("CreateWindow Parent in.\n");
2230 //UserAttachThreadInput(pti, Window->spwndParent->head.pti, TRUE);
2231 }
2232 }
2233 }
2234
2235 /* Send the NCCREATE message */
2236 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_NCCREATE, 0, (LPARAM) Cs);
2237 if (!Result)
2238 {
2239 ERR("co_UserCreateWindowEx(): NCCREATE message failed\n");
2240 goto cleanup;
2241 }
2242
2243 /* Send the WM_NCCALCSIZE message */
2244 MaxPos.x = Window->rcWindow.left;
2245 MaxPos.y = Window->rcWindow.top;
2246
2247 Result = co_WinPosGetNonClientSize(Window, &Window->rcWindow, &Window->rcClient);
2248
2249 RECTL_vOffsetRect(&Window->rcWindow, MaxPos.x - Window->rcWindow.left,
2250 MaxPos.y - Window->rcWindow.top);
2251
2252
2253 /* Send the WM_CREATE message. */
2254 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_CREATE, 0, (LPARAM) Cs);
2255 if (Result == (LRESULT)-1)
2256 {
2257 ERR("co_UserCreateWindowEx(): WM_CREATE message failed\n");
2258 goto cleanup;
2259 }
2260
2261 /* Send the EVENT_OBJECT_CREATE event */
2262 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2263
2264 /* By setting the flag below it can be examined to determine if the window
2265 was created successfully and a valid pwnd was passed back to caller since
2266 from here the function has to succeed. */
2267 Window->state2 |= WNDS2_WMCREATEMSGPROCESSED;
2268
2269 /* Send the WM_SIZE and WM_MOVE messages. */
2270 if (!(Window->state & WNDS_SENDSIZEMOVEMSGS))
2271 {
2272 co_WinPosSendSizeMove(Window);
2273 }
2274
2275 /* Show or maybe minimize or maximize the window. */
2276
2277 style = IntSetStyle( Window, 0, WS_MAXIMIZE | WS_MINIMIZE );
2278 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2279 {
2280 RECTL NewPos;
2281 UINT SwFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
2282
2283 SwFlag = co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2284 SwFlag |= SWP_NOZORDER|SWP_FRAMECHANGED; /* Frame always gets changed */
2285 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || UserGetActiveWindow()) SwFlag |= SWP_NOACTIVATE;
2286 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2287 NewPos.right, NewPos.bottom, SwFlag);
2288 }
2289
2290 /* Send the WM_PARENTNOTIFY message */
2291 IntSendParentNotify(Window, WM_CREATE);
2292
2293 /* Notify the shell that a new window was created */
2294 if ((!hWndParent) && (!hWndOwner))
2295 {
2296 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0);
2297 }
2298
2299 /* Initialize and show the window's scrollbars */
2300 if (Window->style & WS_VSCROLL)
2301 {
2302 co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE);
2303 }
2304 if (Window->style & WS_HSCROLL)
2305 {
2306 co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE);
2307 }
2308
2309 /* Show the new window */
2310 if (Cs->style & WS_VISIBLE)
2311 {
2312 if (Window->style & WS_MAXIMIZE)
2313 dwShowMode = SW_SHOW;
2314 else if (Window->style & WS_MINIMIZE)
2315 dwShowMode = SW_SHOWMINIMIZED;
2316
2317 co_WinPosShowWindow(Window, dwShowMode);
2318
2319 if (Window->ExStyle & WS_EX_MDICHILD)
2320 {
2321 ASSERT(ParentWindow);
2322 if(!ParentWindow)
2323 goto cleanup;
2324 co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0);
2325 /* ShowWindow won't activate child windows */
2326 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2327 }
2328 }
2329
2330 TRACE("co_UserCreateWindowEx(): Created window %X\n", hWnd);
2331 ret = Window;
2332
2333 cleanup:
2334 if (!ret)
2335 {
2336 TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2337 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2338 if (Window)
2339 co_UserDestroyWindow(Window);
2340 else if (Class)
2341 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2342 }
2343
2344 if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
2345 if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
2346 if (pszName) UserHeapFree(pszName);
2347 if (pszClass) UserHeapFree(pszClass);
2348
2349 if (Window)
2350 {
2351 UserDerefObjectCo(Window);
2352 }
2353 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2354
2355 return ret;
2356 }
2357
2358 NTSTATUS
2359 NTAPI
2360 ProbeAndCaptureLargeString(
2361 OUT PLARGE_STRING plstrSafe,
2362 IN PLARGE_STRING plstrUnsafe)
2363 {
2364 LARGE_STRING lstrTemp;
2365 PVOID pvBuffer = NULL;
2366
2367 _SEH2_TRY
2368 {
2369 /* Probe and copy the string */
2370 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2371 lstrTemp = *plstrUnsafe;
2372 }
2373 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2374 {
2375 /* Fail */
2376 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2377 }
2378 _SEH2_END
2379
2380 if (lstrTemp.Length != 0)
2381 {
2382 /* Allocate a buffer from paged pool */
2383 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2384 if (!pvBuffer)
2385 {
2386 return STATUS_NO_MEMORY;
2387 }
2388
2389 _SEH2_TRY
2390 {
2391 /* Probe and copy the buffer */
2392 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2393 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2394 }
2395 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2396 {
2397 /* Cleanup and fail */
2398 ExFreePool(pvBuffer);
2399 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2400 }
2401 _SEH2_END
2402 }
2403
2404 /* Set the output string */
2405 plstrSafe->Buffer = pvBuffer;
2406 plstrSafe->Length = lstrTemp.Length;
2407 plstrSafe->MaximumLength = lstrTemp.Length;
2408
2409 return STATUS_SUCCESS;
2410 }
2411
2412 /**
2413 * \todo Allow passing plstrClassName as ANSI.
2414 */
2415 HWND
2416 NTAPI
2417 NtUserCreateWindowEx(
2418 DWORD dwExStyle,
2419 PLARGE_STRING plstrClassName,
2420 PLARGE_STRING plstrClsVersion,
2421 PLARGE_STRING plstrWindowName,
2422 DWORD dwStyle,
2423 int x,
2424 int y,
2425 int nWidth,
2426 int nHeight,
2427 HWND hWndParent,
2428 HMENU hMenu,
2429 HINSTANCE hInstance,
2430 LPVOID lpParam,
2431 DWORD dwFlags,
2432 PVOID acbiBuffer)
2433 {
2434 NTSTATUS Status;
2435 LARGE_STRING lstrWindowName;
2436 LARGE_STRING lstrClassName;
2437 UNICODE_STRING ustrClassName;
2438 CREATESTRUCTW Cs;
2439 HWND hwnd = NULL;
2440 PWND pwnd;
2441
2442 lstrWindowName.Buffer = NULL;
2443 lstrClassName.Buffer = NULL;
2444
2445 ASSERT(plstrWindowName);
2446
2447 /* Copy the window name to kernel mode */
2448 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2449 if (!NT_SUCCESS(Status))
2450 {
2451 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2452 SetLastNtError(Status);
2453 return NULL;
2454 }
2455
2456 plstrWindowName = &lstrWindowName;
2457
2458 /* Check if the class is an atom */
2459 if (IS_ATOM(plstrClassName))
2460 {
2461 /* It is, pass the atom in the UNICODE_STRING */
2462 ustrClassName.Buffer = (PVOID)plstrClassName;
2463 ustrClassName.Length = 0;
2464 ustrClassName.MaximumLength = 0;
2465 }
2466 else
2467 {
2468 /* It's not, capture the class name */
2469 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2470 if (!NT_SUCCESS(Status))
2471 {
2472 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2473 /* Set last error, cleanup and return */
2474 SetLastNtError(Status);
2475 goto cleanup;
2476 }
2477
2478 /* We pass it on as a UNICODE_STRING */
2479 ustrClassName.Buffer = lstrClassName.Buffer;
2480 ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2481 ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
2482 }
2483
2484 /* Fill the CREATESTRUCTW */
2485 /* we will keep here the original parameters */
2486 Cs.style = dwStyle;
2487 Cs.lpCreateParams = lpParam;
2488 Cs.hInstance = hInstance;
2489 Cs.hMenu = hMenu;
2490 Cs.hwndParent = hWndParent;
2491 Cs.cx = nWidth;
2492 Cs.cy = nHeight;
2493 Cs.x = x;
2494 Cs.y = y;
2495 Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
2496 if (IS_ATOM(plstrClassName))
2497 Cs.lpszClass = (LPCWSTR) plstrClassName;
2498 else
2499 Cs.lpszClass = (LPCWSTR) plstrClassName->Buffer;
2500 Cs.dwExStyle = dwExStyle;
2501
2502 UserEnterExclusive();
2503
2504 /* Call the internal function */
2505 pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName, acbiBuffer);
2506
2507 if(!pwnd)
2508 {
2509 ERR("co_UserCreateWindowEx failed!\n");
2510 }
2511 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2512
2513 UserLeave();
2514
2515 cleanup:
2516 if (lstrWindowName.Buffer)
2517 {
2518 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2519 }
2520 if (lstrClassName.Buffer)
2521 {
2522 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2523 }
2524
2525 return hwnd;
2526 }
2527
2528
2529 BOOLEAN FASTCALL co_UserDestroyWindow(PWND Window)
2530 {
2531 HWND hWnd;
2532 PWND pwndTemp;
2533 PTHREADINFO ti;
2534 MSG msg;
2535
2536 ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
2537
2538 hWnd = Window->head.h;
2539 ti = PsGetCurrentThreadWin32Thread();
2540
2541 TRACE("co_UserDestroyWindow \n");
2542
2543 /* Check for owner thread */
2544 if ( (Window->head.pti->pEThread != PsGetCurrentThread()) ||
2545 Window->head.pti != PsGetCurrentThreadWin32Thread() )
2546 {
2547 EngSetLastError(ERROR_ACCESS_DENIED);
2548 return FALSE;
2549 }
2550
2551 /* If window was created successfully and it is hooked */
2552 if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
2553 {
2554 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0))
2555 {
2556 ERR("Destroy Window WH_CBT Call Hook return!\n");
2557 return FALSE;
2558 }
2559 }
2560
2561 if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
2562 {
2563 if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2564 {
2565 if (Window->spwndOwner)
2566 {
2567 ERR("DestroyWindow Owner out.\n");
2568 //UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2569 }
2570 }
2571 }
2572
2573 /* Inform the parent */
2574 if (Window->style & WS_CHILD)
2575 {
2576 IntSendParentNotify(Window, WM_DESTROY);
2577 }
2578
2579 /* Look whether the focus is within the tree of windows we will
2580 * be destroying.
2581 */
2582 if (!co_WinPosShowWindow(Window, SW_HIDE))
2583 { // Rule #1.
2584 if (ti->MessageQueue->spwndActive == Window && ti->MessageQueue == IntGetFocusMessageQueue())
2585 {
2586 co_WinPosActivateOtherWindow(Window);
2587 }
2588 }
2589
2590 // Adjust last active.
2591 if ((pwndTemp = Window->spwndOwner))
2592 {
2593 while (pwndTemp->spwndOwner)
2594 pwndTemp = pwndTemp->spwndOwner;
2595
2596 if (pwndTemp->spwndLastActive == Window)
2597 pwndTemp->spwndLastActive = Window->spwndOwner;
2598 }
2599
2600 if (Window->spwndParent && IntIsWindow(Window->head.h))
2601 {
2602 if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
2603 {
2604 if (!IntIsTopLevelWindow(Window))
2605 {
2606 ERR("DestroyWindow Parent out.\n");
2607 //UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2608 }
2609 }
2610 }
2611
2612 if (Window->head.pti->MessageQueue->spwndActive == Window)
2613 Window->head.pti->MessageQueue->spwndActive = NULL;
2614 if (Window->head.pti->MessageQueue->spwndFocus == Window)
2615 Window->head.pti->MessageQueue->spwndFocus = NULL;
2616 if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
2617 Window->head.pti->MessageQueue->spwndActivePrev = NULL;
2618 if (Window->head.pti->MessageQueue->spwndCapture == Window)
2619 Window->head.pti->MessageQueue->spwndCapture = NULL;
2620
2621 /*
2622 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2623 */
2624
2625 if ((ti != NULL) & (ti->pDeskInfo != NULL))
2626 {
2627 if (ti->pDeskInfo->hShellWindow == hWnd)
2628 {
2629 ERR("Destroying the ShellWindow!\n");
2630 ti->pDeskInfo->hShellWindow = NULL;
2631 }
2632 }
2633
2634 IntEngWindowChanged(Window, WOC_DELETE);
2635
2636 if (!IntIsWindow(Window->head.h))
2637 {
2638 return TRUE;
2639 }
2640
2641 /* Recursively destroy owned windows */
2642
2643 if (! (Window->style & WS_CHILD))
2644 {
2645 for (;;)
2646 {
2647 BOOL GotOne = FALSE;
2648 HWND *Children;
2649 HWND *ChildHandle;
2650 PWND Child, Desktop;
2651
2652 Desktop = IntIsDesktopWindow(Window) ? Window :
2653 UserGetWindowObject(IntGetDesktopWindow());
2654 Children = IntWinListChildren(Desktop);
2655
2656 if (Children)
2657 {
2658 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2659 {
2660 Child = UserGetWindowObject(*ChildHandle);
2661 if (Child == NULL)
2662 continue;
2663 if (Child->spwndOwner != Window)
2664 {
2665 continue;
2666 }
2667
2668 if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
2669 {
2670 USER_REFERENCE_ENTRY ChildRef;
2671 UserRefObjectCo(Child, &ChildRef); // Temp HACK?
2672 co_UserDestroyWindow(Child);
2673 UserDerefObjectCo(Child); // Temp HACK?
2674
2675 GotOne = TRUE;
2676 continue;
2677 }
2678
2679 if (Child->spwndOwner != NULL)
2680 {
2681 Child->spwndOwner = NULL;
2682 }
2683
2684 }
2685 ExFreePool(Children);
2686 }
2687 if (! GotOne)
2688 {
2689 break;
2690 }
2691 }
2692 }
2693
2694 /* Generate mouse move message for the next window */
2695 msg.message = WM_MOUSEMOVE;
2696 msg.wParam = UserGetMouseButtonsState();
2697 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2698 msg.pt = gpsi->ptCursor;
2699 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2700
2701 if (!IntIsWindow(Window->head.h))
2702 {
2703 return TRUE;
2704 }
2705
2706 /* Destroy the window storage */
2707 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2708
2709 return TRUE;
2710 }
2711
2712
2713 /*
2714 * @implemented
2715 */
2716 BOOLEAN APIENTRY
2717 NtUserDestroyWindow(HWND Wnd)
2718 {
2719 PWND Window;
2720 DECLARE_RETURN(BOOLEAN);
2721 BOOLEAN ret;
2722 USER_REFERENCE_ENTRY Ref;
2723
2724 TRACE("Enter NtUserDestroyWindow\n");
2725 UserEnterExclusive();
2726
2727 if (!(Window = UserGetWindowObject(Wnd)))
2728 {
2729 RETURN(FALSE);
2730 }
2731
2732 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
2733 ret = co_UserDestroyWindow(Window);
2734 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
2735
2736 RETURN(ret);
2737
2738 CLEANUP:
2739 TRACE("Leave NtUserDestroyWindow, ret=%i\n",_ret_);
2740 UserLeave();
2741 END_CLEANUP;
2742 }
2743
2744
2745 static HWND FASTCALL
2746 IntFindWindow(PWND Parent,
2747 PWND ChildAfter,
2748 RTL_ATOM ClassAtom,
2749 PUNICODE_STRING WindowName)
2750 {
2751 BOOL CheckWindowName;
2752 HWND *List, *phWnd;
2753 HWND Ret = NULL;
2754 UNICODE_STRING CurrentWindowName;
2755
2756 ASSERT(Parent);
2757
2758 CheckWindowName = WindowName->Buffer != 0;
2759
2760 if((List = IntWinListChildren(Parent)))
2761 {
2762 phWnd = List;
2763 if(ChildAfter)
2764 {
2765 /* skip handles before and including ChildAfter */
2766 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2767 ;
2768 }
2769
2770 /* search children */
2771 while(*phWnd)
2772 {
2773 PWND Child;
2774 if(!(Child = UserGetWindowObject(*(phWnd++))))
2775 {
2776 continue;
2777 }
2778
2779 /* Do not send WM_GETTEXT messages in the kernel mode version!
2780 The user mode version however calls GetWindowText() which will
2781 send WM_GETTEXT messages to windows belonging to its processes */
2782 if (!ClassAtom || Child->pcls->atomClassName == ClassAtom)
2783 {
2784 // FIXME: LARGE_STRING truncated
2785 CurrentWindowName.Buffer = Child->strName.Buffer;
2786 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
2787 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
2788 if(!CheckWindowName ||
2789 (Child->strName.Length < 0xFFFF &&
2790 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
2791 {
2792 Ret = Child->head.h;
2793 break;
2794 }
2795 }
2796 }
2797 ExFreePool(List);
2798 }
2799
2800 return Ret;
2801 }
2802
2803 /*
2804 * FUNCTION:
2805 * Searches a window's children for a window with the specified
2806 * class and name
2807 * ARGUMENTS:
2808 * hwndParent = The window whose childs are to be searched.
2809 * NULL = desktop
2810 * HWND_MESSAGE = message-only windows
2811 *
2812 * hwndChildAfter = Search starts after this child window.
2813 * NULL = start from beginning
2814 *
2815 * ucClassName = Class name to search for
2816 * Reguired parameter.
2817 *
2818 * ucWindowName = Window name
2819 * ->Buffer == NULL = don't care
2820 *
2821 * RETURNS:
2822 * The HWND of the window if it was found, otherwise NULL
2823 */
2824 /*
2825 * @implemented
2826 */
2827 HWND APIENTRY
2828 NtUserFindWindowEx(HWND hwndParent,
2829 HWND hwndChildAfter,
2830 PUNICODE_STRING ucClassName,
2831 PUNICODE_STRING ucWindowName,
2832 DWORD dwUnknown)
2833 {
2834 PWND Parent, ChildAfter;
2835 UNICODE_STRING ClassName = {0}, WindowName = {0};
2836 HWND Desktop, Ret = NULL;
2837 BOOL DoMessageWnd = FALSE;
2838 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2839 DECLARE_RETURN(HWND);
2840
2841 TRACE("Enter NtUserFindWindowEx\n");
2842 UserEnterShared();
2843
2844 if (ucClassName != NULL || ucWindowName != NULL)
2845 {
2846 _SEH2_TRY
2847 {
2848 if (ucClassName != NULL)
2849 {
2850 ClassName = ProbeForReadUnicodeString(ucClassName);
2851 if (ClassName.Length != 0)
2852 {
2853 ProbeForRead(ClassName.Buffer,
2854 ClassName.Length,
2855 sizeof(WCHAR));
2856 }
2857 else if (!IS_ATOM(ClassName.Buffer))
2858 {
2859 EngSetLastError(ERROR_INVALID_PARAMETER);
2860 _SEH2_LEAVE;
2861 }
2862
2863 if (!IntGetAtomFromStringOrAtom(&ClassName,
2864 &ClassAtom))
2865 {
2866 _SEH2_LEAVE;
2867 }
2868 }
2869
2870 if (ucWindowName != NULL)
2871 {
2872 WindowName = ProbeForReadUnicodeString(ucWindowName);
2873 if (WindowName.Length != 0)
2874 {
2875 ProbeForRead(WindowName.Buffer,
2876 WindowName.Length,
2877 sizeof(WCHAR));
2878 }
2879 }
2880 }
2881 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2882 {
2883 SetLastNtError(_SEH2_GetExceptionCode());
2884 _SEH2_YIELD(RETURN(NULL));
2885 }
2886 _SEH2_END;
2887
2888 if (ucClassName != NULL)
2889 {
2890 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
2891 !IS_ATOM(ClassName.Buffer))
2892 {
2893 EngSetLastError(ERROR_INVALID_PARAMETER);
2894 RETURN(NULL);
2895 }
2896 else if (ClassAtom == (RTL_ATOM)0)
2897 {
2898 /* LastError code was set by IntGetAtomFromStringOrAtom */
2899 RETURN(NULL);
2900 }
2901 }
2902 }
2903
2904 Desktop = IntGetCurrentThreadDesktopWindow();
2905
2906 if(hwndParent == NULL)
2907 {
2908 hwndParent = Desktop;
2909 DoMessageWnd = TRUE;
2910 }
2911 else if(hwndParent == HWND_MESSAGE)
2912 {
2913 hwndParent = IntGetMessageWindow();
2914 }
2915
2916 if(!(Parent = UserGetWindowObject(hwndParent)))
2917 {
2918 RETURN( NULL);
2919 }
2920
2921 ChildAfter = NULL;
2922 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
2923 {
2924 RETURN( NULL);
2925 }
2926
2927 _SEH2_TRY
2928 {
2929 if(Parent->head.h == Desktop)
2930 {
2931 HWND *List, *phWnd;
2932 PWND TopLevelWindow;
2933 BOOLEAN CheckWindowName;
2934 BOOLEAN WindowMatches;
2935 BOOLEAN ClassMatches;
2936
2937 /* windows searches through all top-level windows if the parent is the desktop
2938 window */
2939
2940 if((List = IntWinListChildren(Parent)))
2941 {
2942 phWnd = List;
2943
2944 if(ChildAfter)
2945 {
2946 /* skip handles before and including ChildAfter */
2947 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2948 ;
2949 }
2950
2951 CheckWindowName = WindowName.Buffer != 0;
2952
2953 /* search children */
2954 while(*phWnd)
2955 {
2956 UNICODE_STRING ustr;
2957
2958 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
2959 {
2960 continue;
2961 }
2962
2963 /* Do not send WM_GETTEXT messages in the kernel mode version!
2964 The user mode version however calls GetWindowText() which will
2965 send WM_GETTEXT messages to windows belonging to its processes */
2966 ustr.Buffer = TopLevelWindow->strName.Buffer;
2967 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
2968 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
2969 WindowMatches = !CheckWindowName ||
2970 (TopLevelWindow->strName.Length < 0xFFFF &&
2971 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
2972 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
2973 ClassAtom == TopLevelWindow->pcls->atomClassName;
2974
2975 if (WindowMatches && ClassMatches)
2976 {
2977 Ret = TopLevelWindow->head.h;
2978 break;
2979 }
2980
2981 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
2982 {
2983 /* window returns the handle of the top-level window, in case it found
2984 the child window */
2985 Ret = TopLevelWindow->head.h;
2986 break;
2987 }
2988
2989 }
2990 ExFreePool(List);
2991 }
2992 }
2993 else
2994 {
2995 ERR("FindWindowEx: Not Desktop Parent!\n");
2996 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
2997 }
2998
2999 if (Ret == NULL && DoMessageWnd)
3000 {
3001 PWND MsgWindows;
3002
3003 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3004 {
3005 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3006 }
3007 }
3008 }
3009 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3010 {
3011 SetLastNtError(_SEH2_GetExceptionCode());
3012 Ret = NULL;
3013 }
3014 _SEH2_END;
3015
3016 RETURN( Ret);
3017
3018 CLEANUP:
3019 TRACE("Leave NtUserFindWindowEx, ret %i\n",_ret_);
3020 UserLeave();
3021 END_CLEANUP;
3022 }
3023
3024
3025 /*
3026 * @implemented
3027 */
3028 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
3029 {
3030 PWND WndAncestor, Parent;
3031
3032 if (Wnd->head.h == IntGetDesktopWindow())
3033 {
3034 return NULL;
3035 }
3036
3037 switch (Type)
3038 {
3039 case GA_PARENT:
3040 {
3041 WndAncestor = Wnd->spwndParent;
3042 break;
3043 }
3044
3045 case GA_ROOT:
3046 {
3047 WndAncestor = Wnd;
3048 Parent = NULL;
3049
3050 for(;;)
3051 {
3052 if(!(Parent = WndAncestor->spwndParent))
3053 {
3054 break;
3055 }
3056 if(IntIsDesktopWindow(Parent))
3057 {
3058 break;
3059 }
3060
3061 WndAncestor = Parent;
3062 }
3063 break;
3064 }
3065
3066 case GA_ROOTOWNER:
3067 {
3068 WndAncestor = Wnd;
3069
3070 for (;;)
3071 {
3072 PWND Parent;
3073
3074 Parent = IntGetParent(WndAncestor);
3075
3076 if (!Parent)
3077 {
3078 break;
3079 }
3080
3081 WndAncestor = Parent;
3082 }
3083 break;
3084 }
3085
3086 default:
3087 {
3088 return NULL;
3089 }
3090 }
3091
3092 return WndAncestor;
3093 }
3094
3095 /*
3096 * @implemented
3097 */
3098 HWND APIENTRY
3099 NtUserGetAncestor(HWND hWnd, UINT Type)
3100 {
3101 PWND Window, Ancestor;
3102 DECLARE_RETURN(HWND);
3103
3104 TRACE("Enter NtUserGetAncestor\n");
3105 UserEnterExclusive();
3106
3107 if (!(Window = UserGetWindowObject(hWnd)))
3108 {
3109 RETURN(NULL);
3110 }
3111
3112 Ancestor = UserGetAncestor(Window, Type);
3113 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3114
3115 RETURN(Ancestor ? Ancestor->head.h : NULL);
3116
3117 CLEANUP:
3118 TRACE("Leave NtUserGetAncestor, ret=%i\n",_ret_);
3119 UserLeave();
3120 END_CLEANUP;
3121 }
3122
3123
3124 BOOL
3125 APIENTRY
3126 NtUserGetComboBoxInfo(
3127 HWND hWnd,
3128 PCOMBOBOXINFO pcbi)
3129 {
3130 PWND Wnd;
3131 DECLARE_RETURN(BOOL);
3132
3133 TRACE("Enter NtUserGetComboBoxInfo\n");
3134 UserEnterShared();
3135
3136 if (!(Wnd = UserGetWindowObject(hWnd)))
3137 {
3138 RETURN( FALSE );
3139 }
3140 _SEH2_TRY
3141 {
3142 if(pcbi)
3143 {
3144 ProbeForWrite(pcbi,
3145 sizeof(COMBOBOXINFO),
3146 1);
3147 }
3148 }
3149 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3150 {
3151 SetLastNtError(_SEH2_GetExceptionCode());
3152 _SEH2_YIELD(RETURN(FALSE));
3153 }
3154 _SEH2_END;
3155
3156 // Pass the user pointer, it was already probed.
3157 RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3158
3159 CLEANUP:
3160 TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3161 UserLeave();
3162 END_CLEANUP;
3163 }
3164
3165
3166 DWORD
3167 APIENTRY
3168 NtUserGetListBoxInfo(
3169 HWND hWnd)
3170 {
3171 PWND Wnd;
3172 DECLARE_RETURN(DWORD);
3173
3174 TRACE("Enter NtUserGetListBoxInfo\n");
3175 UserEnterShared();
3176
3177 if (!(Wnd = UserGetWindowObject(hWnd)))
3178 {
3179 RETURN( 0 );
3180 }
3181
3182 RETURN( (DWORD) co_IntSendMessage( Wnd->head.h, LB_GETLISTBOXINFO, 0, 0 ));
3183
3184 CLEANUP:
3185 TRACE("Leave NtUserGetListBoxInfo, ret=%i\n",_ret_);
3186 UserLeave();
3187 END_CLEANUP;
3188 }
3189
3190 /*
3191 * NtUserSetParent
3192 *
3193 * The NtUserSetParent function changes the parent window of the specified
3194 * child window.
3195 *
3196 * Remarks
3197 * The new parent window and the child window must belong to the same
3198 * application. If the window identified by the hWndChild parameter is
3199 * visible, the system performs the appropriate redrawing and repainting.
3200 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3201 * or WS_POPUP window styles of the window whose parent is being changed.
3202 *
3203 * Status
3204 * @implemented
3205 */
3206
3207 HWND APIENTRY
3208 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3209 {
3210 DECLARE_RETURN(HWND);
3211
3212 TRACE("Enter NtUserSetParent\n");
3213 UserEnterExclusive();
3214
3215 /*
3216 Check Parent first from user space, set it here.
3217 */
3218 if (!hWndNewParent)
3219 {
3220 hWndNewParent = IntGetDesktopWindow();
3221 }
3222 else if (hWndNewParent == HWND_MESSAGE)
3223 {
3224 hWndNewParent = IntGetMessageWindow();
3225 }
3226
3227 RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3228
3229 CLEANUP:
3230 TRACE("Leave NtUserSetParent, ret=%i\n",_ret_);
3231 UserLeave();
3232 END_CLEANUP;
3233 }
3234
3235 /*
3236 * UserGetShellWindow
3237 *
3238 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3239 *
3240 * Status
3241 * @implemented
3242 */
3243 HWND FASTCALL UserGetShellWindow(VOID)
3244 {
3245 PWINSTATION_OBJECT WinStaObject;
3246 HWND Ret;
3247
3248 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3249 KernelMode,
3250 0,
3251 &WinStaObject);
3252
3253 if (!NT_SUCCESS(Status))
3254 {
3255 SetLastNtError(Status);
3256 return( (HWND)0);
3257 }
3258
3259 Ret = (HWND)WinStaObject->ShellWindow;
3260
3261 ObDereferenceObject(WinStaObject);
3262 return( Ret);
3263 }
3264
3265 /*
3266 * NtUserSetShellWindowEx
3267 *
3268 * This is undocumented function to set global shell window. The global
3269 * shell window has special handling of window position.
3270 *
3271 * Status
3272 * @implemented
3273 */
3274 BOOL APIENTRY
3275 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3276 {
3277 PWINSTATION_OBJECT WinStaObject;
3278 PWND WndShell, WndListView;
3279 DECLARE_RETURN(BOOL);
3280 USER_REFERENCE_ENTRY Ref;
3281 NTSTATUS Status;
3282 PTHREADINFO ti;
3283
3284 TRACE("Enter NtUserSetShellWindowEx\n");
3285 UserEnterExclusive();
3286
3287 if (!(WndShell = UserGetWindowObject(hwndShell)))
3288 {
3289 RETURN(FALSE);
3290 }
3291
3292 if(!(WndListView = UserGetWindowObject(hwndListView)))
3293 {
3294 RETURN(FALSE);
3295 }
3296
3297 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3298 KernelMode,
3299 0,
3300 &WinStaObject);
3301
3302 if (!NT_SUCCESS(Status))
3303 {
3304 SetLastNtError(Status);
3305 RETURN( FALSE);
3306 }
3307
3308 /*
3309 * Test if we are permitted to change the shell window.
3310 */
3311 if (WinStaObject->ShellWindow)
3312 {
3313 ObDereferenceObject(WinStaObject);
3314 RETURN( FALSE);
3315 }
3316
3317 /*
3318 * Move shell window into background.
3319 */
3320 if (hwndListView && hwndListView != hwndShell)
3321 {
3322 /*
3323 * Disabled for now to get Explorer working.
3324 * -- Filip, 01/nov/2003
3325 */
3326 #if 0
3327 co_WinPosSetWindowPos(WndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3328 #endif
3329
3330 if (WndListView->ExStyle & WS_EX_TOPMOST)
3331 {
3332 ObDereferenceObject(WinStaObject);
3333 RETURN( FALSE);
3334 }
3335 }
3336
3337 if (WndShell->ExStyle & WS_EX_TOPMOST)
3338 {
3339 ObDereferenceObject(WinStaObject);
3340 RETURN( FALSE);
3341 }
3342
3343 UserRefObjectCo(WndShell, &Ref);
3344 co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3345
3346 WinStaObject->ShellWindow = hwndShell;
3347 WinStaObject->ShellListView = hwndListView;
3348
3349 ti = GetW32ThreadInfo();
3350 if (ti->pDeskInfo)
3351 {
3352 ti->pDeskInfo->hShellWindow = hwndShell;
3353 ti->pDeskInfo->ppiShellProcess = ti->ppi;
3354 }
3355
3356 UserDerefObjectCo(WndShell);
3357
3358 ObDereferenceObject(WinStaObject);
3359 RETURN( TRUE);
3360
3361 CLEANUP:
3362 TRACE("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3363 UserLeave();
3364 END_CLEANUP;
3365 }
3366
3367 /*
3368 * NtUserGetSystemMenu
3369 *
3370 * The NtUserGetSystemMenu function allows the application to access the
3371 * window menu (also known as the system menu or the control menu) for
3372 * copying and modifying.
3373 *
3374 * Parameters
3375 * hWnd
3376 * Handle to the window that will own a copy of the window menu.
3377 * bRevert
3378 * Specifies the action to be taken. If this parameter is FALSE,
3379 * NtUserGetSystemMenu returns a handle to the copy of the window menu
3380 * currently in use. The copy is initially identical to the window menu
3381 * but it can be modified.
3382 * If this parameter is TRUE, GetSystemMenu resets the window menu back
3383 * to the default state. The previous window menu, if any, is destroyed.
3384 *
3385 * Return Value
3386 * If the bRevert parameter is FALSE, the return value is a handle to a
3387 * copy of the window menu. If the bRevert parameter is TRUE, the return
3388 * value is NULL.
3389 *
3390 * Status
3391 * @implemented
3392 */
3393
3394 HMENU APIENTRY
3395 NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
3396 {
3397 PWND Window;
3398 PMENU_OBJECT Menu;
3399 DECLARE_RETURN(HMENU);
3400
3401 TRACE("Enter NtUserGetSystemMenu\n");
3402 UserEnterShared();
3403
3404 if (!(Window = UserGetWindowObject(hWnd)))
3405 {
3406 RETURN(NULL);
3407 }
3408
3409 if (!(Menu = IntGetSystemMenu(Window, bRevert, FALSE)))
3410 {
3411 RETURN(NULL);
3412 }
3413
3414 RETURN(Menu->MenuInfo.Self);
3415
3416 CLEANUP:
3417 TRACE("Leave NtUserGetSystemMenu, ret=%i\n",_ret_);
3418 UserLeave();
3419 END_CLEANUP;
3420 }
3421
3422 /*
3423 * NtUserSetSystemMenu
3424 *
3425 * Status
3426 * @implemented
3427 */
3428
3429 BOOL APIENTRY
3430 NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
3431 {
3432 BOOL Result = FALSE;
3433 PWND Window;
3434 PMENU_OBJECT Menu;
3435 DECLARE_RETURN(BOOL);
3436
3437 TRACE("Enter NtUserSetSystemMenu\n");
3438 UserEnterExclusive();
3439
3440 if (!(Window = UserGetWindowObject(hWnd)))
3441 {
3442 RETURN( FALSE);
3443 }
3444
3445 if (hMenu)
3446 {
3447 /*
3448 * Assign new menu handle.
3449 */
3450 if (!(Menu = UserGetMenuObject(hMenu)))
3451 {
3452 RETURN( FALSE);
3453 }
3454
3455 Result = IntSetSystemMenu(Window, Menu);
3456 }
3457
3458 RETURN( Result);
3459
3460 CLEANUP:
3461 TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_);
3462 UserLeave();
3463 END_CLEANUP;
3464 }
3465
3466 // Fixes wine Win test_window_styles and todo tests...
3467 static BOOL FASTCALL
3468 IntCheckFrameEdge(ULONG Style, ULONG ExStyle)
3469 {
3470 if (ExStyle & WS_EX_DLGMODALFRAME)
3471 return TRUE;
3472 else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME)))
3473 return TRUE;
3474 else
3475 return FALSE;
3476 }
3477
3478 LONG FASTCALL
3479 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3480 {
3481 PWND Window, Parent;
3482 PWINSTATION_OBJECT WindowStation;
3483 LONG OldValue;
3484 STYLESTRUCT Style;
3485
3486 if (!(Window = UserGetWindowObject(hWnd)))
3487 {
3488 return( 0);
3489 }
3490
3491 if ((INT)Index >= 0)
3492 {
3493 if ((Index + sizeof(LONG)) > Window->cbwndExtra)
3494 {
3495 EngSetLastError(ERROR_INVALID_INDEX);
3496 return( 0);
3497 }
3498
3499 OldValue = *((LONG *)((PCHAR)(Window + 1) + Index));
3500 /*
3501 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3502 {
3503 OldValue = (LONG)IntSetWindowProc( Wnd,
3504 (WNDPROC)NewValue,
3505 Ansi);
3506 if (!OldValue) return 0;
3507 }
3508 */
3509 *((LONG *)((PCHAR)(Window + 1) + Index)) = NewValue;
3510 }
3511 else
3512 {
3513 switch (Index)
3514 {
3515 case GWL_EXSTYLE:
3516 OldValue = (LONG) Window->ExStyle;
3517 Style.styleOld = OldValue;
3518 Style.styleNew = NewValue;
3519
3520 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3521
3522 /*
3523 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3524 */
3525 WindowStation = Window->head.pti->rpdesk->rpwinstaParent;
3526 if(WindowStation)
3527 {
3528 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3529 Style.styleNew &= ~WS_EX_TOPMOST;
3530 }
3531 /* WS_EX_WINDOWEDGE depends on some other styles */
3532 if (IntCheckFrameEdge(Window->style, NewValue))
3533 Style.styleNew |= WS_EX_WINDOWEDGE;
3534 else
3535 Style.styleNew &= ~WS_EX_WINDOWEDGE;
3536
3537 Window->ExStyle = (DWORD)Style.styleNew;
3538 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3539 break;
3540
3541 case GWL_STYLE:
3542 OldValue = (LONG) Window->style;
3543 Style.styleOld = OldValue;
3544 Style.styleNew = NewValue;
3545 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3546
3547 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
3548 if (Window->spwndParent == UserGetDesktopWindow()) Style.styleNew |= WS_CLIPSIBLINGS;
3549 /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */
3550 if (IntCheckFrameEdge(NewValue, Window->ExStyle))
3551 Window->ExStyle |= WS_EX_WINDOWEDGE;
3552 else
3553 Window->ExStyle &= ~WS_EX_WINDOWEDGE;
3554
3555 Window->style = (DWORD)Style.styleNew;
3556 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3557 break;
3558
3559 case GWL_WNDPROC:
3560 {
3561 if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
3562 Window->fnid & FNID_FREED)
3563 {
3564 EngSetLastError(ERROR_ACCESS_DENIED);
3565 return( 0);
3566 }
3567 OldValue = (LONG)IntSetWindowProc(Window,
3568 (WNDPROC)NewValue,
3569 Ansi);
3570 break;
3571 }
3572
3573 case GWL_HINSTANCE:
3574 OldValue = (LONG) Window->hModule;
3575 Window->hModule = (HINSTANCE) NewValue;
3576 break;
3577
3578 case GWL_HWNDPARENT:
3579 Parent = Window->spwndParent;
3580 if (Parent && (Parent->head.h == IntGetDesktopWindow()))
3581 OldValue = (LONG) IntSetOwner(Window->head.h, (HWND) NewValue);
3582 else
3583 OldValue = (LONG) co_UserSetParent(Window->head.h, (HWND) NewValue);
3584 break;
3585
3586 case GWL_ID:
3587 OldValue = (LONG) Window->IDMenu;
3588 Window->IDMenu = (UINT) NewValue;
3589 break;
3590
3591 case GWL_USERDATA:
3592 OldValue = Window->dwUserData;
3593 Window->dwUserData = NewValue;
3594 break;
3595
3596 default:
3597 ERR("NtUserSetWindowLong(): Unsupported index %d\n", Index);
3598 EngSetLastError(ERROR_INVALID_INDEX);
3599 OldValue = 0;
3600 break;
3601 }
3602 }
3603
3604 return( OldValue);
3605 }
3606
3607 /*
3608 * NtUserSetWindowLong
3609 *
3610 * The NtUserSetWindowLong function changes an attribute of the specified
3611 * window. The function also sets the 32-bit (long) value at the specified
3612 * offset into the extra window memory.
3613 *
3614 * Status
3615 * @implemented
3616 */
3617
3618 LONG APIENTRY
3619 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3620 {
3621 DECLARE_RETURN(LONG);
3622
3623 TRACE("Enter NtUserSetWindowLong\n");
3624 UserEnterExclusive();
3625
3626 if (hWnd == IntGetDesktopWindow())
3627 {
3628 EngSetLastError(STATUS_ACCESS_DENIED);
3629 RETURN( 0);
3630 }
3631
3632 RETURN( co_UserSetWindowLong(hWnd, Index, NewValue, Ansi));
3633
3634 CLEANUP:
3635 TRACE("Leave NtUserSetWindowLong, ret=%i\n",_ret_);
3636 UserLeave();
3637 END_CLEANUP;
3638 }
3639
3640 /*
3641 * NtUserSetWindowWord
3642 *
3643 * Legacy function similar to NtUserSetWindowLong.
3644 *
3645 * Status
3646 * @implemented
3647 */
3648
3649 WORD APIENTRY
3650 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
3651 {
3652 PWND Window;
3653 WORD OldValue;
3654 DECLARE_RETURN(WORD);
3655
3656 TRACE("Enter NtUserSetWindowWord\n");
3657 UserEnterExclusive();
3658
3659 if (hWnd == IntGetDesktopWindow())
3660 {
3661 EngSetLastError(STATUS_ACCESS_DENIED);
3662 RETURN( 0);
3663 }
3664
3665 if (!(Window = UserGetWindowObject(hWnd)))
3666 {
3667 RETURN( 0);
3668 }
3669
3670 switch (Index)
3671 {
3672 case GWL_ID:
3673 case GWL_HINSTANCE:
3674 case GWL_HWNDPARENT:
3675 RETURN( (WORD)co_UserSetWindowLong(UserHMGetHandle(Window), Index, (UINT)NewValue, TRUE));
3676 default:
3677 if (Index < 0)
3678 {
3679 EngSetLastError(ERROR_INVALID_INDEX);
3680 RETURN( 0);
3681 }
3682 }
3683
3684 if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD)))
3685 {
3686 EngSetLastError(ERROR_INVALID_PARAMETER);
3687 RETURN( 0);
3688 }
3689
3690 OldValue = *((WORD *)((PCHAR)(Window + 1) + Index));
3691 *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue;
3692
3693 RETURN( OldValue);
3694
3695 CLEANUP:
3696 TRACE("Leave NtUserSetWindowWord, ret=%i\n",_ret_);
3697 UserLeave();
3698 END_CLEANUP;
3699 }
3700
3701 /*
3702 QueryWindow based on KJK::Hyperion and James Tabor.
3703
3704 0 = QWUniqueProcessId
3705 1 = QWUniqueThreadId
3706 2 = QWActiveWindow
3707 3 = QWFocusWindow
3708 4 = QWIsHung Implements IsHungAppWindow found
3709 by KJK::Hyperion.
3710
3711 9 = QWKillWindow When I called this with hWnd ==
3712 DesktopWindow, it shutdown the system
3713 and rebooted.
3714 */
3715 /*
3716 * @implemented
3717 */
3718 DWORD APIENTRY
3719 NtUserQueryWindow(HWND hWnd, DWORD Index)
3720 {
3721 PWND pWnd;
3722 DWORD Result;
3723 DECLARE_RETURN(UINT);
3724
3725 TRACE("Enter NtUserQueryWindow\n");
3726 UserEnterShared();
3727
3728 if (!(pWnd = UserGetWindowObject(hWnd)))
3729 {
3730 RETURN( 0);
3731 }
3732
3733 switch(Index)
3734 {
3735 case QUERY_WINDOW_UNIQUE_PROCESS_ID:
3736 Result = (DWORD)IntGetWndProcessId(pWnd);
3737 break;
3738
3739 case QUERY_WINDOW_UNIQUE_THREAD_ID:
3740 Result = (DWORD)IntGetWndThreadId(pWnd);
3741 break;
3742
3743 case QUERY_WINDOW_ACTIVE:
3744 Result = (DWORD)(pWnd->head.pti->MessageQueue->spwndActive ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndActive) : 0);
3745 break;
3746
3747 case QUERY_WINDOW_FOCUS:
3748 Result = (DWORD)(pWnd->head.pti->MessageQueue->spwndFocus ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndFocus) : 0);
3749 break;
3750
3751 case QUERY_WINDOW_ISHUNG:
3752 Result = (DWORD)MsqIsHung(pWnd->head.pti->MessageQueue);
3753 break;
3754
3755 case QUERY_WINDOW_REAL_ID:
3756 Result = (DWORD)pWnd->head.pti->pEThread->Cid.UniqueProcess;
3757 break;
3758
3759 case QUERY_WINDOW_FOREGROUND:
3760 Result = (pWnd->head.pti->MessageQueue == gpqForeground);
3761 break;
3762
3763 default:
3764 Result = (DWORD)NULL;
3765 break;
3766 }
3767
3768 RETURN( Result);
3769
3770 CLEANUP:
3771 TRACE("Leave NtUserQueryWindow, ret=%i\n",_ret_);
3772 UserLeave();
3773 END_CLEANUP;
3774 }
3775
3776
3777 /*
3778 * @implemented
3779 */
3780 UINT APIENTRY
3781 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
3782 {
3783 UNICODE_STRING SafeMessageName;
3784 NTSTATUS Status;
3785 UINT Ret;
3786 DECLARE_RETURN(UINT);
3787
3788 TRACE("Enter NtUserRegisterWindowMessage\n");
3789 UserEnterExclusive();
3790
3791 if(MessageNameUnsafe == NULL)
3792 {
3793 EngSetLastError(ERROR_INVALID_PARAMETER);
3794 RETURN( 0);
3795 }
3796
3797 Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
3798 if(!NT_SUCCESS(Status))
3799 {
3800 SetLastNtError(Status);
3801 RETURN( 0);
3802 }
3803
3804 Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
3805 if (SafeMessageName.Buffer)
3806 ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING);
3807 RETURN( Ret);
3808
3809 CLEANUP:
3810 TRACE("Leave NtUserRegisterWindowMessage, ret=%i\n",_ret_);
3811 UserLeave();
3812 END_CLEANUP;
3813 }
3814
3815
3816 /*
3817 * @implemented
3818 */
3819 BOOL APIENTRY
3820 NtUserSetMenu(
3821 HWND hWnd,
3822 HMENU Menu,
3823 BOOL Repaint)
3824 {
3825 PWND Window;
3826 BOOL Changed;
3827 DECLARE_RETURN(BOOL);
3828
3829 TRACE("Enter NtUserSetMenu\n");
3830 UserEnterExclusive();
3831
3832 if (!(Window = UserGetWindowObject(hWnd)))
3833 {
3834 RETURN( FALSE);
3835 }
3836
3837 if (! IntSetMenu(Window, Menu, &Changed))
3838 {
3839 RETURN( FALSE);
3840 }
3841
3842 if (Changed && Repaint)
3843 {
3844 USER_REFERENCE_ENTRY Ref;
3845
3846 UserRefObjectCo(Window, &Ref);
3847 co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3848 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
3849
3850 UserDerefObjectCo(Window);
3851 }
3852
3853 RETURN( TRUE);
3854
3855 CLEANUP:
3856 TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_);
3857 UserLeave();
3858 END_CLEANUP;
3859 }
3860
3861 /*
3862 * @implemented
3863 */
3864 BOOL APIENTRY
3865 NtUserSetWindowFNID(HWND hWnd,
3866 WORD fnID)
3867 {
3868 PWND Wnd;
3869 DECLARE_RETURN(BOOL);
3870
3871 TRACE("Enter NtUserSetWindowFNID\n");
3872 UserEnterExclusive();
3873
3874 if (!(Wnd = UserGetWindowObject(hWnd)))
3875 {
3876 RETURN( FALSE);
3877 }
3878
3879 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
3880 {
3881 EngSetLastError(ERROR_ACCESS_DENIED);
3882 RETURN( FALSE);
3883 }
3884
3885 // From user land we only set these.
3886 if (fnID != FNID_DESTROY)
3887 { // Hacked so we can mark desktop~!
3888 if ( (/*(fnID < FNID_BUTTON)*/ (fnID < FNID_FIRST) && (fnID > FNID_GHOST)) ||
3889 Wnd->fnid != 0 )
3890 {
3891 EngSetLastError(ERROR_INVALID_PARAMETER);
3892 RETURN( FALSE);
3893 }
3894 }
3895
3896 Wnd->fnid |= fnID;
3897 RETURN( TRUE);
3898
3899 CLEANUP:
3900 TRACE("Leave NtUserSetWindowFNID\n");
3901 UserLeave();
3902 END_CLEANUP;
3903 }
3904
3905 /*
3906 * NtUserDefSetText
3907 *
3908 * Undocumented function that is called from DefWindowProc to set
3909 * window text.
3910 *
3911 * Status
3912 * @implemented
3913 */
3914 BOOL APIENTRY
3915 NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText)
3916 {
3917 PWND Wnd;
3918 LARGE_STRING SafeText;
3919 UNICODE_STRING UnicodeString;
3920 BOOL Ret = TRUE;
3921
3922 TRACE("Enter NtUserDefSetText\n");
3923
3924 if (WindowText != NULL)
3925 {
3926 _SEH2_TRY
3927 {
3928 SafeText = ProbeForReadLargeString(WindowText);
3929 }
3930 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3931 {
3932 Ret = FALSE;
3933 SetLastNtError(_SEH2_GetExceptionCode());
3934 }
3935 _SEH2_END;
3936
3937 if (!Ret)
3938 return FALSE;
3939 }
3940 else
3941 return TRUE;
3942
3943 UserEnterExclusive();
3944
3945 if(!(Wnd = UserGetWindowObject(hWnd)))
3946 {
3947 UserLeave();
3948 return FALSE;
3949 }
3950
3951 // ReactOS uses Unicode and not mixed. Up/Down converting will take time.
3952 // Brought to you by: The Wine Project! Dysfunctional Thought Processes!
3953 // Now we know what the bAnsi is for.
3954 RtlInitUnicodeString(&UnicodeString, NULL);
3955 if (SafeText.Buffer)
3956 {
3957 _SEH2_TRY
3958 {
3959 if (SafeText.bAnsi)
3960 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR));
3961 else
3962 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR));
3963 Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText);
3964 }
3965 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3966 {
3967 Ret = FALSE;
3968 SetLastNtError(_SEH2_GetExceptionCode());
3969 }
3970 _SEH2_END;
3971 if (!Ret) goto Exit;
3972 }
3973
3974 if (UnicodeString.Length != 0)
3975 {
3976 if (Wnd->strName.MaximumLength > 0 &&
3977 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
3978 {
3979 ASSERT(Wnd->strName.Buffer != NULL);
3980
3981 Wnd->strName.Length = UnicodeString.Length;
3982 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
3983 RtlCopyMemory(Wnd->strName.Buffer,
3984 UnicodeString.Buffer,
3985 UnicodeString.Length);
3986 }
3987 else
3988 {
3989 PWCHAR buf;
3990 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
3991 buf = Wnd->strName.Buffer;
3992 Wnd->strName.Buffer = NULL;
3993 if (buf != NULL)
3994 {
3995 DesktopHeapFree(Wnd->head.rpdesk, buf);
3996 }
3997
3998 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
3999 UnicodeString.Length + sizeof(UNICODE_NULL));
4000 if (Wnd->strName.Buffer != NULL)
4001 {
4002 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4003 RtlCopyMemory(Wnd->strName.Buffer,
4004 UnicodeString.Buffer,
4005 UnicodeString.Length);
4006 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4007 Wnd->strName.Length = UnicodeString.Length;
4008 }
4009 else
4010 {
4011 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4012 Ret = FALSE;
4013 goto Exit;
4014 }
4015 }
4016 }
4017 else
4018 {
4019 Wnd->strName.Length = 0;
4020 if (Wnd->strName.Buffer != NULL)
4021 Wnd->strName.Buffer[0] = L'\0';
4022 }
4023
4024 // FIXME: HAX! Windows does not do this in here!
4025 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4026 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4027 /* Send shell notifications */
4028 if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4029 {
4030 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) hWnd, FALSE); // FIXME Flashing?
4031 }
4032
4033 Ret = TRUE;
4034 Exit:
4035 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4036 TRACE("Leave NtUserDefSetText, ret=%i\n", Ret);
4037 UserLeave();
4038 return Ret;
4039 }
4040
4041 /*
4042 * NtUserInternalGetWindowText
4043 *
4044 * Status
4045 * @implemented
4046 */
4047
4048 INT APIENTRY
4049 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount)
4050 {
4051 PWND Wnd;
4052 NTSTATUS Status;
4053 INT Result;
4054 DECLARE_RETURN(INT);
4055
4056 TRACE("Enter NtUserInternalGetWindowText\n");
4057 UserEnterShared();
4058
4059 if(lpString && (nMaxCount <= 1))
4060 {
4061 EngSetLastError(ERROR_INVALID_PARAMETER);
4062 RETURN( 0);
4063 }
4064
4065 if(!(Wnd = UserGetWindowObject(hWnd)))
4066 {
4067 RETURN( 0);
4068 }
4069
4070 Result = Wnd->strName.Length / sizeof(WCHAR);
4071 if(lpString)
4072 {
4073 const WCHAR Terminator = L'\0';
4074 INT Copy;
4075 WCHAR *Buffer = (WCHAR*)lpString;
4076
4077 Copy = min(nMaxCount - 1, Result);
4078 if(Copy > 0)
4079 {
4080 Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR));
4081 if(!NT_SUCCESS(Status))
4082 {
4083 SetLastNtError(Status);
4084 RETURN( 0);
4085 }
4086 Buffer += Copy;
4087 }
4088
4089 Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
4090 if(!NT_SUCCESS(Status))
4091 {
4092 SetLastNtError(Status);
4093 RETURN( 0);
4094 }
4095
4096 Result = Copy;
4097 }
4098
4099 RETURN( Result);
4100
4101 CLEANUP:
4102 TRACE("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_);
4103 UserLeave();
4104 END_CLEANUP;
4105 }
4106
4107 /*
4108 API Call
4109 */
4110 BOOL
4111 FASTCALL
4112 IntShowOwnedPopups(PWND OwnerWnd, BOOL fShow )
4113 {
4114 int count = 0;
4115 PWND pWnd;
4116 HWND *win_array;
4117
4118 // ASSERT(OwnerWnd);
4119
4120 TRACE("Enter ShowOwnedPopups Show: %s\n", (fShow ? "TRUE" : "FALSE"));
4121 win_array = IntWinListChildren(OwnerWnd);
4122
4123 if (!win_array)
4124 return TRUE;
4125
4126 while (win_array[count])
4127 count++;
4128 while (--count >= 0)
4129 {
4130 if (!(pWnd = ValidateHwndNoErr( win_array[count] )))
4131 continue;
4132 if (pWnd->spwndOwner != OwnerWnd)
4133 continue;
4134
4135 if (fShow)
4136 {
4137 if (pWnd->state & WNDS_HIDDENPOPUP)
4138 {
4139 /* In Windows, ShowOwnedPopups(TRUE) generates
4140 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
4141 * regardless of the state of the owner
4142 */
4143 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
4144 continue;
4145 }
4146 }
4147 else
4148 {
4149 if (pWnd->style & WS_VISIBLE)
4150 {
4151 /* In Windows, ShowOwnedPopups(FALSE) generates
4152 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
4153 * regardless of the state of the owner
4154 */
4155 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
4156 continue;
4157 }
4158 }
4159
4160 }
4161 ExFreePool( win_array );
4162 TRACE("Leave ShowOwnedPopups\n");
4163 return TRUE;
4164 }
4165
4166 /* EOF */