[WIN32K]
[reactos.git] / win32ss / user / ntuser / window.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Windows
5 * FILE: subsystems/win32/win32k/ntuser/window.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserWnd);
11
12 INT gNestedWindowLimit = 50;
13
14 /* HELPER FUNCTIONS ***********************************************************/
15
16 BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam)
17 {
18 WORD Action = LOWORD(wParam);
19 WORD Flags = HIWORD(wParam);
20
21 if (Flags & ~(UISF_HIDEFOCUS | UISF_HIDEACCEL | UISF_ACTIVE))
22 {
23 EngSetLastError(ERROR_INVALID_PARAMETER);
24 return FALSE;
25 }
26
27 switch (Action)
28 {
29 case UIS_INITIALIZE:
30 EngSetLastError(ERROR_INVALID_PARAMETER);
31 return FALSE;
32
33 case UIS_SET:
34 if (Flags & UISF_HIDEFOCUS)
35 Wnd->HideFocus = TRUE;
36 if (Flags & UISF_HIDEACCEL)
37 Wnd->HideAccel = TRUE;
38 break;
39
40 case UIS_CLEAR:
41 if (Flags & UISF_HIDEFOCUS)
42 Wnd->HideFocus = FALSE;
43 if (Flags & UISF_HIDEACCEL)
44 Wnd->HideAccel = FALSE;
45 break;
46 }
47
48 return TRUE;
49 }
50
51 PWND FASTCALL IntGetWindowObject(HWND hWnd)
52 {
53 PWND Window;
54
55 if (!hWnd) return NULL;
56
57 Window = UserGetWindowObject(hWnd);
58 if (Window)
59 Window->head.cLockObj++;
60
61 return Window;
62 }
63
64 PWND FASTCALL VerifyWnd(PWND pWnd)
65 {
66 HWND hWnd;
67 UINT State, State2;
68
69 if (!pWnd) return NULL;
70
71 _SEH2_TRY
72 {
73 hWnd = UserHMGetHandle(pWnd);
74 State = pWnd->state;
75 State2 = pWnd->state2;
76 }
77 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
78 {
79 _SEH2_YIELD(return NULL);
80 }
81 _SEH2_END
82
83 if ( UserObjectInDestroy(hWnd) ||
84 State & WNDS_DESTROYED ||
85 State2 & WNDS2_INDESTROY )
86 return NULL;
87
88 return pWnd;
89 }
90
91 PWND FASTCALL ValidateHwndNoErr(HWND hWnd)
92 {
93 if (hWnd) return (PWND)UserGetObjectNoErr(gHandleTable, hWnd, TYPE_WINDOW);
94 return NULL;
95 }
96
97 /* Temp HACK */
98 PWND FASTCALL UserGetWindowObject(HWND hWnd)
99 {
100 PWND Window;
101
102 if (!hWnd)
103 {
104 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
105 return NULL;
106 }
107
108 Window = (PWND)UserGetObject(gHandleTable, hWnd, TYPE_WINDOW);
109 if (!Window || 0 != (Window->state & WNDS_DESTROYED))
110 {
111 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
112 return NULL;
113 }
114
115 return Window;
116 }
117
118 ULONG FASTCALL
119 IntSetStyle( PWND pwnd, ULONG set_bits, ULONG clear_bits )
120 {
121 ULONG styleOld, styleNew;
122 styleOld = pwnd->style;
123 styleNew = (pwnd->style | set_bits) & ~clear_bits;
124 if (styleNew == styleOld) return styleNew;
125 pwnd->style = styleNew;
126 if ((styleOld ^ styleNew) & WS_VISIBLE) 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 if (WndOldParent) UserReferenceObject(WndOldParent); /* Caller must deref */
1218
1219 if (WndNewParent != WndOldParent)
1220 {
1221 /* Unlink the window from the siblings list */
1222 IntUnlinkWindow(Wnd);
1223 Wnd->ExStyle2 &= ~WS_EX2_LINKED;
1224
1225 /* Set the new parent */
1226 Wnd->spwndParent = WndNewParent;
1227
1228 if ( Wnd->style & WS_CHILD &&
1229 Wnd->spwndOwner &&
1230 Wnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1231 {
1232 ERR("SetParent Top Most from Pop up!\n");
1233 Wnd->ExStyle |= WS_EX_TOPMOST;
1234 }
1235
1236 /* Link the window with its new siblings */
1237 IntLinkHwnd( Wnd,
1238 ((0 == (Wnd->ExStyle & WS_EX_TOPMOST) &&
1239 WndNewParent == UserGetDesktopWindow() ) ? HWND_TOP : HWND_TOPMOST ) );
1240
1241 }
1242
1243 if ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1244 {
1245 if ( Wnd->spwndParent != co_GetDesktopWindow(Wnd))
1246 {
1247 if (Wnd->head.pti != WndOldParent->head.pti)
1248 {
1249 ERR("SetParent Old out.\n");
1250 //UserAttachThreadInput(Wnd->head.pti, WndOldParent->head.pti, FALSE);
1251 }
1252 }
1253 if ( WndNewParent != co_GetDesktopWindow(Wnd))
1254 {
1255 if (Wnd->head.pti != WndNewParent->head.pti)
1256 {
1257 ERR("SetParent New in.\n");
1258 //UserAttachThreadInput(Wnd->head.pti, WndNewParent->head.pti, TRUE);
1259 }
1260 }
1261 }
1262
1263 if (WndOldParent == UserGetMessageWindow() || WndNewParent == UserGetMessageWindow())
1264 swFlags |= SWP_NOACTIVATE;
1265
1266 IntNotifyWinEvent(EVENT_OBJECT_PARENTCHANGE, Wnd ,OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1267 /*
1268 * SetParent additionally needs to make hwnd the top window
1269 * in the z-order and send the expected WM_WINDOWPOSCHANGING and
1270 * WM_WINDOWPOSCHANGED notification messages.
1271 */
1272 co_WinPosSetWindowPos( Wnd,
1273 (0 == (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
1274 pt.x, pt.y, 0, 0, swFlags);
1275
1276 if (WasVisible) co_WinPosShowWindow(Wnd, SW_SHOWNORMAL);
1277
1278 return WndOldParent;
1279 }
1280
1281 HWND FASTCALL
1282 co_UserSetParent(HWND hWndChild, HWND hWndNewParent)
1283 {
1284 PWND Wnd = NULL, WndParent = NULL, WndOldParent;
1285 HWND hWndOldParent = NULL;
1286 USER_REFERENCE_ENTRY Ref, ParentRef;
1287
1288 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
1289 {
1290 EngSetLastError(ERROR_INVALID_PARAMETER);
1291 return( NULL);
1292 }
1293
1294 if (hWndChild == IntGetDesktopWindow())
1295 {
1296 EngSetLastError(ERROR_ACCESS_DENIED);
1297 return( NULL);
1298 }
1299
1300 if (hWndNewParent)
1301 {
1302 if (!(WndParent = UserGetWindowObject(hWndNewParent)))
1303 {
1304 return( NULL);
1305 }
1306 }
1307 else
1308 {
1309 if (!(WndParent = UserGetWindowObject(IntGetDesktopWindow())))
1310 {
1311 return( NULL);
1312 }
1313 }
1314
1315 if (!(Wnd = UserGetWindowObject(hWndChild)))
1316 {
1317 return( NULL);
1318 }
1319
1320 UserRefObjectCo(Wnd, &Ref);
1321 UserRefObjectCo(WndParent, &ParentRef);
1322 //ERR("Enter co_IntSetParent\n");
1323 WndOldParent = co_IntSetParent(Wnd, WndParent);
1324 //ERR("Leave co_IntSetParent\n");
1325 UserDerefObjectCo(WndParent);
1326 UserDerefObjectCo(Wnd);
1327
1328 if (WndOldParent)
1329 {
1330 hWndOldParent = WndOldParent->head.h;
1331 UserDereferenceObject(WndOldParent);
1332 }
1333
1334 return( hWndOldParent);
1335 }
1336
1337 BOOL FASTCALL
1338 IntSetSystemMenu(PWND Window, PMENU_OBJECT Menu)
1339 {
1340 PMENU_OBJECT OldMenu;
1341 if(Window->SystemMenu)
1342 {
1343 OldMenu = IntGetMenuObject(Window->SystemMenu);
1344 if(OldMenu)
1345 {
1346 OldMenu->MenuInfo.Flags &= ~ MF_SYSMENU;
1347 IntReleaseMenuObject(OldMenu);
1348 }
1349 }
1350
1351 if(Menu)
1352 {
1353 /* FIXME: Check window style, propably return FALSE? */
1354 Window->SystemMenu = Menu->MenuInfo.Self;
1355 Menu->MenuInfo.Flags |= MF_SYSMENU;
1356 }
1357 else
1358 Window->SystemMenu = (HMENU)0;
1359
1360 return TRUE;
1361 }
1362
1363 /* Unlink the window from siblings. children and parent are kept in place. */
1364 VOID FASTCALL
1365 IntUnlinkWindow(PWND Wnd)
1366 {
1367 if (Wnd->spwndNext)
1368 Wnd->spwndNext->spwndPrev = Wnd->spwndPrev;
1369
1370 if (Wnd->spwndPrev)
1371 Wnd->spwndPrev->spwndNext = Wnd->spwndNext;
1372
1373 if (Wnd->spwndParent && Wnd->spwndParent->spwndChild == Wnd)
1374 Wnd->spwndParent->spwndChild = Wnd->spwndNext;
1375
1376 Wnd->spwndPrev = Wnd->spwndNext = NULL;
1377 }
1378
1379 /* FUNCTIONS *****************************************************************/
1380
1381 /*
1382 * As best as I can figure, this function is used by EnumWindows,
1383 * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
1384 *
1385 * It's supposed to build a list of HWNDs to return to the caller.
1386 * We can figure out what kind of list by what parameters are
1387 * passed to us.
1388 */
1389 /*
1390 * @implemented
1391 */
1392 NTSTATUS
1393 APIENTRY
1394 NtUserBuildHwndList(
1395 HDESK hDesktop,
1396 HWND hwndParent,
1397 BOOLEAN bChildren,
1398 ULONG dwThreadId,
1399 ULONG lParam,
1400 HWND* pWnd,
1401 ULONG* pBufSize)
1402 {
1403 NTSTATUS Status;
1404 ULONG dwCount = 0;
1405
1406 if (pBufSize == 0)
1407 return ERROR_INVALID_PARAMETER;
1408
1409 if (hwndParent || !dwThreadId)
1410 {
1411 PDESKTOP Desktop;
1412 PWND Parent, Window;
1413
1414 if(!hwndParent)
1415 {
1416 if(hDesktop == NULL && !(Desktop = IntGetActiveDesktop()))
1417 {
1418 return ERROR_INVALID_HANDLE;
1419 }
1420
1421 if(hDesktop)
1422 {
1423 Status = IntValidateDesktopHandle(hDesktop,
1424 UserMode,
1425 0,
1426 &Desktop);
1427 if(!NT_SUCCESS(Status))
1428 {
1429 return ERROR_INVALID_HANDLE;
1430 }
1431 }
1432 hwndParent = Desktop->DesktopWindow;
1433 }
1434 else
1435 {
1436 hDesktop = 0;
1437 }
1438
1439 if((Parent = UserGetWindowObject(hwndParent)) &&
1440 (Window = Parent->spwndChild))
1441 {
1442 BOOL bGoDown = TRUE;
1443
1444 Status = STATUS_SUCCESS;
1445 while(TRUE)
1446 {
1447 if (bGoDown)
1448 {
1449 if(dwCount++ < *pBufSize && pWnd)
1450 {
1451 _SEH2_TRY
1452 {
1453 ProbeForWrite(pWnd, sizeof(HWND), 1);
1454 *pWnd = Window->head.h;
1455 pWnd++;
1456 }
1457 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1458 {
1459 Status = _SEH2_GetExceptionCode();
1460 }
1461 _SEH2_END
1462 if(!NT_SUCCESS(Status))
1463 {
1464 SetLastNtError(Status);
1465 break;
1466 }
1467 }
1468 if (Window->spwndChild && bChildren)
1469 {
1470 Window = Window->spwndChild;
1471 continue;
1472 }
1473 bGoDown = FALSE;
1474 }
1475 if (Window->spwndNext)
1476 {
1477 Window = Window->spwndNext;
1478 bGoDown = TRUE;
1479 continue;
1480 }
1481 Window = Window->spwndParent;
1482 if (Window == Parent)
1483 {
1484 break;
1485 }
1486 }
1487 }
1488
1489 if(hDesktop)
1490 {
1491 ObDereferenceObject(Desktop);
1492 }
1493 }
1494 else // Build EnumThreadWindows list!
1495 {
1496 PETHREAD Thread;
1497 PTHREADINFO W32Thread;
1498 PLIST_ENTRY Current;
1499 PWND Window;
1500
1501 Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
1502 if (!NT_SUCCESS(Status))
1503 {
1504 ERR("Thread Id is not valid!\n");
1505 return ERROR_INVALID_PARAMETER;
1506 }
1507 if (!(W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread))
1508 {
1509 ObDereferenceObject(Thread);
1510 ERR("Thread is not initialized!\n");
1511 return ERROR_INVALID_PARAMETER;
1512 }
1513
1514 Current = W32Thread->WindowListHead.Flink;
1515 while (Current != &(W32Thread->WindowListHead))
1516 {
1517 Window = CONTAINING_RECORD(Current, WND, ThreadListEntry);
1518 ASSERT(Window);
1519
1520 if (dwCount < *pBufSize && pWnd)
1521 {
1522 _SEH2_TRY
1523 {
1524 ProbeForWrite(pWnd, sizeof(HWND), 1);
1525 *pWnd = Window->head.h;
1526 pWnd++;
1527 }
1528 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1529 {
1530 Status = _SEH2_GetExceptionCode();
1531 }
1532 _SEH2_END
1533 if (!NT_SUCCESS(Status))
1534 {
1535 ERR("Failure to build window list!\n");
1536 SetLastNtError(Status);
1537 break;
1538 }
1539 }
1540 dwCount++;
1541 Current = Window->ThreadListEntry.Flink;
1542 }
1543
1544 ObDereferenceObject(Thread);
1545 }
1546
1547 *pBufSize = dwCount;
1548 return STATUS_SUCCESS;
1549 }
1550
1551 static void IntSendParentNotify( PWND pWindow, UINT msg )
1552 {
1553 if ( (pWindow->style & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
1554 !(pWindow->style & WS_EX_NOPARENTNOTIFY))
1555 {
1556 if (pWindow->spwndParent && pWindow->spwndParent != UserGetDesktopWindow())
1557 {
1558 USER_REFERENCE_ENTRY Ref;
1559 UserRefObjectCo(pWindow->spwndParent, &Ref);
1560 co_IntSendMessage( pWindow->spwndParent->head.h,
1561 WM_PARENTNOTIFY,
1562 MAKEWPARAM( msg, pWindow->IDMenu),
1563 (LPARAM)pWindow->head.h );
1564 UserDerefObjectCo(pWindow->spwndParent);
1565 }
1566 }
1567 }
1568
1569 void FASTCALL
1570 IntFixWindowCoordinates(CREATESTRUCTW* Cs, PWND ParentWindow, DWORD* dwShowMode)
1571 {
1572 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1573
1574 /* default positioning for overlapped windows */
1575 if(!(Cs->style & (WS_POPUP | WS_CHILD)))
1576 {
1577 PMONITOR pMonitor;
1578 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
1579
1580 pMonitor = UserGetPrimaryMonitor();
1581
1582 /* Check if we don't have a monitor attached yet */
1583 if(pMonitor == NULL)
1584 {
1585 Cs->x = Cs->y = 0;
1586 Cs->cx = 800;
1587 Cs->cy = 600;
1588 return;
1589 }
1590
1591 ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
1592
1593 if (IS_DEFAULT(Cs->x))
1594 {
1595 if (!IS_DEFAULT(Cs->y)) *dwShowMode = Cs->y;
1596
1597 if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
1598 {
1599 Cs->x = ProcessParams->StartingX;
1600 Cs->y = ProcessParams->StartingY;
1601 }
1602 else
1603 {
1604 Cs->x = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CXSIZE) + UserGetSystemMetrics(SM_CXFRAME));
1605 Cs->y = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CYSIZE) + UserGetSystemMetrics(SM_CYFRAME));
1606 if (Cs->x > ((pMonitor->rcWork.right - pMonitor->rcWork.left) / 4) ||
1607 Cs->y > ((pMonitor->rcWork.bottom - pMonitor->rcWork.top) / 4))
1608 {
1609 /* reset counter and position */
1610 Cs->x = 0;
1611 Cs->y = 0;
1612 pMonitor->cWndStack = 0;
1613 }
1614 pMonitor->cWndStack++;
1615 }
1616 }
1617
1618 if (IS_DEFAULT(Cs->cx))
1619 {
1620 if (ProcessParams->WindowFlags & STARTF_USEPOSITION)
1621 {
1622 Cs->cx = ProcessParams->CountX;
1623 Cs->cy = ProcessParams->CountY;
1624 }
1625 else
1626 {
1627 Cs->cx = (pMonitor->rcWork.right - pMonitor->rcWork.left) * 3 / 4;
1628 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1629 }
1630 }
1631 /* neither x nor cx are default. Check the y values .
1632 * In the trace we see Outlook and Outlook Express using
1633 * cy set to CW_USEDEFAULT when opening the address book.
1634 */
1635 else if (IS_DEFAULT(Cs->cy))
1636 {
1637 TRACE("Strange use of CW_USEDEFAULT in nHeight\n");
1638 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1639 }
1640 }
1641 else
1642 {
1643 /* if CW_USEDEFAULT is set for non-overlapped windows, both values are set to zero */
1644 if(IS_DEFAULT(Cs->x))
1645 {
1646 Cs->x = 0;
1647 Cs->y = 0;
1648 }
1649 if(IS_DEFAULT(Cs->cx))
1650 {
1651 Cs->cx = 0;
1652 Cs->cy = 0;
1653 }
1654 }
1655
1656 #undef IS_DEFAULT
1657 }
1658
1659 /* Allocates and initializes a window */
1660 PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
1661 PLARGE_STRING WindowName,
1662 PCLS Class,
1663 PWND ParentWindow,
1664 PWND OwnerWindow,
1665 PVOID acbiBuffer,
1666 PDESKTOP pdeskCreated)
1667 {
1668 PWND pWnd = NULL;
1669 HWND hWnd;
1670 PTHREADINFO pti = NULL;
1671 PMENU_OBJECT SystemMenu;
1672 BOOL MenuChanged;
1673 BOOL bUnicodeWindow;
1674
1675 pti = pdeskCreated ? gptiDesktopThread : GetW32ThreadInfo();
1676
1677 if (!(Cs->dwExStyle & WS_EX_LAYOUTRTL))
1678 {
1679 if (ParentWindow)
1680 {
1681 if ( (Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD &&
1682 ParentWindow->ExStyle & WS_EX_LAYOUTRTL &&
1683 !(ParentWindow->ExStyle & WS_EX_NOINHERITLAYOUT) )
1684 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1685 }
1686 else
1687 { /*
1688 * Note from MSDN <http://msdn.microsoft.com/en-us/library/aa913269.aspx>:
1689 *
1690 * Dialog boxes and message boxes do not inherit layout, so you must
1691 * set the layout explicitly.
1692 */
1693 if ( Class->fnid != FNID_DIALOG )
1694 {
1695 if (pti->ppi->dwLayout & LAYOUT_RTL)
1696 {
1697 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1698 }
1699 }
1700 }
1701 }
1702
1703 /* Automatically add WS_EX_WINDOWEDGE */
1704 if ((Cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1705 ((!(Cs->dwExStyle & WS_EX_STATICEDGE)) &&
1706 (Cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1707 Cs->dwExStyle |= WS_EX_WINDOWEDGE;
1708 else
1709 Cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1710
1711 /* Is it a unicode window? */
1712 bUnicodeWindow =!(Cs->dwExStyle & WS_EX_SETANSICREATOR);
1713 Cs->dwExStyle &= ~WS_EX_SETANSICREATOR;
1714
1715 /* Allocate the new window */
1716 pWnd = (PWND) UserCreateObject( gHandleTable,
1717 pdeskCreated ? pdeskCreated : pti->rpdesk,
1718 pti,
1719 (PHANDLE)&hWnd,
1720 TYPE_WINDOW,
1721 sizeof(WND) + Class->cbwndExtra);
1722
1723 if (!pWnd)
1724 {
1725 goto AllocError;
1726 }
1727
1728 TRACE("Created window object with handle %X\n", hWnd);
1729
1730 if (pdeskCreated && pdeskCreated->DesktopWindow == NULL )
1731 { /* HACK: Helper for win32csr/desktopbg.c */
1732 /* If there is no desktop window yet, we must be creating it */
1733 TRACE("CreateWindow setting desktop.\n");
1734 pdeskCreated->DesktopWindow = hWnd;
1735 pdeskCreated->pDeskInfo->spwnd = pWnd;
1736 }
1737
1738 /*
1739 * Fill out the structure describing it.
1740 */
1741 /* Remember, pWnd->head is setup in object.c ... */
1742 pWnd->spwndParent = ParentWindow;
1743 pWnd->spwndOwner = OwnerWindow;
1744 pWnd->fnid = 0;
1745 pWnd->spwndLastActive = pWnd;
1746 pWnd->state2 |= WNDS2_WIN40COMPAT; // FIXME!!!
1747 pWnd->pcls = Class;
1748 pWnd->hModule = Cs->hInstance;
1749 pWnd->style = Cs->style & ~WS_VISIBLE;
1750 pWnd->ExStyle = Cs->dwExStyle;
1751 pWnd->cbwndExtra = pWnd->pcls->cbwndExtra;
1752 pWnd->pActCtx = acbiBuffer;
1753 pWnd->InternalPos.MaxPos.x = pWnd->InternalPos.MaxPos.y = -1;
1754 pWnd->InternalPos.IconPos.x = pWnd->InternalPos.IconPos.y = -1;
1755
1756 IntReferenceMessageQueue(pWnd->head.pti->MessageQueue);
1757 if (pWnd->spwndParent != NULL && Cs->hwndParent != 0)
1758 {
1759 pWnd->HideFocus = pWnd->spwndParent->HideFocus;
1760 pWnd->HideAccel = pWnd->spwndParent->HideAccel;
1761 }
1762
1763 if (pWnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
1764 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
1765
1766 /* BugBoy Comments: Comment below say that System classes are always created
1767 as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
1768 sets the window to ansi as verified by testing with IsUnicodeWindow API.
1769
1770 No where can I see in code or through testing does the window change back
1771 to ANSI after being created as UNICODE in ROS. I didnt do more testing to
1772 see what problems this would cause. */
1773
1774 // Set WndProc from Class.
1775 pWnd->lpfnWndProc = pWnd->pcls->lpfnWndProc;
1776
1777 // GetWindowProc, test for non server side default classes and set WndProc.
1778 if ( pWnd->pcls->fnid <= FNID_GHOST && pWnd->pcls->fnid >= FNID_BUTTON )
1779 {
1780 if (bUnicodeWindow)
1781 {
1782 if (GETPFNCLIENTA(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1783 pWnd->lpfnWndProc = GETPFNCLIENTW(pWnd->pcls->fnid);
1784 }
1785 else
1786 {
1787 if (GETPFNCLIENTW(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1788 pWnd->lpfnWndProc = GETPFNCLIENTA(pWnd->pcls->fnid);
1789 }
1790 }
1791
1792 // If not an Unicode caller, set Ansi creator bit.
1793 if (!bUnicodeWindow) pWnd->state |= WNDS_ANSICREATOR;
1794
1795 // Clone Class Ansi/Unicode proc type.
1796 if (pWnd->pcls->CSF_flags & CSF_ANSIPROC)
1797 {
1798 pWnd->state |= WNDS_ANSIWINDOWPROC;
1799 pWnd->Unicode = FALSE;
1800 }
1801 else
1802 { /*
1803 * It seems there can be both an Ansi creator and Unicode Class Window
1804 * WndProc, unless the following overriding conditions occur:
1805 */
1806 if ( !bUnicodeWindow &&
1807 ( Class->atomClassName == gpsi->atomSysClass[ICLS_BUTTON] ||
1808 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX] ||
1809 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOLBOX] ||
1810 Class->atomClassName == gpsi->atomSysClass[ICLS_DIALOG] ||
1811 Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT] ||
1812 Class->atomClassName == gpsi->atomSysClass[ICLS_IME] ||
1813 Class->atomClassName == gpsi->atomSysClass[ICLS_LISTBOX] ||
1814 Class->atomClassName == gpsi->atomSysClass[ICLS_MDICLIENT] ||
1815 Class->atomClassName == gpsi->atomSysClass[ICLS_STATIC] ) )
1816 { // Override Class and set the window Ansi WndProc.
1817 pWnd->state |= WNDS_ANSIWINDOWPROC;
1818 pWnd->Unicode = FALSE;
1819 }
1820 else
1821 { // Set the window Unicode WndProc.
1822 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
1823 pWnd->Unicode = TRUE;
1824 }
1825 }
1826
1827 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
1828 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
1829 Dont understand why it does this. */
1830 if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT])
1831 {
1832 PCALLPROCDATA CallProc;
1833 CallProc = CreateCallProc(NULL, pWnd->lpfnWndProc, pWnd->Unicode , pWnd->head.pti->ppi);
1834
1835 if (!CallProc)
1836 {
1837 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1838 ERR("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %x\n",hWnd);
1839 }
1840 else
1841 {
1842 UserAddCallProcToClass(pWnd->pcls, CallProc);
1843 }
1844 }
1845
1846 InitializeListHead(&pWnd->PropListHead);
1847
1848 if ( WindowName->Buffer != NULL && WindowName->Length > 0 )
1849 {
1850 pWnd->strName.Buffer = DesktopHeapAlloc(pWnd->head.rpdesk,
1851 WindowName->Length + sizeof(UNICODE_NULL));
1852 if (pWnd->strName.Buffer == NULL)
1853 {
1854 goto AllocError;
1855 }
1856
1857 RtlCopyMemory(pWnd->strName.Buffer, WindowName->Buffer, WindowName->Length);
1858 pWnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
1859 pWnd->strName.Length = WindowName->Length;
1860 pWnd->strName.MaximumLength = WindowName->Length + sizeof(UNICODE_NULL);
1861 }
1862
1863 /* Correct the window style. */
1864 if ((pWnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1865 {
1866 pWnd->style |= WS_CLIPSIBLINGS;
1867 if (!(pWnd->style & WS_POPUP))
1868 {
1869 pWnd->style |= WS_CAPTION;
1870 }
1871 }
1872
1873 /* WS_EX_WINDOWEDGE depends on some other styles */
1874 if (pWnd->ExStyle & WS_EX_DLGMODALFRAME)
1875 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1876 else if (pWnd->style & (WS_DLGFRAME | WS_THICKFRAME))
1877 {
1878 if (!((pWnd->ExStyle & WS_EX_STATICEDGE) &&
1879 (pWnd->style & (WS_CHILD | WS_POPUP))))
1880 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1881 }
1882 else
1883 pWnd->ExStyle &= ~WS_EX_WINDOWEDGE;
1884
1885 if (!(pWnd->style & (WS_CHILD | WS_POPUP)))
1886 pWnd->state |= WNDS_SENDSIZEMOVEMSGS;
1887
1888 /* Create system menu */
1889 if ((Cs->style & WS_SYSMENU)) // && (dwStyle & WS_CAPTION) == WS_CAPTION)
1890 {
1891 SystemMenu = IntGetSystemMenu(pWnd, TRUE, TRUE);
1892 if(SystemMenu)
1893 {
1894 pWnd->SystemMenu = SystemMenu->MenuInfo.Self;
1895 IntReleaseMenuObject(SystemMenu);
1896 }
1897 }
1898
1899 /* Set the window menu */
1900 if ((Cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1901 {
1902 if (Cs->hMenu)
1903 IntSetMenu(pWnd, Cs->hMenu, &MenuChanged);
1904 else if (pWnd->pcls->lpszMenuName) // Take it from the parent.
1905 {
1906 UNICODE_STRING MenuName;
1907 HMENU hMenu;
1908
1909 if (IS_INTRESOURCE(pWnd->pcls->lpszMenuName))
1910 {
1911 MenuName.Length = 0;
1912 MenuName.MaximumLength = 0;
1913 MenuName.Buffer = pWnd->pcls->lpszMenuName;
1914 }
1915 else
1916 {
1917 RtlInitUnicodeString( &MenuName, pWnd->pcls->lpszMenuName);
1918 }
1919 hMenu = co_IntCallLoadMenu( pWnd->pcls->hModule, &MenuName);
1920 if (hMenu) IntSetMenu(pWnd, hMenu, &MenuChanged);
1921 }
1922 }
1923 else // Not a child
1924 pWnd->IDMenu = (UINT) Cs->hMenu;
1925
1926
1927 if ( ParentWindow &&
1928 ParentWindow != ParentWindow->head.rpdesk->spwndMessage &&
1929 ParentWindow != ParentWindow->head.rpdesk->pDeskInfo->spwnd )
1930 {
1931 PWND Owner = IntGetNonChildAncestor(ParentWindow);
1932
1933 if (!IntValidateOwnerDepth(pWnd, Owner))
1934 {
1935 EngSetLastError(ERROR_INVALID_PARAMETER);
1936 goto Error;
1937 }
1938 if ( pWnd->spwndOwner &&
1939 pWnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1940 {
1941 pWnd->ExStyle |= WS_EX_TOPMOST;
1942 }
1943 if ( pWnd->spwndOwner &&
1944 Class->atomClassName != gpsi->atomSysClass[ICLS_IME] &&
1945 pti != pWnd->spwndOwner->head.pti)
1946 {
1947 ERR("CreateWindow Owner in.\n");
1948 //UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE);
1949 }
1950 }
1951
1952 /* Insert the window into the thread's window list. */
1953 InsertTailList (&pti->WindowListHead, &pWnd->ThreadListEntry);
1954
1955 /* Handle "CS_CLASSDC", it is tested first. */
1956 if ( (pWnd->pcls->style & CS_CLASSDC) && !(pWnd->pcls->pdce) )
1957 { /* One DCE per class to have CLASS. */
1958 pWnd->pcls->pdce = DceAllocDCE( pWnd, DCE_CLASS_DC );
1959 }
1960 else if ( pWnd->pcls->style & CS_OWNDC)
1961 { /* Allocate a DCE for this window. */
1962 DceAllocDCE(pWnd, DCE_WINDOW_DC);
1963 }
1964
1965 return pWnd;
1966
1967 AllocError:
1968 ERR("IntCreateWindow Allocation Error.\n");
1969 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1970 Error:
1971 if(pWnd)
1972 UserDereferenceObject(pWnd);
1973 return NULL;
1974 }
1975
1976 /*
1977 * @implemented
1978 */
1979 PWND FASTCALL
1980 co_UserCreateWindowEx(CREATESTRUCTW* Cs,
1981 PUNICODE_STRING ClassName,
1982 PLARGE_STRING WindowName,
1983 PVOID acbiBuffer)
1984 {
1985 ULONG style;
1986 PWND Window = NULL, ParentWindow = NULL, OwnerWindow;
1987 HWND hWnd, hWndParent, hWndOwner, hwndInsertAfter;
1988 PWINSTATION_OBJECT WinSta;
1989 PCLS Class = NULL;
1990 SIZE Size;
1991 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
1992 CBT_CREATEWNDW * pCbtCreate;
1993 LRESULT Result;
1994 USER_REFERENCE_ENTRY ParentRef, Ref;
1995 PTHREADINFO pti;
1996 DWORD dwShowMode = SW_SHOW;
1997 CREATESTRUCTW *pCsw = NULL;
1998 PVOID pszClass = NULL, pszName = NULL;
1999 PWND ret = NULL;
2000
2001 /* Get the current window station and reference it */
2002 pti = GetW32ThreadInfo();
2003 if (pti == NULL || pti->rpdesk == NULL)
2004 {
2005 ERR("Thread is not attached to a desktop! Cannot create window!\n");
2006 return NULL; // There is nothing to cleanup.
2007 }
2008 WinSta = pti->rpdesk->rpwinstaParent;
2009 ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
2010
2011 pCsw = NULL;
2012 pCbtCreate = NULL;
2013
2014 /* Get the class and reference it */
2015 Class = IntGetAndReferenceClass(ClassName, Cs->hInstance, FALSE);
2016 if(!Class)
2017 {
2018 ERR("Failed to find class %wZ\n", ClassName);
2019 goto cleanup;
2020 }
2021
2022 /* Now find the parent and the owner window */
2023 hWndParent = IntGetDesktopWindow();
2024 hWndOwner = NULL;
2025
2026 if (Cs->hwndParent == HWND_MESSAGE)
2027 {
2028 Cs->hwndParent = hWndParent = IntGetMessageWindow();
2029 }
2030 else if (Cs->hwndParent)
2031 {
2032 if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
2033 hWndOwner = Cs->hwndParent;
2034 else
2035 hWndParent = Cs->hwndParent;
2036 }
2037 else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2038 {
2039 ERR("Cannot create a child window without a parrent!\n");
2040 EngSetLastError(ERROR_TLW_WITH_WSCHILD);
2041 goto cleanup; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
2042 }
2043
2044 ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
2045 OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
2046
2047 /* FIXME: Is this correct? */
2048 if(OwnerWindow)
2049 OwnerWindow = UserGetAncestor(OwnerWindow, GA_ROOT);
2050
2051 /* Fix the position and the size of the window */
2052 if (ParentWindow)
2053 {
2054 UserRefObjectCo(ParentWindow, &ParentRef);
2055 IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode);
2056 }
2057
2058 /* Allocate and initialize the new window */
2059 Window = IntCreateWindow(Cs,
2060 WindowName,
2061 Class,
2062 ParentWindow,
2063 OwnerWindow,
2064 acbiBuffer,
2065 NULL);
2066 if(!Window)
2067 {
2068 ERR("IntCreateWindow failed!\n");
2069 goto cleanup;
2070 }
2071
2072 hWnd = UserHMGetHandle(Window);
2073 hwndInsertAfter = HWND_TOP;
2074
2075 UserRefObjectCo(Window, &Ref);
2076 UserDereferenceObject(Window);
2077 ObDereferenceObject(WinSta);
2078
2079 //// Check for a hook to eliminate overhead. ////
2080 if ( ISITHOOKED(WH_CBT) || (pti->rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)) )
2081 {
2082 // Allocate the calling structures Justin Case this goes Global.
2083 pCsw = ExAllocatePoolWithTag(NonPagedPool, sizeof(CREATESTRUCTW), TAG_HOOK);
2084 pCbtCreate = ExAllocatePoolWithTag(NonPagedPool, sizeof(CBT_CREATEWNDW), TAG_HOOK);
2085 if (!pCsw || !pCbtCreate)
2086 {
2087 ERR("UserHeapAlloc() failed!\n");
2088 goto cleanup;
2089 }
2090
2091 /* Fill the new CREATESTRUCTW */
2092 RtlCopyMemory(pCsw, Cs, sizeof(CREATESTRUCTW));
2093 pCsw->style = Window->style; /* HCBT_CREATEWND needs the real window style */
2094
2095 // Based on the assumption this is from "unicode source" user32, ReactOS, answer is yes.
2096 if (!IS_ATOM(ClassName->Buffer))
2097 {
2098 if (Window->state & WNDS_ANSICREATOR)
2099 {
2100 ANSI_STRING AnsiString;
2101 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(ClassName)+sizeof(CHAR);
2102 pszClass = UserHeapAlloc(AnsiString.MaximumLength);
2103 if (!pszClass)
2104 {
2105 ERR("UserHeapAlloc() failed!\n");
2106 goto cleanup;
2107 }
2108 RtlZeroMemory(pszClass, AnsiString.MaximumLength);
2109 AnsiString.Buffer = (PCHAR)pszClass;
2110 RtlUnicodeStringToAnsiString(&AnsiString, ClassName, FALSE);
2111 }
2112 else
2113 {
2114 UNICODE_STRING UnicodeString;
2115 UnicodeString.MaximumLength = ClassName->Length + sizeof(UNICODE_NULL);
2116 pszClass = UserHeapAlloc(UnicodeString.MaximumLength);
2117 if (!pszClass)
2118 {
2119 ERR("UserHeapAlloc() failed!\n");
2120 goto cleanup;
2121 }
2122 RtlZeroMemory(pszClass, UnicodeString.MaximumLength);
2123 UnicodeString.Buffer = (PWSTR)pszClass;
2124 RtlCopyUnicodeString(&UnicodeString, ClassName);
2125 }
2126 pCsw->lpszClass = UserHeapAddressToUser(pszClass);
2127 }
2128 if (WindowName->Length)
2129 {
2130 UNICODE_STRING Name;
2131 Name.Buffer = WindowName->Buffer;
2132 Name.Length = (USHORT)min(WindowName->Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2133 Name.MaximumLength = (USHORT)min(WindowName->MaximumLength, MAXUSHORT);
2134
2135 if (Window->state & WNDS_ANSICREATOR)
2136 {
2137 ANSI_STRING AnsiString;
2138 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(&Name) + sizeof(CHAR);
2139 pszName = UserHeapAlloc(AnsiString.MaximumLength);
2140 if (!pszName)
2141 {
2142 ERR("UserHeapAlloc() failed!\n");
2143 goto cleanup;
2144 }
2145 RtlZeroMemory(pszName, AnsiString.MaximumLength);
2146 AnsiString.Buffer = (PCHAR)pszName;
2147 RtlUnicodeStringToAnsiString(&AnsiString, &Name, FALSE);
2148 }
2149 else
2150 {
2151 UNICODE_STRING UnicodeString;
2152 UnicodeString.MaximumLength = Name.Length + sizeof(UNICODE_NULL);
2153 pszName = UserHeapAlloc(UnicodeString.MaximumLength);
2154 if (!pszName)
2155 {
2156 ERR("UserHeapAlloc() failed!\n");
2157 goto cleanup;
2158 }
2159 RtlZeroMemory(pszName, UnicodeString.MaximumLength);
2160 UnicodeString.Buffer = (PWSTR)pszName;
2161 RtlCopyUnicodeString(&UnicodeString, &Name);
2162 }
2163 pCsw->lpszName = UserHeapAddressToUser(pszName);
2164 }
2165
2166 pCbtCreate->lpcs = pCsw;
2167 pCbtCreate->hwndInsertAfter = hwndInsertAfter;
2168
2169 //// Call the WH_CBT hook ////
2170 Result = co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) pCbtCreate);
2171 if (Result != 0)
2172 {
2173 ERR("WH_CBT HCBT_CREATEWND hook failed! 0x%x\n", Result);
2174 goto cleanup;
2175 }
2176 // Write back changes.
2177 Cs->cx = pCsw->cx;
2178 Cs->cy = pCsw->cy;
2179 Cs->x = pCsw->x;
2180 Cs->y = pCsw->y;
2181 hwndInsertAfter = pCbtCreate->hwndInsertAfter;
2182 }
2183
2184 /* NCCREATE and WM_NCCALCSIZE need the original values */
2185 Cs->lpszName = (LPCWSTR) WindowName;
2186 Cs->lpszClass = (LPCWSTR) ClassName;
2187
2188 /* Send the WM_GETMINMAXINFO message */
2189 Size.cx = Cs->cx;
2190 Size.cy = Cs->cy;
2191
2192 if ((Cs->style & WS_THICKFRAME) || !(Cs->style & (WS_POPUP | WS_CHILD)))
2193 {
2194 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
2195 if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
2196 if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
2197 if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
2198 if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
2199 }
2200
2201 Window->rcWindow.left = Cs->x;
2202 Window->rcWindow.top = Cs->y;
2203 Window->rcWindow.right = Cs->x + Size.cx;
2204 Window->rcWindow.bottom = Cs->y + Size.cy;
2205 if (0 != (Window->style & WS_CHILD) && ParentWindow)
2206 {
2207 // ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
2208 RECTL_vOffsetRect(&Window->rcWindow,
2209 ParentWindow->rcClient.left,
2210 ParentWindow->rcClient.top);
2211 }
2212 Window->rcClient = Window->rcWindow;
2213
2214 /* Link the window */
2215 if (NULL != ParentWindow)
2216 {
2217 /* Link the window into the siblings list */
2218 if ((Cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2219 IntLinkHwnd(Window, HWND_BOTTOM);
2220 else
2221 IntLinkHwnd(Window, hwndInsertAfter);
2222 }
2223
2224 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2225 {
2226 if ( !IntIsTopLevelWindow(Window) )
2227 {
2228 if (pti != Window->spwndParent->head.pti)
2229 {
2230 ERR("CreateWindow Parent in.\n");
2231 //UserAttachThreadInput(pti, Window->spwndParent->head.pti, TRUE);
2232 }
2233 }
2234 }
2235
2236 /* Send the NCCREATE message */
2237 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_NCCREATE, 0, (LPARAM) Cs);
2238 if (!Result)
2239 {
2240 ERR("co_UserCreateWindowEx(): NCCREATE message failed\n");
2241 goto cleanup;
2242 }
2243
2244 /* Send the WM_NCCALCSIZE message */
2245 MaxPos.x = Window->rcWindow.left;
2246 MaxPos.y = Window->rcWindow.top;
2247
2248 Result = co_WinPosGetNonClientSize(Window, &Window->rcWindow, &Window->rcClient);
2249
2250 RECTL_vOffsetRect(&Window->rcWindow, MaxPos.x - Window->rcWindow.left,
2251 MaxPos.y - Window->rcWindow.top);
2252
2253
2254 /* Send the WM_CREATE message. */
2255 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_CREATE, 0, (LPARAM) Cs);
2256 if (Result == (LRESULT)-1)
2257 {
2258 ERR("co_UserCreateWindowEx(): WM_CREATE message failed\n");
2259 goto cleanup;
2260 }
2261
2262 /* Send the EVENT_OBJECT_CREATE event */
2263 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2264
2265 /* By setting the flag below it can be examined to determine if the window
2266 was created successfully and a valid pwnd was passed back to caller since
2267 from here the function has to succeed. */
2268 Window->state2 |= WNDS2_WMCREATEMSGPROCESSED;
2269
2270 /* Send the WM_SIZE and WM_MOVE messages. */
2271 if (!(Window->state & WNDS_SENDSIZEMOVEMSGS))
2272 {
2273 co_WinPosSendSizeMove(Window);
2274 }
2275
2276 /* Show or maybe minimize or maximize the window. */
2277
2278 style = IntSetStyle( Window, 0, WS_MAXIMIZE | WS_MINIMIZE );
2279 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2280 {
2281 RECTL NewPos;
2282 UINT SwFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
2283
2284 SwFlag = co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2285 SwFlag |= SWP_NOZORDER|SWP_FRAMECHANGED; /* Frame always gets changed */
2286 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || UserGetActiveWindow()) SwFlag |= SWP_NOACTIVATE;
2287 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2288 NewPos.right, NewPos.bottom, SwFlag);
2289 }
2290
2291 /* Send the WM_PARENTNOTIFY message */
2292 IntSendParentNotify(Window, WM_CREATE);
2293
2294 /* Notify the shell that a new window was created */
2295 if ((!hWndParent) && (!hWndOwner))
2296 {
2297 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0);
2298 }
2299
2300 /* Initialize and show the window's scrollbars */
2301 if (Window->style & WS_VSCROLL)
2302 {
2303 co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE);
2304 }
2305 if (Window->style & WS_HSCROLL)
2306 {
2307 co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE);
2308 }
2309
2310 /* Show the new window */
2311 if (Cs->style & WS_VISIBLE)
2312 {
2313 if (Window->style & WS_MAXIMIZE)
2314 dwShowMode = SW_SHOW;
2315 else if (Window->style & WS_MINIMIZE)
2316 dwShowMode = SW_SHOWMINIMIZED;
2317
2318 co_WinPosShowWindow(Window, dwShowMode);
2319
2320 if (Window->ExStyle & WS_EX_MDICHILD)
2321 {
2322 ASSERT(ParentWindow);
2323 if(!ParentWindow)
2324 goto cleanup;
2325 co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0);
2326 /* ShowWindow won't activate child windows */
2327 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2328 }
2329 }
2330
2331 TRACE("co_UserCreateWindowEx(): Created window %X\n", hWnd);
2332 ret = Window;
2333
2334 cleanup:
2335 if (!ret)
2336 {
2337 TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2338 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2339 if (Window)
2340 co_UserDestroyWindow(Window);
2341 else if (Class)
2342 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2343 }
2344
2345 if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
2346 if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
2347 if (pszName) UserHeapFree(pszName);
2348 if (pszClass) UserHeapFree(pszClass);
2349
2350 if (Window)
2351 {
2352 UserDerefObjectCo(Window);
2353 }
2354 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2355
2356 return ret;
2357 }
2358
2359 NTSTATUS
2360 NTAPI
2361 ProbeAndCaptureLargeString(
2362 OUT PLARGE_STRING plstrSafe,
2363 IN PLARGE_STRING plstrUnsafe)
2364 {
2365 LARGE_STRING lstrTemp;
2366 PVOID pvBuffer = NULL;
2367
2368 _SEH2_TRY
2369 {
2370 /* Probe and copy the string */
2371 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2372 lstrTemp = *plstrUnsafe;
2373 }
2374 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2375 {
2376 /* Fail */
2377 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2378 }
2379 _SEH2_END
2380
2381 if (lstrTemp.Length != 0)
2382 {
2383 /* Allocate a buffer from paged pool */
2384 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2385 if (!pvBuffer)
2386 {
2387 return STATUS_NO_MEMORY;
2388 }
2389
2390 _SEH2_TRY
2391 {
2392 /* Probe and copy the buffer */
2393 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2394 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2395 }
2396 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2397 {
2398 /* Cleanup and fail */
2399 ExFreePoolWithTag(pvBuffer, TAG_STRING);
2400 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2401 }
2402 _SEH2_END
2403 }
2404
2405 /* Set the output string */
2406 plstrSafe->Buffer = pvBuffer;
2407 plstrSafe->Length = lstrTemp.Length;
2408 plstrSafe->MaximumLength = lstrTemp.Length;
2409
2410 return STATUS_SUCCESS;
2411 }
2412
2413 /**
2414 * \todo Allow passing plstrClassName as ANSI.
2415 */
2416 HWND
2417 NTAPI
2418 NtUserCreateWindowEx(
2419 DWORD dwExStyle,
2420 PLARGE_STRING plstrClassName,
2421 PLARGE_STRING plstrClsVersion,
2422 PLARGE_STRING plstrWindowName,
2423 DWORD dwStyle,
2424 int x,
2425 int y,
2426 int nWidth,
2427 int nHeight,
2428 HWND hWndParent,
2429 HMENU hMenu,
2430 HINSTANCE hInstance,
2431 LPVOID lpParam,
2432 DWORD dwFlags,
2433 PVOID acbiBuffer)
2434 {
2435 NTSTATUS Status;
2436 LARGE_STRING lstrWindowName;
2437 LARGE_STRING lstrClassName;
2438 UNICODE_STRING ustrClassName;
2439 CREATESTRUCTW Cs;
2440 HWND hwnd = NULL;
2441 PWND pwnd;
2442
2443 lstrWindowName.Buffer = NULL;
2444 lstrClassName.Buffer = NULL;
2445
2446 ASSERT(plstrWindowName);
2447
2448 /* Copy the window name to kernel mode */
2449 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2450 if (!NT_SUCCESS(Status))
2451 {
2452 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2453 SetLastNtError(Status);
2454 return NULL;
2455 }
2456
2457 plstrWindowName = &lstrWindowName;
2458
2459 /* Check if the class is an atom */
2460 if (IS_ATOM(plstrClassName))
2461 {
2462 /* It is, pass the atom in the UNICODE_STRING */
2463 ustrClassName.Buffer = (PVOID)plstrClassName;
2464 ustrClassName.Length = 0;
2465 ustrClassName.MaximumLength = 0;
2466 }
2467 else
2468 {
2469 /* It's not, capture the class name */
2470 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2471 if (!NT_SUCCESS(Status))
2472 {
2473 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2474 /* Set last error, cleanup and return */
2475 SetLastNtError(Status);
2476 goto cleanup;
2477 }
2478
2479 /* We pass it on as a UNICODE_STRING */
2480 ustrClassName.Buffer = lstrClassName.Buffer;
2481 ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2482 ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
2483 }
2484
2485 /* Fill the CREATESTRUCTW */
2486 /* we will keep here the original parameters */
2487 Cs.style = dwStyle;
2488 Cs.lpCreateParams = lpParam;
2489 Cs.hInstance = hInstance;
2490 Cs.hMenu = hMenu;
2491 Cs.hwndParent = hWndParent;
2492 Cs.cx = nWidth;
2493 Cs.cy = nHeight;
2494 Cs.x = x;
2495 Cs.y = y;
2496 Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
2497 if (IS_ATOM(plstrClassName))
2498 Cs.lpszClass = (LPCWSTR) plstrClassName;
2499 else
2500 Cs.lpszClass = (LPCWSTR) plstrClassName->Buffer;
2501 Cs.dwExStyle = dwExStyle;
2502
2503 UserEnterExclusive();
2504
2505 /* Call the internal function */
2506 pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName, acbiBuffer);
2507
2508 if(!pwnd)
2509 {
2510 ERR("co_UserCreateWindowEx failed!\n");
2511 }
2512 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2513
2514 UserLeave();
2515
2516 cleanup:
2517 if (lstrWindowName.Buffer)
2518 {
2519 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2520 }
2521 if (lstrClassName.Buffer)
2522 {
2523 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2524 }
2525
2526 return hwnd;
2527 }
2528
2529
2530 BOOLEAN FASTCALL co_UserDestroyWindow(PWND Window)
2531 {
2532 HWND hWnd;
2533 PWND pwndTemp;
2534 PTHREADINFO ti;
2535 MSG msg;
2536
2537 ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
2538
2539 hWnd = Window->head.h;
2540 ti = PsGetCurrentThreadWin32Thread();
2541
2542 TRACE("co_UserDestroyWindow \n");
2543
2544 /* Check for owner thread */
2545 if ( Window->head.pti != PsGetCurrentThreadWin32Thread())
2546 {
2547 /* Check if we are destroying the desktop window */
2548 if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
2549 {
2550 EngSetLastError(ERROR_ACCESS_DENIED);
2551 return FALSE;
2552 }
2553 }
2554
2555 /* If window was created successfully and it is hooked */
2556 if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
2557 {
2558 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0))
2559 {
2560 ERR("Destroy Window WH_CBT Call Hook return!\n");
2561 return FALSE;
2562 }
2563 }
2564
2565 if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
2566 {
2567 if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2568 {
2569 if (Window->spwndOwner)
2570 {
2571 ERR("DestroyWindow Owner out.\n");
2572 //UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2573 }
2574 }
2575 }
2576
2577 /* Inform the parent */
2578 if (Window->style & WS_CHILD)
2579 {
2580 IntSendParentNotify(Window, WM_DESTROY);
2581 }
2582
2583 /* Look whether the focus is within the tree of windows we will
2584 * be destroying.
2585 */
2586 if (!co_WinPosShowWindow(Window, SW_HIDE))
2587 { // Rule #1.
2588 if (ti->MessageQueue->spwndActive == Window && ti->MessageQueue == IntGetFocusMessageQueue())
2589 {
2590 co_WinPosActivateOtherWindow(Window);
2591 }
2592 }
2593
2594 // Adjust last active.
2595 if ((pwndTemp = Window->spwndOwner))
2596 {
2597 while (pwndTemp->spwndOwner)
2598 pwndTemp = pwndTemp->spwndOwner;
2599
2600 if (pwndTemp->spwndLastActive == Window)
2601 pwndTemp->spwndLastActive = Window->spwndOwner;
2602 }
2603
2604 if (Window->spwndParent && IntIsWindow(Window->head.h))
2605 {
2606 if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
2607 {
2608 if (!IntIsTopLevelWindow(Window))
2609 {
2610 ERR("DestroyWindow Parent out.\n");
2611 //UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2612 }
2613 }
2614 }
2615
2616 if (Window->head.pti->MessageQueue->spwndActive == Window)
2617 Window->head.pti->MessageQueue->spwndActive = NULL;
2618 if (Window->head.pti->MessageQueue->spwndFocus == Window)
2619 Window->head.pti->MessageQueue->spwndFocus = NULL;
2620 if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
2621 Window->head.pti->MessageQueue->spwndActivePrev = NULL;
2622 if (Window->head.pti->MessageQueue->spwndCapture == Window)
2623 Window->head.pti->MessageQueue->spwndCapture = NULL;
2624
2625 /*
2626 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2627 */
2628
2629 if ((ti != NULL) && (ti->pDeskInfo != NULL))
2630 {
2631 if (ti->pDeskInfo->hShellWindow == hWnd)
2632 {
2633 ERR("Destroying the ShellWindow!\n");
2634 ti->pDeskInfo->hShellWindow = NULL;
2635 }
2636 }
2637
2638 IntEngWindowChanged(Window, WOC_DELETE);
2639
2640 if (!IntIsWindow(Window->head.h))
2641 {
2642 return TRUE;
2643 }
2644
2645 /* Recursively destroy owned windows */
2646
2647 if (! (Window->style & WS_CHILD))
2648 {
2649 for (;;)
2650 {
2651 BOOL GotOne = FALSE;
2652 HWND *Children;
2653 HWND *ChildHandle;
2654 PWND Child, Desktop;
2655
2656 Desktop = IntIsDesktopWindow(Window) ? Window :
2657 UserGetWindowObject(IntGetDesktopWindow());
2658 Children = IntWinListChildren(Desktop);
2659
2660 if (Children)
2661 {
2662 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2663 {
2664 Child = UserGetWindowObject(*ChildHandle);
2665 if (Child == NULL)
2666 continue;
2667 if (Child->spwndOwner != Window)
2668 {
2669 continue;
2670 }
2671
2672 if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
2673 {
2674 USER_REFERENCE_ENTRY ChildRef;
2675 UserRefObjectCo(Child, &ChildRef); // Temp HACK?
2676 co_UserDestroyWindow(Child);
2677 UserDerefObjectCo(Child); // Temp HACK?
2678
2679 GotOne = TRUE;
2680 continue;
2681 }
2682
2683 if (Child->spwndOwner != NULL)
2684 {
2685 Child->spwndOwner = NULL;
2686 }
2687
2688 }
2689 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
2690 }
2691 if (! GotOne)
2692 {
2693 break;
2694 }
2695 }
2696 }
2697
2698 /* Generate mouse move message for the next window */
2699 msg.message = WM_MOUSEMOVE;
2700 msg.wParam = UserGetMouseButtonsState();
2701 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2702 msg.pt = gpsi->ptCursor;
2703 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2704
2705 if (!IntIsWindow(Window->head.h))
2706 {
2707 return TRUE;
2708 }
2709
2710 /* Destroy the window storage */
2711 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2712
2713 return TRUE;
2714 }
2715
2716
2717 /*
2718 * @implemented
2719 */
2720 BOOLEAN APIENTRY
2721 NtUserDestroyWindow(HWND Wnd)
2722 {
2723 PWND Window;
2724 DECLARE_RETURN(BOOLEAN);
2725 BOOLEAN ret;
2726 USER_REFERENCE_ENTRY Ref;
2727
2728 TRACE("Enter NtUserDestroyWindow\n");
2729 UserEnterExclusive();
2730
2731 if (!(Window = UserGetWindowObject(Wnd)))
2732 {
2733 RETURN(FALSE);
2734 }
2735
2736 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
2737 ret = co_UserDestroyWindow(Window);
2738 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
2739
2740 RETURN(ret);
2741
2742 CLEANUP:
2743 TRACE("Leave NtUserDestroyWindow, ret=%i\n",_ret_);
2744 UserLeave();
2745 END_CLEANUP;
2746 }
2747
2748
2749 static HWND FASTCALL
2750 IntFindWindow(PWND Parent,
2751 PWND ChildAfter,
2752 RTL_ATOM ClassAtom,
2753 PUNICODE_STRING WindowName)
2754 {
2755 BOOL CheckWindowName;
2756 HWND *List, *phWnd;
2757 HWND Ret = NULL;
2758 UNICODE_STRING CurrentWindowName;
2759
2760 ASSERT(Parent);
2761
2762 CheckWindowName = WindowName->Buffer != 0;
2763
2764 if((List = IntWinListChildren(Parent)))
2765 {
2766 phWnd = List;
2767 if(ChildAfter)
2768 {
2769 /* skip handles before and including ChildAfter */
2770 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2771 ;
2772 }
2773
2774 /* search children */
2775 while(*phWnd)
2776 {
2777 PWND Child;
2778 if(!(Child = UserGetWindowObject(*(phWnd++))))
2779 {
2780 continue;
2781 }
2782
2783 /* Do not send WM_GETTEXT messages in the kernel mode version!
2784 The user mode version however calls GetWindowText() which will
2785 send WM_GETTEXT messages to windows belonging to its processes */
2786 if (!ClassAtom || Child->pcls->atomClassName == ClassAtom)
2787 {
2788 // FIXME: LARGE_STRING truncated
2789 CurrentWindowName.Buffer = Child->strName.Buffer;
2790 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
2791 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
2792 if(!CheckWindowName ||
2793 (Child->strName.Length < 0xFFFF &&
2794 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
2795 {
2796 Ret = Child->head.h;
2797 break;
2798 }
2799 }
2800 }
2801 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2802 }
2803
2804 return Ret;
2805 }
2806
2807 /*
2808 * FUNCTION:
2809 * Searches a window's children for a window with the specified
2810 * class and name
2811 * ARGUMENTS:
2812 * hwndParent = The window whose childs are to be searched.
2813 * NULL = desktop
2814 * HWND_MESSAGE = message-only windows
2815 *
2816 * hwndChildAfter = Search starts after this child window.
2817 * NULL = start from beginning
2818 *
2819 * ucClassName = Class name to search for
2820 * Reguired parameter.
2821 *
2822 * ucWindowName = Window name
2823 * ->Buffer == NULL = don't care
2824 *
2825 * RETURNS:
2826 * The HWND of the window if it was found, otherwise NULL
2827 */
2828 /*
2829 * @implemented
2830 */
2831 HWND APIENTRY
2832 NtUserFindWindowEx(HWND hwndParent,
2833 HWND hwndChildAfter,
2834 PUNICODE_STRING ucClassName,
2835 PUNICODE_STRING ucWindowName,
2836 DWORD dwUnknown)
2837 {
2838 PWND Parent, ChildAfter;
2839 UNICODE_STRING ClassName = {0}, WindowName = {0};
2840 HWND Desktop, Ret = NULL;
2841 BOOL DoMessageWnd = FALSE;
2842 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2843 DECLARE_RETURN(HWND);
2844
2845 TRACE("Enter NtUserFindWindowEx\n");
2846 UserEnterShared();
2847
2848 if (ucClassName != NULL || ucWindowName != NULL)
2849 {
2850 _SEH2_TRY
2851 {
2852 if (ucClassName != NULL)
2853 {
2854 ClassName = ProbeForReadUnicodeString(ucClassName);
2855 if (ClassName.Length != 0)
2856 {
2857 ProbeForRead(ClassName.Buffer,
2858 ClassName.Length,
2859 sizeof(WCHAR));
2860 }
2861 else if (!IS_ATOM(ClassName.Buffer))
2862 {
2863 EngSetLastError(ERROR_INVALID_PARAMETER);
2864 _SEH2_LEAVE;
2865 }
2866
2867 if (!IntGetAtomFromStringOrAtom(&ClassName,
2868 &ClassAtom))
2869 {
2870 _SEH2_LEAVE;
2871 }
2872 }
2873
2874 if (ucWindowName != NULL)
2875 {
2876 WindowName = ProbeForReadUnicodeString(ucWindowName);
2877 if (WindowName.Length != 0)
2878 {
2879 ProbeForRead(WindowName.Buffer,
2880 WindowName.Length,
2881 sizeof(WCHAR));
2882 }
2883 }
2884 }
2885 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2886 {
2887 SetLastNtError(_SEH2_GetExceptionCode());
2888 _SEH2_YIELD(RETURN(NULL));
2889 }
2890 _SEH2_END;
2891
2892 if (ucClassName != NULL)
2893 {
2894 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
2895 !IS_ATOM(ClassName.Buffer))
2896 {
2897 EngSetLastError(ERROR_INVALID_PARAMETER);
2898 RETURN(NULL);
2899 }
2900 else if (ClassAtom == (RTL_ATOM)0)
2901 {
2902 /* LastError code was set by IntGetAtomFromStringOrAtom */
2903 RETURN(NULL);
2904 }
2905 }
2906 }
2907
2908 Desktop = IntGetCurrentThreadDesktopWindow();
2909
2910 if(hwndParent == NULL)
2911 {
2912 hwndParent = Desktop;
2913 DoMessageWnd = TRUE;
2914 }
2915 else if(hwndParent == HWND_MESSAGE)
2916 {
2917 hwndParent = IntGetMessageWindow();
2918 }
2919
2920 if(!(Parent = UserGetWindowObject(hwndParent)))
2921 {
2922 RETURN( NULL);
2923 }
2924
2925 ChildAfter = NULL;
2926 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
2927 {
2928 RETURN( NULL);
2929 }
2930
2931 _SEH2_TRY
2932 {
2933 if(Parent->head.h == Desktop)
2934 {
2935 HWND *List, *phWnd;
2936 PWND TopLevelWindow;
2937 BOOLEAN CheckWindowName;
2938 BOOLEAN WindowMatches;
2939 BOOLEAN ClassMatches;
2940
2941 /* windows searches through all top-level windows if the parent is the desktop
2942 window */
2943
2944 if((List = IntWinListChildren(Parent)))
2945 {
2946 phWnd = List;
2947
2948 if(ChildAfter)
2949 {
2950 /* skip handles before and including ChildAfter */
2951 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2952 ;
2953 }
2954
2955 CheckWindowName = WindowName.Buffer != 0;
2956
2957 /* search children */
2958 while(*phWnd)
2959 {
2960 UNICODE_STRING ustr;
2961
2962 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
2963 {
2964 continue;
2965 }
2966
2967 /* Do not send WM_GETTEXT messages in the kernel mode version!
2968 The user mode version however calls GetWindowText() which will
2969 send WM_GETTEXT messages to windows belonging to its processes */
2970 ustr.Buffer = TopLevelWindow->strName.Buffer;
2971 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
2972 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
2973 WindowMatches = !CheckWindowName ||
2974 (TopLevelWindow->strName.Length < 0xFFFF &&
2975 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
2976 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
2977 ClassAtom == TopLevelWindow->pcls->atomClassName;
2978
2979 if (WindowMatches && ClassMatches)
2980 {
2981 Ret = TopLevelWindow->head.h;
2982 break;
2983 }
2984
2985 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
2986 {
2987 /* window returns the handle of the top-level window, in case it found
2988 the child window */
2989 Ret = TopLevelWindow->head.h;
2990 break;
2991 }
2992
2993 }
2994 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2995 }
2996 }
2997 else
2998 {
2999 ERR("FindWindowEx: Not Desktop Parent!\n");
3000 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
3001 }
3002
3003 if (Ret == NULL && DoMessageWnd)
3004 {
3005 PWND MsgWindows;
3006
3007 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3008 {
3009 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3010 }
3011 }
3012 }
3013 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3014 {
3015 SetLastNtError(_SEH2_GetExceptionCode());
3016 Ret = NULL;
3017 }
3018 _SEH2_END;
3019
3020 RETURN( Ret);
3021
3022 CLEANUP:
3023 TRACE("Leave NtUserFindWindowEx, ret %i\n",_ret_);
3024 UserLeave();
3025 END_CLEANUP;
3026 }
3027
3028
3029 /*
3030 * @implemented
3031 */
3032 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
3033 {
3034 PWND WndAncestor, Parent;
3035
3036 if (Wnd->head.h == IntGetDesktopWindow())
3037 {
3038 return NULL;
3039 }
3040
3041 switch (Type)
3042 {
3043 case GA_PARENT:
3044 {
3045 WndAncestor = Wnd->spwndParent;
3046 break;
3047 }
3048
3049 case GA_ROOT:
3050 {
3051 WndAncestor = Wnd;
3052 Parent = NULL;
3053
3054 for(;;)
3055 {
3056 if(!(Parent = WndAncestor->spwndParent))
3057 {
3058 break;
3059 }
3060 if(IntIsDesktopWindow(Parent))
3061 {
3062 break;
3063 }
3064
3065 WndAncestor = Parent;
3066 }
3067 break;
3068 }
3069
3070 case GA_ROOTOWNER:
3071 {
3072 WndAncestor = Wnd;
3073
3074 for (;;)
3075 {
3076 Parent = IntGetParent(WndAncestor);
3077
3078 if (!Parent)
3079 {
3080 break;
3081 }
3082
3083 WndAncestor = Parent;
3084 }
3085 break;
3086 }
3087
3088 default:
3089 {
3090 return NULL;
3091 }
3092 }
3093
3094 return WndAncestor;
3095 }
3096
3097 /*
3098 * @implemented
3099 */
3100 HWND APIENTRY
3101 NtUserGetAncestor(HWND hWnd, UINT Type)
3102 {
3103 PWND Window, Ancestor;
3104 DECLARE_RETURN(HWND);
3105
3106 TRACE("Enter NtUserGetAncestor\n");
3107 UserEnterExclusive();
3108
3109 if (!(Window = UserGetWindowObject(hWnd)))
3110 {
3111 RETURN(NULL);
3112 }
3113
3114 Ancestor = UserGetAncestor(Window, Type);
3115 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3116
3117 RETURN(Ancestor ? Ancestor->head.h : NULL);
3118
3119 CLEANUP:
3120 TRACE("Leave NtUserGetAncestor, ret=%i\n",_ret_);
3121 UserLeave();
3122 END_CLEANUP;
3123 }
3124
3125
3126 BOOL
3127 APIENTRY
3128 NtUserGetComboBoxInfo(
3129 HWND hWnd,
3130 PCOMBOBOXINFO pcbi)
3131 {
3132 PWND Wnd;
3133 DECLARE_RETURN(BOOL);
3134
3135 TRACE("Enter NtUserGetComboBoxInfo\n");
3136 UserEnterShared();
3137
3138 if (!(Wnd = UserGetWindowObject(hWnd)))
3139 {
3140 RETURN( FALSE );
3141 }
3142 _SEH2_TRY
3143 {
3144 if(pcbi)
3145 {
3146 ProbeForWrite(pcbi,
3147 sizeof(COMBOBOXINFO),
3148 1);
3149 }
3150 }
3151 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3152 {
3153 SetLastNtError(_SEH2_GetExceptionCode());
3154 _SEH2_YIELD(RETURN(FALSE));
3155 }
3156 _SEH2_END;
3157
3158 // Pass the user pointer, it was already probed.
3159 RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3160
3161 CLEANUP:
3162 TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3163 UserLeave();
3164 END_CLEANUP;
3165 }
3166
3167
3168 DWORD
3169 APIENTRY
3170 NtUserGetListBoxInfo(
3171 HWND hWnd)
3172 {
3173 PWND Wnd;
3174 DECLARE_RETURN(DWORD);
3175
3176 TRACE("Enter NtUserGetListBoxInfo\n");
3177 UserEnterShared();
3178
3179 if (!(Wnd = UserGetWindowObject(hWnd)))
3180 {
3181 RETURN( 0 );
3182 }
3183
3184 RETURN( (DWORD) co_IntSendMessage( Wnd->head.h, LB_GETLISTBOXINFO, 0, 0 ));
3185
3186 CLEANUP:
3187 TRACE("Leave NtUserGetListBoxInfo, ret=%i\n",_ret_);
3188 UserLeave();
3189 END_CLEANUP;
3190 }
3191
3192 /*
3193 * NtUserSetParent
3194 *
3195 * The NtUserSetParent function changes the parent window of the specified
3196 * child window.
3197 *
3198 * Remarks
3199 * The new parent window and the child window must belong to the same
3200 * application. If the window identified by the hWndChild parameter is
3201 * visible, the system performs the appropriate redrawing and repainting.
3202 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3203 * or WS_POPUP window styles of the window whose parent is being changed.
3204 *
3205 * Status
3206 * @implemented
3207 */
3208
3209 HWND APIENTRY
3210 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3211 {
3212 DECLARE_RETURN(HWND);
3213
3214 TRACE("Enter NtUserSetParent\n");
3215 UserEnterExclusive();
3216
3217 /*
3218 Check Parent first from user space, set it here.
3219 */
3220 if (!hWndNewParent)
3221 {
3222 hWndNewParent = IntGetDesktopWindow();
3223 }
3224 else if (hWndNewParent == HWND_MESSAGE)
3225 {
3226 hWndNewParent = IntGetMessageWindow();
3227 }
3228
3229 RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3230
3231 CLEANUP:
3232 TRACE("Leave NtUserSetParent, ret=%i\n",_ret_);
3233 UserLeave();
3234 END_CLEANUP;
3235 }
3236
3237 /*
3238 * UserGetShellWindow
3239 *
3240 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3241 *
3242 * Status
3243 * @implemented
3244 */
3245 HWND FASTCALL UserGetShellWindow(VOID)
3246 {
3247 PWINSTATION_OBJECT WinStaObject;
3248 HWND Ret;
3249
3250 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3251 KernelMode,
3252 0,
3253 &WinStaObject);
3254
3255 if (!NT_SUCCESS(Status))
3256 {
3257 SetLastNtError(Status);
3258 return( (HWND)0);
3259 }
3260
3261 Ret = (HWND)WinStaObject->ShellWindow;
3262
3263 ObDereferenceObject(WinStaObject);
3264 return( Ret);
3265 }
3266
3267 /*
3268 * NtUserSetShellWindowEx
3269 *
3270 * This is undocumented function to set global shell window. The global
3271 * shell window has special handling of window position.
3272 *
3273 * Status
3274 * @implemented
3275 */
3276 BOOL APIENTRY
3277 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3278 {
3279 PWINSTATION_OBJECT WinStaObject;
3280 PWND WndShell, WndListView;
3281 DECLARE_RETURN(BOOL);
3282 USER_REFERENCE_ENTRY Ref;
3283 NTSTATUS Status;
3284 PTHREADINFO ti;
3285
3286 TRACE("Enter NtUserSetShellWindowEx\n");
3287 UserEnterExclusive();
3288
3289 if (!(WndShell = UserGetWindowObject(hwndShell)))
3290 {
3291 RETURN(FALSE);
3292 }
3293
3294 if(!(WndListView = UserGetWindowObject(hwndListView)))
3295 {
3296 RETURN(FALSE);
3297 }
3298
3299 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3300 KernelMode,
3301 0,
3302 &WinStaObject);
3303
3304 if (!NT_SUCCESS(Status))
3305 {
3306 SetLastNtError(Status);
3307 RETURN( FALSE);
3308 }
3309
3310 /*
3311 * Test if we are permitted to change the shell window.
3312 */
3313 if (WinStaObject->ShellWindow)
3314 {
3315 ObDereferenceObject(WinStaObject);
3316 RETURN( FALSE);
3317 }
3318
3319 /*
3320 * Move shell window into background.
3321 */
3322 if (hwndListView && hwndListView != hwndShell)
3323 {
3324 /*
3325 * Disabled for now to get Explorer working.
3326 * -- Filip, 01/nov/2003
3327 */
3328 #if 0
3329 co_WinPosSetWindowPos(WndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3330 #endif
3331
3332 if (WndListView->ExStyle & WS_EX_TOPMOST)
3333 {
3334 ObDereferenceObject(WinStaObject);
3335 RETURN( FALSE);
3336 }
3337 }
3338
3339 if (WndShell->ExStyle & WS_EX_TOPMOST)
3340 {
3341 ObDereferenceObject(WinStaObject);
3342 RETURN( FALSE);
3343 }
3344
3345 UserRefObjectCo(WndShell, &Ref);
3346 co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3347
3348 WinStaObject->ShellWindow = hwndShell;
3349 WinStaObject->ShellListView = hwndListView;
3350
3351 ti = GetW32ThreadInfo();
3352 if (ti->pDeskInfo)
3353 {
3354 ti->pDeskInfo->hShellWindow = hwndShell;
3355 ti->pDeskInfo->ppiShellProcess = ti->ppi;
3356 }
3357
3358 UserDerefObjectCo(WndShell);
3359
3360 ObDereferenceObject(WinStaObject);
3361 RETURN( TRUE);
3362
3363 CLEANUP:
3364 TRACE("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3365 UserLeave();
3366 END_CLEANUP;
3367 }
3368
3369 /*
3370 * NtUserGetSystemMenu
3371 *
3372 * The NtUserGetSystemMenu function allows the application to access the
3373 * window menu (also known as the system menu or the control menu) for
3374 * copying and modifying.
3375 *
3376 * Parameters
3377 * hWnd
3378 * Handle to the window that will own a copy of the window menu.
3379 * bRevert
3380 * Specifies the action to be taken. If this parameter is FALSE,
3381 * NtUserGetSystemMenu returns a handle to the copy of the window menu
3382 * currently in use. The copy is initially identical to the window menu
3383 * but it can be modified.
3384 * If this parameter is TRUE, GetSystemMenu resets the window menu back
3385 * to the default state. The previous window menu, if any, is destroyed.
3386 *
3387 * Return Value
3388 * If the bRevert parameter is FALSE, the return value is a handle to a
3389 * copy of the window menu. If the bRevert parameter is TRUE, the return
3390 * value is NULL.
3391 *
3392 * Status
3393 * @implemented
3394 */
3395
3396 HMENU APIENTRY
3397 NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
3398 {
3399 PWND Window;
3400 PMENU_OBJECT Menu;
3401 DECLARE_RETURN(HMENU);
3402
3403 TRACE("Enter NtUserGetSystemMenu\n");
3404 UserEnterShared();
3405
3406 if (!(Window = UserGetWindowObject(hWnd)))
3407 {
3408 RETURN(NULL);
3409 }
3410
3411 if (!(Menu = IntGetSystemMenu(Window, bRevert, FALSE)))
3412 {
3413 RETURN(NULL);
3414 }
3415
3416 RETURN(Menu->MenuInfo.Self);
3417
3418 CLEANUP:
3419 TRACE("Leave NtUserGetSystemMenu, ret=%i\n",_ret_);
3420 UserLeave();
3421 END_CLEANUP;
3422 }
3423
3424 /*
3425 * NtUserSetSystemMenu
3426 *
3427 * Status
3428 * @implemented
3429 */
3430
3431 BOOL APIENTRY
3432 NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
3433 {
3434 BOOL Result = FALSE;
3435 PWND Window;
3436 PMENU_OBJECT Menu;
3437 DECLARE_RETURN(BOOL);
3438
3439 TRACE("Enter NtUserSetSystemMenu\n");
3440 UserEnterExclusive();
3441
3442 if (!(Window = UserGetWindowObject(hWnd)))
3443 {
3444 RETURN( FALSE);
3445 }
3446
3447 if (hMenu)
3448 {
3449 /*
3450 * Assign new menu handle.
3451 */
3452 if (!(Menu = UserGetMenuObject(hMenu)))
3453 {
3454 RETURN( FALSE);
3455 }
3456
3457 Result = IntSetSystemMenu(Window, Menu);
3458 }
3459
3460 RETURN( Result);
3461
3462 CLEANUP:
3463 TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_);
3464 UserLeave();
3465 END_CLEANUP;
3466 }
3467
3468 // Fixes wine Win test_window_styles and todo tests...
3469 static BOOL FASTCALL
3470 IntCheckFrameEdge(ULONG Style, ULONG ExStyle)
3471 {
3472 if (ExStyle & WS_EX_DLGMODALFRAME)
3473 return TRUE;
3474 else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME)))
3475 return TRUE;
3476 else
3477 return FALSE;
3478 }
3479
3480 LONG FASTCALL
3481 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3482 {
3483 PWND Window, Parent;
3484 PWINSTATION_OBJECT WindowStation;
3485 LONG OldValue;
3486 STYLESTRUCT Style;
3487
3488 if (!(Window = UserGetWindowObject(hWnd)))
3489 {
3490 return( 0);
3491 }
3492
3493 if ((INT)Index >= 0)
3494 {
3495 if ((Index + sizeof(LONG)) > Window->cbwndExtra)
3496 {
3497 EngSetLastError(ERROR_INVALID_INDEX);
3498 return( 0);
3499 }
3500
3501 OldValue = *((LONG *)((PCHAR)(Window + 1) + Index));
3502 /*
3503 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3504 {
3505 OldValue = (LONG)IntSetWindowProc( Wnd,
3506 (WNDPROC)NewValue,
3507 Ansi);
3508 if (!OldValue) return 0;
3509 }
3510 */
3511 *((LONG *)((PCHAR)(Window + 1) + Index)) = NewValue;
3512 }
3513 else
3514 {
3515 switch (Index)
3516 {
3517 case GWL_EXSTYLE:
3518 OldValue = (LONG) Window->ExStyle;
3519 Style.styleOld = OldValue;
3520 Style.styleNew = NewValue;
3521
3522 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3523
3524 /*
3525 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3526 */
3527 WindowStation = Window->head.pti->rpdesk->rpwinstaParent;
3528 if(WindowStation)
3529 {
3530 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3531 Style.styleNew &= ~WS_EX_TOPMOST;
3532 }
3533 /* WS_EX_WINDOWEDGE depends on some other styles */
3534 if (IntCheckFrameEdge(Window->style, NewValue))
3535 Style.styleNew |= WS_EX_WINDOWEDGE;
3536 else
3537 Style.styleNew &= ~WS_EX_WINDOWEDGE;
3538
3539 Window->ExStyle = (DWORD)Style.styleNew;
3540 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3541 break;
3542
3543 case GWL_STYLE:
3544 OldValue = (LONG) Window->style;
3545 Style.styleOld = OldValue;
3546 Style.styleNew = NewValue;
3547 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3548
3549 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
3550 if (Window->spwndParent == UserGetDesktopWindow()) Style.styleNew |= WS_CLIPSIBLINGS;
3551 /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */
3552 if (IntCheckFrameEdge(NewValue, Window->ExStyle))
3553 Window->ExStyle |= WS_EX_WINDOWEDGE;
3554 else
3555 Window->ExStyle &= ~WS_EX_WINDOWEDGE;
3556
3557 Window->style = (DWORD)Style.styleNew;
3558 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3559 break;
3560
3561 case GWL_WNDPROC:
3562 {
3563 if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
3564 Window->fnid & FNID_FREED)
3565 {
3566 EngSetLastError(ERROR_ACCESS_DENIED);
3567 return( 0);
3568 }
3569 OldValue = (LONG)IntSetWindowProc(Window,
3570 (WNDPROC)NewValue,
3571 Ansi);
3572 break;
3573 }
3574
3575 case GWL_HINSTANCE:
3576 OldValue = (LONG) Window->hModule;
3577 Window->hModule = (HINSTANCE) NewValue;
3578 break;
3579
3580 case GWL_HWNDPARENT:
3581 Parent = Window->spwndParent;
3582 if (Parent && (Parent->head.h == IntGetDesktopWindow()))
3583 OldValue = (LONG) IntSetOwner(Window->head.h, (HWND) NewValue);
3584 else
3585 OldValue = (LONG) co_UserSetParent(Window->head.h, (HWND) NewValue);
3586 break;
3587
3588 case GWL_ID:
3589 OldValue = (LONG) Window->IDMenu;
3590 Window->IDMenu = (UINT) NewValue;
3591 break;
3592
3593 case GWL_USERDATA:
3594 OldValue = Window->dwUserData;
3595 Window->dwUserData = NewValue;
3596 break;
3597
3598 default:
3599 ERR("NtUserSetWindowLong(): Unsupported index %d\n", Index);
3600 EngSetLastError(ERROR_INVALID_INDEX);
3601 OldValue = 0;
3602 break;
3603 }
3604 }
3605
3606 return( OldValue);
3607 }
3608
3609 /*
3610 * NtUserSetWindowLong
3611 *
3612 * The NtUserSetWindowLong function changes an attribute of the specified
3613 * window. The function also sets the 32-bit (long) value at the specified
3614 * offset into the extra window memory.
3615 *
3616 * Status
3617 * @implemented
3618 */
3619
3620 LONG APIENTRY
3621 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3622 {
3623 DECLARE_RETURN(LONG);
3624
3625 TRACE("Enter NtUserSetWindowLong\n");
3626 UserEnterExclusive();
3627
3628 if (hWnd == IntGetDesktopWindow())
3629 {
3630 EngSetLastError(STATUS_ACCESS_DENIED);
3631 RETURN( 0);
3632 }
3633
3634 RETURN( co_UserSetWindowLong(hWnd, Index, NewValue, Ansi));
3635
3636 CLEANUP:
3637 TRACE("Leave NtUserSetWindowLong, ret=%i\n",_ret_);
3638 UserLeave();
3639 END_CLEANUP;
3640 }
3641
3642 /*
3643 * NtUserSetWindowWord
3644 *
3645 * Legacy function similar to NtUserSetWindowLong.
3646 *
3647 * Status
3648 * @implemented
3649 */
3650
3651 WORD APIENTRY
3652 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
3653 {
3654 PWND Window;
3655 WORD OldValue;
3656 DECLARE_RETURN(WORD);
3657
3658 TRACE("Enter NtUserSetWindowWord\n");
3659 UserEnterExclusive();
3660
3661 if (hWnd == IntGetDesktopWindow())
3662 {
3663 EngSetLastError(STATUS_ACCESS_DENIED);
3664 RETURN( 0);
3665 }
3666
3667 if (!(Window = UserGetWindowObject(hWnd)))
3668 {
3669 RETURN( 0);
3670 }
3671
3672 switch (Index)
3673 {
3674 case GWL_ID:
3675 case GWL_HINSTANCE:
3676 case GWL_HWNDPARENT:
3677 RETURN( (WORD)co_UserSetWindowLong(UserHMGetHandle(Window), Index, (UINT)NewValue, TRUE));
3678 default:
3679 if (Index < 0)
3680 {
3681 EngSetLastError(ERROR_INVALID_INDEX);
3682 RETURN( 0);
3683 }
3684 }
3685
3686 if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD)))
3687 {
3688 EngSetLastError(ERROR_INVALID_PARAMETER);
3689 RETURN( 0);
3690 }
3691
3692 OldValue = *((WORD *)((PCHAR)(Window + 1) + Index));
3693 *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue;
3694
3695 RETURN( OldValue);
3696
3697 CLEANUP:
3698 TRACE("Leave NtUserSetWindowWord, ret=%i\n",_ret_);
3699 UserLeave();
3700 END_CLEANUP;
3701 }
3702
3703 /*
3704 QueryWindow based on KJK::Hyperion and James Tabor.
3705
3706 0 = QWUniqueProcessId
3707 1 = QWUniqueThreadId
3708 2 = QWActiveWindow
3709 3 = QWFocusWindow
3710 4 = QWIsHung Implements IsHungAppWindow found
3711 by KJK::Hyperion.
3712
3713 9 = QWKillWindow When I called this with hWnd ==
3714 DesktopWindow, it shutdown the system
3715 and rebooted.
3716 */
3717 /*
3718 * @implemented
3719 */
3720 DWORD APIENTRY
3721 NtUserQueryWindow(HWND hWnd, DWORD Index)
3722 {
3723 /* Console Leader Process CID Window offsets */
3724 #define GWLP_CONSOLE_LEADER_PID 0
3725 #define GWLP_CONSOLE_LEADER_TID 4
3726
3727 PWND pWnd;
3728 DWORD Result;
3729 DECLARE_RETURN(UINT);
3730
3731 TRACE("Enter NtUserQueryWindow\n");
3732 UserEnterShared();
3733
3734 if (!(pWnd = UserGetWindowObject(hWnd)))
3735 {
3736 RETURN( 0);
3737 }
3738
3739 switch(Index)
3740 {
3741 case QUERY_WINDOW_UNIQUE_PROCESS_ID:
3742 {
3743 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
3744 ( (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) ||
3745 (pWnd->pcls->atomClassName == gaTuiConsoleWndClass) ) )
3746 {
3747 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_PID)
3748 Result = (DWORD)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_PID)));
3749 }
3750 else
3751 {
3752 Result = (DWORD)IntGetWndProcessId(pWnd);
3753 }
3754 break;
3755 }
3756
3757 case QUERY_WINDOW_UNIQUE_THREAD_ID:
3758 {
3759 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
3760 ( (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) ||
3761 (pWnd->pcls->atomClassName == gaTuiConsoleWndClass) ) )
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->MessageQueue);
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 */