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