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