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