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