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