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