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