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