ReactOS 0.4.16-dev-13-ge2fc578
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 <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 {
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))
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 (UserHMGetHandle(Window) == ThreadData->rpdesk->rpwinstaParent->ShellWindow)
661 ThreadData->rpdesk->rpwinstaParent->ShellWindow = NULL;
662
663 if (UserHMGetHandle(Window) == 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 /* Even if WndNewParent == WndOldParent continue because the
1222 * child window (Wnd) should be moved to the top of the z-order */
1223
1224 /* Unlink the window from the siblings list */
1225 IntUnlinkWindow(Wnd);
1226 Wnd->ExStyle2 &= ~WS_EX2_LINKED;
1227
1228 /* Set the new parent */
1229 WndSetParent(Wnd, WndNewParent);
1230
1231 if (Wnd->style & WS_CHILD &&
1232 Wnd->spwndOwner &&
1233 Wnd->spwndOwner->ExStyle & WS_EX_TOPMOST)
1234 {
1235 ERR("SetParent Top Most from Pop up\n");
1236 Wnd->ExStyle |= WS_EX_TOPMOST;
1237 }
1238
1239 /* Link the window with its new siblings */
1240 IntLinkHwnd(Wnd,
1241 ((0 == (Wnd->ExStyle & WS_EX_TOPMOST) &&
1242 UserIsDesktopWindow(WndNewParent)) ? HWND_TOP : HWND_TOPMOST));
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 = UserHMGetHandle(WndOldParent);
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 {
1411 pwl = IntPopulateHwndList(pwl, pwnd->spwndChild, IACE_CHILDREN | IACE_LIST);
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 = UserHMGetHandle(Window);
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 = UserHMGetHandle(Window);
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);
1703 MAKEWPARAM( msg, pWindow->IDMenu),
1704 (LPARAM)UserHMGetHandle(pWindow) );
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 = UserHMGetHandle(pti->rpdesk->pDeskInfo->spwnd);
2219 hWndOwner = NULL;
2220
2221 if (Cs->hwndParent == HWND_MESSAGE)
2222 {
2223 Cs->hwndParent = hWndParent = UserHMGetHandle(pti->rpdesk->spwndMessage);
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(UserHMGetHandle(Window), 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
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;
3040 BOOLEAN ret = FALSE;
3042
3043 TRACE("Enter NtUserDestroyWindow\n");
3045
3047 if (Window)
3048 {
3049 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
3051 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
3052 }
3053
3054 TRACE("Leave NtUserDestroyWindow, ret=%u\n", ret);
3055 UserLeave();
3056 return ret;
3057}
3058
3059
3062 PWND ChildAfter,
3063 RTL_ATOM ClassAtom,
3064 PUNICODE_STRING WindowName)
3065{
3066 BOOL CheckWindowName;
3067 HWND *List, *phWnd;
3068 HWND Ret = NULL;
3069 UNICODE_STRING CurrentWindowName;
3070
3071 ASSERT(Parent);
3072
3073 CheckWindowName = WindowName->Buffer != 0;
3074
3076 {
3077 phWnd = List;
3078 if(ChildAfter)
3079 {
3080 /* skip handles before and including ChildAfter */
3081 while(*phWnd && (*(phWnd++) != UserHMGetHandle(ChildAfter)))
3082 ;
3083 }
3084
3085 /* search children */
3086 while(*phWnd)
3087 {
3088 PWND Child;
3089 if(!(Child = UserGetWindowObject(*(phWnd++))))
3090 {
3091 continue;
3092 }
3093
3094 /* Do not send WM_GETTEXT messages in the kernel mode version!
3095 The user mode version however calls GetWindowText() which will
3096 send WM_GETTEXT messages to windows belonging to its processes */
3097 if (!ClassAtom || Child->pcls->atomNVClassName == ClassAtom)
3098 {
3099 // FIXME: LARGE_STRING truncated
3100 CurrentWindowName.Buffer = Child->strName.Buffer;
3101 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
3102 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
3103 if(!CheckWindowName ||
3104 (Child->strName.Length < 0xFFFF &&
3105 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
3106 {
3107 Ret = UserHMGetHandle(Child);
3108 break;
3109 }
3110 }
3111 }
3113 }
3114
3115 return Ret;
3116}
3117
3118/*
3119 * FUNCTION:
3120 * Searches a window's children for a window with the specified
3121 * class and name
3122 * ARGUMENTS:
3123 * hwndParent = The window whose childs are to be searched.
3124 * NULL = desktop
3125 * HWND_MESSAGE = message-only windows
3126 *
3127 * hwndChildAfter = Search starts after this child window.
3128 * NULL = start from beginning
3129 *
3130 * ucClassName = Class name to search for
3131 * Reguired parameter.
3132 *
3133 * ucWindowName = Window name
3134 * ->Buffer == NULL = don't care
3135 *
3136 * RETURNS:
3137 * The HWND of the window if it was found, otherwise NULL
3138 */
3139/*
3140 * @implemented
3141 */
3144 HWND hwndChildAfter,
3145 PUNICODE_STRING ucClassName,
3146 PUNICODE_STRING ucWindowName,
3147 DWORD dwUnknown)
3148{
3149 PWND Parent, ChildAfter;
3150 UNICODE_STRING ClassName = {0}, WindowName = {0};
3151 HWND Desktop, Ret = NULL;
3152 BOOL DoMessageWnd = FALSE;
3153 RTL_ATOM ClassAtom = (RTL_ATOM)0;
3154
3155 TRACE("Enter NtUserFindWindowEx\n");
3157
3158 if (ucClassName != NULL || ucWindowName != NULL)
3159 {
3160 _SEH2_TRY
3161 {
3162 if (ucClassName != NULL)
3163 {
3164 ClassName = ProbeForReadUnicodeString(ucClassName);
3165 if (ClassName.Length != 0)
3166 {
3167 ProbeForRead(ClassName.Buffer,
3168 ClassName.Length,
3169 sizeof(WCHAR));
3170 }
3171 else if (!IS_ATOM(ClassName.Buffer))
3172 {
3175 }
3176
3177 if (!IntGetAtomFromStringOrAtom(&ClassName,
3178 &ClassAtom))
3179 {
3182 }
3183 }
3184
3185 if (ucWindowName != NULL)
3186 {
3187 WindowName = ProbeForReadUnicodeString(ucWindowName);
3188 if (WindowName.Length != 0)
3189 {
3190 ProbeForRead(WindowName.Buffer,
3191 WindowName.Length,
3192 sizeof(WCHAR));
3193 }
3194 }
3195 }
3197 {
3199 _SEH2_YIELD(goto Exit); // Return NULL
3200 }
3201 _SEH2_END;
3202
3203 if (ucClassName != NULL)
3204 {
3205 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
3206 !IS_ATOM(ClassName.Buffer))
3207 {
3209 goto Exit; // Return NULL
3210 }
3211 else if (ClassAtom == (RTL_ATOM)0)
3212 {
3213 /* LastError code was set by IntGetAtomFromStringOrAtom */
3214 goto Exit; // Return NULL
3215 }
3216 }
3217 }
3218
3220
3221 if(hwndParent == NULL)
3222 {
3224 DoMessageWnd = TRUE;
3225 }
3226 else if(hwndParent == HWND_MESSAGE)
3227 {
3229 }
3230
3232 {
3233 goto Exit; // Return NULL
3234 }
3235
3236 ChildAfter = NULL;
3237 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
3238 {
3239 goto Exit; // Return NULL
3240 }
3241
3242 _SEH2_TRY
3243 {
3245 {
3246 HWND *List, *phWnd;
3247 PWND TopLevelWindow;
3248 BOOLEAN CheckWindowName;
3249 BOOLEAN WindowMatches;
3250 BOOLEAN ClassMatches;
3251
3252 /* windows searches through all top-level windows if the parent is the desktop
3253 window */
3254
3256 {
3257 phWnd = List;
3258
3259 if(ChildAfter)
3260 {
3261 /* skip handles before and including ChildAfter */
3262 while(*phWnd && (*(phWnd++) != UserHMGetHandle(ChildAfter)))
3263 ;
3264 }
3265
3266 CheckWindowName = WindowName.Buffer != 0;
3267
3268 /* search children */
3269 while(*phWnd)
3270 {
3271 UNICODE_STRING ustr;
3272
3273 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
3274 {
3275 continue;
3276 }
3277
3278 /* Do not send WM_GETTEXT messages in the kernel mode version!
3279 The user mode version however calls GetWindowText() which will
3280 send WM_GETTEXT messages to windows belonging to its processes */
3281 ustr.Buffer = TopLevelWindow->strName.Buffer;
3282 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
3283 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
3284 WindowMatches = !CheckWindowName ||
3285 (TopLevelWindow->strName.Length < 0xFFFF &&
3286 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
3287 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
3288 ClassAtom == TopLevelWindow->pcls->atomNVClassName;
3289
3290 if (WindowMatches && ClassMatches)
3291 {
3292 Ret = UserHMGetHandle(TopLevelWindow);
3293 break;
3294 }
3295
3296 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
3297 {
3298 /* window returns the handle of the top-level window, in case it found
3299 the child window */
3300 Ret = UserHMGetHandle(TopLevelWindow);
3301 break;
3302 }
3303
3304 }
3306 }
3307 }
3308 else
3309 {
3310 TRACE("FindWindowEx: Not Desktop Parent!\n");
3311 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
3312 }
3313
3314 if (Ret == NULL && DoMessageWnd)
3315 {
3316 PWND MsgWindows;
3317
3318 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3319 {
3320 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3321 }
3322 }
3323 }
3325 {
3327 Ret = NULL;
3328 }
3329 _SEH2_END;
3330
3331Exit:
3332 TRACE("Leave NtUserFindWindowEx, ret %p\n", Ret);
3333 UserLeave();
3334 return Ret;
3335}
3336
3337
3338/*
3339 * @implemented
3340 */
3342{
3343 PWND WndAncestor, Parent;
3344
3346 {
3347 return NULL;
3348 }
3349
3350 switch (Type)
3351 {
3352 case GA_PARENT:
3353 {
3354 WndAncestor = Wnd->spwndParent;
3355 break;
3356 }
3357
3358 case GA_ROOT:
3359 {
3360 WndAncestor = Wnd;
3361 Parent = NULL;
3362
3363 for(;;)
3364 {
3365 if(!(Parent = WndAncestor->spwndParent))
3366 {
3367 break;
3368 }
3370 {
3371 break;
3372 }
3373
3374 WndAncestor = Parent;
3375 }
3376 break;
3377 }
3378
3379 case GA_ROOTOWNER:
3380 {
3381 WndAncestor = Wnd;
3382
3383 for (;;)
3384 {
3385 Parent = IntGetParent(WndAncestor);
3386
3387 if (!Parent)
3388 {
3389 break;
3390 }
3391
3392 WndAncestor = Parent;
3393 }
3394 break;
3395 }
3396
3397 default:
3398 {
3399 return NULL;
3400 }
3401 }
3402
3403 return WndAncestor;
3404}
3405
3406/*
3407 * @implemented
3408 */
3411{
3412 PWND Window, Ancestor;
3413 HWND Ret = NULL;
3414
3415 TRACE("Enter NtUserGetAncestor\n");
3417
3419 if (Window)
3420 {
3421 Ancestor = UserGetAncestor(Window, Type);
3422 /* fixme: can UserGetAncestor ever return NULL for a valid window? */
3423
3424 Ret = (Ancestor ? UserHMGetHandle(Ancestor) : NULL);
3425 }
3426
3427 TRACE("Leave NtUserGetAncestor, ret=%p\n", Ret);
3428 UserLeave();
3429 return Ret;
3430}
3431
3435/* combo state struct */
3436typedef struct
3437{
3438 HWND self;
3439 HWND owner;
3440 UINT dwStyle;
3441 HWND hWndEdit;
3442 HWND hWndLBox;
3443 UINT wState;
3444 HFONT hFont;
3445 RECT textRect;
3446 RECT buttonRect;
3447 RECT droppedRect;
3448 INT droppedIndex;
3449 INT fixedOwnerDrawHeight;
3450 INT droppedWidth; /* last two are not used unless set */
3451 INT editHeight; /* explicitly */
3454
3455// Window Extra data container.
3456typedef struct _WND2CBOX
3457{
3461
3462#define CBF_BUTTONDOWN 0x0002
3466BOOL
3469 HWND hWnd,
3470 PCOMBOBOXINFO pcbi)
3471{
3472 PWND Wnd;
3473 PPROCESSINFO ppi;
3474 BOOL NotSameppi = FALSE;
3475 BOOL Ret = TRUE;
3476
3477 TRACE("Enter NtUserGetComboBoxInfo\n");
3479
3480 if (!(Wnd = UserGetWindowObject(hWnd)))
3481 {
3482 Ret = FALSE;
3483 goto Exit;
3484 }
3485 _SEH2_TRY
3486 {
3487 ProbeForWrite(pcbi, sizeof(COMBOBOXINFO), 1);
3488 }
3490 {
3492 Ret = FALSE;
3493 _SEH2_YIELD(goto Exit);
3494 }
3495 _SEH2_END;
3496
3497 if (pcbi->cbSize < sizeof(COMBOBOXINFO))
3498 {
3500 Ret = FALSE;
3501 goto Exit;
3502 }
3503
3504 // Pass the user pointer, it was already probed.
3506 {
3508 goto Exit;
3509 }
3510
3512 NotSameppi = ppi != Wnd->head.pti->ppi;
3513 if (NotSameppi)
3514 {
3515 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3516 }
3517
3518 _SEH2_TRY
3519 {
3520 LPHEADCOMBO lphc = ((PWND2CBOX)Wnd)->pCBox;
3521 pcbi->rcItem = lphc->textRect;
3522 pcbi->rcButton = lphc->buttonRect;
3523 pcbi->stateButton = 0;
3524 if (lphc->wState & CBF_BUTTONDOWN)
3526 if (RECTL_bIsEmptyRect(&lphc->buttonRect))
3528 pcbi->hwndCombo = lphc->self;
3529 pcbi->hwndItem = lphc->hWndEdit;
3530 pcbi->hwndList = lphc->hWndLBox;
3531 }
3533 {
3534 Ret = FALSE;
3536 }
3537 _SEH2_END;
3538
3539Exit:
3540 if (NotSameppi) KeDetachProcess();
3541 TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n", Ret);
3542 UserLeave();
3543 return Ret;
3544}
3545
3549/* Listbox structure */
3550typedef struct
3551{
3552 HWND self; /* Our own window handle */
3553 HWND owner; /* Owner window to send notifications to */
3554 UINT style; /* Window style */
3555 INT width; /* Window width */
3556 INT height; /* Window height */
3557 VOID *items; /* Array of items */
3558 INT nb_items; /* Number of items */
3559 INT top_item; /* Top visible item */
3560 INT selected_item; /* Selected item */
3561 INT focus_item; /* Item that has the focus */
3562 INT anchor_item; /* Anchor item for extended selection */
3563 INT item_height; /* Default item height */
3564 INT page_size; /* Items per listbox page */
3565 INT column_width; /* Column width for multi-column listboxes */
3566} LB_DESCR;
3567
3568// Window Extra data container.
3569typedef struct _WND2LB
3570{
3577DWORD
3580 HWND hWnd)
3581{
3582 PWND Wnd;
3583 PPROCESSINFO ppi;
3584 BOOL NotSameppi = FALSE;
3585 DWORD Ret = 0;
3586
3587 TRACE("Enter NtUserGetListBoxInfo\n");
3589
3590 if (!(Wnd = UserGetWindowObject(hWnd)))
3591 {
3592 goto Exit; // Return 0
3593 }
3594
3595 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && Wnd->fnid != FNID_LISTBOX)
3596 {
3598 goto Exit;
3599 }
3600
3601 // wine lisbox:test_GetListBoxInfo lb_getlistboxinfo = 0, should not send a message!
3603 NotSameppi = ppi != Wnd->head.pti->ppi;
3604 if (NotSameppi)
3605 {
3606 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3607 }
3608
3609 _SEH2_TRY
3610 {
3611 LB_DESCR *descr = ((PWND2LB)Wnd)->pLBiv;
3612 // See Controls ListBox.c:LB_GETLISTBOXINFO must match...
3613 Ret = descr->page_size;
3614 }
3616 {
3617 Ret = 0;
3619 }
3620 _SEH2_END;
3621
3622Exit:
3623 if (NotSameppi) KeDetachProcess();
3624 TRACE("Leave NtUserGetListBoxInfo, ret=%lu\n", Ret);
3625 UserLeave();
3626 return Ret;
3627}
3628
3629/*
3630 * NtUserSetParent
3631 *
3632 * The NtUserSetParent function changes the parent window of the specified
3633 * child window.
3634 *
3635 * Remarks
3636 * The new parent window and the child window must belong to the same
3637 * application. If the window identified by the hWndChild parameter is
3638 * visible, the system performs the appropriate redrawing and repainting.
3639 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3640 * or WS_POPUP window styles of the window whose parent is being changed.
3641 *
3642 * Status
3643 * @implemented
3644 */
3645
3648{
3649 HWND Ret;
3650
3651 TRACE("Enter NtUserSetParent\n");
3653
3654 /*
3655 Check Parent first from user space, set it here.
3656 */
3657 if (!hWndNewParent)
3658 {
3659 hWndNewParent = IntGetDesktopWindow();
3660 }
3661 else if (hWndNewParent == HWND_MESSAGE)
3662 {
3663 hWndNewParent = IntGetMessageWindow();
3664 }
3665
3666 Ret = co_UserSetParent(hWndChild, hWndNewParent);
3667
3668 TRACE("Leave NtUserSetParent, ret=%p\n", Ret);
3669 UserLeave();
3670 return Ret;
3671}
3672
3673/*
3674 * UserGetShellWindow
3675 *
3676 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3677 *
3678 * Status
3679 * @implemented
3680 */
3682{
3683 PWINSTATION_OBJECT WinStaObject;
3684 HWND Ret;
3685
3687 UserMode,
3688 0,
3689 &WinStaObject,
3690 0);
3691
3692 if (!NT_SUCCESS(Status))
3693 {
3695 return NULL;
3696 }
3697
3698 Ret = (HWND)WinStaObject->ShellWindow;
3699
3700 ObDereferenceObject(WinStaObject);
3701 return Ret;
3702}
3703
3704/*
3705 * NtUserSetShellWindowEx
3706 *
3707 * This is undocumented function to set global shell window. The global
3708 * shell window has special handling of window position.
3709 *
3710 * Status
3711 * @implemented
3712 */
3715{
3716 PWINSTATION_OBJECT WinStaObject;
3717 PWND WndShell, WndListView;
3718 BOOL Ret = FALSE;
3721 PTHREADINFO ti;
3722
3723 TRACE("Enter NtUserSetShellWindowEx\n");
3725
3726 if (!(WndShell = UserGetWindowObject(hwndShell)))
3727 {
3728 goto Exit; // Return FALSE
3729 }
3730
3731 if (!(WndListView = UserGetWindowObject(hwndListView)))
3732 {
3733 goto Exit; // Return FALSE
3734 }
3735
3737 UserMode,
3738 0,
3739 &WinStaObject,
3740 0);
3741
3742 if (!NT_SUCCESS(Status))
3743 {
3745 goto Exit; // Return FALSE
3746 }
3747
3748 /*
3749 * Test if we are permitted to change the shell window.
3750 */
3751 if (WinStaObject->ShellWindow)
3752 {
3753 ObDereferenceObject(WinStaObject);
3754 goto Exit; // Return FALSE
3755 }
3756
3757 /*
3758 * Move shell window into background.
3759 */
3760 if (hwndListView && hwndListView != hwndShell)
3761 {
3762 /*
3763 * Disabled for now to get Explorer working.
3764 * -- Filip, 01/nov/2003
3765 */
3766#if 0
3768#endif
3769
3770 if (WndListView->ExStyle & WS_EX_TOPMOST)
3771 {
3772 ObDereferenceObject(WinStaObject);
3773 goto Exit; // Return FALSE
3774 }
3775 }
3776
3777 if (WndShell->ExStyle & WS_EX_TOPMOST)
3778 {
3779 ObDereferenceObject(WinStaObject);
3780 goto Exit; // Return FALSE
3781 }
3782
3783 UserRefObjectCo(WndShell, &Ref);
3784 WndShell->state2 |= WNDS2_BOTTOMMOST;
3786
3787 WinStaObject->ShellWindow = hwndShell;
3788 WinStaObject->ShellListView = hwndListView;
3789
3790 ti = GetW32ThreadInfo();
3791 if (ti->pDeskInfo)
3792 {
3793 ti->pDeskInfo->hShellWindow = hwndShell;
3794 ti->pDeskInfo->spwndShell = WndShell;
3795 ti->pDeskInfo->spwndBkGnd = WndListView;
3796 ti->pDeskInfo->ppiShellProcess = ti->ppi;
3797 }
3798
3800
3801 UserDerefObjectCo(WndShell);
3802
3803 ObDereferenceObject(WinStaObject);
3804 Ret = TRUE;
3805
3806Exit:
3807 TRACE("Leave NtUserSetShellWindowEx, ret=%i\n", Ret);
3808 UserLeave();
3809 return Ret;
3810}
3811
3812// Fixes wine Win test_window_styles and todo tests...
3813static BOOL FASTCALL
3815{
3817 return TRUE;
3818 else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME)))
3819 return TRUE;
3820 else
3821 return FALSE;
3822}
3823
3824static LONG_PTR
3826{
3828 PWINSTATION_OBJECT WindowStation;
3829 LONG_PTR OldValue;
3831
3833 {
3834 return 0;
3835 }
3836
3837 if ((INT)Index >= 0)
3838 {
3839 if ((Index + Size) > Window->cbwndExtra)
3840 {
3842 return 0;
3843 }
3844
3845#ifdef _WIN64
3846 if (Size == sizeof(LONG))
3847 {
3848 OldValue = *((LONG *)((PCHAR)(Window + 1) + Index));
3849 *((LONG*)((PCHAR)(Window + 1) + Index)) = (LONG)NewValue;
3850 }
3851 else
3852#endif
3853 {
3854 OldValue = *((LONG_PTR *)((PCHAR)(Window + 1) + Index));
3855 /*
3856 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3857 {
3858 OldValue = (LONG_PTR)IntSetWindowProc( Wnd, (WNDPROC)NewValue, Ansi);
3859 if (!OldValue) return 0;
3860 }
3861 */
3862 *((LONG_PTR*)((PCHAR)(Window + 1) + Index)) = NewValue;
3863 }
3864
3865 }
3866 else
3867 {
3868#ifdef _WIN64
3869 if (Size == sizeof(LONG))
3870 {
3871 if ((Index != GWL_STYLE) &&
3872 (Index != GWL_EXSTYLE) &&
3873 (Index != GWL_ID) &&
3874 (Index != GWL_USERDATA))
3875 {
3876 ERR("NtUserSetWindowLong(): Index requires pointer size: %lu\n", Index);
3878 return 0;
3879 }
3880 }
3881#endif
3882
3883 switch (Index)
3884 {
3885 case GWL_EXSTYLE: // LONG
3886 OldValue = (LONG) Window->ExStyle;
3887 Style.styleOld = OldValue;
3888 Style.styleNew = NewValue;
3889
3890 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3891
3892 /*
3893 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3894 */
3895 WindowStation = Window->head.pti->rpdesk->rpwinstaParent;
3896 if(WindowStation)
3897 {
3898 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3899 Style.styleNew &= ~WS_EX_TOPMOST;
3900 }
3901 /* WS_EX_WINDOWEDGE depends on some other styles */
3902 if (IntCheckFrameEdge(Window->style, NewValue))
3903 Style.styleNew |= WS_EX_WINDOWEDGE;
3904 else
3905 Style.styleNew &= ~WS_EX_WINDOWEDGE;
3906
3907 if (!(Window->ExStyle & WS_EX_LAYERED))
3908 {
3910 }
3911
3912 Window->ExStyle = (DWORD)Style.styleNew;
3913
3914 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3915 break;
3916
3917 case GWL_STYLE: // LONG
3918 OldValue = (LONG) Window->style;
3919 Style.styleOld = OldValue;
3920 Style.styleNew = NewValue;
3921
3922 if (!bAlter)
3923 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3924
3925 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
3926 if (UserIsDesktopWindow(Window->spwndParent)) Style.styleNew |= WS_CLIPSIBLINGS;
3927 /* WS_MINIMIZE can't be reset */
3928 if (OldValue & WS_MINIMIZE) Style.styleNew |= WS_MINIMIZE;
3929 /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */
3930 if (IntCheckFrameEdge(NewValue, Window->ExStyle))
3931 Window->ExStyle |= WS_EX_WINDOWEDGE;
3932 else
3933 Window->ExStyle &= ~WS_EX_WINDOWEDGE;
3934
3935 if ((OldValue & (WS_CHILD | WS_POPUP)) == WS_CHILD)
3936 {
3937 if ((NewValue & (WS_CHILD | WS_POPUP)) != WS_CHILD)
3938 {
3940 ERR("IDMenu going null! %d\n",Window->IDMenu);
3941 Window->IDMenu = 0; // Window->spmenu = 0;
3942 }
3943 }
3944 else
3945 {
3946 if ((NewValue & (WS_CHILD | WS_POPUP)) == WS_CHILD)
3947 {
3948 PMENU pMenu = UserGetMenuObject(UlongToHandle(Window->IDMenu));
3949 Window->state &= ~WNDS_HASMENU;
3950 if (pMenu)
3951 {
3952 ERR("IDMenu released 0x%p\n",pMenu);
3953 // ROS may not hold a lock after setting menu to window. But it should!
3954 //IntReleaseMenuObject(pMenu);
3955 }
3956 }
3957 }
3958
3959 if ((Style.styleOld ^ Style.styleNew) & WS_VISIBLE)
3960 {
3961 if (Style.styleOld & WS_VISIBLE) Window->head.pti->cVisWindows--;
3962 if (Style.styleNew & WS_VISIBLE) Window->head.pti->cVisWindows++;
3964 }
3965 Window->style = (DWORD)Style.styleNew;
3966
3967 if (!bAlter)
3968 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3969 break;
3970
3971 case GWLP_WNDPROC: // LONG_PTR
3972 {
3973 if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
3974 Window->fnid & FNID_FREED)
3975 {
3977 return 0;
3978 }
3979 OldValue = (LONG_PTR)IntSetWindowProc(Window,
3980 (WNDPROC)NewValue,
3981 Ansi);
3982 break;
3983 }
3984
3985 case GWLP_HINSTANCE: // LONG_PTR
3986 OldValue = (LONG_PTR) Window->hModule;
3987 Window->hModule = (HINSTANCE) NewValue;
3988 break;
3989
3990 case GWLP_HWNDPARENT: // LONG_PTR
3991 Parent = Window->spwndParent;
3993 OldValue = (LONG_PTR)IntSetOwner(UserHMGetHandle(Window), (HWND)NewValue);
3994 else
3995 OldValue = (LONG_PTR)co_UserSetParent(UserHMGetHandle(Window), (HWND)NewValue);
3996 break;
3997
3998 case GWLP_ID: // LONG
3999 OldValue = (LONG) Window->IDMenu;
4000 Window->IDMenu = (UINT) NewValue;
4001 break;
4002
4003 case GWLP_USERDATA: // LONG or LONG_PTR
4004 OldValue = Window->dwUserData;
4005 Window->dwUserData = NewValue;
4006 break;
4007
4008 default:
4009 ERR("NtUserSetWindowLong(): Unsupported index %lu\n", Index);
4011 OldValue = 0;
4012 break;
4013 }
4014 }
4015
4016 return OldValue;
4017}
4018
4021{
4022 return (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE);
4023}
4024
4027{
4028 return co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE);
4029}
4030
4031/*
4032 * NtUserSetWindowLong
4033 *
4034 * The NtUserSetWindowLong function changes an attribute of the specified
4035 * window. The function also sets the 32-bit (long) value at the specified
4036 * offset into the extra window memory.
4037 *
4038 * Status
4039 * @implemented
4040 */
4041
4044{
4045 LONG ret;
4046
4048
4049 if (hWnd == IntGetDesktopWindow())
4050 {
4052 UserLeave();
4053 return 0;
4054 }
4055
4056 ret = (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE);
4057
4058 UserLeave();
4059
4060 return ret;
4061}
4062
4063#ifdef _WIN64
4066{
4067 LONG_PTR ret;
4068
4070
4071 if (hWnd == IntGetDesktopWindow())
4072 {
4074 UserLeave();
4075 return 0;
4076 }
4077
4078 ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE);
4079
4080 UserLeave();
4081
4082 return ret;
4083}
4084#endif // _WIN64
4085
4088{
4089 LONG ret;
4090
4092
4093 if (hWnd == IntGetDesktopWindow())
4094 {
4096 UserLeave();
4097 return 0;
4098 }
4099
4100 ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, FALSE, sizeof(LONG), TRUE);
4101
4102 UserLeave();
4103
4104 return ret;
4105}
4106
4107
4108/*
4109 * NtUserSetWindowWord
4110 *
4111 * Legacy function similar to NtUserSetWindowLong.
4112 *
4113 * Status
4114 * @implemented
4115 */
4116
4119{
4120 PWND Window;
4121 WORD OldValue;
4122 WORD Ret = 0;
4123
4124 TRACE("Enter NtUserSetWindowWord\n");
4126
4127 if (hWnd == IntGetDesktopWindow())
4128 {
4130 goto Exit; // Return 0
4131 }
4132
4134 {
4135 goto Exit; // Return 0
4136 }
4137
4138 switch (Index)
4139 {
4140 case GWL_ID:
4141 case GWL_HINSTANCE:
4142 case GWL_HWNDPARENT:
4144 goto Exit;
4145
4146 default:
4147 if (Index < 0)
4148 {
4150 goto Exit; // Return 0
4151 }
4152 }
4153
4154 if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD)))
4155 {
4157 goto Exit; // Return 0
4158 }
4159
4160 OldValue = *((WORD *)((PCHAR)(Window + 1) + Index));
4161 *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue;
4162
4163 Ret = OldValue;
4164
4165Exit:
4166 TRACE("Leave NtUserSetWindowWord, ret=%u\n", Ret);
4167 UserLeave();
4168 return Ret;
4169}
4170
4171/*
4172 QueryWindow based on KJK::Hyperion and James Tabor.
4173
4174 0 = QWUniqueProcessId
4175 1 = QWUniqueThreadId
4176 2 = QWActiveWindow
4177 3 = QWFocusWindow
4178 4 = QWIsHung Implements IsHungAppWindow found
4179 by KJK::Hyperion.
4180
4181 9 = QWKillWindow When I called this with hWnd ==
4182 DesktopWindow, it shutdown the system
4183 and rebooted.
4184*/
4185/*
4186 * @implemented
4187 */
4190{
4191/* Console Leader Process CID Window offsets */
4192#define GWLP_CONSOLE_LEADER_PID 0
4193#define GWLP_CONSOLE_LEADER_TID 4
4194
4195 DWORD_PTR Result = 0;
4196 PWND pWnd, pwndActive;
4197 PTHREADINFO pti, ptiActive;
4198
4199 TRACE("Enter NtUserQueryWindow\n");
4201
4202 if (!(pWnd = UserGetWindowObject(hWnd)))
4203 {
4204 goto Exit; // Return 0
4205 }
4206
4207 switch(Index)
4208 {
4210 {
4211 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
4213 {
4214 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_PID)
4215 Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_PID)));
4216 }
4217 else
4218 {
4220 }
4221 break;
4222 }
4223
4225 {
4226 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
4228 {
4229 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_TID)
4230 Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_TID)));
4231 }
4232 else
4233 {
4235 }
4236 break;
4237 }
4238
4240 Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndActive ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndActive) : 0);
4241 break;
4242
4243 case QUERY_WINDOW_FOCUS:
4244 Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndFocus ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndFocus) : 0);
4245 break;
4246
4248 Result = (pWnd->fnid == FNID_GHOST) || MsqIsHung(pWnd->head.pti, MSQ_HUNG);
4249 break;
4250
4252 Result = (DWORD_PTR)pWnd->head.pti->pEThread->Cid.UniqueProcess;
4253 break;
4254
4256 Result = (pWnd->head.pti->MessageQueue == gpqForeground);
4257 break;
4258
4259 case QUERY_WINDOW_DEFAULT_IME: /* default IME window */
4260 if (pWnd->head.pti->spwndDefaultIme)
4261 Result = (DWORD_PTR)UserHMGetHandle(pWnd->head.pti->spwndDefaultIme);
4262 break;
4263
4264 case QUERY_WINDOW_DEFAULT_ICONTEXT: /* default input context handle */
4265 if (pWnd->head.pti->spDefaultImc)
4266 Result = (DWORD_PTR)UserHMGetHandle(pWnd->head.pti->spDefaultImc);
4267 break;
4268
4271 {
4272 pwndActive = gpqForeground->spwndActive;
4274 if (pti->rpdesk == pwndActive->head.rpdesk)
4275 {
4276 ptiActive = pwndActive->head.pti;
4277 if (ptiActive->spwndDefaultIme)
4279 }
4280 }
4281 break;
4282 }
4283
4284Exit:
4285 TRACE("Leave NtUserQueryWindow, ret=%u\n", Result);
4286 UserLeave();
4287 return Result;
4288}
4289
4290/*
4291 * @implemented
4292 */
4295{
4296 UNICODE_STRING SafeMessageName;
4298 UINT Ret = 0;
4299
4300 TRACE("Enter NtUserRegisterWindowMessage\n");
4302
4303 if(MessageNameUnsafe == NULL)
4304 {
4306 goto Exit; // Return 0
4307 }
4308
4309 Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
4310 if(!NT_SUCCESS(Status))
4311 {
4313 goto Exit; // Return 0
4314 }
4315
4316 Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
4317 if (SafeMessageName.Buffer)
4318 ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING);
4319
4320Exit:
4321 TRACE("Leave NtUserRegisterWindowMessage, ret=%u\n", Ret);
4322 UserLeave();
4323 return Ret;
4324}
4325
4326/*
4327 * @implemented
4328 */
4331 WORD fnID)
4332{
4333 PWND Wnd;
4334 BOOL Ret = FALSE;
4335
4336 TRACE("Enter NtUserSetWindowFNID\n");
4338
4339 if (!(Wnd = UserGetWindowObject(hWnd)))
4340 {
4341 goto Exit; // Return FALSE
4342 }
4343
4344 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
4345 {
4347 goto Exit; // Return FALSE
4348 }
4349
4350 // From user land we only set these.
4351 if (fnID != FNID_DESTROY)
4352 {
4353 /* HACK: The minimum should be FNID_BUTTON, but menu code relies on this */
4354 if (fnID < FNID_FIRST || fnID > FNID_GHOST ||
4355 Wnd->fnid != 0)
4356 {
4358 goto Exit; // Return FALSE
4359 }
4360 }
4361
4362 Wnd->fnid |= fnID;
4363 Ret = TRUE;
4364
4365Exit:
4366 TRACE("Leave NtUserSetWindowFNID\n");
4367 UserLeave();
4368 return Ret;
4369}
4370
4372DefSetText(PWND Wnd, PCWSTR WindowText)
4373{
4375 BOOL Ret = FALSE;
4376
4377 RtlInitUnicodeString(&UnicodeString, WindowText);
4378
4379 if (UnicodeString.Length != 0)
4380 {
4381 if (Wnd->strName.MaximumLength > 0 &&
4382 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4383 {
4384 ASSERT(Wnd->strName.Buffer != NULL);
4385
4386 Wnd->strName.Length = UnicodeString.Length;
4387 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4389 UnicodeString.Buffer,
4390 UnicodeString.Length);
4391 }
4392 else
4393 {
4394 PWCHAR buf;
4395 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4396 buf = Wnd->strName.Buffer;
4397 Wnd->strName.Buffer = NULL;
4398 if (buf != NULL)
4399 {
4401 }
4402
4404 UnicodeString.Length + sizeof(UNICODE_NULL));
4405 if (Wnd->strName.Buffer != NULL)
4406 {
4407 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4409 UnicodeString.Buffer,
4410 UnicodeString.Length);
4411 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4412 Wnd->strName.Length = UnicodeString.Length;
4413 }
4414 else
4415 {
4417 goto Exit;
4418 }
4419 }
4420 }
4421 else
4422 {
4423 Wnd->strName.Length = 0;
4424 if (Wnd->strName.Buffer != NULL)
4425 Wnd->strName.Buffer[0] = L'\0';
4426 }
4427
4428 // FIXME: HAX! Windows does not do this in here!
4429 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4430 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4431 /* Send shell notifications */
4432 if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4433 {
4434 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) UserHMGetHandle(Wnd), FALSE); // FIXME Flashing?
4435 }
4436
4437 Ret = TRUE;
4438Exit:
4440 return Ret;
4441}
4442
4443/*
4444 * NtUserDefSetText
4445 *
4446 * Undocumented function that is called from DefWindowProc to set
4447 * window text.
4448 *
4449 * Status
4450 * @implemented
4451 */
4454{
4455 PWND Wnd;
4456 LARGE_STRING SafeText;
4458 BOOL Ret = TRUE;
4459
4460 TRACE("Enter NtUserDefSetText\n");
4461
4462 if (WindowText != NULL)
4463 {
4464 _SEH2_TRY
4465 {
4466 SafeText = ProbeForReadLargeString(WindowText);
4467 }
4469 {
4470 Ret = FALSE;
4472 }
4473 _SEH2_END;
4474
4475 if (!Ret)
4476 return FALSE;
4477 }
4478 else
4479 return TRUE;
4480
4482
4483 if(!(Wnd = UserGetWindowObject(hWnd)))
4484 {
4485 UserLeave();
4486 return FALSE;
4487 }
4488
4489 // ReactOS uses Unicode and not mixed. Up/Down converting will take time.
4490 // Brought to you by: The Wine Project! Dysfunctional Thought Processes!
4491 // Now we know what the bAnsi is for.
4493 if (SafeText.Buffer)
4494 {
4495 _SEH2_TRY
4496 {
4497 if (SafeText.bAnsi)
4498 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR));
4499 else
4500 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR));
4502 }
4504 {
4505 Ret = FALSE;
4507 }
4508 _SEH2_END;
4509 if (!Ret) goto Exit;
4510 }
4511
4512 if (UnicodeString.Length != 0)
4513 {
4514 if (Wnd->strName.MaximumLength > 0 &&
4515 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4516 {
4517 ASSERT(Wnd->strName.Buffer != NULL);
4518
4519 Wnd->strName.Length = UnicodeString.Length;
4520 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4522 UnicodeString.Buffer,
4523 UnicodeString.Length);
4524 }
4525 else
4526 {
4527 PWCHAR buf;
4528 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4529 buf = Wnd->strName.Buffer;
4530 Wnd->strName.Buffer = NULL;
4531 if (buf != NULL)
4532 {
4534 }
4535
4537 UnicodeString.Length + sizeof(UNICODE_NULL));
4538 if (Wnd->strName.Buffer != NULL)
4539 {
4540 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4542 UnicodeString.Buffer,
4543 UnicodeString.Length);
4544 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4545 Wnd->strName.Length = UnicodeString.Length;
4546 }
4547 else
4548 {
4550 Ret = FALSE;
4551 goto Exit;
4552 }
4553 }
4554 }
4555 else
4556 {
4557 Wnd->strName.Length = 0;
4558 if (Wnd->strName.Buffer != NULL)
4559 Wnd->strName.Buffer[0] = L'\0';
4560 }
4561
4562 // FIXME: HAX! Windows does not do this in here!
4563 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4564 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4565 /* Send shell notifications */
4566 if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4567 {
4568 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) hWnd, FALSE); // FIXME Flashing?
4569 }
4570
4571 Ret = TRUE;
4572Exit:
4574 TRACE("Leave NtUserDefSetText, ret=%i\n", Ret);
4575 UserLeave();
4576 return Ret;
4577}
4578
4579/*
4580 * NtUserInternalGetWindowText
4581 *
4582 * Status
4583 * @implemented
4584 */
4585
4588{
4589 PWND Wnd;
4591 INT Result = 0;
4592
4593 TRACE("Enter NtUserInternalGetWindowText\n");
4595
4596 if(lpString && (nMaxCount <= 1))
4597 {
4599 goto Exit; // Return 0
4600 }
4601
4602 if(!(Wnd = UserGetWindowObject(hWnd)))