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