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