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