ReactOS 0.4.15-dev-7089-gea8a49d
window.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Windows
5 * FILE: win32ss/user/ntuser/window.c
6 * PROGRAMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
8 */
9
10#include <win32k.h>
11#include <ddk/immdev.h>
13
15
18
19/* HELPER FUNCTIONS ***********************************************************/
20
24 PVOID pOld,
25 SIZE_T cbOld,
26 SIZE_T cbNew,
27 ULONG Tag)
28{
30 if (!pNew)
31 return NULL;
32
33 RtlCopyMemory(pNew, pOld, min(cbOld, cbNew));
35 return pNew;
36}
37
39{
42
43 if (Flags & ~(UISF_HIDEFOCUS | UISF_HIDEACCEL | UISF_ACTIVE))
44 {
46 return FALSE;
47 }
48
49 switch (Action)
50 {
51 case UIS_INITIALIZE:
53 return FALSE;
54
55 case UIS_SET:
56 if (Flags & UISF_HIDEFOCUS)
57 Wnd->HideFocus = TRUE;
58 if (Flags & UISF_HIDEACCEL)
59 Wnd->HideAccel = TRUE;
60 break;
61
62 case UIS_CLEAR:
63 if (Flags & UISF_HIDEFOCUS)
64 Wnd->HideFocus = FALSE;
65 if (Flags & UISF_HIDEACCEL)
66 Wnd->HideAccel = FALSE;
67 break;
68 }
69
70 return TRUE;
71}
72
74{
76
77 if (!hWnd) return NULL;
78
80 if (Window)
81 Window->head.cLockObj++;
82
83 return Window;
84}
85
87{
89
90 if (!pWnd ||
91 (pWnd->state & WNDS_DESTROYED) ||
92 (pWnd->state2 & WNDS2_INDESTROY))
93 {
94 return NULL;
95 }
96
98
100 pWnd = NULL;
101
103 return pWnd;
104}
105
107{
108 PWND Window;
109
110 if (!hWnd)
111 return NULL;
112
114 if (!Window || (Window->state & WNDS_DESTROYED))
115 return NULL;
116
117 return Window;
118}
119
120/* Temp HACK */
121// Win: ValidateHwnd
123{
124 PWND Window;
125
126 if (!hWnd)
127 {
129 return NULL;
130 }
131
133 if (!Window || 0 != (Window->state & WNDS_DESTROYED))
134 {
136 return NULL;
137 }
138
139 return Window;
140}
141
143IntSetStyle( PWND pwnd, ULONG set_bits, ULONG clear_bits )
144{
145 ULONG styleOld, styleNew;
146 styleOld = pwnd->style;
147 styleNew = (pwnd->style | set_bits) & ~clear_bits;
148 if (styleNew == styleOld) return styleNew;
149 pwnd->style = styleNew;
150 if ((styleOld ^ styleNew) & WS_VISIBLE) // State Change.
151 {
152 if (styleOld & WS_VISIBLE) pwnd->head.pti->cVisWindows--;
153 if (styleNew & WS_VISIBLE) pwnd->head.pti->cVisWindows++;
154 DceResetActiveDCEs( pwnd );
155 }
156 return styleOld;
157}
158
159/*
160 * IntIsWindow
161 *
162 * The function determines whether the specified window handle identifies
163 * an existing window.
164 *
165 * Parameters
166 * hWnd
167 * Handle to the window to test.
168 *
169 * Return Value
170 * If the window handle identifies an existing window, the return value
171 * is TRUE. If the window handle does not identify an existing window,
172 * the return value is FALSE.
173 */
174
177{
178 PWND Window;
179
181 {
182 return FALSE;
183 }
184
185 return TRUE;
186}
187
190{
191 PWND Temp = Wnd;
192 for (;;)
193 {
194 if (!Temp) return TRUE;
195 if (!(Temp->style & WS_VISIBLE)) break;
196 if (Temp->style & WS_MINIMIZE && Temp != Wnd) break;
197 if (Temp->fnid == FNID_DESKTOP) return TRUE;
198 Temp = Temp->spwndParent;
199 }
200 return FALSE;
201}
202
205{
206 if (Wnd->style & WS_POPUP)
207 {
208 return Wnd->spwndOwner;
209 }
210 else if (Wnd->style & WS_CHILD)
211 {
212 return Wnd->spwndParent;
213 }
214
215 return NULL;
216}
217
218BOOL
221{
222 BOOL Update;
223 PWND pWnd;
224 UINT bIsDisabled;
225
226 if(!(pWnd = UserGetWindowObject(hWnd)))
227 {
228 return FALSE;
229 }
230
231 /* check if updating is needed */
232 bIsDisabled = !!(pWnd->style & WS_DISABLED);
233 Update = bIsDisabled;
234
235 if (bEnable)
236 {
237 IntSetStyle( pWnd, 0, WS_DISABLED );
238 }
239 else
240 {
241 Update = !bIsDisabled;
242
244
245 /* Remove keyboard focus from that window if it had focus */
247 {
248 TRACE("IntEnableWindow SF NULL\n");
250 }
251 IntSetStyle( pWnd, WS_DISABLED, 0 );
252 }
253
254 if (Update)
255 {
256 IntNotifyWinEvent(EVENT_OBJECT_STATECHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, 0);
258 }
259 // Return nonzero if it was disabled, or zero if it wasn't:
260 return bIsDisabled;
261}
262
263/*
264 * IntWinListChildren
265 *
266 * Compile a list of all child window handles from given window.
267 *
268 * Remarks
269 * This function is similar to Wine WIN_ListChildren. The caller
270 * must free the returned list with ExFreePool.
271 */
272
275{
276 PWND Child;
277 HWND *List;
278 UINT Index, NumChildren = 0;
279
280 if (!Window) return NULL;
281
282 for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
283 {
284 ++NumChildren;
285 }
286
287 List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), USERTAG_WINDOWLIST);
288 if(!List)
289 {
290 ERR("Failed to allocate memory for children array\n");
292 return NULL;
293 }
294
295 Index = 0;
296 for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
297 {
298 List[Index++] = Child->head.h;
299 }
300 List[Index] = NULL;
301
302 return List;
303}
304
305static BOOL
307{
308 PTHREADINFO pti = Window->head.pti;
309
310 return (IS_IMM_MODE() && !(pti->TIF_flags & TIF_INCLEANUP) &&
311 Window == pti->spwndDefaultIme);
312}
313
316{
318 HWND *List;
319 UINT Index, NumOwned = 0;
320
322 if (!Desktop)
323 return NULL;
324
325 for (Child = Desktop->spwndChild; Child; Child = Child->spwndNext)
326 {
327 if (Child->spwndOwner == Window && !IntWndIsDefaultIme(Child))
328 ++NumOwned;
329 }
330
331 List = ExAllocatePoolWithTag(PagedPool, (NumOwned + 1) * sizeof(HWND), USERTAG_WINDOWLIST);
332 if (!List)
333 {
334 ERR("Failed to allocate memory for children array\n");
336 return NULL;
337 }
338
339 Index = 0;
340 for (Child = Desktop->spwndChild; Child; Child = Child->spwndNext)
341 {
342 if (Child->spwndOwner == Window && !IntWndIsDefaultIme(Child))
343 List[Index++] = Child->head.h;
344 }
345 List[Index] = NULL;
346
347 return List;
348}
349
352{
353 while(pWnd && (pWnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
354 pWnd = pWnd->spwndParent;
355 return pWnd;
356}
357
360{
361 if ( pWnd->spwndParent &&
362 pWnd->spwndParent == co_GetDesktopWindow(pWnd) ) return TRUE;
363 return FALSE;
364}
365
368{
369 INT Depth = 1;
370 for (;;)
371 {
372 if ( !Owner ) return gNestedWindowLimit >= Depth;
373 if (Owner == Wnd) break;
374 Owner = Owner->spwndOwner;
375 Depth++;
376 }
377 return FALSE;
378}
379
382 UINT uCmd)
383{
384 PWND Wnd, FoundWnd;
385 HWND Ret = NULL;
386
387 Wnd = ValidateHwndNoErr(hWnd);
388 if (!Wnd)
389 return NULL;
390
391 FoundWnd = NULL;
392 switch (uCmd)
393 {
394 case GW_OWNER:
395 if (Wnd->spwndOwner != NULL)
396 FoundWnd = Wnd->spwndOwner;
397 break;
398
399 case GW_HWNDFIRST:
400 if(Wnd->spwndParent != NULL)
401 {
402 FoundWnd = Wnd->spwndParent;
403 if (FoundWnd->spwndChild != NULL)
404 FoundWnd = FoundWnd->spwndChild;
405 }
406 break;
407 case GW_HWNDNEXT:
408 if (Wnd->spwndNext != NULL)
409 FoundWnd = Wnd->spwndNext;
410 break;
411
412 case GW_HWNDPREV:
413 if (Wnd->spwndPrev != NULL)
414 FoundWnd = Wnd->spwndPrev;
415 break;
416
417 case GW_CHILD:
418 if (Wnd->spwndChild != NULL)
419 FoundWnd = Wnd->spwndChild;
420 break;
421
422 case GW_HWNDLAST:
423 FoundWnd = Wnd;
424 while ( FoundWnd->spwndNext != NULL)
425 FoundWnd = FoundWnd->spwndNext;
426 break;
427
428 default:
429 Wnd = NULL;
430 break;
431 }
432
433 if (FoundWnd != NULL)
434 Ret = UserHMGetHandle(FoundWnd);
435 return Ret;
436}
437
439{
440 DWORD HelpId;
441
442 do
443 {
445 if (!HelpId) break;
446 pWnd = IntGetParent(pWnd);
447 }
448 while (pWnd && pWnd->fnid != FNID_DESKTOP);
449 return HelpId;
450}
451
452
453VOID
456 PDESKTOP pDesk);
457
458/***********************************************************************
459 * IntSendDestroyMsg
460 */
462{
463 PTHREADINFO ti;
464 PWND Window;
465
468
469 if (Window)
470 {
471 /*
472 * Look whether the focus is within the tree of windows
473 * we will be destroying.
474 */
475 // Rule #1
476 if ( ti->MessageQueue->spwndActive == Window || // Fixes CORE-106 RegSvr32 exit and return focus to CMD.
477 (ti->MessageQueue->spwndActive == NULL && ti->MessageQueue == IntGetFocusMessageQueue()) )
478 {
480 }
481
482 /* Fixes CMD properties closing and returning focus to CMD */
483 if (ti->MessageQueue->spwndFocus == Window)
484 {
485 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
486 {
487 co_UserSetFocus(Window->spwndParent);
488 }
489 else
490 {
492 }
493 }
494
495 if (ti->MessageQueue->CaretInfo.hWnd == UserHMGetHandle(Window))
496 {
498 }
499
500 /* If the window being destroyed is currently tracked... */
501 if (ti->rpdesk && ti->rpdesk->spwndTrack == Window)
502 {
504 }
505 }
506
507 /* If the window being destroyed is the current clipboard owner... */
508 if (ti->ppi->prpwinsta != NULL && Window == ti->ppi->prpwinsta->spwndClipOwner)
509 {
510 /* ... make it release the clipboard */
512 }
513
514 /* Send the WM_DESTROY to the window */
516
517 /*
518 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
519 * make sure that the window still exists when we come back.
520 */
521 if (IntIsWindow(hWnd))
522 {
523 HWND* pWndArray;
524 int i;
525
526 if (!(pWndArray = IntWinListChildren( Window ))) return;
527
528 for (i = 0; pWndArray[i]; i++)
529 {
530 if (IntIsWindow( pWndArray[i] )) IntSendDestroyMsg( pWndArray[i] );
531 }
533 }
534 else
535 {
536 TRACE("destroyed itself while in WM_DESTROY!\n");
537 }
538}
539
540static VOID
542{
544
545 if (!Wnd) return;
546
547 if (ClientInfo->CallbackWnd.pWnd == DesktopHeapAddressToUser(Wnd))
548 {
549 ClientInfo->CallbackWnd.hWnd = NULL;
550 ClientInfo->CallbackWnd.pWnd = NULL;
551 }
552
553 if (Wnd->strName.Buffer != NULL)
554 {
555 Wnd->strName.Length = 0;
556 Wnd->strName.MaximumLength = 0;
558 Wnd->strName.Buffer);
559 Wnd->strName.Buffer = NULL;
560 }
561
562// DesktopHeapFree(Wnd->head.rpdesk, Wnd);
563// WindowObject->hWnd = NULL;
564}
565
566/***********************************************************************
567 * co_UserFreeWindow
568 *
569 * Destroy storage associated to a window. "Internals" p.358
570 *
571 * This is the "functional" DestroyWindows function i.e. all stuff
572 * done in CreateWindow is undone here and not in DestroyWindow :-P
573 */
575 PPROCESSINFO ProcessData,
577 BOOLEAN SendMessages)
578{
579 HWND *Children;
580 HWND *ChildHandle;
581 PWND Child;
582 PMENU Menu;
583 BOOLEAN BelongsToThreadData;
584
585 ASSERT(Window);
586
587 if(Window->state2 & WNDS2_INDESTROY)
588 {
589 TRACE("Tried to call co_UserFreeWindow() twice\n");
590 return 0;
591 }
592 Window->state2 |= WNDS2_INDESTROY;
593 Window->style &= ~WS_VISIBLE;
594 Window->head.pti->cVisWindows--;
595
596 /* remove the window already at this point from the thread window list so we
597 don't get into trouble when destroying the thread windows while we're still
598 in co_UserFreeWindow() */
599 if (!IsListEmpty(&Window->ThreadListEntry))
600 RemoveEntryList(&Window->ThreadListEntry);
601
602 BelongsToThreadData = IntWndBelongsToThread(Window, ThreadData);
603
605
606 /* free child windows */
607 Children = IntWinListChildren(Window);
608 if (Children)
609 {
610 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
611 {
612 if ((Child = IntGetWindowObject(*ChildHandle)))
613 {
615 {
616 /* send WM_DESTROY messages to windows not belonging to the same thread */
618 }
619 else
620 co_UserFreeWindow(Child, ProcessData, ThreadData, SendMessages);
621
623 }
624 }
626 }
627
628 if (SendMessages)
629 {
630 /*
631 * Clear the update region to make sure no WM_PAINT messages will be
632 * generated for this window while processing the WM_NCDESTROY.
633 */
637 if (BelongsToThreadData)
639 }
640
642
644
645 /* Unregister hot keys */
647
648 /* flush the message queue */
650
651 /* from now on no messages can be sent to this window anymore */
652 Window->state |= WNDS_DESTROYED;
653 Window->fnid |= FNID_FREED;
654
655 /* don't remove the WINDOWSTATUS_DESTROYING bit */
656
657 /* reset shell window handles */
658 if (ThreadData->rpdesk)
659 {
660 if (Window->head.h == ThreadData->rpdesk->rpwinstaParent->ShellWindow)
661 ThreadData->rpdesk->rpwinstaParent->ShellWindow = NULL;
662
663 if (Window->head.h == ThreadData->rpdesk->rpwinstaParent->ShellListView)
664 ThreadData->rpdesk->rpwinstaParent->ShellListView = NULL;
665 }
666
667 if (ThreadData->spwndDefaultIme &&
668 ThreadData->spwndDefaultIme->spwndOwner == Window)
669 {
670 WndSetOwner(ThreadData->spwndDefaultIme, NULL);
671 }
672
673 if (IS_IMM_MODE() && Window == ThreadData->spwndDefaultIme)
674 {
675 UserAssignmentUnlock((PVOID*)&(ThreadData->spwndDefaultIme));
676 }
677
678 /* Fixes dialog test_focus breakage due to r66237. */
679 if (ThreadData->MessageQueue->spwndFocus == Window)
680 ThreadData->MessageQueue->spwndFocus = NULL;
681
682 if (ThreadData->MessageQueue->spwndActive == Window)
683 ThreadData->MessageQueue->spwndActive = NULL;
684
685 if (ThreadData->MessageQueue->spwndCapture == Window)
686 {
688 }
689
691 if ( Window->hrgnUpdate != NULL || Window->state & WNDS_INTERNALPAINT )
692 {
693 MsqDecPaintCountQueue(Window->head.pti);
694 if (Window->hrgnUpdate > HRGN_WINDOW && GreIsHandleValid(Window->hrgnUpdate))
695 {
697 GreDeleteObject(Window->hrgnUpdate);
698 }
699 Window->hrgnUpdate = NULL;
700 Window->state &= ~WNDS_INTERNALPAINT;
701 }
702
704 {
706 }
707
708 if ( ((Window->style & (WS_CHILD|WS_POPUP)) != WS_CHILD) &&
709 Window->IDMenu &&
710 (Menu = UserGetMenuObject((HMENU)Window->IDMenu)))
711 {
712 TRACE("UFW: IDMenu %p\n",Window->IDMenu);
714 Window->IDMenu = 0;
715 }
716
717 if (Window->SystemMenu
718 && (Menu = UserGetMenuObject(Window->SystemMenu)))
719 {
721 Window->SystemMenu = (HMENU)0;
722 }
723
724 DceFreeWindowDCE(Window); /* Always do this to catch orphaned DCs */
725
727
728 if (Window->PropListItems)
729 {
731 TRACE("Window->PropListItems %lu\n",Window->PropListItems);
732 ASSERT(Window->PropListItems==0);
733 }
734
735 /* Kill any reference to linked windows. Prev & Next are taken care of in IntUnlinkWindow */
740
743
745
746 if (Window->pcls->atomClassName == gaGuiConsoleWndClass)
747 {
748 /* Count only console windows manually */
750 }
751
752 /* dereference the class */
753 NT_ASSERT(Window->head.pti != NULL);
755 Window->head.pti->pDeskInfo,
756 Window->head.pti->ppi);
757 Window->pcls = NULL;
758
759 if (Window->hrgnClip)
760 {
762 GreDeleteObject(Window->hrgnClip);
763 Window->hrgnClip = NULL;
764 }
765 Window->head.pti->cWindows--;
766
767// ASSERT(Window != NULL);
768 UserFreeWindowInfo(Window->head.pti, Window);
769
772
773 return 0;
774}
775
776//
777// Same as User32:IntGetWndProc.
778//
781 BOOL Ansi)
782{
783 INT i;
784 PCLS Class;
785 WNDPROC gcpd, Ret = 0;
786
788
789 Class = pWnd->pcls;
790
792 {
793 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
794 {
795 if (GETPFNSERVER(i) == pWnd->lpfnWndProc)
796 {
797 if (Ansi)
798 Ret = GETPFNCLIENTA(i);
799 else
800 Ret = GETPFNCLIENTW(i);
801 }
802 }
803 return Ret;
804 }
805
806 if (Class->fnid == FNID_EDIT)
807 Ret = pWnd->lpfnWndProc;
808 else
809 {
810 Ret = pWnd->lpfnWndProc;
811
812 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
813 {
814 if (Ansi)
815 {
816 if (GETPFNCLIENTW(Class->fnid) == pWnd->lpfnWndProc)
817 Ret = GETPFNCLIENTA(Class->fnid);
818 }
819 else
820 {
821 if (GETPFNCLIENTA(Class->fnid) == pWnd->lpfnWndProc)
822 Ret = GETPFNCLIENTW(Class->fnid);
823 }
824 }
825 if ( Ret != pWnd->lpfnWndProc)
826 return Ret;
827 }
828 if ( Ansi == !!(pWnd->state & WNDS_ANSIWINDOWPROC) )
829 return Ret;
830
831 gcpd = (WNDPROC)UserGetCPD(
832 pWnd,
834 (ULONG_PTR)Ret);
835
836 return (gcpd ? gcpd : Ret);
837}
838
839static WNDPROC
841 WNDPROC NewWndProc,
842 BOOL Ansi)
843{
844 INT i;
845 PCALLPROCDATA CallProc;
846 PCLS Class;
847 WNDPROC Ret, chWndProc = NULL;
848
849 // Retrieve previous window proc.
850 Ret = IntGetWindowProc(pWnd, Ansi);
851
852 Class = pWnd->pcls;
853
854 if (IsCallProcHandle(NewWndProc))
855 {
856 CallProc = UserGetObject(gHandleTable, NewWndProc, TYPE_CALLPROC);
857 if (CallProc)
858 { // Reset new WndProc.
859 NewWndProc = CallProc->pfnClientPrevious;
860 // Reset Ansi from CallProc handle. This is expected with wine "deftest".
861 Ansi = !!(CallProc->wType & UserGetCPDU2A);
862 }
863 }
864 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
865 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
866 {
867 if (GETPFNCLIENTW(i) == NewWndProc)
868 {
869 chWndProc = GETPFNSERVER(i);
870 break;
871 }
872 if (GETPFNCLIENTA(i) == NewWndProc)
873 {
874 chWndProc = GETPFNSERVER(i);
875 break;
876 }
877 }
878 // If match, set/reset to Server Side and clear ansi.
879 if (chWndProc)
880 {
881 pWnd->lpfnWndProc = chWndProc;
882 pWnd->Unicode = TRUE;
883 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
885 }
886 else
887 {
888 pWnd->Unicode = !Ansi;
889 // Handle the state change in here.
890 if (Ansi)
891 pWnd->state |= WNDS_ANSIWINDOWPROC;
892 else
893 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
894
896 pWnd->state &= ~WNDS_SERVERSIDEWINDOWPROC;
897
898 if (!NewWndProc) NewWndProc = pWnd->lpfnWndProc;
899
900 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
901 {
902 if (Ansi)
903 {
904 if (GETPFNCLIENTW(Class->fnid) == NewWndProc)
905 chWndProc = GETPFNCLIENTA(Class->fnid);
906 }
907 else
908 {
909 if (GETPFNCLIENTA(Class->fnid) == NewWndProc)
910 chWndProc = GETPFNCLIENTW(Class->fnid);
911 }
912 }
913 // Now set the new window proc.
914 pWnd->lpfnWndProc = (chWndProc ? chWndProc : NewWndProc);
915 }
916 return Ret;
917}
918
919
920/* INTERNAL ******************************************************************/
921
923// This fixes a check for children messages that need paint while searching the parents messages!
924// Fixes wine msg:test_paint_messages:WmParentErasePaint ..
928{
930 do
931 {
932 if ( Window == NULL || (Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD )
933 return FALSE;
934
935 Window = Window->spwndParent;
936 }
937 while(Parent != Window);
938 return TRUE;
939}
941
942/* Link the window into siblings list. Children and parent are kept in place. */
945 PWND Wnd,
946 PWND WndInsertAfter /* Set to NULL if top sibling */
947)
948{
949 if (Wnd == WndInsertAfter)
950 {
951 ERR("Trying to link window 0x%p to itself\n", Wnd);
952 ASSERT(WndInsertAfter != Wnd);
953 return;
954 }
955
956 WndSetPrev(Wnd, WndInsertAfter);
957 if (Wnd->spwndPrev)
958 {
959 /* Link after WndInsertAfter */
960 ASSERT(Wnd != WndInsertAfter->spwndNext);
961 WndSetNext(Wnd, WndInsertAfter->spwndNext);
962 if (Wnd->spwndNext)
963 WndSetPrev(Wnd->spwndNext, Wnd);
964
965 ASSERT(Wnd != Wnd->spwndPrev);
966 WndSetNext(Wnd->spwndPrev, Wnd);
967 }
968 else
969 {
970 /* Link at the top */
971 ASSERT(Wnd != Wnd->spwndParent->spwndChild);
972 WndSetNext(Wnd, Wnd->spwndParent->spwndChild);
973 if (Wnd->spwndNext)
974 WndSetPrev(Wnd->spwndNext, Wnd);
975
976 WndSetChild(Wnd->spwndParent, Wnd);
977 }
978}
979
980/*
981 Note: Wnd->spwndParent can be null if it is the desktop.
982*/
984{
985 if (hWndPrev == HWND_NOTOPMOST)
986 {
987 if (!(Wnd->ExStyle & WS_EX_TOPMOST) && (Wnd->ExStyle2 & WS_EX2_LINKED))
988 return; /* nothing to do */
989 Wnd->ExStyle &= ~WS_EX_TOPMOST;
990 hWndPrev = HWND_TOP; /* fallback to the HWND_TOP case */
991 }
992
993 IntUnlinkWindow(Wnd); /* unlink it from the previous location */
994
995 if (hWndPrev == HWND_BOTTOM)
996 {
997 /* Link in the bottom of the list */
998 PWND WndInsertAfter;
999
1000 WndInsertAfter = Wnd->spwndParent->spwndChild;
1001 while (WndInsertAfter && WndInsertAfter->spwndNext)
1002 {
1003 WndInsertAfter = WndInsertAfter->spwndNext;
1004 }
1005
1006 IntLinkWindow(Wnd, WndInsertAfter);
1007 Wnd->ExStyle &= ~WS_EX_TOPMOST;
1008 }
1009 else if (hWndPrev == HWND_TOPMOST)
1010 {
1011 /* Link in the top of the list */
1012 IntLinkWindow(Wnd, NULL);
1013 Wnd->ExStyle |= WS_EX_TOPMOST;
1014 }
1015 else if (hWndPrev == HWND_TOP)
1016 {
1017 /* Link it after the last topmost window */
1018 PWND WndInsertBefore;
1019
1020 WndInsertBefore = Wnd->spwndParent->spwndChild;
1021
1022 if (!(Wnd->ExStyle & WS_EX_TOPMOST)) /* put it above the first non-topmost window */
1023 {
1024 while (WndInsertBefore != NULL && WndInsertBefore->spwndNext != NULL)
1025 {
1026 if (!(WndInsertBefore->ExStyle & WS_EX_TOPMOST))
1027 break;
1028
1029 if (WndInsertBefore == Wnd->spwndOwner) /* keep it above owner */
1030 {
1031 Wnd->ExStyle |= WS_EX_TOPMOST;
1032 break;
1033 }
1034 WndInsertBefore = WndInsertBefore->spwndNext;
1035 }
1036 }
1037
1038 IntLinkWindow(Wnd, WndInsertBefore ? WndInsertBefore->spwndPrev : NULL);
1039 }
1040 else
1041 {
1042 /* Link it after hWndPrev */
1043 PWND WndInsertAfter;
1044
1045 WndInsertAfter = UserGetWindowObject(hWndPrev);
1046 /* Are we called with an erroneous handle */
1047 if (WndInsertAfter == NULL)
1048 {
1049 /* Link in a default position */
1050 IntLinkHwnd(Wnd, HWND_TOP);
1051 return;
1052 }
1053
1054 if (Wnd == WndInsertAfter)
1055 {
1056 ERR("Trying to link window 0x%p to itself\n", Wnd);
1057 ASSERT(WndInsertAfter != Wnd);
1058 // FIXME: IntUnlinkWindow(Wnd) was already called. Continuing as is seems wrong!
1059 }
1060 else
1061 {
1062 IntLinkWindow(Wnd, WndInsertAfter);
1063 }
1064
1065 /* Fix the WS_EX_TOPMOST flag */
1066 if (!(WndInsertAfter->ExStyle & WS_EX_TOPMOST))
1067 {
1068 Wnd->ExStyle &= ~WS_EX_TOPMOST;
1069 }
1070 else
1071 {
1072 if (WndInsertAfter->spwndNext &&
1073 (WndInsertAfter->spwndNext->ExStyle & WS_EX_TOPMOST))
1074 {
1075 Wnd->ExStyle |= WS_EX_TOPMOST;
1076 }
1077 }
1078 }
1079 Wnd->ExStyle2 |= WS_EX2_LINKED;
1080}
1081
1083IntProcessOwnerSwap(PWND Wnd, PWND WndNewOwner, PWND WndOldOwner)
1084{
1085 if (WndOldOwner)
1086 {
1087 if (Wnd->head.pti != WndOldOwner->head.pti)
1088 {
1089 if (!WndNewOwner ||
1090 Wnd->head.pti == WndNewOwner->head.pti ||
1091 WndOldOwner->head.pti != WndNewOwner->head.pti )
1092 {
1093 //ERR("ProcessOwnerSwap Old out.\n");
1094 UserAttachThreadInput(Wnd->head.pti, WndOldOwner->head.pti, FALSE);
1095 }
1096 }
1097 }
1098 if (WndNewOwner)
1099 {
1100 if (Wnd->head.pti != WndNewOwner->head.pti)
1101 {
1102 if (!WndOldOwner ||
1103 WndOldOwner->head.pti != WndNewOwner->head.pti )
1104 {
1105 //ERR("ProcessOwnerSwap New in.\n");
1106 UserAttachThreadInput(Wnd->head.pti, WndNewOwner->head.pti, TRUE);
1107 }
1108 }
1109 }
1110 // FIXME: System Tray checks.
1111}
1112
1113static
1116{
1117 PWND Wnd, WndOldOwner, WndNewOwner;
1118 HWND ret;
1119
1120 Wnd = IntGetWindowObject(hWnd);
1121 if(!Wnd)
1122 return NULL;
1123
1124 WndOldOwner = Wnd->spwndOwner;
1125
1126 ret = WndOldOwner ? UserHMGetHandle(WndOldOwner) : 0;
1127 WndNewOwner = UserGetWindowObject(hWndNewOwner);
1128
1129 if (!WndNewOwner && hWndNewOwner)
1130 {
1132 ret = NULL;
1133 goto Error;
1134 }
1135
1136 /* if parent belongs to a different thread and the window isn't */
1137 /* top-level, attach the two threads */
1138 IntProcessOwnerSwap(Wnd, WndNewOwner, WndOldOwner);
1139
1140 if (IntValidateOwnerDepth(Wnd, WndNewOwner))
1141 {
1142 WndSetOwner(Wnd, WndNewOwner);
1143 }
1144 else
1145 {
1146 IntProcessOwnerSwap(Wnd, WndOldOwner, WndNewOwner);
1148 ret = NULL;
1149 }
1150Error:
1152 return ret;
1153}
1154
1156co_IntSetParent(PWND Wnd, PWND WndNewParent)
1157{
1158 PWND WndOldParent, pWndExam;
1159 BOOL WasVisible;
1160 POINT pt;
1161 int swFlags = SWP_NOSIZE|SWP_NOZORDER;
1162
1163 ASSERT(Wnd);
1164 ASSERT(WndNewParent);
1165 ASSERT_REFS_CO(Wnd);
1166 ASSERT_REFS_CO(WndNewParent);
1167
1168 if (Wnd == Wnd->head.rpdesk->spwndMessage)
1169 {
1171 return( NULL);
1172 }
1173
1174 /* Some applications try to set a child as a parent */
1175 if (IntIsChildWindow(Wnd, WndNewParent))
1176 {
1177 TRACE("IntSetParent try to set a child as a parent.\n");
1179 return NULL;
1180 }
1181
1182 pWndExam = WndNewParent; // Load parent Window to examine.
1183 // Now test for set parent to parent hit.
1184 while (pWndExam)
1185 {
1186 if (Wnd == pWndExam)
1187 {
1188 TRACE("IntSetParent Failed Test for set parent to parent!\n");
1190 return NULL;
1191 }
1192 pWndExam = pWndExam->spwndParent;
1193 }
1194
1195 /*
1196 * Windows hides the window first, then shows it again
1197 * including the WM_SHOWWINDOW messages and all
1198 */
1199 WasVisible = co_WinPosShowWindow(Wnd, SW_HIDE);
1200
1201 /* Window must belong to current process */
1202 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
1203 {
1204 ERR("IntSetParent Window must belong to current process!\n");
1205 return NULL;
1206 }
1207
1208 WndOldParent = Wnd->spwndParent;
1209
1210 if ( WndOldParent &&
1211 WndOldParent->ExStyle & WS_EX_LAYOUTRTL)
1212 pt.x = Wnd->rcWindow.right;
1213 else
1214 pt.x = Wnd->rcWindow.left;
1215 pt.y = Wnd->rcWindow.top;
1216
1217 IntScreenToClient(WndOldParent, &pt);
1218
1219 if (WndOldParent) UserReferenceObject(WndOldParent); /* Caller must deref */
1220
1221 if (WndNewParent != WndOldParent)
1222 {
1223 /* Unlink the window from the siblings list */
1224 IntUnlinkWindow(Wnd);
1225 Wnd->ExStyle2 &= ~WS_EX2_LINKED;
1226
1227 /* Set the new parent */
1228 WndSetParent(Wnd, WndNewParent);
1229
1230 if ( Wnd->style & WS_CHILD &&
1231 Wnd->spwndOwner &&
1232 Wnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1233 {
1234 ERR("SetParent Top Most from Pop up!\n");
1235 Wnd->ExStyle |= WS_EX_TOPMOST;
1236 }
1237
1238 /* Link the window with its new siblings */
1239 IntLinkHwnd( Wnd,
1240 ((0 == (Wnd->ExStyle & WS_EX_TOPMOST) &&
1241 UserIsDesktopWindow(WndNewParent) ) ? HWND_TOP : HWND_TOPMOST ) );
1242 }
1243
1244 if ( WndNewParent == co_GetDesktopWindow(Wnd) &&
1245 !(Wnd->style & WS_CLIPSIBLINGS) )
1246 {
1247 Wnd->style |= WS_CLIPSIBLINGS;
1248 DceResetActiveDCEs(Wnd);
1249 }
1250
1251 /* if parent belongs to a different thread and the window isn't */
1252 /* top-level, attach the two threads */
1253 if ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1254 {
1255 if ( Wnd->spwndParent != co_GetDesktopWindow(Wnd))
1256 {
1257 if (WndOldParent && (Wnd->head.pti != WndOldParent->head.pti))
1258 {
1259 //ERR("SetParent Old out.\n");
1260 UserAttachThreadInput(Wnd->head.pti, WndOldParent->head.pti, FALSE);
1261 }
1262 }
1263 if ( WndNewParent != co_GetDesktopWindow(Wnd))
1264 {
1265 if (Wnd->head.pti != WndNewParent->head.pti)
1266 {
1267 //ERR("SetParent New in.\n");
1268 UserAttachThreadInput(Wnd->head.pti, WndNewParent->head.pti, TRUE);
1269 }
1270 }
1271 }
1272
1273 if (UserIsMessageWindow(WndOldParent) || UserIsMessageWindow(WndNewParent))
1274 swFlags |= SWP_NOACTIVATE;
1275
1276 IntNotifyWinEvent(EVENT_OBJECT_PARENTCHANGE, Wnd ,OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1277 /*
1278 * SetParent additionally needs to make hwnd the top window
1279 * in the z-order and send the expected WM_WINDOWPOSCHANGING and
1280 * WM_WINDOWPOSCHANGED notification messages.
1281 */
1282 //ERR("IntSetParent SetWindowPos 1\n");
1284 (0 == (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
1285 pt.x, pt.y, 0, 0, swFlags);
1286 //ERR("IntSetParent SetWindowPos 2 X %d Y %d\n",pt.x, pt.y);
1287 if (WasVisible) co_WinPosShowWindow(Wnd, SW_SHOWNORMAL);
1288
1289 return WndOldParent;
1290}
1291
1292// Win: xxxSetParent
1295{
1296 PWND Wnd = NULL, WndParent = NULL, WndOldParent;
1297 HWND hWndOldParent = NULL;
1298 USER_REFERENCE_ENTRY Ref, ParentRef;
1299
1300 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
1301 {
1303 return( NULL);
1304 }
1305
1307 {
1308 ERR("UserSetParent Access Denied!\n");
1310 return( NULL);
1311 }
1312
1313 if (hWndNewParent)
1314 {
1315 if (!(WndParent = UserGetWindowObject(hWndNewParent)))
1316 {
1317 ERR("UserSetParent Bad New Parent!\n");
1318 return( NULL);
1319 }
1320 }
1321 else
1322 {
1323 if (!(WndParent = UserGetWindowObject(IntGetDesktopWindow())))
1324 {
1325 return( NULL);
1326 }
1327 }
1328
1329 if (!(Wnd = UserGetWindowObject(hWndChild)))
1330 {
1331 ERR("UserSetParent Bad Child!\n");
1332 return( NULL);
1333 }
1334
1335 UserRefObjectCo(Wnd, &Ref);
1336 UserRefObjectCo(WndParent, &ParentRef);
1337 //ERR("Enter co_IntSetParent\n");
1338 WndOldParent = co_IntSetParent(Wnd, WndParent);
1339 //ERR("Leave co_IntSetParent\n");
1340 UserDerefObjectCo(WndParent);
1341 UserDerefObjectCo(Wnd);
1342
1343 if (WndOldParent)
1344 {
1345 hWndOldParent = WndOldParent->head.h;
1346 UserDereferenceObject(WndOldParent);
1347 }
1348
1349 return( hWndOldParent);
1350}
1351
1352/* Unlink the window from siblings. Children and parent are kept in place. */
1355{
1356 ASSERT(Wnd != Wnd->spwndNext);
1357 ASSERT(Wnd != Wnd->spwndPrev);
1358
1359 if (Wnd->spwndNext)
1360 WndSetPrev(Wnd->spwndNext, Wnd->spwndPrev);
1361
1362 if (Wnd->spwndPrev)
1363 WndSetNext(Wnd->spwndPrev, Wnd->spwndNext);
1364
1365 if (Wnd->spwndParent && Wnd->spwndParent->spwndChild == Wnd)
1366 WndSetChild(Wnd->spwndParent, Wnd->spwndNext);
1367
1368 WndSetPrev(Wnd, NULL);
1369 WndSetNext(Wnd, NULL);
1370}
1371
1372// Win: ExpandWindowList
1374{
1375 PWINDOWLIST pwlOld, pwlNew;
1376 SIZE_T ibOld, ibNew;
1377
1378#define GROW_COUNT 8
1379 pwlOld = *ppwl;
1380 ibOld = (LPBYTE)pwlOld->phwndLast - (LPBYTE)pwlOld;
1381 ibNew = ibOld + GROW_COUNT * sizeof(HWND);
1382#undef GROW_COUNT
1383 pwlNew = IntReAllocatePoolWithTag(PagedPool, pwlOld, ibOld, ibNew, USERTAG_WINDOWLIST);
1384 if (!pwlNew)
1385 return FALSE;
1386
1387 pwlNew->phwndLast = (HWND *)((LPBYTE)pwlNew + ibOld);
1388 pwlNew->phwndEnd = (HWND *)((LPBYTE)pwlNew + ibNew);
1389 *ppwl = pwlNew;
1390 return TRUE;
1391}
1392
1393// Win: InternalBuildHwndList
1395{
1396 ASSERT(!WL_IS_BAD(pwl));
1397
1398 for (; pwnd; pwnd = pwnd->spwndNext)
1399 {
1400 if (!pwl->pti || pwl->pti == pwnd->head.pti)
1401 {
1402 *(pwl->phwndLast) = UserHMGetHandle(pwnd);
1403 ++(pwl->phwndLast);
1404
1405 if (pwl->phwndLast == pwl->phwndEnd && !IntGrowHwndList(&pwl))
1406 break;
1407 }
1408
1409 if ((dwFlags & IACE_CHILDREN) && pwnd->spwndChild)
1410 {
1412 if (WL_IS_BAD(pwl))
1413 break;
1414 }
1415
1416 if (!(dwFlags & IACE_LIST))
1417 break;
1418 }
1419
1420 return pwl;
1421}
1422
1423// Win: BuildHwndList
1425{
1426 PWINDOWLIST pwl;
1427 DWORD cbWL;
1428
1429 if (gpwlCache)
1430 {
1431 pwl = gpwlCache;
1432 gpwlCache = NULL;
1433 }
1434 else
1435 {
1436#define INITIAL_COUNT 32
1437 cbWL = sizeof(WINDOWLIST) + (INITIAL_COUNT - 1) * sizeof(HWND);
1439 if (!pwl)
1440 return NULL;
1441
1442 pwl->phwndEnd = &pwl->ahwnd[INITIAL_COUNT];
1443#undef INITIAL_COUNT
1444 }
1445
1446 pwl->pti = pti;
1447 pwl->phwndLast = pwl->ahwnd;
1448 pwl = IntPopulateHwndList(pwl, pwnd, dwFlags);
1449 if (WL_IS_BAD(pwl))
1450 {
1452 return NULL;
1453 }
1454
1455 *(pwl->phwndLast) = HWND_TERMINATOR;
1456
1457 if (dwFlags & 0x8)
1458 {
1459 // TODO:
1460 }
1461
1462 pwl->pti = GetW32ThreadInfo();
1463 pwl->pNextList = gpwlList;
1464 gpwlList = pwl;
1465
1466 return pwl;
1467}
1468
1469// Win: FreeHwndList
1471{
1472 PWINDOWLIST pwl, *ppwl;
1473
1474 for (ppwl = &gpwlList; *ppwl; ppwl = &(*ppwl)->pNextList)
1475 {
1476 if (*ppwl != pwlTarget)
1477 continue;
1478
1479 *ppwl = pwlTarget->pNextList;
1480
1481 if (gpwlCache)
1482 {
1483 if (WL_CAPACITY(pwlTarget) > WL_CAPACITY(gpwlCache))
1484 {
1485 pwl = gpwlCache;
1486 gpwlCache = pwlTarget;
1488 }
1489 else
1490 {
1492 }
1493 }
1494 else
1495 {
1496 gpwlCache = pwlTarget;
1497 }
1498
1499 break;
1500 }
1501}
1502
1503/* FUNCTIONS *****************************************************************/
1504
1505/*
1506 * As best as I can figure, this function is used by EnumWindows,
1507 * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
1508 *
1509 * It's supposed to build a list of HWNDs to return to the caller.
1510 * We can figure out what kind of list by what parameters are
1511 * passed to us.
1512 */
1513/*
1514 * @implemented
1515 */
1517NTAPI
1519 HDESK hDesktop,
1521 BOOLEAN bChildren,
1523 ULONG cHwnd,
1524 HWND* phwndList,
1525 ULONG* pcHwndNeeded)
1526{
1528 ULONG dwCount = 0;
1529
1530 if (pcHwndNeeded == NULL)
1532
1534
1535 if (hwndParent || !dwThreadId)
1536 {
1539
1540 if(!hwndParent)
1541 {
1542 if(hDesktop == NULL && !(Desktop = IntGetActiveDesktop()))
1543 {
1545 goto Quit;
1546 }
1547
1548 if(hDesktop)
1549 {
1551 UserMode,
1552 0,
1553 &Desktop);
1554 if(!NT_SUCCESS(Status))
1555 {
1557 goto Quit;
1558 }
1559 }
1560 hwndParent = Desktop->DesktopWindow;
1561 }
1562 else
1563 {
1564 hDesktop = 0;
1565 }
1566
1568 (Window = Parent->spwndChild))
1569 {
1570 BOOL bGoDown = TRUE;
1571
1573 while(TRUE)
1574 {
1575 if (bGoDown)
1576 {
1577 if (dwCount++ < cHwnd && phwndList)
1578 {
1579 _SEH2_TRY
1580 {
1581 ProbeForWrite(phwndList, sizeof(HWND), 1);
1582 *phwndList = Window->head.h;
1583 phwndList++;
1584 }
1586 {
1588 }
1589 _SEH2_END
1590 if(!NT_SUCCESS(Status))
1591 {
1592 break;
1593 }
1594 }
1595 if (Window->spwndChild && bChildren)
1596 {
1597 Window = Window->spwndChild;
1598 continue;
1599 }
1600 bGoDown = FALSE;
1601 }
1602 if (Window->spwndNext)
1603 {
1604 Window = Window->spwndNext;
1605 bGoDown = TRUE;
1606 continue;
1607 }
1608 Window = Window->spwndParent;
1609 if (Window == Parent)
1610 {
1611 break;
1612 }
1613 }
1614 }
1615
1616 if(hDesktop)
1617 {
1619 }
1620 }
1621 else // Build EnumThreadWindows list!
1622 {
1624 PTHREADINFO W32Thread;
1625 PWND Window;
1626 HWND *List = NULL;
1627
1629 if (!NT_SUCCESS(Status))
1630 {
1631 ERR("Thread Id is not valid!\n");
1633 goto Quit;
1634 }
1635 if (!(W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread))
1636 {
1638 TRACE("Tried to enumerate windows of a non gui thread\n");
1640 goto Quit;
1641 }
1642
1643 // Do not use Thread link list due to co_UserFreeWindow!!!
1644 // Current = W32Thread->WindowListHead.Flink;
1645 // Fixes Api:CreateWindowEx tests!!!
1647 if (List)
1648 {
1649 int i;
1650 for (i = 0; List[i]; i++)
1651 {
1653 if (Window && Window->head.pti == W32Thread)
1654 {
1655 if (dwCount < cHwnd && phwndList)
1656 {
1657 _SEH2_TRY
1658 {
1659 ProbeForWrite(phwndList, sizeof(HWND), 1);
1660 *phwndList = Window->head.h;
1661 phwndList++;
1662 }
1664 {
1666 }
1667 _SEH2_END
1668 if (!NT_SUCCESS(Status))
1669 {
1670 ERR("Failure to build window list!\n");
1671 break;
1672 }
1673 }
1674 dwCount++;
1675 }
1676 }
1678 }
1679
1681 }
1682
1683 *pcHwndNeeded = dwCount;
1685
1686Quit:
1688 UserLeave();
1689 return Status;
1690}
1691
1692static void IntSendParentNotify( PWND pWindow, UINT msg )
1693{
1694 if ( (pWindow->style & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
1695 !(pWindow->ExStyle & WS_EX_NOPARENTNOTIFY))
1696 {
1697 if (VerifyWnd(pWindow->spwndParent) && !UserIsDesktopWindow(pWindow->spwndParent))
1698 {
1700 UserRefObjectCo(pWindow->spwndParent, &Ref);
1701 co_IntSendMessage( pWindow->spwndParent->head.h,
1703 MAKEWPARAM( msg, pWindow->IDMenu),
1704 (LPARAM)pWindow->head.h );
1706 }
1707 }
1708}
1709
1710void FASTCALL
1711IntFixWindowCoordinates(CREATESTRUCTW* Cs, PWND ParentWindow, DWORD* dwShowMode)
1712{
1713#define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1714
1715 /* default positioning for overlapped windows */
1716 if(!(Cs->style & (WS_POPUP | WS_CHILD)))
1717 {
1718 PMONITOR pMonitor;
1719 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
1720
1721 pMonitor = UserGetPrimaryMonitor();
1722
1723 /* Check if we don't have a monitor attached yet */
1724 if(pMonitor == NULL)
1725 {
1726 Cs->x = Cs->y = 0;
1727 Cs->cx = 800;
1728 Cs->cy = 600;
1729 return;
1730 }
1731
1732 ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
1733
1734 if (IS_DEFAULT(Cs->x))
1735 {
1736 if (!IS_DEFAULT(Cs->y)) *dwShowMode = Cs->y;
1737
1738 if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
1739 {
1740 Cs->x = ProcessParams->StartingX;
1741 Cs->y = ProcessParams->StartingY;
1742 }
1743 else
1744 {
1747 if (Cs->x > ((pMonitor->rcWork.right - pMonitor->rcWork.left) / 4) ||
1748 Cs->y > ((pMonitor->rcWork.bottom - pMonitor->rcWork.top) / 4))
1749 {
1750 /* reset counter and position */
1751 Cs->x = 0;
1752 Cs->y = 0;
1753 pMonitor->cWndStack = 0;
1754 }
1755 pMonitor->cWndStack++;
1756 }
1757 }
1758
1759 if (IS_DEFAULT(Cs->cx))
1760 {
1761 if (ProcessParams->WindowFlags & STARTF_USEPOSITION)
1762 {
1763 Cs->cx = ProcessParams->CountX;
1764 Cs->cy = ProcessParams->CountY;
1765 }
1766 else
1767 {
1768 Cs->cx = (pMonitor->rcWork.right - pMonitor->rcWork.left) * 3 / 4;
1769 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1770 }
1771 }
1772 /* neither x nor cx are default. Check the y values .
1773 * In the trace we see Outlook and Outlook Express using
1774 * cy set to CW_USEDEFAULT when opening the address book.
1775 */
1776 else if (IS_DEFAULT(Cs->cy))
1777 {
1778 TRACE("Strange use of CW_USEDEFAULT in nHeight\n");
1779 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1780 }
1781 }
1782 else
1783 {
1784 /* if CW_USEDEFAULT is set for non-overlapped windows, both values are set to zero */
1785 if(IS_DEFAULT(Cs->x))
1786 {
1787 Cs->x = 0;
1788 Cs->y = 0;
1789 }
1790 if(IS_DEFAULT(Cs->cx))
1791 {
1792 Cs->cx = 0;
1793 Cs->cy = 0;
1794 }
1795 }
1796
1797#undef IS_DEFAULT
1798}
1799
1800/* Allocates and initializes a window */
1802 PLARGE_STRING WindowName,
1803 PCLS Class,
1804 PWND ParentWindow,
1805 PWND OwnerWindow,
1806 PVOID acbiBuffer,
1807 PDESKTOP pdeskCreated,
1808 DWORD dwVer )
1809{
1810 PWND pWnd = NULL;
1811 HWND hWnd;
1812 PTHREADINFO pti;
1813 BOOL MenuChanged;
1814 BOOL bUnicodeWindow;
1815 PCALLPROCDATA pcpd;
1816
1817 pti = pdeskCreated ? gptiDesktopThread : GetW32ThreadInfo();
1818
1819 if (!(Cs->dwExStyle & WS_EX_LAYOUTRTL))
1820 { // Need both here for wine win.c test_CreateWindow.
1821 //if (Cs->hwndParent && ParentWindow)
1822 if (ParentWindow) // It breaks more tests..... WIP.
1823 {
1824 if ( (Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD &&
1825 ParentWindow->ExStyle & WS_EX_LAYOUTRTL &&
1826 !(ParentWindow->ExStyle & WS_EX_NOINHERITLAYOUT) )
1828 }
1829 else
1830 { /*
1831 * Note from MSDN <http://msdn.microsoft.com/en-us/library/aa913269.aspx>:
1832 *
1833 * Dialog boxes and message boxes do not inherit layout, so you must
1834 * set the layout explicitly.
1835 */
1836 if ( Class->fnid != FNID_DIALOG )
1837 {
1838 if (pti->ppi->dwLayout & LAYOUT_RTL)
1839 {
1841 }
1842 }
1843 }
1844 }
1845
1846 /* Automatically add WS_EX_WINDOWEDGE */
1847 if ((Cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1848 ((!(Cs->dwExStyle & WS_EX_STATICEDGE)) &&
1849 (Cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1851 else
1852 Cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1853
1854 /* Is it a unicode window? */
1855 bUnicodeWindow =!(Cs->dwExStyle & WS_EX_SETANSICREATOR);
1856 Cs->dwExStyle &= ~WS_EX_SETANSICREATOR;
1857
1858 /* Allocate the new window */
1860 pdeskCreated ? pdeskCreated : pti->rpdesk,
1861 pti,
1862 (PHANDLE)&hWnd,
1864 sizeof(WND) + Class->cbwndExtra);
1865
1866 if (!pWnd)
1867 {
1868 goto AllocError;
1869 }
1870
1871 TRACE("Created window object with handle %p\n", hWnd);
1872
1873 if (pdeskCreated && pdeskCreated->DesktopWindow == NULL )
1874 { /* HACK: Helper for win32csr/desktopbg.c */
1875 /* If there is no desktop window yet, we must be creating it */
1876 TRACE("CreateWindow setting desktop.\n");
1877 pdeskCreated->DesktopWindow = hWnd;
1878 pdeskCreated->pDeskInfo->spwnd = pWnd;
1879 }
1880
1881 /*
1882 * Fill out the structure describing it.
1883 */
1884 /* Remember, pWnd->head is setup in object.c ... */
1885 WndSetParent(pWnd, ParentWindow);
1886 WndSetOwner(pWnd, OwnerWindow);
1887 pWnd->fnid = 0;
1888 WndSetLastActive(pWnd, pWnd);
1889 // Ramp up compatible version sets.
1890 if ( dwVer >= WINVER_WIN31 )
1891 {
1892 pWnd->state2 |= WNDS2_WIN31COMPAT;
1893 if ( dwVer >= WINVER_WINNT4 )
1894 {
1895 pWnd->state2 |= WNDS2_WIN40COMPAT;
1896 if ( dwVer >= WINVER_WIN2K )
1897 {
1898 pWnd->state2 |= WNDS2_WIN50COMPAT;
1899 }
1900 }
1901 }
1902 pWnd->pcls = Class;
1903 pWnd->hModule = Cs->hInstance;
1904 pWnd->style = Cs->style & ~WS_VISIBLE;
1905 pWnd->ExStyle = Cs->dwExStyle;
1906 pWnd->cbwndExtra = pWnd->pcls->cbwndExtra;
1907 pWnd->pActCtx = acbiBuffer;
1908
1909 if (pti->spDefaultImc && Class->atomClassName != gpsi->atomSysClass[ICLS_BUTTON])
1910 pWnd->hImc = UserHMGetHandle(pti->spDefaultImc);
1911
1912 pWnd->InternalPos.MaxPos.x = pWnd->InternalPos.MaxPos.y = -1;
1913 pWnd->InternalPos.IconPos.x = pWnd->InternalPos.IconPos.y = -1;
1914
1915 if (pWnd->spwndParent != NULL && Cs->hwndParent != 0)
1916 {
1917 pWnd->HideFocus = pWnd->spwndParent->HideFocus;
1918 pWnd->HideAccel = pWnd->spwndParent->HideAccel;
1919 }
1920
1922 pWnd->head.pti->cWindows++;
1923
1924 if (Class->spicn && !Class->spicnSm)
1925 {
1926 HICON IconSmHandle = NULL;
1927 if((Class->spicn->CURSORF_flags & (CURSORF_LRSHARED | CURSORF_FROMRESOURCE))
1929 {
1930 IconSmHandle = co_IntCopyImage(
1931 UserHMGetHandle(Class->spicn),
1932 IMAGE_ICON,
1936 }
1937 if (!IconSmHandle)
1938 {
1939 /* Retry without copying from resource */
1940 IconSmHandle = co_IntCopyImage(
1941 UserHMGetHandle(Class->spicn),
1942 IMAGE_ICON,
1945 0);
1946 }
1947
1948 if (IconSmHandle)
1949 {
1950 Class->spicnSm = UserGetCurIconObject(IconSmHandle);
1951 Class->CSF_flags |= CSF_CACHEDSMICON;
1952 }
1953 }
1954
1955 if (pWnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
1957
1958 /* BugBoy Comments: Comment below say that System classes are always created
1959 as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
1960 sets the window to ansi as verified by testing with IsUnicodeWindow API.
1961
1962 No where can I see in code or through testing does the window change back
1963 to ANSI after being created as UNICODE in ROS. I didnt do more testing to
1964 see what problems this would cause. */
1965
1966 // Set WndProc from Class.
1967 if (IsCallProcHandle(pWnd->pcls->lpfnWndProc))
1968 {
1970 if (pcpd)
1971 pWnd->lpfnWndProc = pcpd->pfnClientPrevious;
1972 }
1973 else
1974 {
1975 pWnd->lpfnWndProc = pWnd->pcls->lpfnWndProc;
1976 }
1977
1978 // GetWindowProc, test for non server side default classes and set WndProc.
1979 if ( pWnd->pcls->fnid <= FNID_GHOST && pWnd->pcls->fnid >= FNID_BUTTON )
1980 {
1981 if (bUnicodeWindow)
1982 {
1983 if (GETPFNCLIENTA(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1984 pWnd->lpfnWndProc = GETPFNCLIENTW(pWnd->pcls->fnid);
1985 }
1986 else
1987 {
1988 if (GETPFNCLIENTW(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1989 pWnd->lpfnWndProc = GETPFNCLIENTA(pWnd->pcls->fnid);
1990 }
1991 }
1992
1993 // If not an Unicode caller, set Ansi creator bit.
1994 if (!bUnicodeWindow) pWnd->state |= WNDS_ANSICREATOR;
1995
1996 // Clone Class Ansi/Unicode proc type.
1997 if (pWnd->pcls->CSF_flags & CSF_ANSIPROC)
1998 {
1999 pWnd->state |= WNDS_ANSIWINDOWPROC;
2000 pWnd->Unicode = FALSE;
2001 }
2002 else
2003 { /*
2004 * It seems there can be both an Ansi creator and Unicode Class Window
2005 * WndProc, unless the following overriding conditions occur:
2006 */
2007 if ( !bUnicodeWindow &&
2008 ( Class->atomClassName == gpsi->atomSysClass[ICLS_BUTTON] ||
2009 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX] ||
2010 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOLBOX] ||
2011 Class->atomClassName == gpsi->atomSysClass[ICLS_DIALOG] ||
2012 Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT] ||
2013 Class->atomClassName == gpsi->atomSysClass[ICLS_IME] ||
2014 Class->atomClassName == gpsi->atomSysClass[ICLS_LISTBOX] ||
2015 Class->atomClassName == gpsi->atomSysClass[ICLS_MDICLIENT] ||
2016 Class->atomClassName == gpsi->atomSysClass[ICLS_STATIC] ) )
2017 { // Override Class and set the window Ansi WndProc.
2018 pWnd->state |= WNDS_ANSIWINDOWPROC;
2019 pWnd->Unicode = FALSE;
2020 }
2021 else
2022 { // Set the window Unicode WndProc.
2023 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
2024 pWnd->Unicode = TRUE;
2025 }
2026 }
2027
2028 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
2029 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
2030 Dont understand why it does this. */
2031 if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT])
2032 {
2033 PCALLPROCDATA CallProc;
2034 CallProc = CreateCallProc(pWnd->head.rpdesk, pWnd->lpfnWndProc, pWnd->Unicode , pWnd->head.pti->ppi);
2035
2036 if (!CallProc)
2037 {
2039 ERR("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %p\n", hWnd);
2040 }
2041 else
2042 {
2043 UserAddCallProcToClass(pWnd->pcls, CallProc);
2044 }
2045 }
2046
2048 pWnd->PropListItems = 0;
2049
2050 if ( WindowName->Buffer != NULL && WindowName->Length > 0 )
2051 {
2053 WindowName->Length + sizeof(UNICODE_NULL));
2054 if (pWnd->strName.Buffer == NULL)
2055 {
2056 goto AllocError;
2057 }
2058
2059 RtlCopyMemory(pWnd->strName.Buffer, WindowName->Buffer, WindowName->Length);
2060 pWnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
2061 pWnd->strName.Length = WindowName->Length;
2062 pWnd->strName.MaximumLength = WindowName->Length + sizeof(UNICODE_NULL);
2063 }
2064
2065 /* Correct the window style. */
2066 if ((pWnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
2067 {
2068 pWnd->style |= WS_CLIPSIBLINGS;
2069 if (!(pWnd->style & WS_POPUP))
2070 {
2071 pWnd->style |= WS_CAPTION;
2072 }
2073 }
2074
2075 /* WS_EX_WINDOWEDGE depends on some other styles */
2076 if (pWnd->ExStyle & WS_EX_DLGMODALFRAME)
2077 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
2078 else if (pWnd->style & (WS_DLGFRAME | WS_THICKFRAME))
2079 {
2080 if (!((pWnd->ExStyle & WS_EX_STATICEDGE) &&
2081 (pWnd->style & (WS_CHILD | WS_POPUP))))
2082 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
2083 }
2084 else
2085 pWnd->ExStyle &= ~WS_EX_WINDOWEDGE;
2086
2087 if (!(pWnd->style & (WS_CHILD | WS_POPUP)))
2089
2090 /* Set the window menu */
2091 if ((Cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
2092 {
2093 if (Cs->hMenu)
2094 {
2095 IntSetMenu(pWnd, Cs->hMenu, &MenuChanged);
2096 }
2097 else if (pWnd->pcls->lpszMenuName) // Take it from the parent.
2098 {
2099 UNICODE_STRING MenuName;
2100 HMENU hMenu;
2101
2102 if (IS_INTRESOURCE(pWnd->pcls->lpszMenuName))
2103 {
2104 MenuName.Length = 0;
2105 MenuName.MaximumLength = 0;
2106 MenuName.Buffer = pWnd->pcls->lpszMenuName;
2107 }
2108 else
2109 {
2110 RtlInitUnicodeString( &MenuName, pWnd->pcls->lpszMenuName);
2111 }
2112 hMenu = co_IntCallLoadMenu( pWnd->pcls->hModule, &MenuName);
2113 if (hMenu) IntSetMenu(pWnd, hMenu, &MenuChanged);
2114 }
2115 }
2116 else // Not a child
2117 pWnd->IDMenu = (UINT_PTR)Cs->hMenu;
2118
2119
2120 if ( ParentWindow &&
2121 ParentWindow != ParentWindow->head.rpdesk->spwndMessage &&
2122 ParentWindow != ParentWindow->head.rpdesk->pDeskInfo->spwnd )
2123 {
2124 PWND Owner = IntGetNonChildAncestor(ParentWindow);
2125
2126 if (!IntValidateOwnerDepth(pWnd, Owner))
2127 {
2129 goto Error;
2130 }
2131 if ( pWnd->spwndOwner &&
2132 pWnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
2133 {
2134 pWnd->ExStyle |= WS_EX_TOPMOST;
2135 }
2136 if ( pWnd->spwndOwner &&
2137 Class->atomClassName != gpsi->atomSysClass[ICLS_IME] &&
2138 pti != pWnd->spwndOwner->head.pti)
2139 {
2140 //ERR("CreateWindow Owner in.\n");
2141 UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE);
2142 }
2143 }
2144
2145 /* Insert the window into the thread's window list. */
2147
2148 /* Handle "CS_CLASSDC", it is tested first. */
2149 if ( (pWnd->pcls->style & CS_CLASSDC) && !(pWnd->pcls->pdce) )
2150 { /* One DCE per class to have CLASS. */
2151 pWnd->pcls->pdce = DceAllocDCE( pWnd, DCE_CLASS_DC );
2152 }
2153 else if ( pWnd->pcls->style & CS_OWNDC)
2154 { /* Allocate a DCE for this window. */
2156 }
2157
2158 return pWnd;
2159
2160AllocError:
2161 ERR("IntCreateWindow Allocation Error.\n");
2163Error:
2164 if(pWnd)
2166 return NULL;
2167}
2168
2169/*
2170 * @implemented
2171 */
2174 PUNICODE_STRING ClassName,
2175 PLARGE_STRING WindowName,
2176 PVOID acbiBuffer,
2177 DWORD dwVer )
2178{
2179 ULONG style;
2180 PWND Window = NULL, ParentWindow = NULL, OwnerWindow;
2181 HWND hWnd, hWndParent, hWndOwner, hwndInsertAfter;
2182 PWINSTATION_OBJECT WinSta;
2183 PCLS Class = NULL;
2184 SIZE Size;
2185 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
2186 CBT_CREATEWNDW * pCbtCreate;
2188 USER_REFERENCE_ENTRY ParentRef, Ref;
2189 PTHREADINFO pti;
2190 DWORD dwShowMode = SW_SHOW;
2191 CREATESTRUCTW *pCsw = NULL;
2192 PVOID pszClass = NULL, pszName = NULL;
2193 PWND ret = NULL;
2194
2195 /* Get the current window station and reference it */
2196 pti = GetW32ThreadInfo();
2197 if (pti == NULL || pti->rpdesk == NULL)
2198 {
2199 ERR("Thread is not attached to a desktop! Cannot create window (%wZ)\n", ClassName);
2200 return NULL; // There is nothing to cleanup.
2201 }
2202 WinSta = pti->rpdesk->rpwinstaParent;
2204
2205 pCsw = NULL;
2206 pCbtCreate = NULL;
2207
2208 /* Get the class and reference it */
2209 Class = IntGetAndReferenceClass(ClassName, Cs->hInstance, FALSE);
2210 if(!Class)
2211 {
2213 ERR("Failed to find class %wZ\n", ClassName);
2214 goto cleanup;
2215 }
2216
2217 /* Now find the parent and the owner window */
2218 hWndParent = pti->rpdesk->pDeskInfo->spwnd->head.h;
2219 hWndOwner = NULL;
2220
2221 if (Cs->hwndParent == HWND_MESSAGE)
2222 {
2223 Cs->hwndParent = hWndParent = pti->rpdesk->spwndMessage->head.h;
2224 }
2225 else if (Cs->hwndParent)
2226 {
2227 if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
2228 hWndOwner = Cs->hwndParent;
2229 else
2230 hWndParent = Cs->hwndParent;
2231 }
2232 else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2233 {
2234 ERR("Cannot create a child window (%wZ) without a parent\n", ClassName);
2236 goto cleanup; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
2237 }
2239 (IS_INTRESOURCE(Cs->lpszClass) ||
2240 Cs->lpszClass != (LPCWSTR)MAKEINTATOM(gpsi->atomSysClass[ICLS_HWNDMESSAGE]) ||
2241 _wcsicmp(Cs->lpszClass, L"Message") != 0))
2242 {
2243 if (pti->ppi->dwLayout & LAYOUT_RTL)
2244 {
2246 }
2247 }
2248
2249 ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
2250 OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
2251
2252 if (hWndParent && !ParentWindow)
2253 {
2254 ERR("Got invalid parent window handle for %wZ\n", ClassName);
2255 goto cleanup;
2256 }
2257 else if (hWndOwner && !OwnerWindow)
2258 {
2259 ERR("Got invalid owner window handle for %wZ\n", ClassName);
2260 ParentWindow = NULL;
2261 goto cleanup;
2262 }
2263
2264 if(OwnerWindow)
2265 {
2266 if (IntIsDesktopWindow(OwnerWindow)) OwnerWindow = NULL;
2267 else if (ParentWindow && !IntIsDesktopWindow(ParentWindow))
2268 {
2269 ERR("an owned window must be created as top-level\n");
2271 goto cleanup;
2272 }
2273 else /* owner must be a top-level window */
2274 {
2275 while ((OwnerWindow->style & (WS_POPUP|WS_CHILD)) == WS_CHILD && !IntIsDesktopWindow(OwnerWindow->spwndParent))
2276 OwnerWindow = OwnerWindow->spwndParent;
2277 }
2278 }
2279
2280 /* Fix the position and the size of the window */
2281 if (ParentWindow)
2282 {
2283 UserRefObjectCo(ParentWindow, &ParentRef);
2284 IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode);
2285 }
2286
2287 /* Allocate and initialize the new window */
2289 WindowName,
2290 Class,
2291 ParentWindow,
2292 OwnerWindow,
2293 acbiBuffer,
2294 NULL,
2295 dwVer );
2296 if(!Window)
2297 {
2298 ERR("IntCreateWindow(%wZ) failed\n", ClassName);
2299 goto cleanup;
2300 }
2301
2303 hwndInsertAfter = HWND_TOP;
2304
2305 UserRefObjectCo(Window, &Ref);
2307 ObDereferenceObject(WinSta);
2308
2309 /* NCCREATE, WM_NCCALCSIZE and Hooks need the original values */
2310 Cs->lpszName = (LPCWSTR) WindowName;
2311 Cs->lpszClass = (LPCWSTR) ClassName;
2312
2314 if ( ISITHOOKED(WH_CBT) || (pti->rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)) )
2315 {
2316 // Allocate the calling structures Justin Case this goes Global.
2319 if (!pCsw || !pCbtCreate)
2320 {
2321 ERR("UserHeapAlloc() failed!\n");
2322 goto cleanup;
2323 }
2324
2325 if (!IntMsgCreateStructW( Window, pCsw, Cs, &pszClass, &pszName ) )
2326 {
2327 ERR("IntMsgCreateStructW() failed!\n");
2328 goto cleanup;
2329 }
2330
2331 pCbtCreate->lpcs = pCsw;
2332 pCbtCreate->hwndInsertAfter = hwndInsertAfter;
2333
2336 if (Result != 0)
2337 {
2338 ERR("WH_CBT HCBT_CREATEWND hook failed! 0x%x\n", Result);
2339 goto cleanup;
2340 }
2341 // Write back changes.
2342 Cs->cx = pCsw->cx;
2343 Cs->cy = pCsw->cy;
2344 Cs->x = pCsw->x;
2345 Cs->y = pCsw->y;
2346 hwndInsertAfter = pCbtCreate->hwndInsertAfter;
2347 }
2348
2349 if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2350 {
2351 if (ParentWindow != co_GetDesktopWindow(Window))
2352 {
2353 Cs->x += ParentWindow->rcClient.left;
2354 Cs->y += ParentWindow->rcClient.top;
2355 }
2356 }
2357
2358 /* Send the WM_GETMINMAXINFO message */
2359 Size.cx = Cs->cx;
2360 Size.cy = Cs->cy;
2361
2362 if ((Cs->style & WS_THICKFRAME) || !(Cs->style & (WS_POPUP | WS_CHILD)))
2363 {
2364 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
2365 if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
2366 if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
2367 if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
2368 if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
2369 }
2370
2371 Window->rcWindow.left = Cs->x;
2372 Window->rcWindow.top = Cs->y;
2373 Window->rcWindow.right = Cs->x + Size.cx;
2374 Window->rcWindow.bottom = Cs->y + Size.cy;
2375 /*
2376 if (0 != (Window->style & WS_CHILD) && ParentWindow)
2377 {
2378 ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
2379 RECTL_vOffsetRect(&Window->rcWindow,
2380 ParentWindow->rcClient.left,
2381 ParentWindow->rcClient.top);
2382 }
2383 */
2384 /* correct child window coordinates if mirroring on parent is enabled */
2385 if (ParentWindow != NULL)
2386 {
2387 if ( ((Cs->style & WS_CHILD) == WS_CHILD) &&
2388 ((ParentWindow->ExStyle & WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL))
2389 {
2390 Window->rcWindow.right = ParentWindow->rcClient.right - (Window->rcWindow.left - ParentWindow->rcClient.left);
2391 Window->rcWindow.left = Window->rcWindow.right - Size.cx;
2392 }
2393 }
2394
2395 Window->rcClient = Window->rcWindow;
2396
2397 if (Window->spwndNext || Window->spwndPrev)
2398 {
2399 ERR("Window 0x%p has been linked too early!\n", Window);
2400 }
2401
2402 if (!(Window->state2 & WNDS2_WIN31COMPAT))
2403 {
2404 if (Class->style & CS_PARENTDC && !(ParentWindow->style & WS_CLIPCHILDREN))
2405 Window->style &= ~(WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
2406 }
2407
2408 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2409 {
2411 {
2412 if (pti != ParentWindow->head.pti)
2413 {
2414 //ERR("CreateWindow Parent in.\n");
2415 UserAttachThreadInput(pti, ParentWindow->head.pti, TRUE);
2416 }
2417 }
2418 }
2419
2420 /* Send the NCCREATE message */
2422 if (!Result)
2423 {
2424 ERR("co_UserCreateWindowEx(%wZ): NCCREATE message failed\n", ClassName);
2425 goto cleanup;
2426 }
2427
2428 /* Link the window */
2429 if (ParentWindow != NULL)
2430 {
2431 /* Link the window into the siblings list */
2432 if ((Cs->style & (WS_CHILD | WS_MAXIMIZE)) == WS_CHILD)
2434 else
2435 IntLinkHwnd(Window, hwndInsertAfter);
2436 }
2437
2438 /* Create the IME window for pWnd */
2440 {
2441 PWND pwndDefaultIme = co_IntCreateDefaultImeWindow(Window, Window->hModule);
2442 UserAssignmentLock((PVOID*)&pti->spwndDefaultIme, pwndDefaultIme);
2443
2444 if (pwndDefaultIme)
2445 {
2446 HWND hImeWnd;
2448 UserRefObjectCo(pwndDefaultIme, &Ref);
2449
2450 hImeWnd = UserHMGetHandle(pwndDefaultIme);
2451
2453
2454 if (pti->pClientInfo->CI_flags & CI_IMMACTIVATE)
2455 {
2456 HKL hKL = pti->KeyboardLayout->hkl;
2458 pti->pClientInfo->CI_flags &= ~CI_IMMACTIVATE;
2459 }
2460
2461 UserDerefObjectCo(pwndDefaultIme);
2462 }
2463 }
2464
2465 /* Send the WM_NCCALCSIZE message */
2466 {
2467 // RECT rc;
2468 MaxPos.x = Window->rcWindow.left;
2469 MaxPos.y = Window->rcWindow.top;
2470
2471 Result = co_WinPosGetNonClientSize(Window, &Window->rcWindow, &Window->rcClient);
2472 //rc = Window->rcWindow;
2473 //Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM)&rc);
2474 //Window->rcClient = rc;
2475
2476 RECTL_vOffsetRect(&Window->rcWindow, MaxPos.x - Window->rcWindow.left,
2477 MaxPos.y - Window->rcWindow.top);
2478 }
2479
2480 /* Send the WM_CREATE message. */
2482 if (Result == (LRESULT)-1)
2483 {
2484 ERR("co_UserCreateWindowEx(%wZ): WM_CREATE message failed\n", ClassName);
2485 goto cleanup;
2486 }
2487
2488 /* Send the EVENT_OBJECT_CREATE event */
2489 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2490
2491 /* By setting the flag below it can be examined to determine if the window
2492 was created successfully and a valid pwnd was passed back to caller since
2493 from here the function has to succeed. */
2495
2496 /* Send the WM_SIZE and WM_MOVE messages. */
2497 if (!(Window->state & WNDS_SENDSIZEMOVEMSGS))
2498 {
2500 }
2501
2502 /* Show or maybe minimize or maximize the window. */
2503
2505 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2506 {
2507 RECTL NewPos;
2508 UINT SwFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
2509
2510 SwFlag = co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2511 SwFlag |= SWP_NOZORDER|SWP_FRAMECHANGED; /* Frame always gets changed */
2512 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || UserGetActiveWindow() ||
2513 (Window->ExStyle & WS_EX_NOACTIVATE))
2514 {
2515 SwFlag |= SWP_NOACTIVATE;
2516 }
2517 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2518 NewPos.right, NewPos.bottom, SwFlag);
2519 }
2520
2521 /* Send the WM_PARENTNOTIFY message */
2523
2524 /* Notify the shell that a new window was created */
2525 if (Window->spwndOwner == NULL ||
2526 !(Window->spwndOwner->style & WS_VISIBLE) ||
2527 (Window->spwndOwner->ExStyle & WS_EX_TOOLWINDOW))
2528 {
2529 if (UserIsDesktopWindow(Window->spwndParent) &&
2530 (Window->style & WS_VISIBLE) &&
2531 (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
2532 (Window->ExStyle & WS_EX_APPWINDOW)))
2533 {
2535 }
2536 }
2537
2538 /* Initialize and show the window's scrollbars */
2539 if (Window->style & WS_VSCROLL)
2540 {
2542 }
2543 if (Window->style & WS_HSCROLL)
2544 {
2546 }
2547
2548 /* Show the new window */
2549 if (Cs->style & WS_VISIBLE)
2550 {
2551 if (Window->style & WS_MAXIMIZE)
2552 dwShowMode = SW_SHOW;
2553 else if (Window->style & WS_MINIMIZE)
2554 dwShowMode = SW_SHOWMINIMIZED;
2555
2556 co_WinPosShowWindow(Window, dwShowMode);
2557
2558 if (Window->ExStyle & WS_EX_MDICHILD)
2559 {
2560 ASSERT(ParentWindow);
2561 if(!ParentWindow)
2562 goto cleanup;
2564 /* ShowWindow won't activate child windows */
2566 }
2567 }
2568
2569 if (Class->atomClassName == gaGuiConsoleWndClass)
2570 {
2571 /* Count only console windows manually */
2573 }
2574
2575 TRACE("co_UserCreateWindowEx(%wZ): Created window %p\n", ClassName, hWnd);
2576 ret = Window;
2577
2578cleanup:
2579 if (!ret)
2580 {
2581 TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2582 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2583 if (Window)
2585 else if (Class)
2587 }
2588
2589 if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
2590 if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
2591 if (pszName) UserHeapFree(pszName);
2592 if (pszClass) UserHeapFree(pszClass);
2593
2594 if (Window)
2595 {
2597 }
2598 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2599
2600 // See CORE-13717, not setting error on success.
2601 if (ret)
2603
2604 return ret;
2605}
2606
2608NTAPI
2610 OUT PLARGE_STRING plstrSafe,
2611 IN PLARGE_STRING plstrUnsafe)
2612{
2613 LARGE_STRING lstrTemp;
2614 PVOID pvBuffer = NULL;
2615
2616 _SEH2_TRY
2617 {
2618 /* Probe and copy the string */
2619 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2620 lstrTemp = *plstrUnsafe;
2621 }
2623 {
2624 /* Fail */
2626 }
2627 _SEH2_END
2628
2629 if (lstrTemp.Length != 0)
2630 {
2631 /* Allocate a buffer from paged pool */
2632 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2633 if (!pvBuffer)
2634 {
2635 return STATUS_NO_MEMORY;
2636 }
2637
2638 _SEH2_TRY
2639 {
2640 /* Probe and copy the buffer */
2641 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2642 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2643 }
2645 {
2646 /* Cleanup and fail */
2647 ExFreePoolWithTag(pvBuffer, TAG_STRING);
2649 }
2650 _SEH2_END
2651 }
2652
2653 /* Set the output string */
2654 plstrSafe->Buffer = pvBuffer;
2655 plstrSafe->Length = lstrTemp.Length;
2656 plstrSafe->MaximumLength = lstrTemp.Length;
2657
2658 return STATUS_SUCCESS;
2659}
2660
2664HWND
2665NTAPI
2667 DWORD dwExStyle,
2668 PLARGE_STRING plstrClassName,
2669 PLARGE_STRING plstrClsVersion,
2670 PLARGE_STRING plstrWindowName,
2671 DWORD dwStyle,
2672 int x,
2673 int y,
2674 int nWidth,
2675 int nHeight,
2677 HMENU hMenu,
2679 LPVOID lpParam,
2680 DWORD dwFlags,
2681 PVOID acbiBuffer)
2682{
2684 LARGE_STRING lstrWindowName;
2685 LARGE_STRING lstrClassName;
2686 LARGE_STRING lstrClsVersion;
2687 UNICODE_STRING ustrClassName;
2688 UNICODE_STRING ustrClsVersion;
2689 CREATESTRUCTW Cs;
2690 HWND hwnd = NULL;
2691 PWND pwnd;
2692
2693 lstrWindowName.Buffer = NULL;
2694 lstrClassName.Buffer = NULL;
2695 lstrClsVersion.Buffer = NULL;
2696
2697 if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2698 {
2699 /* check hMenu is valid handle */
2700 if (hMenu && !UserGetMenuObject(hMenu))
2701 {
2702 ERR("NtUserCreateWindowEx: Got an invalid menu handle!\n");
2704 return NULL;
2705 }
2706 }
2707
2708 /* Copy the window name to kernel mode */
2709 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2710 if (!NT_SUCCESS(Status))
2711 {
2712 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2714 return NULL;
2715 }
2716
2717 plstrWindowName = &lstrWindowName;
2718
2719 /* Check if the class is an atom */
2720 if (IS_ATOM(plstrClassName))
2721 {
2722 /* It is, pass the atom in the UNICODE_STRING */
2723 ustrClassName.Buffer = (PVOID)plstrClassName;
2724 ustrClassName.Length = 0;
2725 ustrClassName.MaximumLength = 0;
2726 }
2727 else
2728 {
2729 /* It's not, capture the class name */
2730 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2731 if (!NT_SUCCESS(Status))
2732 {
2733 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2734 /* Set last error, cleanup and return */
2736 goto cleanup;
2737 }
2738
2739 /* We pass it on as a UNICODE_STRING */
2740 ustrClassName.Buffer = lstrClassName.Buffer;
2741 ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2742 ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
2743 }
2744
2745 /* Check if the class version is an atom */
2746 if (IS_ATOM(plstrClsVersion))
2747 {
2748 /* It is, pass the atom in the UNICODE_STRING */
2749 ustrClsVersion.Buffer = (PVOID)plstrClsVersion;
2750 ustrClsVersion.Length = 0;
2751 ustrClsVersion.MaximumLength = 0;
2752 }
2753 else
2754 {
2755 /* It's not, capture the class name */
2756 Status = ProbeAndCaptureLargeString(&lstrClsVersion, plstrClsVersion);
2757 if (!NT_SUCCESS(Status))
2758 {
2759 ERR("NtUserCreateWindowEx: failed to capture plstrClsVersion\n");
2760 /* Set last error, cleanup and return */
2762 goto cleanup;
2763 }
2764
2765 /* We pass it on as a UNICODE_STRING */
2766 ustrClsVersion.Buffer = lstrClsVersion.Buffer;
2767 ustrClsVersion.Length = (USHORT)min(lstrClsVersion.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2768 ustrClsVersion.MaximumLength = (USHORT)min(lstrClsVersion.MaximumLength, MAXUSHORT);
2769 }
2770
2771 /* Fill the CREATESTRUCTW */
2772 /* we will keep here the original parameters */
2773 Cs.style = dwStyle;
2774 Cs.lpCreateParams = lpParam;
2775 Cs.hInstance = hInstance;
2776 Cs.hMenu = hMenu;
2778 Cs.cx = nWidth;
2779 Cs.cy = nHeight;
2780 Cs.x = x;
2781 Cs.y = y;
2782 Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
2783 Cs.lpszClass = ustrClassName.Buffer;
2784 Cs.dwExStyle = dwExStyle;
2785
2787
2788 /* Call the internal function */
2789 pwnd = co_UserCreateWindowEx(&Cs, &ustrClsVersion, plstrWindowName, acbiBuffer, dwFlags);
2790
2791 if(!pwnd)
2792 {
2793 ERR("co_UserCreateWindowEx failed!\n");
2794 }
2795 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2796
2797 UserLeave();
2798
2799cleanup:
2800 if (lstrWindowName.Buffer)
2801 {
2802 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2803 }
2804 if (lstrClassName.Buffer)
2805 {
2806 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2807 }
2808 if (lstrClsVersion.Buffer)
2809 {
2810 ExFreePoolWithTag(lstrClsVersion.Buffer, TAG_STRING);
2811 }
2812
2813 return hwnd;
2814}
2815
2816// Win: xxxDW_DestroyOwnedWindows
2818{
2819 HWND* List;
2820 HWND* phWnd;
2821 PWND pWnd;
2823
2825 if (!List)
2826 return;
2827
2828 for (phWnd = List; *phWnd; ++phWnd)
2829 {
2830 pWnd = ValidateHwndNoErr(*phWnd);
2831 if (pWnd == NULL)
2832 continue;
2833 ASSERT(pWnd->spwndOwner == Window);
2834 ASSERT(pWnd != Window);
2835
2836 WndSetOwner(pWnd, NULL);
2838 {
2839 UserRefObjectCo(pWnd, &Ref); // Temp HACK?
2841 UserDerefObjectCo(pWnd); // Temp HACK?
2842 }
2843 else
2844 {
2845 ERR("IntWndBelongsToThread(0x%p) is FALSE, ignoring.\n", pWnd);
2846 }
2847 }
2848
2850}
2851
2852// Win: xxxDestroyWindow
2854{
2855 HWND hWnd;
2856 PWND pwndTemp;
2857 PTHREADINFO ti;
2858 MSG msg;
2859 PWND Window = Object;
2860
2861 ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
2862
2863 /* NtUserDestroyWindow does check if the window has already been destroyed
2864 but co_UserDestroyWindow can be called from more paths which means
2865 that it can also be called for a window that has already been destroyed. */
2867 {
2868 TRACE("Tried to destroy a window twice\n");
2869 return TRUE;
2870 }
2871
2872 hWnd = Window->head.h;
2874
2875 TRACE("co_UserDestroyWindow(Window = 0x%p, hWnd = 0x%p)\n", Window, hWnd);
2876
2877 /* Check for owner thread */
2878 if (Window->head.pti != ti)
2879 {
2880 /* Check if we are destroying the desktop window */
2881 if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
2882 {
2884 return FALSE;
2885 }
2886 }
2887
2888 /* If window was created successfully and it is hooked */
2889 if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
2890 {
2892 {
2893 ERR("Destroy Window WH_CBT Call Hook return!\n");
2894 return FALSE;
2895 }
2896 }
2897
2898 if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
2899 {
2900 if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2901 {
2902 if (Window->spwndOwner)
2903 {
2904 //ERR("DestroyWindow Owner out.\n");
2905 UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2906 }
2907 }
2908 }
2909
2910 /* Inform the parent */
2911 if (Window->style & WS_CHILD)
2912 {
2914 }
2915
2916 if (!Window->spwndOwner && !IntGetParent(Window))
2917 {
2919 }
2920
2921 /* Hide the window */
2922 if (Window->style & WS_VISIBLE)
2923 {
2924 if (Window->style & WS_CHILD)
2925 {
2926 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
2928 }
2929 else
2930 {
2932 }
2933 }
2934
2935 /* Adjust last active */
2936 if ((pwndTemp = Window->spwndOwner))
2937 {
2938 while (pwndTemp->spwndOwner)
2939 pwndTemp = pwndTemp->spwndOwner;
2940
2941 if (pwndTemp->spwndLastActive == Window)
2942 WndSetLastActive(pwndTemp, Window->spwndOwner);
2943 }
2944
2945 if (Window->spwndParent && IntIsWindow(UserHMGetHandle(Window)))
2946 {
2947 if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
2948 {
2950 {
2951 //ERR("DestroyWindow Parent out.\n");
2952 UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2953 }
2954 }
2955 }
2956
2957 if (Window->head.pti->MessageQueue->spwndActive == Window)
2958 Window->head.pti->MessageQueue->spwndActive = NULL;
2959 if (Window->head.pti->MessageQueue->spwndFocus == Window)
2960 Window->head.pti->MessageQueue->spwndFocus = NULL;
2961 if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
2962 Window->head.pti->MessageQueue->spwndActivePrev = NULL;
2963 if (Window->head.pti->MessageQueue->spwndCapture == Window)
2964 Window->head.pti->MessageQueue->spwndCapture = NULL;
2965
2966 /*
2967 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2968 */
2969
2970 if (ti->pDeskInfo != NULL)
2971 {
2972 if (ti->pDeskInfo->hShellWindow == hWnd)
2973 {
2974 ERR("Destroying the ShellWindow!\n");
2975 ti->pDeskInfo->hShellWindow = NULL;
2976 }
2977 }
2978
2980
2982 {
2983 return TRUE;
2984 }
2985
2986 /* Recursively destroy owned windows */
2987 if (!(Window->style & WS_CHILD))
2988 {
2990 }
2991
2992 /* Generate mouse move message for the next window */
2993 msg.message = WM_MOUSEMOVE;
2994 msg.wParam = UserGetMouseButtonsState();
2995 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2996 msg.pt = gpsi->ptCursor;
2998
2999 IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Window, OBJID_WINDOW, CHILDID_SELF, 0);
3000
3001 /* Send destroy messages */
3003
3004 /* Destroy the default IME window if necessary */
3005 if (IS_IMM_MODE() && !(ti->TIF_flags & TIF_INCLEANUP) &&
3006 ti->spwndDefaultIme && (ti->spwndDefaultIme != Window) &&
3007 !(Window->state & WNDS_DESTROYED) && !IS_WND_IMELIKE(Window))
3008 {
3009 if (IS_WND_CHILD(Window))
3010 {
3013 }
3014 else
3015 {
3018 }
3019 }
3020
3022 {
3023 return TRUE;
3024 }
3025
3026 /* Destroy the window storage */
3028
3029 return TRUE;
3030}
3031
3032
3033/*
3034 * @implemented
3035 */
3038{
3039 PWND Window;
3041 BOOLEAN ret;
3043
3044 TRACE("Enter NtUserDestroyWindow\n");
3046
3047 if (!(Window = UserGetWindowObject(Wnd)))
3048 {
3049 RETURN(FALSE);
3050 }
3051
3052 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
3054 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
3055
3056 RETURN(ret);
3057
3058CLEANUP:
3059 TRACE("Leave NtUserDestroyWindow, ret=%u\n", _ret_);
3060 UserLeave();
3062}
3063
3064
3067 PWND ChildAfter,
3068 RTL_ATOM ClassAtom,
3069 PUNICODE_STRING WindowName)
3070{
3071 BOOL CheckWindowName;
3072 HWND *List, *phWnd;
3073 HWND Ret = NULL;
3074 UNICODE_STRING CurrentWindowName;
3075
3076 ASSERT(Parent);
3077
3078 CheckWindowName = WindowName->Buffer != 0;
3079
3081 {
3082 phWnd = List;
3083 if(ChildAfter)
3084 {
3085 /* skip handles before and including ChildAfter */
3086 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
3087 ;
3088 }
3089
3090 /* search children */
3091 while(*phWnd)
3092 {
3093 PWND Child;
3094 if(!(Child = UserGetWindowObject(*(phWnd++))))
3095 {
3096 continue;
3097 }
3098
3099 /* Do not send WM_GETTEXT messages in the kernel mode version!
3100 The user mode version however calls GetWindowText() which will
3101 send WM_GETTEXT messages to windows belonging to its processes */
3102 if (!ClassAtom || Child->pcls->atomNVClassName == ClassAtom)
3103 {
3104 // FIXME: LARGE_STRING truncated
3105 CurrentWindowName.Buffer = Child->strName.Buffer;
3106 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
3107 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
3108 if(!CheckWindowName ||
3109 (Child->strName.Length < 0xFFFF &&
3110 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
3111 {
3112 Ret = Child->head.h;
3113 break;
3114 }
3115 }
3116 }
3118 }
3119
3120 return Ret;
3121}
3122
3123/*
3124 * FUNCTION:
3125 * Searches a window's children for a window with the specified
3126 * class and name
3127 * ARGUMENTS:
3128 * hwndParent = The window whose childs are to be searched.
3129 * NULL = desktop
3130 * HWND_MESSAGE = message-only windows
3131 *
3132 * hwndChildAfter = Search starts after this child window.
3133 * NULL = start from beginning
3134 *
3135 * ucClassName = Class name to search for
3136 * Reguired parameter.
3137 *
3138 * ucWindowName = Window name
3139 * ->Buffer == NULL = don't care
3140 *
3141 * RETURNS:
3142 * The HWND of the window if it was found, otherwise NULL
3143 */
3144/*
3145 * @implemented
3146 */
3149 HWND hwndChildAfter,
3150 PUNICODE_STRING ucClassName,
3151 PUNICODE_STRING ucWindowName,
3152 DWORD dwUnknown)
3153{
3154 PWND Parent, ChildAfter;
3155 UNICODE_STRING ClassName = {0}, WindowName = {0};
3156 HWND Desktop, Ret = NULL;
3157 BOOL DoMessageWnd = FALSE;
3158 RTL_ATOM ClassAtom = (RTL_ATOM)0;
3160
3161 TRACE("Enter NtUserFindWindowEx\n");
3163
3164 if (ucClassName != NULL || ucWindowName != NULL)
3165 {
3166 _SEH2_TRY
3167 {
3168 if (ucClassName != NULL)
3169 {
3170 ClassName = ProbeForReadUnicodeString(ucClassName);
3171 if (ClassName.Length != 0)
3172 {
3173 ProbeForRead(ClassName.Buffer,
3174 ClassName.Length,
3175 sizeof(WCHAR));
3176 }
3177 else if (!IS_ATOM(ClassName.Buffer))
3178 {
3181 }
3182
3183 if (!IntGetAtomFromStringOrAtom(&ClassName,
3184 &ClassAtom))
3185 {
3188 }
3189 }
3190
3191 if (ucWindowName != NULL)
3192 {
3193 WindowName = ProbeForReadUnicodeString(ucWindowName);
3194 if (WindowName.Length != 0)
3195 {
3196 ProbeForRead(WindowName.Buffer,
3197 WindowName.Length,
3198 sizeof(WCHAR));
3199 }
3200 }
3201 }
3203 {
3206 }
3207 _SEH2_END;
3208
3209 if (ucClassName != NULL)
3210 {
3211 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
3212 !IS_ATOM(ClassName.Buffer))
3213 {
3215 RETURN(NULL);
3216 }
3217 else if (ClassAtom == (RTL_ATOM)0)
3218 {
3219 /* LastError code was set by IntGetAtomFromStringOrAtom */
3220 RETURN(NULL);
3221 }
3222 }
3223 }
3224
3226
3227 if(hwndParent == NULL)
3228 {
3230 DoMessageWnd = TRUE;
3231 }
3232 else if(hwndParent == HWND_MESSAGE)
3233 {
3235 }
3236
3238 {
3239 RETURN( NULL);
3240 }
3241
3242 ChildAfter = NULL;
3243 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
3244 {
3245 RETURN( NULL);
3246 }
3247
3248 _SEH2_TRY
3249 {
3250 if(Parent->head.h == Desktop)
3251 {
3252 HWND *List, *phWnd;
3253 PWND TopLevelWindow;
3254 BOOLEAN CheckWindowName;
3255 BOOLEAN WindowMatches;
3256 BOOLEAN ClassMatches;
3257
3258 /* windows searches through all top-level windows if the parent is the desktop
3259 window */
3260
3262 {
3263 phWnd = List;
3264
3265 if(ChildAfter)
3266 {
3267 /* skip handles before and including ChildAfter */
3268 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
3269 ;
3270 }
3271
3272 CheckWindowName = WindowName.Buffer != 0;
3273
3274 /* search children */
3275 while(*phWnd)
3276 {
3277 UNICODE_STRING ustr;
3278
3279 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
3280 {
3281 continue;
3282 }
3283
3284 /* Do not send WM_GETTEXT messages in the kernel mode version!
3285 The user mode version however calls GetWindowText() which will
3286 send WM_GETTEXT messages to windows belonging to its processes */
3287 ustr.Buffer = TopLevelWindow->strName.Buffer;
3288 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
3289 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
3290 WindowMatches = !CheckWindowName ||
3291 (TopLevelWindow->strName.Length < 0xFFFF &&
3292 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
3293 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
3294 ClassAtom == TopLevelWindow->pcls->atomNVClassName;
3295
3296 if (WindowMatches && ClassMatches)
3297 {
3298 Ret = TopLevelWindow->head.h;
3299 break;
3300 }
3301
3302 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
3303 {
3304 /* window returns the handle of the top-level window, in case it found
3305 the child window */
3306 Ret = TopLevelWindow->head.h;
3307 break;
3308 }
3309
3310 }
3312 }
3313 }
3314 else
3315 {
3316 TRACE("FindWindowEx: Not Desktop Parent!\n");
3317 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
3318 }
3319
3320 if (Ret == NULL && DoMessageWnd)
3321 {
3322 PWND MsgWindows;
3323
3324 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3325 {
3326 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3327 }
3328 }
3329 }
3331 {
3333 Ret = NULL;
3334 }
3335 _SEH2_END;
3336
3337 RETURN( Ret);
3338
3339CLEANUP:
3340 TRACE("Leave NtUserFindWindowEx, ret %p\n", _ret_);
3341 UserLeave();
3343}
3344
3345
3346/*
3347 * @implemented
3348 */
3350{
3351 PWND WndAncestor, Parent;
3352
3353 if (Wnd->head.h == IntGetDesktopWindow())
3354 {
3355 return NULL;
3356 }
3357
3358 switch (Type)
3359 {
3360 case GA_PARENT:
3361 {
3362 WndAncestor = Wnd->spwndParent;
3363 break;
3364 }
3365
3366 case GA_ROOT:
3367 {
3368 WndAncestor = Wnd;
3369 Parent = NULL;
3370
3371 for(;;)
3372 {
3373 if(!(Parent = WndAncestor->spwndParent))
3374 {
3375 break;
3376 }
3378 {
3379 break;
3380 }
3381
3382 WndAncestor = Parent;
3383 }
3384 break;
3385 }
3386
3387 case GA_ROOTOWNER:
3388 {
3389 WndAncestor = Wnd;
3390
3391 for (;;)
3392 {
3393 Parent = IntGetParent(WndAncestor);
3394
3395 if (!Parent)
3396 {
3397 break;
3398 }
3399
3400 WndAncestor = Parent;
3401 }
3402 break;
3403 }
3404
3405 default:
3406 {
3407 return NULL;
3408 }
3409 }
3410
3411 return WndAncestor;
3412}
3413
3414/*
3415 * @implemented
3416 */
3419{
3420 PWND Window, Ancestor;
3422
3423 TRACE("Enter NtUserGetAncestor\n");
3425
3427 {
3428 RETURN(NULL);
3429 }
3430
3431 Ancestor = UserGetAncestor(Window, Type);
3432 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3433
3434 RETURN(Ancestor ? Ancestor->head.h : NULL);
3435
3436CLEANUP:
3437 TRACE("Leave NtUserGetAncestor, ret=%p\n", _ret_);
3438 UserLeave();
3440}
3441
3445/* combo state struct */
3446typedef struct
3447{
3448 HWND self;
3449 HWND owner;
3450 UINT dwStyle;
3451 HWND hWndEdit;
3452 HWND hWndLBox;
3453 UINT wState;
3454 HFONT hFont;
3455 RECT textRect;
3456 RECT buttonRect;
3457 RECT droppedRect;
3458 INT droppedIndex;
3459 INT fixedOwnerDrawHeight;
3460 INT droppedWidth; /* last two are not used unless set */
3461 INT editHeight; /* explicitly */
3464
3465// Window Extra data container.
3466typedef struct _WND2CBOX
3467{
3471
3472#define CBF_BUTTONDOWN 0x0002
3476BOOL
3479 HWND hWnd,
3480 PCOMBOBOXINFO pcbi)
3481{
3482 PWND Wnd;
3483 PPROCESSINFO ppi;
3484 BOOL NotSameppi = FALSE;
3485 BOOL Ret = TRUE;
3487
3488 TRACE("Enter NtUserGetComboBoxInfo\n");
3490
3491 if (!(Wnd = UserGetWindowObject(hWnd)))
3492 {
3493 RETURN( FALSE );
3494 }
3495 _SEH2_TRY
3496 {
3497 ProbeForWrite(pcbi, sizeof(COMBOBOXINFO), 1);
3498 }
3500 {
3503 }
3504 _SEH2_END;
3505
3506 if (pcbi->cbSize < sizeof(COMBOBOXINFO))
3507 {
3509 RETURN(FALSE);
3510 }
3511
3512 // Pass the user pointer, it was already probed.
3514 {
3516 }
3517
3519 NotSameppi = ppi != Wnd->head.pti->ppi;
3520 if (NotSameppi)
3521 {
3522 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3523 }
3524
3525 _SEH2_TRY
3526 {
3527 LPHEADCOMBO lphc = ((PWND2CBOX)Wnd)->pCBox;
3528 pcbi->rcItem = lphc->textRect;
3529 pcbi->rcButton = lphc->buttonRect;
3530 pcbi->stateButton = 0;
3531 if (lphc->wState & CBF_BUTTONDOWN)
3533 if (RECTL_bIsEmptyRect(&lphc->buttonRect))
3535 pcbi->hwndCombo = lphc->self;
3536 pcbi->hwndItem = lphc->hWndEdit;
3537 pcbi->hwndList = lphc->hWndLBox;
3538 }
3540 {
3541 Ret = FALSE;
3543 }
3544 _SEH2_END;
3545
3546 RETURN( Ret);
3547
3548CLEANUP:
3549 if (NotSameppi) KeDetachProcess();
3550 TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3551 UserLeave();
3553}
3554
3558/* Listbox structure */
3559typedef struct
3560{
3561 HWND self; /* Our own window handle */
3562 HWND owner; /* Owner window to send notifications to */
3563 UINT style; /* Window style */
3564 INT width; /* Window width */
3565 INT height; /* Window height */
3566 VOID *items; /* Array of items */
3567 INT nb_items; /* Number of items */
3568 INT top_item; /* Top visible item */
3569 INT selected_item; /* Selected item */
3570 INT focus_item; /* Item that has the focus */
3571 INT anchor_item; /* Anchor item for extended selection */
3572 INT item_height; /* Default item height */
3573 INT page_size; /* Items per listbox page */
3574 INT column_width; /* Column width for multi-column listboxes */
3575} LB_DESCR;
3576
3577// Window Extra data container.
3578typedef struct _WND2LB
3579{
3586DWORD
3589 HWND hWnd)
3590{
3591 PWND Wnd;
3592 PPROCESSINFO ppi;
3593 BOOL NotSameppi = FALSE;
3594 DWORD Ret = 0;
3596
3597 TRACE("Enter NtUserGetListBoxInfo\n");
3599
3600 if (!(Wnd = UserGetWindowObject(hWnd)))
3601 {
3602 RETURN( 0 );
3603 }
3604
3605 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && Wnd->fnid != FNID_LISTBOX)
3606 {
3608 }
3609
3610 // wine lisbox:test_GetListBoxInfo lb_getlistboxinfo = 0, should not send a message!
3612 NotSameppi = ppi != Wnd->head.pti->ppi;
3613 if (NotSameppi)
3614 {
3615 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3616 }
3617
3618 _SEH2_TRY
3619 {
3620 LB_DESCR *descr = ((PWND2LB)Wnd)->pLBiv;
3621 // See Controls ListBox.c:LB_GETLISTBOXINFO must match...
3622 Ret = descr->page_size;
3623 }
3625 {
3626 Ret = 0;
3628 }
3629 _SEH2_END;
3630
3631 RETURN( Ret);
3632
3633CLEANUP:
3634 if (NotSameppi) KeDetachProcess();
3635 TRACE("Leave NtUserGetListBoxInfo, ret=%lu\n", _ret_);
3636 UserLeave();
3638}
3639
3640/*
3641 * NtUserSetParent
3642 *
3643 * The NtUserSetParent function changes the parent window of the specified
3644 * child window.
3645 *
3646 * Remarks
3647 * The new parent window and the child window must belong to the same
3648 * application. If the window identified by the hWndChild parameter is
3649 * visible, the system performs the appropriate redrawing and repainting.
3650 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3651 * or WS_POPUP window styles of the window whose parent is being changed.
3652 *
3653 * Status
3654 * @implemented
3655 */
3656
3659{
3661
3662 TRACE("Enter NtUserSetParent\n");
3664
3665 /*
3666 Check Parent first from user space, set it here.
3667 */
3668 if (!hWndNewParent)
3669 {
3670 hWndNewParent = IntGetDesktopWindow();
3671 }
3672 else if (hWndNewParent == HWND_MESSAGE)
3673 {
3674 hWndNewParent = IntGetMessageWindow();
3675 }
3676
3677 RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3678
3679CLEANUP:
3680 TRACE("Leave NtUserSetParent, ret=%p\n", _ret_);
3681 UserLeave();
3683}
3684
3685/*
3686 * UserGetShellWindow
3687 *
3688 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3689 *
3690 * Status
3691 * @implemented
3692 */
3694{
3695 PWINSTATION_OBJECT WinStaObject;
3696 HWND Ret;
3697
3699 UserMode,
3700 0,
3701 &WinStaObject,
3702 0);
3703
3704 if (!NT_SUCCESS(Status))
3705 {
3707 return( (HWND)0);
3708 }
3709
3710 Ret = (HWND)WinStaObject->ShellWindow;
3711
3712 ObDereferenceObject(WinStaObject);
3713 return( Ret);
3714}
3715
3716/*
3717 * NtUserSetShellWindowEx
3718 *
3719 * This is undocumented function to set global shell window. The global
3720 * shell window has special handling of window position.
3721 *
3722 * Status
3723 * @implemented
3724 */
3727{
3728 PWINSTATION_OBJECT WinStaObject;
3729 PWND WndShell, WndListView;
3733 PTHREADINFO ti;
3734
3735 TRACE("Enter NtUserSetShellWindowEx\n");
3737
3738 if (!(WndShell = UserGetWindowObject(hwndShell)))
3739 {
3740 RETURN(FALSE);
3741 }
3742
3743 if (!(WndListView = UserGetWindowObject(hwndListView)))
3744 {
3745 RETURN(FALSE);
3746 }
3747
3749 UserMode,
3750 0,
3751 &WinStaObject,
3752 0);
3753
3754 if (!NT_SUCCESS(Status))
3755 {
3757 RETURN( FALSE);
3758 }
3759
3760 /*
3761 * Test if we are permitted to change the shell window.
3762 */
3763 if (WinStaObject->ShellWindow)
3764 {
3765 ObDereferenceObject(WinStaObject);
3766 RETURN( FALSE);
3767 }
3768
3769 /*
3770 * Move shell window into background.
3771 */
3772 if (hwndListView && hwndListView != hwndShell)
3773 {
3774 /*
3775 * Disabled for now to get Explorer working.
3776 * -- Filip, 01/nov/2003
3777 */
3778#if 0
3780#endif
3781
3782 if (WndListView->ExStyle & WS_EX_TOPMOST)
3783 {
3784 ObDereferenceObject(WinStaObject);
3785 RETURN( FALSE);
3786 }
3787 }
3788
3789 if (WndShell->ExStyle & WS_EX_TOPMOST)
3790 {
3791 ObDereferenceObject(WinStaObject);
3792 RETURN( FALSE);
3793 }
3794
3795 UserRefObjectCo(WndShell, &Ref);
3796 WndShell->state2 |= WNDS2_BOTTOMMOST;
3798
3799 WinStaObject->ShellWindow = hwndShell;
3800 WinStaObject->ShellListView = hwndListView;
3801
3802 ti = GetW32ThreadInfo();
3803 if (ti->pDeskInfo)
3804 {
3805 ti->pDeskInfo->hShellWindow = hwndShell;
3806 ti->pDeskInfo->spwndShell = WndShell;
3807 ti->pDeskInfo->spwndBkGnd = WndListView;
3808 ti->pDeskInfo->ppiShellProcess = ti->ppi;
3809 }
3810
3812
3813 UserDerefObjectCo(WndShell);
3814
3815 ObDereferenceObject(WinStaObject);
3816 RETURN( TRUE);
3817
3818CLEANUP:
3819 TRACE("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3820 UserLeave();
3822}
3823
3824// Fixes wine Win test_window_styles and todo tests...
3825static BOOL FASTCALL
3827{
3829 return TRUE;
3830 else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME)))
3831 return TRUE;
3832 else
3833 return FALSE;
3834}
3835
3836static LONG_PTR
3838{
3840 PWINSTATION_OBJECT WindowStation;
3841 LONG_PTR OldValue;
3843
3845 {
3846 return( 0);
3847 }
3848
3849 if ((INT)Index >= 0)
3850 {
3851 if ((Index + Size) > Window->cbwndExtra)
3852 {
3854 return( 0);
3855 }
3856
3857#ifdef _WIN64
3858 if (Size == sizeof(LONG))
3859 {
3860 OldValue = *((LONG *)((PCHAR)(Window + 1) + Index));
3861 *((LONG*)((PCHAR)(Window + 1) + Index)) = (LONG)NewValue;
3862 }
3863 else
3864#endif
3865 {
3866 OldValue = *((LONG_PTR *)((PCHAR)(Window + 1) + Index));
3867 /*
3868 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3869 {
3870 OldValue = (LONG_PTR)IntSetWindowProc( Wnd, (WNDPROC)NewValue, Ansi);
3871 if (!OldValue) return 0;
3872 }
3873 */
3874 *((LONG_PTR*)((PCHAR)(Window + 1) + Index)) = NewValue;
3875 }
3876
3877 }
3878 else
3879 {
3880#ifdef _WIN64
3881 if (Size == sizeof(LONG))
3882 {
3883 if ((Index != GWL_STYLE) &&
3884 (Index != GWL_EXSTYLE) &&
3885 (Index != GWL_ID) &&
3886 (Index != GWL_USERDATA))
3887 {
3888 ERR("NtUserSetWindowLong(): Index requires pointer size: %lu\n", Index);
3890 return 0;
3891 }
3892 }
3893#endif
3894
3895 switch (Index)
3896 {
3897 case GWL_EXSTYLE: // LONG
3898 OldValue = (LONG) Window->ExStyle;
3899 Style.styleOld = OldValue;
3900 Style.styleNew = NewValue;
3901
3902 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3903
3904 /*
3905 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3906 */
3907 WindowStation = Window->head.pti->rpdesk->rpwinstaParent;
3908 if(WindowStation)
3909 {
3910 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3911 Style.styleNew &= ~WS_EX_TOPMOST;
3912 }
3913 /* WS_EX_WINDOWEDGE depends on some other styles */
3914 if (IntCheckFrameEdge(Window->style, NewValue))
3915 Style.styleNew |= WS_EX_WINDOWEDGE;
3916 else
3917 Style.styleNew &= ~WS_EX_WINDOWEDGE;
3918
3919 if (!(Window->ExStyle & WS_EX_LAYERED))
3920 {
3922 }
3923
3924 Window->ExStyle = (DWORD)Style.styleNew;
3925
3926 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3927 break;
3928
3929 case GWL_STYLE: // LONG
3930 OldValue = (LONG) Window->style;
3931 Style.styleOld = OldValue;
3932 Style.styleNew = NewValue;
3933
3934 if (!bAlter)
3935 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3936
3937 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
3938 if (UserIsDesktopWindow(Window->spwndParent)) Style.styleNew |= WS_CLIPSIBLINGS;
3939 /* WS_MINIMIZE can't be reset */
3940 if (OldValue & WS_MINIMIZE) Style.styleNew |= WS_MINIMIZE;
3941 /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */
3942 if (IntCheckFrameEdge(NewValue, Window->ExStyle))
3943 Window->ExStyle |= WS_EX_WINDOWEDGE;
3944 else
3945 Window->ExStyle &= ~WS_EX_WINDOWEDGE;
3946
3947 if ((OldValue & (WS_CHILD | WS_POPUP)) == WS_CHILD)
3948 {
3949 if ((NewValue & (WS_CHILD | WS_POPUP)) != WS_CHILD)
3950 {
3952 ERR("IDMenu going null! %d\n",Window->IDMenu);
3953 Window->IDMenu = 0; // Window->spmenu = 0;
3954 }
3955 }
3956 else
3957 {
3958 if ((NewValue & (WS_CHILD | WS_POPUP)) == WS_CHILD)
3959 {
3960 PMENU pMenu = UserGetMenuObject(UlongToHandle(Window->IDMenu));
3961 Window->state &= ~WNDS_HASMENU;
3962 if (pMenu)
3963 {
3964 ERR("IDMenu released 0x%p\n",pMenu);
3965 // ROS may not hold a lock after setting menu to window. But it should!
3966 //IntReleaseMenuObject(pMenu);
3967 }
3968 }
3969 }
3970
3971 if ((Style.styleOld ^ Style.styleNew) & WS_VISIBLE)
3972 {
3973 if (Style.styleOld & WS_VISIBLE) Window->head.pti->cVisWindows--;
3974 if (Style.styleNew & WS_VISIBLE) Window->head.pti->cVisWindows++;
3976 }
3977 Window->style = (DWORD)Style.styleNew;
3978
3979 if (!bAlter)
3980 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3981 break;
3982
3983 case GWLP_WNDPROC: // LONG_PTR
3984 {
3985 if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
3986 Window->fnid & FNID_FREED)
3987 {
3989 return( 0);
3990 }
3991 OldValue = (LONG_PTR)IntSetWindowProc(Window,
3992 (WNDPROC)NewValue,
3993 Ansi);
3994 break;
3995 }
3996
3997 case GWLP_HINSTANCE: // LONG_PTR
3998 OldValue = (LONG_PTR) Window->hModule;
3999 Window->hModule = (HINSTANCE) NewValue;
4000 break;
4001
4002 case GWLP_HWNDPARENT: // LONG_PTR
4003 Parent = Window->spwndParent;
4004 if (Parent && (Parent->head.h == IntGetDesktopWindow()))
4005 OldValue = (LONG_PTR) IntSetOwner(Window->head.h, (HWND) NewValue);
4006 else
4007 OldValue = (LONG_PTR) co_UserSetParent(Window->head.h, (HWND) NewValue);
4008 break;
4009
4010 case GWLP_ID: // LONG
4011 OldValue = (LONG) Window->IDMenu;
4012 Window->IDMenu = (UINT) NewValue;
4013 break;
4014
4015 case GWLP_USERDATA: // LONG or LONG_PTR
4016 OldValue = Window->dwUserData;
4017 Window->dwUserData = NewValue;
4018 break;
4019
4020 default:
4021 ERR("NtUserSetWindowLong(): Unsupported index %lu\n", Index);
4023 OldValue = 0;
4024 break;
4025 }
4026 }
4027
4028 return( OldValue);
4029}
4030
4033{
4034 return (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE);
4035}
4036
4039{
4040 return co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE);
4041}
4042
4043/*
4044 * NtUserSetWindowLong
4045 *
4046 * The NtUserSetWindowLong function changes an attribute of the specified
4047 * window. The function also sets the 32-bit (long) value at the specified
4048 * offset into the extra window memory.
4049 *
4050 * Status
4051 * @implemented
4052 */
4053
4056{
4057 LONG ret;
4058
4060
4061 if (hWnd == IntGetDesktopWindow())
4062 {
4064 UserLeave();
4065 return 0;
4066 }
4067
4068 ret = (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE);
4069
4070 UserLeave();
4071
4072 return ret;
4073}
4074
4075#ifdef _WIN64
4078{
4079 LONG_PTR ret;
4080
4082
4083 if (hWnd == IntGetDesktopWindow())
4084 {
4086 UserLeave();
4087 return 0;
4088 }
4089
4090 ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE);
4091
4092 UserLeave();
4093
4094 return ret;
4095}
4096#endif // _WIN64
4097
4100{
4101 LONG ret;
4102
4104
4105 if (hWnd == IntGetDesktopWindow())
4106 {
4108 UserLeave();
4109 return 0;
4110 }
4111
4112 ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, FALSE, sizeof(LONG), TRUE);
4113
4114 UserLeave();
4115
4116 return ret;
4117}
4118
4119
4120/*
4121 * NtUserSetWindowWord
4122 *
4123 * Legacy function similar to NtUserSetWindowLong.
4124 *
4125 * Status
4126 * @implemented
4127 */
4128
4131{
4132 PWND Window;
4133 WORD OldValue;
4135
4136 TRACE("Enter NtUserSetWindowWord\n");
4138
4139 if (hWnd == IntGetDesktopWindow())
4140 {
4142 RETURN( 0);
4143 }
4144
4146 {
4147 RETURN( 0);
4148 }
4149
4150 switch (Index)
4151 {
4152 case GWL_ID:
4153 case GWL_HINSTANCE:
4154 case GWL_HWNDPARENT:
4156 default:
4157 if (Index < 0)
4158 {
4160 RETURN( 0);
4161 }
4162 }
4163
4164 if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD)))
4165 {
4167 RETURN( 0);
4168 }
4169
4170 OldValue = *((WORD *)((PCHAR)(Window + 1) + Index));
4171 *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue;
4172
4173 RETURN( OldValue);
4174
4175CLEANUP:
4176 TRACE("Leave NtUserSetWindowWord, ret=%u\n", _ret_);
4177 UserLeave();
4179}
4180
4181/*
4182 QueryWindow based on KJK::Hyperion and James Tabor.
4183
4184 0 = QWUniqueProcessId
4185 1 = QWUniqueThreadId
4186 2 = QWActiveWindow
4187 3 = QWFocusWindow
4188 4 = QWIsHung Implements IsHungAppWindow found
4189 by KJK::Hyperion.
4190
4191 9 = QWKillWindow When I called this with hWnd ==
4192 DesktopWindow, it shutdown the system
4193 and rebooted.
4194*/
4195/*
4196 * @implemented
4197 */
4200{
4201/* Console Leader Process CID Window offsets */
4202#define GWLP_CONSOLE_LEADER_PID 0
4203#define GWLP_CONSOLE_LEADER_TID 4
4204
4206 PWND pWnd, pwndActive;
4207 PTHREADINFO pti, ptiActive;
4209
4210 TRACE("Enter NtUserQueryWindow\n");
4212
4213 if (!(pWnd = UserGetWindowObject(hWnd)))
4214 {
4215 RETURN( 0);
4216 }
4217
4218 switch(Index)
4219 {
4221 {
4222 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
4224 {
4225 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_PID)
4226 Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_PID)));
4227 }
4228 else
4229 {
4231 }
4232 break;
4233 }
4234
4236 {
4237 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
4239 {
4240 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_TID)
4241 Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_TID)));
4242 }
4243 else
4244 {
4246 }
4247 break;
4248 }
4249
4251 Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndActive ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndActive) : 0);
4252 break;
4253
4254 case QUERY_WINDOW_FOCUS:
4255 Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndFocus ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndFocus) : 0);
4256 break;
4257
4259 Result = (pWnd->fnid == FNID_GHOST) || MsqIsHung(pWnd->head.pti, MSQ_HUNG);
4260 break;
4261
4263 Result = (DWORD_PTR)pWnd->head.pti->pEThread->Cid.UniqueProcess;
4264 break;
4265
4267 Result = (pWnd->head.pti->MessageQueue == gpqForeground);
4268 break;
4269
4270 case QUERY_WINDOW_DEFAULT_IME: /* default IME window */
4271 if (pWnd->head.pti->spwndDefaultIme)
4272 Result = (DWORD_PTR)UserHMGetHandle(pWnd->head.pti->spwndDefaultIme);
4273 else
4274 Result = 0;
4275 break;
4276
4277 case QUERY_WINDOW_DEFAULT_ICONTEXT: /* default input context handle */
4278 if (pWnd->head.pti->spDefaultImc)
4279 Result = (DWORD_PTR)UserHMGetHandle(pWnd->head.pti->spDefaultImc);
4280 else
4281 Result = 0;
4282 break;
4283
4285 Result = 0;
4287 {
4288 pwndActive = gpqForeground->spwndActive;
4290 if (pti->rpdesk == pwndActive->head.rpdesk)
4291 {
4292 ptiActive = pwndActive->head.pti;
4293 if (ptiActive->spwndDefaultIme)
4295 }
4296 }
4297 break;
4298
4299 default:
4300 Result = 0;
4301 break;
4302 }
4303
4304 RETURN( Result);
4305
4306CLEANUP:
4307 TRACE("Leave NtUserQueryWindow, ret=%u\n", _ret_);
4308 UserLeave();
4310}
4311
4312/*
4313 * @implemented
4314 */
4317{
4318 UNICODE_STRING SafeMessageName;
4320 UINT Ret;
4322
4323 TRACE("Enter NtUserRegisterWindowMessage\n");
4325
4326 if(MessageNameUnsafe == NULL)
4327 {
4329 RETURN( 0);
4330 }
4331
4332 Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
4333 if(!NT_SUCCESS(Status))
4334 {
4336 RETURN( 0);
4337 }
4338
4339 Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
4340 if (SafeMessageName.Buffer)
4341 ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING);
4342 RETURN( Ret);
4343
4344CLEANUP:
4345 TRACE("Leave NtUserRegisterWindowMessage, ret=%u\n", _ret_);
4346 UserLeave();
4348}
4349
4350/*
4351 * @implemented
4352 */
4355 WORD fnID)
4356{
4357 PWND Wnd;
4359
4360 TRACE("Enter NtUserSetWindowFNID\n");
4362
4363 if (!(Wnd = UserGetWindowObject(hWnd)))
4364 {
4365 RETURN( FALSE);
4366 }
4367
4368 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
4369 {
4371 RETURN( FALSE);
4372 }
4373
4374 // From user land we only set these.
4375 if (fnID != FNID_DESTROY)
4376 {
4377 /* HACK: The minimum should be FNID_BUTTON, but menu code relies on this */
4378 if (fnID < FNID_FIRST || fnID > FNID_GHOST ||
4379 Wnd->fnid != 0)
4380 {
4382 RETURN( FALSE);
4383 }
4384 }
4385
4386 Wnd->fnid |= fnID;
4387 RETURN( TRUE);
4388
4389CLEANUP:
4390 TRACE("Leave NtUserSetWindowFNID\n");
4391 UserLeave();
4393}
4394
4396DefSetText(PWND Wnd, PCWSTR WindowText)
4397{
4399 BOOL Ret = FALSE;
4400
4401 RtlInitUnicodeString(&UnicodeString, WindowText);
4402
4403 if (UnicodeString.Length != 0)
4404 {
4405 if (Wnd->strName.MaximumLength > 0 &&
4406 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4407 {
4408 ASSERT(Wnd->strName.Buffer != NULL);
4409
4410 Wnd->strName.Length = UnicodeString.Length;
4411 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4413 UnicodeString.Buffer,
4414 UnicodeString.Length);
4415 }
4416 else
4417 {
4418 PWCHAR buf;
4419 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4420 buf = Wnd->strName.Buffer;
4421 Wnd->strName.Buffer = NULL;
4422 if (buf != NULL)
4423 {
4425 }
4426
4428 UnicodeString.Length + sizeof(UNICODE_NULL));
4429 if (Wnd->strName.Buffer != NULL)
4430 {
4431 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4433 UnicodeString.Buffer,
4434 UnicodeString.Length);
4435 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4436 Wnd->strName.Length = UnicodeString.Length;
4437 }
4438 else
4439 {
4441 goto Exit;
4442 }
4443 }
4444 }
4445 else
4446 {
4447 Wnd->strName.Length = 0;
4448 if (Wnd->strName.Buffer != NULL)
4449 Wnd->strName.Buffer[0] = L'\0';
4450 }
4451
4452 // FIXME: HAX! Windows does not do this in here!
4453 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4454 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4455 /* Send shell notifications */
4456 if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4457 {
4458 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) UserHMGetHandle(Wnd), FALSE); // FIXME Flashing?
4459 }
4460
4461 Ret = TRUE;
4462Exit:
4464 return Ret;
4465}
4466
4467/*
4468 * NtUserDefSetText
4469 *
4470 * Undocumented function that is called from DefWindowProc to set
4471 * window text.
4472 *
4473 * Status
4474 * @implemented
4475 */
4478{
4479 PWND Wnd;
4480 LARGE_STRING SafeText;
4482 BOOL Ret = TRUE;
4483
4484 TRACE("Enter NtUserDefSetText\n");
4485
4486 if (WindowText != NULL)
4487 {
4488 _SEH2_TRY
4489 {
4490 SafeText = ProbeForReadLargeString(WindowText);
4491 }
4493 {
4494 Ret = FALSE;
4496 }
4497 _SEH2_END;
4498
4499 if (!Ret)
4500 return FALSE;
4501 }
4502 else
4503 return TRUE;
4504
4506
4507 if(!(Wnd = UserGetWindowObject(hWnd)))
4508 {
4509 UserLeave();
4510 return FALSE;
4511 }
4512
4513 // ReactOS uses Unicode and not mixed. Up/Down converting will take time.
4514 // Brought to you by: The Wine Project! Dysfunctional Thought Processes!
4515 // Now we know what the bAnsi is for.
4517 if (SafeText.Buffer)
4518 {
4519 _SEH2_TRY
4520 {
4521 if (SafeText.bAnsi)
4522 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR));
4523 else
4524 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR));
4526 }
4528 {
4529 Ret = FALSE;
4531 }
4532 _SEH2_END;
4533 if (!Ret) goto Exit;
4534 }
4535
4536 if (UnicodeString.Length != 0)
4537 {
4538 if (Wnd->strName.MaximumLength > 0 &&
4539 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4540 {
4541 ASSERT(Wnd->strName.Buffer != NULL);
4542
4543 Wnd->strName.Length = UnicodeString.Length;
4544 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4546 UnicodeString.Buffer,
4547 UnicodeString.Length);
4548 }
4549 else
4550 {
4551 PWCHAR buf;
4552 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4553 buf = Wnd->strName.Buffer;
4554 Wnd->strName.Buffer = NULL;
4555 if (buf != NULL)
4556 {
4558 }
4559
4561 UnicodeString.Length + sizeof(UNICODE_NULL));
4562 if (Wnd->strName.Buffer != NULL)
4563 {
4564 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4566 UnicodeString.Buffer,
4567 UnicodeString.Length);
4568 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4569 Wnd->strName.Length = UnicodeString.Length;
4570 }
4571 else
4572 {
4574 Ret = FALSE;
4575 goto Exit;
4576 }
4577 }
4578 }
4579 else
4580 {
4581 Wnd->strName.Length = 0;
4582 if (Wnd->strName.Buffer != NULL)
4583 Wnd->strName.Buffer[0] = L'\0';
4584 }
4585
4586 // FIXME: HAX! Windows does not do this in here!
4587 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4588 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4589 /* Send shell notifications */
4590 if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4591 {
4592 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) hWnd, FALSE); // FIXME Flashing?
4593 }
4594
4595 Ret = TRUE;
4596Exit:
4597 if (UnicodeString.Buffer) RtlF