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