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