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