a6df96b58476fc56cda06b392c4e9f5cd7a22a7a
[reactos.git] / reactos / subsys / win32k / ntuser / window.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: window.c,v 1.189 2004/02/22 15:14:27 navaraf Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Windows
24 * FILE: subsys/win32k/ntuser/window.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 06-06-2001 CSH Created
28 */
29 /* INCLUDES ******************************************************************/
30
31 #include <ddk/ntddk.h>
32 #include <internal/safe.h>
33 #include <win32k/win32k.h>
34 #include <include/object.h>
35 #include <include/guicheck.h>
36 #include <include/window.h>
37 #include <include/class.h>
38 #include <include/error.h>
39 #include <include/winsta.h>
40 #include <include/desktop.h>
41 #include <include/winpos.h>
42 #include <include/callback.h>
43 #include <include/msgqueue.h>
44 #include <include/rect.h>
45 #include <include/dce.h>
46 #include <include/paint.h>
47 #include <include/painting.h>
48 #include <include/scroll.h>
49 #include <include/vis.h>
50 #include <include/menu.h>
51 #include <include/hotkey.h>
52 #include <include/focus.h>
53 #include <include/hook.h>
54 #include <include/useratom.h>
55 #include <include/tags.h>
56
57 #define NDEBUG
58 #include <win32k/debug1.h>
59 #include <debug.h>
60
61 static WndProcHandle *WndProcHandlesArray = 0;
62 static WORD WndProcHandlesArraySize = 0;
63 #define WPH_SIZE 0x40 /* the size to add to the WndProcHandle array each time */
64
65 #define POINT_IN_RECT(p, r) (((r.bottom >= p.y) && (r.top <= p.y))&&((r.left <= p.x )&&( r.right >= p.x )))
66
67 /* PRIVATE FUNCTIONS **********************************************************/
68
69 /*
70 * InitWindowImpl
71 *
72 * Initialize windowing implementation.
73 */
74
75 NTSTATUS FASTCALL
76 InitWindowImpl(VOID)
77 {
78 WndProcHandlesArray = ExAllocatePoolWithTag(PagedPool,WPH_SIZE * sizeof(WndProcHandle), TAG_WINPROCLST);
79 WndProcHandlesArraySize = WPH_SIZE;
80 return STATUS_SUCCESS;
81 }
82
83 /*
84 * CleanupWindowImpl
85 *
86 * Cleanup windowing implementation.
87 */
88
89 NTSTATUS FASTCALL
90 CleanupWindowImpl(VOID)
91 {
92 ExFreePool(WndProcHandlesArray);
93 WndProcHandlesArray = 0;
94 WndProcHandlesArraySize = 0;
95 return STATUS_SUCCESS;
96 }
97
98 /* HELPER FUNCTIONS ***********************************************************/
99
100 /*
101 * IntIsBroadcastHwnd
102 *
103 * Check if window is a broadcast.
104 *
105 * Return Value
106 * TRUE if window is broadcast, FALSE otherwise.
107 */
108
109 inline BOOL
110 IntIsBroadcastHwnd(HWND hWnd)
111 {
112 return (hWnd == HWND_BROADCAST || hWnd == HWND_TOPMOST);
113 }
114
115 /*
116 * IntIsDesktopWindow
117 *
118 * Check if window is a desktop. Desktop windows has no parent.
119 *
120 * Return Value
121 * TRUE if window is desktop, FALSE otherwise.
122 */
123
124 inline BOOL
125 IntIsDesktopWindow(PWINDOW_OBJECT Wnd)
126 {
127 return Wnd->Parent == NULL;
128 }
129
130 /*
131 * IntIsWindow
132 *
133 * The function determines whether the specified window handle identifies
134 * an existing window.
135 *
136 * Parameters
137 * hWnd
138 * Handle to the window to test.
139 *
140 * Return Value
141 * If the window handle identifies an existing window, the return value
142 * is TRUE. If the window handle does not identify an existing window,
143 * the return value is FALSE.
144 */
145
146 BOOL FASTCALL
147 IntIsWindow(HWND hWnd)
148 {
149 PWINDOW_OBJECT Window;
150
151 if (!(Window = IntGetWindowObject(hWnd)))
152 return FALSE;
153 else
154 IntReleaseWindowObject(Window);
155
156 return TRUE;
157 }
158
159 /*
160 * IntGetProcessWindowObject
161 *
162 * Get window object from handle of specified process.
163 */
164
165 PWINDOW_OBJECT FASTCALL
166 IntGetProcessWindowObject(PW32PROCESS ProcessData, HWND hWnd)
167 {
168 PWINDOW_OBJECT WindowObject;
169 NTSTATUS Status;
170
171 Status = ObmReferenceObjectByHandle(ProcessData->WindowStation->HandleTable,
172 hWnd, otWindow, (PVOID*)&WindowObject);
173 if (!NT_SUCCESS(Status))
174 {
175 return NULL;
176 }
177 return WindowObject;
178 }
179
180 /*
181 * IntGetWindowObject
182 *
183 * Get window object from handle of current process.
184 */
185
186 PWINDOW_OBJECT FASTCALL
187 IntGetWindowObject(HWND hWnd)
188 {
189 return IntGetProcessWindowObject(PsGetWin32Process(), hWnd);
190 }
191
192 /*
193 * IntReleaseWindowObject
194 *
195 * Release window object returned by IntGetWindowObject or
196 * IntGetProcessWindowObject.
197 */
198
199 VOID FASTCALL
200 IntReleaseWindowObject(PWINDOW_OBJECT Window)
201 {
202 ObmDereferenceObject(Window);
203 }
204
205 /*
206 * IntWinListChildren
207 *
208 * Compile a list of all child window handles from given window.
209 *
210 * Remarks
211 * This function is similar to Wine WIN_ListChildren. The caller
212 * must free the returned list with ExFreePool.
213 */
214
215 HWND* FASTCALL
216 IntWinListChildren(PWINDOW_OBJECT Window)
217 {
218 PWINDOW_OBJECT Child;
219 HWND *List;
220 UINT Index, NumChildren = 0;
221
222 ExAcquireFastMutexUnsafe(&Window->ChildrenListLock);
223
224 for (Child = Window->FirstChild; Child; Child = Child->NextSibling)
225 ++NumChildren;
226
227 if (NumChildren != 0)
228 {
229 List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), TAG_WINLIST);
230 if (List != NULL)
231 {
232 for (Child = Window->FirstChild, Index = 0;
233 Child != NULL;
234 Child = Child->NextSibling, ++Index)
235 List[Index] = Child->Self;
236 List[Index] = NULL;
237 }
238 else
239 {
240 DPRINT1("Failed to allocate memory for children array\n");
241 }
242 }
243
244 ExReleaseFastMutexUnsafe(&Window->ChildrenListLock);
245
246 return (NumChildren > 0) ? List : NULL;
247 }
248
249 /***********************************************************************
250 * IntSendDestroyMsg
251 */
252 static void IntSendDestroyMsg(HWND Wnd)
253 {
254 #if 0 /* FIXME */
255 GUITHREADINFO info;
256
257 if (GetGUIThreadInfo(GetCurrentThreadId(), &info))
258 {
259 if (Wnd == info.hwndCaret)
260 {
261 DestroyCaret();
262 }
263 }
264 #endif
265
266 /*
267 * Send the WM_DESTROY to the window.
268 */
269 IntSendMessage(Wnd, WM_DESTROY, 0, 0);
270
271 /*
272 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
273 * make sure that the window still exists when we come back.
274 */
275 #if 0 /* FIXME */
276 if (IsWindow(Wnd))
277 {
278 HWND* pWndArray;
279 int i;
280
281 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
282
283 /* start from the end (FIXME: is this needed?) */
284 for (i = 0; pWndArray[i]; i++) ;
285
286 while (--i >= 0)
287 {
288 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
289 }
290 HeapFree(GetProcessHeap(), 0, pWndArray);
291 }
292 else
293 {
294 DPRINT("destroyed itself while in WM_DESTROY!\n");
295 }
296 #endif
297 }
298
299 /***********************************************************************
300 * IntDestroyWindow
301 *
302 * Destroy storage associated to a window. "Internals" p.358
303 */
304 static LRESULT IntDestroyWindow(PWINDOW_OBJECT Window,
305 PW32PROCESS ProcessData,
306 PW32THREAD ThreadData,
307 BOOLEAN SendMessages)
308 {
309 HWND *Children;
310 HWND *ChildHandle;
311 PWINDOW_OBJECT Child;
312 PMENU_OBJECT Menu;
313
314 if (! IntWndBelongsToThread(Window, ThreadData))
315 {
316 return 0;
317 }
318
319 if(SendMessages)
320 {
321 /* Send destroy messages */
322 IntSendDestroyMsg(Window->Self);
323 }
324
325 /* free child windows */
326 Children = IntWinListChildren(Window);
327 if (Children)
328 {
329 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
330 {
331 Child = IntGetProcessWindowObject(ProcessData, *ChildHandle);
332 if (NULL != Child)
333 {
334 if(IntWndBelongsToThread(Child, ThreadData))
335 {
336 IntDestroyWindow(Child, ProcessData, ThreadData, SendMessages);
337 }
338 else
339 {
340 IntSendDestroyMsg(Child->Self);
341 IntDestroyWindow(Child, ProcessData, Child->OwnerThread->Win32Thread, FALSE);
342 }
343 IntReleaseWindowObject(Child);
344 }
345 }
346 ExFreePool(Children);
347 }
348
349 if (SendMessages)
350 {
351 /*
352 * Clear the update region to make sure no WM_PAINT messages will be
353 * generated for this window while processing the WM_NCDESTROY.
354 */
355 IntRedrawWindow(Window, NULL, 0,
356 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
357 RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
358
359 /*
360 * Send the WM_NCDESTROY to the window being destroyed.
361 */
362 IntSendMessage(Window->Self, WM_NCDESTROY, 0, 0);
363 }
364
365 /* reset shell window handles */
366 if(ProcessData->WindowStation)
367 {
368 if (Window->Self == ProcessData->WindowStation->ShellWindow)
369 ProcessData->WindowStation->ShellWindow = NULL;
370
371 if (Window->Self == ProcessData->WindowStation->ShellListView)
372 ProcessData->WindowStation->ShellListView = NULL;
373 }
374
375 /* Unregister hot keys */
376 UnregisterWindowHotKeys (Window);
377
378 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
379
380 #if 0 /* FIXME */
381 WinPosCheckInternalPos(Window->Self);
382 if (Window->Self == GetCapture())
383 {
384 ReleaseCapture();
385 }
386
387 /* free resources associated with the window */
388 TIMER_RemoveWindowTimers(Window->Self);
389 #endif
390
391 if (!(Window->Style & WS_CHILD) && Window->IDMenu
392 && (Menu = IntGetMenuObject((HMENU)Window->IDMenu)))
393 {
394 IntDestroyMenuObject(Menu, TRUE, TRUE);
395 Window->IDMenu = 0;
396 IntReleaseMenuObject(Menu);
397 }
398
399 if(Window->SystemMenu
400 && (Menu = IntGetMenuObject(Window->SystemMenu)))
401 {
402 IntDestroyMenuObject(Menu, TRUE, TRUE);
403 Window->SystemMenu = (HMENU)0;
404 IntReleaseMenuObject(Menu);
405 }
406
407 DceFreeWindowDCE(Window); /* Always do this to catch orphaned DCs */
408 #if 0 /* FIXME */
409 WINPROC_FreeProc(Window->winproc, WIN_PROC_WINDOW);
410 CLASS_RemoveWindow(Window->Class);
411 #endif
412
413 if (Window->Parent)
414 {
415 PWINDOW_OBJECT Parent = Window->Parent;
416 ExAcquireFastMutexUnsafe(&Parent->ChildrenListLock);
417 IntUnlinkWindow(Window);
418 ExReleaseFastMutexUnsafe(&Parent->ChildrenListLock);
419 }
420
421 ExAcquireFastMutexUnsafe (&ThreadData->WindowListLock);
422 RemoveEntryList(&Window->ThreadListEntry);
423 ExReleaseFastMutexUnsafe (&ThreadData->WindowListLock);
424
425 IntDestroyScrollBar(Window, SB_VERT);
426 IntDestroyScrollBar(Window, SB_HORZ);
427
428 ObmDereferenceObject(Window->Class);
429 Window->Class = NULL;
430 ObmCloseHandle(ProcessData->WindowStation->HandleTable, Window->Self);
431
432 return 0;
433 }
434
435 static BOOL FASTCALL
436 IntSetMenu(
437 PWINDOW_OBJECT WindowObject,
438 HMENU Menu,
439 BOOL *Changed)
440 {
441 PMENU_OBJECT OldMenuObject, NewMenuObject;
442
443 *Changed = (WindowObject->IDMenu != (UINT) Menu);
444 if (! *Changed)
445 {
446 return TRUE;
447 }
448
449 if (0 != WindowObject->IDMenu)
450 {
451 OldMenuObject = IntGetMenuObject((HMENU) WindowObject->IDMenu);
452 ASSERT(NULL == OldMenuObject || OldMenuObject->MenuInfo.Wnd == WindowObject->Self);
453 }
454 else
455 {
456 OldMenuObject = NULL;
457 }
458
459 if (NULL != Menu)
460 {
461 NewMenuObject = IntGetMenuObject(Menu);
462 if (NULL == NewMenuObject)
463 {
464 if (NULL != OldMenuObject)
465 {
466 IntReleaseMenuObject(OldMenuObject);
467 }
468 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
469 return FALSE;
470 }
471 if (NULL != NewMenuObject->MenuInfo.Wnd)
472 {
473 /* Can't use the same menu for two windows */
474 if (NULL != OldMenuObject)
475 {
476 IntReleaseMenuObject(OldMenuObject);
477 }
478 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
479 return FALSE;
480 }
481
482 }
483
484 WindowObject->IDMenu = (UINT) Menu;
485 if (NULL != NewMenuObject)
486 {
487 NewMenuObject->MenuInfo.Wnd = WindowObject->Self;
488 IntReleaseMenuObject(NewMenuObject);
489 }
490 if (NULL != OldMenuObject)
491 {
492 OldMenuObject->MenuInfo.Wnd = NULL;
493 IntReleaseMenuObject(OldMenuObject);
494 }
495
496 return TRUE;
497 }
498
499
500 /* INTERNAL ******************************************************************/
501
502
503 VOID FASTCALL
504 DestroyThreadWindows(struct _ETHREAD *Thread)
505 {
506 PLIST_ENTRY LastHead;
507 PW32PROCESS Win32Process;
508 PW32THREAD Win32Thread;
509 PWINDOW_OBJECT Window;
510
511 Win32Thread = Thread->Win32Thread;
512 Win32Process = Thread->ThreadsProcess->Win32Process;
513 ExAcquireFastMutexUnsafe(&Win32Thread->WindowListLock);
514 LastHead = NULL;
515 while (Win32Thread->WindowListHead.Flink != &(Win32Thread->WindowListHead) &&
516 Win32Thread->WindowListHead.Flink != LastHead)
517 {
518 LastHead = Win32Thread->WindowListHead.Flink;
519 Window = CONTAINING_RECORD(Win32Thread->WindowListHead.Flink, WINDOW_OBJECT, ThreadListEntry);
520 ExReleaseFastMutexUnsafe(&Win32Thread->WindowListLock);
521 WinPosShowWindow(Window->Self, SW_HIDE);
522 IntDestroyWindow(Window, Win32Process, Win32Thread, FALSE);
523 ExAcquireFastMutexUnsafe(&Win32Thread->WindowListLock);
524 }
525 if (Win32Thread->WindowListHead.Flink == LastHead)
526 {
527 /* Window at head of list was not removed, should never happen, infinite loop */
528 KEBUGCHECK(0);
529 }
530 ExReleaseFastMutexUnsafe(&Win32Thread->WindowListLock);
531 }
532
533
534 /*!
535 * Internal function.
536 * Returns client window rectangle relative to the upper-left corner of client area.
537 *
538 * \note Does not check the validity of the parameters
539 */
540 VOID FASTCALL
541 IntGetClientRect(PWINDOW_OBJECT WindowObject, PRECT Rect)
542 {
543 ASSERT( WindowObject );
544 ASSERT( Rect );
545
546 Rect->left = Rect->top = 0;
547 Rect->right = WindowObject->ClientRect.right - WindowObject->ClientRect.left;
548 Rect->bottom =
549 WindowObject->ClientRect.bottom - WindowObject->ClientRect.top;
550 }
551
552
553 #if 0
554 HWND FASTCALL
555 IntGetFocusWindow(VOID)
556 {
557 PUSER_MESSAGE_QUEUE Queue;
558 PDESKTOP_OBJECT pdo = IntGetActiveDesktop();
559
560 if( !pdo )
561 return NULL;
562
563 Queue = (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
564
565 if (Queue == NULL)
566 return(NULL);
567 else
568 return(Queue->FocusWindow);
569 }
570 #endif
571
572 PWINDOW_OBJECT FASTCALL
573 IntGetParent(PWINDOW_OBJECT Wnd)
574 {
575 if (Wnd->Style & WS_POPUP)
576 {
577 return Wnd->Owner;
578 }
579 else if (Wnd->Style & WS_CHILD)
580 {
581 return Wnd->Parent;
582 }
583
584 return NULL;
585 }
586
587
588
589 PMENU_OBJECT FASTCALL
590 IntGetSystemMenu(PWINDOW_OBJECT WindowObject, BOOL bRevert, BOOL RetMenu)
591 {
592 PMENU_OBJECT MenuObject, NewMenuObject, ret = NULL;
593 PW32PROCESS W32Process;
594 HMENU NewMenu;
595
596 if(bRevert)
597 {
598 W32Process = PsGetWin32Process();
599
600 if(!W32Process->WindowStation)
601 return NULL;
602
603 if(WindowObject->SystemMenu)
604 {
605 MenuObject = IntGetMenuObject(WindowObject->SystemMenu);
606 if(MenuObject)
607 {
608 IntDestroyMenuObject(MenuObject, FALSE, TRUE);
609 WindowObject->SystemMenu = (HMENU)0;
610 IntReleaseMenuObject(MenuObject);
611 }
612 }
613
614 if(W32Process->WindowStation->SystemMenuTemplate)
615 {
616 /* clone system menu */
617 MenuObject = IntGetMenuObject(W32Process->WindowStation->SystemMenuTemplate);
618 if(!MenuObject)
619 return NULL;
620
621 NewMenuObject = IntCloneMenu(MenuObject);
622 if(NewMenuObject)
623 {
624 WindowObject->SystemMenu = NewMenuObject->MenuInfo.Self;
625 NewMenuObject->MenuInfo.Flags |= MF_SYSMENU;
626 ret = NewMenuObject;
627 //IntReleaseMenuObject(NewMenuObject);
628 }
629 IntReleaseMenuObject(MenuObject);
630 }
631 else
632 {
633 NewMenu = IntLoadSysMenuTemplate();
634 if(!NewMenu)
635 return NULL;
636 MenuObject = IntGetMenuObject(NewMenu);
637 if(!MenuObject)
638 return NULL;
639
640 NewMenuObject = IntCloneMenu(MenuObject);
641 if(NewMenuObject)
642 {
643 WindowObject->SystemMenu = NewMenuObject->MenuInfo.Self;
644 NewMenuObject->MenuInfo.Flags |= MF_SYSMENU;
645 ret = NewMenuObject;
646 //IntReleaseMenuObject(NewMenuObject);
647 }
648 IntDestroyMenuObject(MenuObject, FALSE, TRUE);
649 IntReleaseMenuObject(MenuObject);
650 }
651 if(RetMenu)
652 return ret;
653 else
654 return NULL;
655 }
656 else
657 {
658 if(WindowObject->SystemMenu)
659 return IntGetMenuObject((HMENU)WindowObject->SystemMenu);
660 else
661 return NULL;
662 }
663 }
664
665
666
667 DWORD FASTCALL
668 IntGetWindowThreadProcessId(PWINDOW_OBJECT Wnd, PDWORD pid)
669 {
670 if (pid) *pid = (DWORD) Wnd->OwnerThread->ThreadsProcess->UniqueProcessId;
671 return (DWORD) Wnd->OwnerThread->Cid.UniqueThread;
672 }
673
674 BOOL FASTCALL
675 IntIsChildWindow(HWND Parent, HWND Child)
676 {
677 PWINDOW_OBJECT BaseWindow = IntGetWindowObject(Child);
678 PWINDOW_OBJECT Window = BaseWindow;
679 while (Window != NULL && Window->Style & WS_CHILD)
680 {
681 if (Window->Self == Parent)
682 {
683 IntReleaseWindowObject(BaseWindow);
684 return(TRUE);
685 }
686 Window = Window->Parent;
687 }
688 IntReleaseWindowObject(BaseWindow);
689 return(FALSE);
690 }
691
692 BOOL FASTCALL
693 IntIsWindowVisible(HWND Wnd)
694 {
695 PWINDOW_OBJECT BaseWindow = IntGetWindowObject(Wnd);
696 PWINDOW_OBJECT Window = BaseWindow;
697 BOOLEAN Result = FALSE;
698 while (Window != NULL && Window->Style & WS_CHILD)
699 {
700 if (!(Window->Style & WS_VISIBLE))
701 {
702 IntReleaseWindowObject(BaseWindow);
703 return(FALSE);
704 }
705 Window = Window->Parent;
706 }
707 if (Window != NULL && Window->Style & WS_VISIBLE)
708 {
709 Result = TRUE;
710 }
711 IntReleaseWindowObject(BaseWindow);
712 return(Result);
713 }
714
715
716 /* link the window into siblings and parent. children are kept in place. */
717 VOID FASTCALL
718 IntLinkWindow(
719 PWINDOW_OBJECT Wnd,
720 PWINDOW_OBJECT WndParent,
721 PWINDOW_OBJECT WndPrevSibling /* set to NULL if top sibling */
722 )
723 {
724 Wnd->Parent = WndParent;
725
726 if ((Wnd->PrevSibling = WndPrevSibling))
727 {
728 /* link after WndPrevSibling */
729 if ((Wnd->NextSibling = WndPrevSibling->NextSibling)) Wnd->NextSibling->PrevSibling = Wnd;
730 else if (Wnd->Parent->LastChild == WndPrevSibling) Wnd->Parent->LastChild = Wnd;
731 Wnd->PrevSibling->NextSibling = Wnd;
732 }
733 else
734 {
735 /* link at top */
736 if ((Wnd->NextSibling = WndParent->FirstChild)) Wnd->NextSibling->PrevSibling = Wnd;
737 else Wnd->Parent->LastChild = Wnd;
738 WndParent->FirstChild = Wnd;
739 }
740
741 }
742
743 HWND FASTCALL
744 IntSetOwner(HWND hWnd, HWND hWndNewOwner)
745 {
746 PWINDOW_OBJECT Wnd, WndOldOwner;
747 HWND ret;
748
749 Wnd = IntGetWindowObject(hWnd);
750 WndOldOwner = Wnd->Owner;
751 if (WndOldOwner)
752 {
753 ret = WndOldOwner->Self;
754 IntReleaseWindowObject(WndOldOwner);
755 }
756 else
757 {
758 ret = 0;
759 }
760 Wnd->Owner = IntGetWindowObject(hWndNewOwner);
761 IntReleaseWindowObject(Wnd);
762 return ret;
763 }
764
765 PWINDOW_OBJECT FASTCALL
766 IntSetParent(PWINDOW_OBJECT Wnd, PWINDOW_OBJECT WndNewParent)
767 {
768 PWINDOW_OBJECT WndOldParent;
769 HWND hWnd, hWndNewParent, hWndOldParent;
770 BOOL WasVisible;
771 BOOL MenuChanged;
772
773 hWnd = Wnd->Self;
774 hWndNewParent = WndNewParent->Self;
775
776 /*
777 * Windows hides the window first, then shows it again
778 * including the WM_SHOWWINDOW messages and all
779 */
780 WasVisible = WinPosShowWindow(hWnd, SW_HIDE);
781
782 /* Validate that window and parent still exist */
783 if (!IntIsWindow(hWnd) || !IntIsWindow(hWndNewParent))
784 return NULL;
785
786 /* Window must belong to current process */
787 if (Wnd->OwnerThread->ThreadsProcess != PsGetCurrentProcess())
788 return NULL;
789
790 WndOldParent = Wnd->Parent;
791 hWndOldParent = WndOldParent->Self;
792
793 if (WndNewParent != WndOldParent)
794 {
795 ExAcquireFastMutexUnsafe(&WndOldParent->ChildrenListLock);
796 IntUnlinkWindow(Wnd);
797 ExReleaseFastMutexUnsafe(&WndOldParent->ChildrenListLock);
798 ExAcquireFastMutexUnsafe(&WndNewParent->ChildrenListLock);
799 IntLinkWindow(Wnd, WndNewParent, NULL /*prev sibling*/);
800 ExReleaseFastMutexUnsafe(&WndNewParent->ChildrenListLock);
801
802 if (WndNewParent->Self != IntGetDesktopWindow()) /* a child window */
803 {
804 if (!(Wnd->Style & WS_CHILD))
805 {
806 //if ( Wnd->Menu ) DestroyMenu ( Wnd->menu );
807 IntSetMenu(Wnd, NULL, &MenuChanged);
808 }
809 }
810 }
811
812 /*
813 * SetParent additionally needs to make hwnd the topmost window
814 * in the x-order and send the expected WM_WINDOWPOSCHANGING and
815 * WM_WINDOWPOSCHANGED notification messages.
816 */
817 WinPosSetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0,
818 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (WasVisible ? SWP_SHOWWINDOW : 0));
819
820 /*
821 * FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
822 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE
823 */
824
825 /*
826 * Validate that the old parent still exist, since it migth have been
827 * destroyed during the last callbacks to user-mode
828 */
829 return !IntIsWindow(hWndOldParent) ? NULL : WndOldParent;
830 }
831
832 BOOL FASTCALL
833 IntSetSystemMenu(PWINDOW_OBJECT WindowObject, PMENU_OBJECT MenuObject)
834 {
835 PMENU_OBJECT OldMenuObject;
836 if(WindowObject->SystemMenu)
837 {
838 OldMenuObject = IntGetMenuObject(WindowObject->SystemMenu);
839 if(OldMenuObject)
840 {
841 OldMenuObject->MenuInfo.Flags &= ~ MF_SYSMENU;
842 IntReleaseMenuObject(OldMenuObject);
843 }
844 }
845
846 if(MenuObject)
847 {
848 /* FIXME check window style, propably return FALSE ? */
849 WindowObject->SystemMenu = MenuObject->MenuInfo.Self;
850 MenuObject->MenuInfo.Flags |= MF_SYSMENU;
851 }
852 else
853 WindowObject->SystemMenu = (HMENU)0;
854
855 return TRUE;
856 }
857
858
859 /* unlink the window from siblings and parent. children are kept in place. */
860 VOID FASTCALL
861 IntUnlinkWindow(PWINDOW_OBJECT Wnd)
862 {
863 PWINDOW_OBJECT WndParent = Wnd->Parent;
864
865 if (Wnd->NextSibling) Wnd->NextSibling->PrevSibling = Wnd->PrevSibling;
866 else if (WndParent->LastChild == Wnd) WndParent->LastChild = Wnd->PrevSibling;
867
868 if (Wnd->PrevSibling) Wnd->PrevSibling->NextSibling = Wnd->NextSibling;
869 else if (WndParent->FirstChild == Wnd) WndParent->FirstChild = Wnd->NextSibling;
870 //else if (parent->first_unlinked == win) parent->first_unlinked = Wnd->NextSibling;
871 }
872
873
874 BOOLEAN FASTCALL
875 IntWndBelongsToThread(PWINDOW_OBJECT Window, PW32THREAD ThreadData)
876 {
877 if (Window->OwnerThread && Window->OwnerThread->Win32Thread)
878 {
879 return (Window->OwnerThread->Win32Thread == ThreadData);
880 }
881
882 return FALSE;
883 }
884
885
886 /* FUNCTIONS *****************************************************************/
887
888 /*
889 * @unimplemented
890 */
891 DWORD STDCALL
892 NtUserAlterWindowStyle(DWORD Unknown0,
893 DWORD Unknown1,
894 DWORD Unknown2)
895 {
896 UNIMPLEMENTED
897
898 return(0);
899 }
900
901
902 /*
903 * As best as I can figure, this function is used by EnumWindows,
904 * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
905 *
906 * It's supposed to build a list of HWNDs to return to the caller.
907 * We can figure out what kind of list by what parameters are
908 * passed to us.
909 */
910 /*
911 * @implemented
912 */
913 ULONG
914 STDCALL
915 NtUserBuildHwndList(
916 HDESK hDesktop,
917 HWND hwndParent,
918 BOOLEAN bChildren,
919 ULONG dwThreadId,
920 ULONG lParam,
921 HWND* pWnd,
922 ULONG nBufSize)
923 {
924 ULONG dwCount = 0;
925
926 /* FIXME handle bChildren */
927 if ( hwndParent )
928 {
929 PWINDOW_OBJECT WindowObject = NULL;
930 PWINDOW_OBJECT Child;
931
932 WindowObject = IntGetWindowObject ( hwndParent );
933 if ( !WindowObject )
934 {
935 DPRINT("Bad window handle 0x%x\n", hwndParent);
936 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
937 return 0;
938 }
939
940 ExAcquireFastMutex ( &WindowObject->ChildrenListLock );
941 Child = WindowObject->FirstChild;
942 while (Child)
943 {
944 if ( pWnd && dwCount < nBufSize )
945 pWnd[dwCount] = Child->Self;
946 dwCount++;
947 Child = Child->NextSibling;
948 }
949 ExReleaseFastMutex ( &WindowObject->ChildrenListLock );
950 IntReleaseWindowObject ( WindowObject );
951 }
952 else if ( dwThreadId )
953 {
954 NTSTATUS Status;
955 struct _ETHREAD* Thread;
956 struct _EPROCESS* ThreadsProcess;
957 struct _W32PROCESS* Win32Process;
958 struct _WINSTATION_OBJECT* WindowStation;
959 PUSER_HANDLE_TABLE HandleTable;
960 PLIST_ENTRY Current;
961 PUSER_HANDLE_BLOCK Block = NULL;
962 ULONG i;
963
964 Status = PsLookupThreadByThreadId ( (PVOID)dwThreadId, &Thread );
965 if ( !NT_SUCCESS(Status) || !Thread )
966 {
967 DPRINT("Bad ThreadId 0x%x\n", dwThreadId );
968 SetLastWin32Error(ERROR_INVALID_HANDLE);
969 return 0;
970 }
971 ThreadsProcess = Thread->ThreadsProcess;
972 ASSERT(ThreadsProcess);
973 Win32Process = ThreadsProcess->Win32Process;
974 ASSERT(Win32Process);
975 WindowStation = Win32Process->WindowStation;
976 ASSERT(WindowStation);
977 HandleTable = (PUSER_HANDLE_TABLE)(WindowStation->HandleTable);
978 ASSERT(HandleTable);
979
980 ObDereferenceObject(Thread);
981
982 ExAcquireFastMutex(&HandleTable->ListLock);
983
984 Current = HandleTable->ListHead.Flink;
985 while ( Current != &HandleTable->ListHead )
986 {
987 Block = CONTAINING_RECORD(Current, USER_HANDLE_BLOCK, ListEntry);
988 for ( i = 0; i < HANDLE_BLOCK_ENTRIES; i++ )
989 {
990 PVOID ObjectBody = Block->Handles[i].ObjectBody;
991 if ( ObjectBody )
992 {
993 if ( pWnd && dwCount < nBufSize )
994 {
995 pWnd[dwCount] =
996 (HWND)ObmReferenceObjectByPointer ( ObjectBody, otWindow );
997 }
998 dwCount++;
999 }
1000 }
1001 Current = Current->Flink;
1002 }
1003
1004 ExReleaseFastMutex(&HandleTable->ListLock);
1005 }
1006 else
1007 {
1008 PDESKTOP_OBJECT DesktopObject = NULL;
1009 KIRQL OldIrql;
1010 PWINDOW_OBJECT Child, WndDesktop;
1011
1012 #if 0
1013 if ( hDesktop )
1014 DesktopObject = IntGetDesktopObject ( hDesktop );
1015 else
1016 #endif
1017 DesktopObject = IntGetActiveDesktop();
1018 if (!DesktopObject)
1019 {
1020 DPRINT("Bad desktop handle 0x%x\n", hDesktop );
1021 SetLastWin32Error(ERROR_INVALID_HANDLE);
1022 return 0;
1023 }
1024
1025 KeAcquireSpinLock ( &DesktopObject->Lock, &OldIrql );
1026
1027 WndDesktop = IntGetWindowObject(DesktopObject->DesktopWindow);
1028 Child = (WndDesktop ? WndDesktop->FirstChild : NULL);
1029 while (Child)
1030 {
1031 if ( pWnd && dwCount < nBufSize )
1032 pWnd[dwCount] = Child->Self;
1033 dwCount++;
1034 Child = Child->NextSibling;
1035 }
1036 KeReleaseSpinLock ( &DesktopObject->Lock, OldIrql );
1037 }
1038
1039 return dwCount;
1040 }
1041
1042
1043 /*
1044 * @implemented
1045 */
1046 HWND STDCALL
1047 NtUserChildWindowFromPointEx(HWND hwndParent,
1048 LONG x,
1049 LONG y,
1050 UINT uiFlags)
1051 {
1052 PWINDOW_OBJECT pParent, pCurrent, pLast;
1053 POINT p = {x,y};
1054 RECT rc;
1055 BOOL bFirstRun = TRUE;
1056
1057 if(hwndParent)
1058 {
1059 pParent = IntGetWindowObject(hwndParent);
1060 if(pParent)
1061 {
1062 ExAcquireFastMutexUnsafe (&pParent->ChildrenListLock);
1063
1064 pLast = IntGetWindowObject(pParent->LastChild->Self);
1065 pCurrent = IntGetWindowObject(pParent->FirstChild->Self);
1066
1067 do
1068 {
1069 if (!bFirstRun)
1070 {
1071 pCurrent = IntGetWindowObject(pCurrent->NextSibling->Self);
1072
1073 }
1074 else
1075 bFirstRun = FALSE;
1076 if(!pCurrent)
1077 return (HWND)NULL;
1078
1079 rc.left = pCurrent->WindowRect.left - pCurrent->Parent->ClientRect.left;
1080 rc.top = pCurrent->WindowRect.top - pCurrent->Parent->ClientRect.top;
1081 rc.right = rc.left + (pCurrent->WindowRect.right - pCurrent->WindowRect.left);
1082 rc.bottom = rc.top + (pCurrent->WindowRect.bottom - pCurrent->WindowRect.top);
1083 DbgPrint("Rect: %i,%i,%i,%i\n",rc.left, rc.top, rc.right, rc.bottom);
1084 if (POINT_IN_RECT(p,rc)) /* Found a match */
1085 {
1086 if ( (uiFlags & CWP_SKIPDISABLED) && (pCurrent->Style & WS_DISABLED) )
1087 continue;
1088 if( (uiFlags & CWP_SKIPTRANSPARENT) && (pCurrent->ExStyle & WS_EX_TRANSPARENT) )
1089 continue;
1090 if( (uiFlags & CWP_SKIPINVISIBLE) && !(pCurrent->Style & WS_VISIBLE) )
1091 continue;
1092
1093 ExReleaseFastMutexUnsafe(&pParent->ChildrenListLock);
1094 return pCurrent->Self;
1095 }
1096 }
1097 while(pCurrent != pLast);
1098
1099 ExReleaseFastMutexUnsafe(&pParent->ChildrenListLock);
1100 return (HWND)NULL;
1101 }
1102 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1103 }
1104
1105 return (HWND)NULL;
1106 }
1107
1108
1109 /*
1110 * @implemented
1111 */
1112 HWND STDCALL
1113 NtUserCreateWindowEx(DWORD dwExStyle,
1114 PUNICODE_STRING lpClassName,
1115 PUNICODE_STRING lpWindowName,
1116 DWORD dwStyle,
1117 LONG x,
1118 LONG y,
1119 LONG nWidth,
1120 LONG nHeight,
1121 HWND hWndParent,
1122 HMENU hMenu,
1123 HINSTANCE hInstance,
1124 LPVOID lpParam,
1125 DWORD dwShowMode,
1126 BOOL bUnicodeWindow)
1127 {
1128 PWINSTATION_OBJECT WinStaObject;
1129 PWNDCLASS_OBJECT ClassObject;
1130 PWINDOW_OBJECT WindowObject;
1131 PWINDOW_OBJECT ParentWindow;
1132 HWND ParentWindowHandle;
1133 HWND OwnerWindowHandle;
1134 PMENU_OBJECT SystemMenu;
1135 UNICODE_STRING WindowName;
1136 NTSTATUS Status;
1137 HANDLE Handle;
1138 #if 0
1139 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
1140 #else
1141 POINT MaxPos;
1142 #endif
1143 CREATESTRUCTW Cs;
1144 CBT_CREATEWNDW CbtCreate;
1145 LRESULT Result;
1146 BOOL MenuChanged;
1147
1148 DPRINT("NtUserCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, nWidth, nHeight);
1149
1150 if (! RtlCreateUnicodeString(&WindowName,
1151 NULL == lpWindowName->Buffer ?
1152 L"" : lpWindowName->Buffer))
1153 {
1154 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1155 return((HWND)0);
1156 }
1157
1158 ParentWindowHandle = PsGetWin32Thread()->Desktop->DesktopWindow;
1159 OwnerWindowHandle = NULL;
1160
1161 if (hWndParent == HWND_MESSAGE)
1162 {
1163 /*
1164 * native ole32.OleInitialize uses HWND_MESSAGE to create the
1165 * message window (style: WS_POPUP|WS_DISABLED)
1166 */
1167 UNIMPLEMENTED;
1168 }
1169 else if (hWndParent)
1170 {
1171 if ((dwStyle & (WS_CHILD | WS_POPUP)) == WS_CHILD)
1172 ParentWindowHandle = hWndParent;
1173 else
1174 OwnerWindowHandle = NtUserGetAncestor(hWndParent, GA_ROOT);
1175 }
1176 else if ((dwStyle & (WS_CHILD | WS_POPUP)) == WS_CHILD)
1177 {
1178 RtlFreeUnicodeString(&WindowName);
1179 return (HWND)0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1180 }
1181
1182 if (NULL != ParentWindowHandle)
1183 {
1184 ParentWindow = IntGetWindowObject(ParentWindowHandle);
1185 }
1186 else
1187 {
1188 ParentWindow = NULL;
1189 }
1190
1191 /* FIXME: parent must belong to the current process */
1192
1193 /* Check the class. */
1194 Status = ClassReferenceClassByNameOrAtom(&ClassObject, lpClassName->Buffer);
1195 if (!NT_SUCCESS(Status))
1196 {
1197 RtlFreeUnicodeString(&WindowName);
1198 if (NULL != ParentWindow)
1199 {
1200 IntReleaseWindowObject(ParentWindow);
1201 }
1202 return((HWND)0);
1203 }
1204
1205 /* Check the window station. */
1206 DPRINT("IoGetCurrentProcess() %X\n", IoGetCurrentProcess());
1207 DPRINT("PROCESS_WINDOW_STATION %X\n", PROCESS_WINDOW_STATION());
1208 Status = IntValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
1209 KernelMode,
1210 0,
1211 &WinStaObject);
1212 if (!NT_SUCCESS(Status))
1213 {
1214 ObmDereferenceObject(ClassObject);
1215 RtlFreeUnicodeString(&WindowName);
1216 if (NULL != ParentWindow)
1217 {
1218 IntReleaseWindowObject(ParentWindow);
1219 }
1220 DPRINT("Validation of window station handle (0x%X) failed\n",
1221 PROCESS_WINDOW_STATION());
1222 return (HWND)0;
1223 }
1224
1225 /* Create the window object. */
1226 WindowObject = (PWINDOW_OBJECT)
1227 ObmCreateObject(PsGetWin32Process()->WindowStation->HandleTable, &Handle,
1228 otWindow, sizeof(WINDOW_OBJECT) + ClassObject->cbWndExtra
1229 );
1230
1231 DPRINT("Created object with handle %X\n", Handle);
1232 if (!WindowObject)
1233 {
1234 ObDereferenceObject(WinStaObject);
1235 ObmDereferenceObject(ClassObject);
1236 RtlFreeUnicodeString(&WindowName);
1237 if (NULL != ParentWindow)
1238 {
1239 IntReleaseWindowObject(ParentWindow);
1240 }
1241 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1242 return (HWND)0;
1243 }
1244 ObDereferenceObject(WinStaObject);
1245
1246 if (NULL == PsGetWin32Thread()->Desktop->DesktopWindow)
1247 {
1248 /* If there is no desktop window yet, we must be creating it */
1249 PsGetWin32Thread()->Desktop->DesktopWindow = Handle;
1250 }
1251
1252 /*
1253 * Fill out the structure describing it.
1254 */
1255 WindowObject->Class = ClassObject;
1256 WindowObject->ExStyle = dwExStyle;
1257 WindowObject->Style = dwStyle & ~WS_VISIBLE;
1258 DPRINT("1: Style is now %d\n", WindowObject->Style);
1259
1260 WindowObject->SystemMenu = (HMENU)0;
1261 WindowObject->ContextHelpId = 0;
1262 WindowObject->IDMenu = 0;
1263 WindowObject->Instance = hInstance;
1264 WindowObject->Self = Handle;
1265 if (0 != (dwStyle & WS_CHILD))
1266 {
1267 WindowObject->IDMenu = (UINT) hMenu;
1268 }
1269 else
1270 {
1271 IntSetMenu(WindowObject, hMenu, &MenuChanged);
1272 }
1273 WindowObject->MessageQueue = PsGetWin32Thread()->MessageQueue;
1274 WindowObject->Parent = ParentWindow;
1275 WindowObject->Owner = IntGetWindowObject(OwnerWindowHandle);
1276 WindowObject->UserData = 0;
1277 if ((((DWORD)ClassObject->lpfnWndProcA & 0xFFFF0000) != 0xFFFF0000)
1278 && (((DWORD)ClassObject->lpfnWndProcW & 0xFFFF0000) != 0xFFFF0000))
1279 {
1280 WindowObject->Unicode = bUnicodeWindow;
1281 }
1282 else
1283 {
1284 WindowObject->Unicode = ClassObject->Unicode;
1285 }
1286 WindowObject->WndProcA = ClassObject->lpfnWndProcA;
1287 WindowObject->WndProcW = ClassObject->lpfnWndProcW;
1288 WindowObject->OwnerThread = PsGetCurrentThread();
1289 WindowObject->FirstChild = NULL;
1290 WindowObject->LastChild = NULL;
1291 WindowObject->PrevSibling = NULL;
1292 WindowObject->NextSibling = NULL;
1293
1294 /* extra window data */
1295 if (ClassObject->cbWndExtra != 0)
1296 {
1297 WindowObject->ExtraData = (PCHAR)(WindowObject + 1);
1298 WindowObject->ExtraDataSize = ClassObject->cbWndExtra;
1299 RtlZeroMemory(WindowObject->ExtraData, WindowObject->ExtraDataSize);
1300 }
1301 else
1302 {
1303 WindowObject->ExtraData = NULL;
1304 WindowObject->ExtraDataSize = 0;
1305 }
1306
1307 InitializeListHead(&WindowObject->PropListHead);
1308 ExInitializeFastMutex(&WindowObject->PropListLock);
1309 ExInitializeFastMutex(&WindowObject->ChildrenListLock);
1310 ExInitializeFastMutex(&WindowObject->UpdateLock);
1311
1312 RtlInitUnicodeString(&WindowObject->WindowName, WindowName.Buffer);
1313
1314 /* Correct the window style. */
1315 if (!(dwStyle & WS_CHILD))
1316 {
1317 WindowObject->Style |= WS_CLIPSIBLINGS;
1318 DPRINT("3: Style is now %d\n", WindowObject->Style);
1319 if (!(dwStyle & WS_POPUP))
1320 {
1321 WindowObject->Style |= WS_CAPTION;
1322 WindowObject->Flags |= WINDOWOBJECT_NEED_SIZE;
1323 DPRINT("4: Style is now %d\n", WindowObject->Style);
1324 /* FIXME: Note the window needs a size. */
1325 }
1326 }
1327
1328 /* create system menu */
1329 if((WindowObject->Style & WS_SYSMENU) && (WindowObject->Style & WS_CAPTION))
1330 {
1331 SystemMenu = IntGetSystemMenu(WindowObject, TRUE, TRUE);
1332 if(SystemMenu)
1333 {
1334 WindowObject->SystemMenu = SystemMenu->MenuInfo.Self;
1335 IntReleaseMenuObject(SystemMenu);
1336 }
1337 }
1338
1339 /* Insert the window into the thread's window list. */
1340 ExAcquireFastMutexUnsafe (&PsGetWin32Thread()->WindowListLock);
1341 InsertTailList (&PsGetWin32Thread()->WindowListHead,
1342 &WindowObject->ThreadListEntry);
1343 ExReleaseFastMutexUnsafe (&PsGetWin32Thread()->WindowListLock);
1344
1345 /* Allocate a DCE for this window. */
1346 if (dwStyle & CS_OWNDC)
1347 {
1348 WindowObject->Dce = DceAllocDCE(WindowObject->Self, DCE_WINDOW_DC);
1349 }
1350 /* FIXME: Handle "CS_CLASSDC" */
1351
1352 /* Initialize the window dimensions. */
1353 WindowObject->WindowRect.left = x;
1354 WindowObject->WindowRect.top = y;
1355 WindowObject->WindowRect.right = x + nWidth;
1356 WindowObject->WindowRect.bottom = y + nHeight;
1357 if (0 != (WindowObject->Style & WS_CHILD))
1358 {
1359 NtGdiOffsetRect(&(WindowObject->WindowRect), WindowObject->Parent->ClientRect.left,
1360 WindowObject->Parent->ClientRect.top);
1361 }
1362 WindowObject->ClientRect = WindowObject->WindowRect;
1363
1364 Cs.lpCreateParams = lpParam;
1365 Cs.hInstance = hInstance;
1366 Cs.hMenu = hMenu;
1367 Cs.hwndParent = ParentWindowHandle;
1368 Cs.cx = nWidth;
1369 Cs.cy = nHeight;
1370 Cs.x = x;
1371 Cs.y = y;
1372 Cs.style = dwStyle;
1373 Cs.lpszName = lpWindowName->Buffer;
1374 Cs.lpszClass = lpClassName->Buffer;
1375 Cs.dwExStyle = dwExStyle;
1376 CbtCreate.lpcs = &Cs;
1377 CbtCreate.hwndInsertAfter = HWND_TOP;
1378 if (HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) Handle, (LPARAM) &CbtCreate))
1379 {
1380 if (NULL != ParentWindow)
1381 {
1382 IntReleaseWindowObject(ParentWindow);
1383 }
1384 DPRINT1("CBT-hook returned !0\n");
1385 return (HWND) NULL;
1386 }
1387
1388 /*
1389 * Get the size and position of the window.
1390 */
1391 if ((dwStyle & WS_THICKFRAME) || !(dwStyle & (WS_POPUP | WS_CHILD)))
1392 {
1393 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
1394
1395 /* WinPosGetMinMaxInfo sends the WM_GETMINMAXINFO message */
1396 WinPosGetMinMaxInfo(WindowObject, &MaxSize, &MaxPos, &MinTrack,
1397 &MaxTrack);
1398 if (MaxSize.x < nWidth) nWidth = MaxSize.x;
1399 if (MaxSize.y < nHeight) nHeight = MaxSize.y;
1400 if (nWidth < MinTrack.x ) nWidth = MinTrack.x;
1401 if (nHeight < MinTrack.y ) nHeight = MinTrack.y;
1402 if (nWidth < 0) nWidth = 0;
1403 if (nHeight < 0) nHeight = 0;
1404 }
1405
1406 WindowObject->WindowRect.left = x;
1407 WindowObject->WindowRect.top = y;
1408 WindowObject->WindowRect.right = x + nWidth;
1409 WindowObject->WindowRect.bottom = y + nHeight;
1410 if (0 != (WindowObject->Style & WS_CHILD))
1411 {
1412 NtGdiOffsetRect(&(WindowObject->WindowRect), WindowObject->Parent->ClientRect.left,
1413 WindowObject->Parent->ClientRect.top);
1414 }
1415 WindowObject->ClientRect = WindowObject->WindowRect;
1416
1417 /* FIXME: Initialize the window menu. */
1418
1419 /* Initialize the window's scrollbars */
1420 if (dwStyle & WS_VSCROLL)
1421 {
1422 WindowObject->Style &= ~WS_VSCROLL;
1423 NtUserShowScrollBar(WindowObject->Self, SB_VERT, TRUE);
1424 }
1425 if (dwStyle & WS_HSCROLL)
1426 {
1427 WindowObject->Style &= ~WS_HSCROLL;
1428 NtUserShowScrollBar(WindowObject->Self, SB_HORZ, TRUE);
1429 }
1430
1431 /* Send a NCCREATE message. */
1432 Cs.cx = nWidth;
1433 Cs.cy = nHeight;
1434 Cs.x = x;
1435 Cs.y = y;
1436
1437 DPRINT("[win32k.window] NtUserCreateWindowEx style %d, exstyle %d, parent %d\n", Cs.style, Cs.dwExStyle, Cs.hwndParent);
1438 DPRINT("NtUserCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, nWidth, nHeight);
1439 DPRINT("NtUserCreateWindowEx(): About to send NCCREATE message.\n");
1440 Result = IntSendMessage(WindowObject->Self, WM_NCCREATE, 0, (LPARAM) &Cs);
1441 if (!Result)
1442 {
1443 /* FIXME: Cleanup. */
1444 if (NULL != ParentWindow)
1445 {
1446 IntReleaseWindowObject(ParentWindow);
1447 }
1448 DPRINT("NtUserCreateWindowEx(): NCCREATE message failed.\n");
1449 return((HWND)0);
1450 }
1451
1452 /* Calculate the non-client size. */
1453 MaxPos.x = WindowObject->WindowRect.left;
1454 MaxPos.y = WindowObject->WindowRect.top;
1455 DPRINT("NtUserCreateWindowEx(): About to get non-client size.\n");
1456 /* WinPosGetNonClientSize SENDS THE WM_NCCALCSIZE message */
1457 Result = WinPosGetNonClientSize(WindowObject->Self,
1458 &WindowObject->WindowRect,
1459 &WindowObject->ClientRect);
1460 NtGdiOffsetRect(&WindowObject->WindowRect,
1461 MaxPos.x - WindowObject->WindowRect.left,
1462 MaxPos.y - WindowObject->WindowRect.top);
1463
1464 if (NULL != ParentWindow)
1465 {
1466 /* link the window into the parent's child list */
1467 ExAcquireFastMutexUnsafe(&ParentWindow->ChildrenListLock);
1468 if ((dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
1469 {
1470 /* link window as bottom sibling */
1471 IntLinkWindow(WindowObject, ParentWindow, ParentWindow->LastChild /*prev sibling*/);
1472 }
1473 else
1474 {
1475 /* link window as top sibling */
1476 IntLinkWindow(WindowObject, ParentWindow, NULL /*prev sibling*/);
1477 }
1478 ExReleaseFastMutexUnsafe(&ParentWindow->ChildrenListLock);
1479 }
1480
1481 /* Send the WM_CREATE message. */
1482 DPRINT("NtUserCreateWindowEx(): about to send CREATE message.\n");
1483 Result = IntSendMessage(WindowObject->Self, WM_CREATE, 0, (LPARAM) &Cs);
1484 if (Result == (LRESULT)-1)
1485 {
1486 /* FIXME: Cleanup. */
1487 if (NULL != ParentWindow)
1488 {
1489 IntReleaseWindowObject(ParentWindow);
1490 }
1491 DPRINT("NtUserCreateWindowEx(): send CREATE message failed.\n");
1492 return((HWND)0);
1493 }
1494
1495 /* Send move and size messages. */
1496 if (!(WindowObject->Flags & WINDOWOBJECT_NEED_SIZE))
1497 {
1498 LONG lParam;
1499
1500 DPRINT("NtUserCreateWindow(): About to send WM_SIZE\n");
1501
1502 if ((WindowObject->ClientRect.right - WindowObject->ClientRect.left) < 0 ||
1503 (WindowObject->ClientRect.bottom - WindowObject->ClientRect.top) < 0)
1504 DPRINT("Sending bogus WM_SIZE\n");
1505
1506 lParam = MAKE_LONG(WindowObject->ClientRect.right -
1507 WindowObject->ClientRect.left,
1508 WindowObject->ClientRect.bottom -
1509 WindowObject->ClientRect.top);
1510 IntSendMessage(WindowObject->Self, WM_SIZE, SIZE_RESTORED,
1511 lParam);
1512
1513 DPRINT("NtUserCreateWindow(): About to send WM_MOVE\n");
1514
1515 if (0 != (WindowObject->Style & WS_CHILD))
1516 {
1517 lParam = MAKE_LONG(WindowObject->ClientRect.left - WindowObject->Parent->ClientRect.left,
1518 WindowObject->ClientRect.top - WindowObject->Parent->ClientRect.top);
1519 }
1520 else
1521 {
1522 lParam = MAKE_LONG(WindowObject->ClientRect.left,
1523 WindowObject->ClientRect.top);
1524 }
1525 IntSendMessage(WindowObject->Self, WM_MOVE, 0, lParam);
1526 }
1527
1528 /* Show or maybe minimize or maximize the window. */
1529 if (WindowObject->Style & (WS_MINIMIZE | WS_MAXIMIZE))
1530 {
1531 RECT NewPos;
1532 UINT16 SwFlag;
1533
1534 SwFlag = (WindowObject->Style & WS_MINIMIZE) ? SW_MINIMIZE :
1535 SW_MAXIMIZE;
1536 WinPosMinMaximize(WindowObject, SwFlag, &NewPos);
1537 SwFlag =
1538 ((WindowObject->Style & WS_CHILD) || NtUserGetActiveWindow()) ?
1539 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED :
1540 SWP_NOZORDER | SWP_FRAMECHANGED;
1541 DPRINT("NtUserCreateWindow(): About to minimize/maximize\n");
1542 DPRINT("%d,%d %dx%d\n", NewPos.left, NewPos.top, NewPos.right, NewPos.bottom);
1543 WinPosSetWindowPos(WindowObject->Self, 0, NewPos.left, NewPos.top,
1544 NewPos.right, NewPos.bottom, SwFlag);
1545 }
1546
1547 /* Notify the parent window of a new child. */
1548 if ((WindowObject->Style & WS_CHILD) &&
1549 (!(WindowObject->ExStyle & WS_EX_NOPARENTNOTIFY)))
1550 {
1551 DPRINT("NtUserCreateWindow(): About to notify parent\n");
1552 IntSendMessage(WindowObject->Parent->Self,
1553 WM_PARENTNOTIFY,
1554 MAKEWPARAM(WM_CREATE, WindowObject->IDMenu),
1555 (LPARAM)WindowObject->Self);
1556 }
1557
1558 if (dwStyle & WS_VISIBLE)
1559 {
1560 DPRINT("NtUserCreateWindow(): About to show window\n");
1561 WinPosShowWindow(WindowObject->Self, dwShowMode);
1562 }
1563
1564 DPRINT("NtUserCreateWindow(): = %X\n", Handle);
1565 DPRINT("WindowObject->SystemMenu = 0x%x\n", WindowObject->SystemMenu);
1566 return((HWND)Handle);
1567 }
1568
1569
1570 /*
1571 * @unimplemented
1572 */
1573 HDWP STDCALL
1574 NtUserDeferWindowPos(HDWP WinPosInfo,
1575 HWND Wnd,
1576 HWND WndInsertAfter,
1577 int x,
1578 int y,
1579 int cx,
1580 int cy,
1581 UINT Flags)
1582 {
1583 UNIMPLEMENTED
1584
1585 return 0;
1586 }
1587
1588
1589 /*
1590 * @implemented
1591 */
1592 BOOLEAN STDCALL
1593 NtUserDestroyWindow(HWND Wnd)
1594 {
1595 PWINDOW_OBJECT Window, Parent;
1596 BOOLEAN isChild;
1597
1598 Window = IntGetWindowObject(Wnd);
1599 if (Window == NULL)
1600 {
1601 return FALSE;
1602 }
1603
1604 /* Check for owner thread and desktop window */
1605 if ((Window->OwnerThread != PsGetCurrentThread()) || IntIsDesktopWindow(Window))
1606 {
1607 IntReleaseWindowObject(Window);
1608 SetLastWin32Error(ERROR_ACCESS_DENIED);
1609 return FALSE;
1610 }
1611
1612 /* Look whether the focus is within the tree of windows we will
1613 * be destroying.
1614 */
1615 if (!WinPosShowWindow(Wnd, SW_HIDE))
1616 {
1617 if (NtUserGetActiveWindow() == Wnd)
1618 {
1619 WinPosActivateOtherWindow(Window);
1620 }
1621 }
1622 ExAcquireFastMutex(&Window->MessageQueue->Lock);
1623 if (Window->MessageQueue->ActiveWindow == Window->Self)
1624 Window->MessageQueue->ActiveWindow = NULL;
1625 if (Window->MessageQueue->FocusWindow == Window->Self)
1626 Window->MessageQueue->FocusWindow = NULL;
1627 if (Window->MessageQueue->CaptureWindow == Window->Self)
1628 Window->MessageQueue->CaptureWindow = NULL;
1629 ExReleaseFastMutex(&Window->MessageQueue->Lock);
1630
1631 /* Call hooks */
1632 #if 0 /* FIXME */
1633 if (HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hwnd, 0, TRUE))
1634 {
1635 return FALSE;
1636 }
1637 #endif
1638
1639 isChild = (0 != (Window->Style & WS_CHILD));
1640
1641 #if 0 /* FIXME */
1642 if (isChild)
1643 {
1644 if (! USER_IsExitingThread(GetCurrentThreadId()))
1645 {
1646 send_parent_notify(hwnd, WM_DESTROY);
1647 }
1648 }
1649 else if (NULL != GetWindow(Wnd, GW_OWNER))
1650 {
1651 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1652 /* FIXME: clean up palette - see "Internals" p.352 */
1653 }
1654
1655 if (! IsWindow(Wnd))
1656 {
1657 return TRUE;
1658 }
1659 #endif
1660
1661 if (!IntIsWindow(Wnd))
1662 {
1663 return TRUE;
1664 }
1665
1666 /* Recursively destroy owned windows */
1667 if (! isChild)
1668 {
1669 for (;;)
1670 {
1671 BOOL GotOne = FALSE;
1672 HWND *Children;
1673 HWND *ChildHandle;
1674 PWINDOW_OBJECT Child, Desktop;
1675
1676 Desktop = IntGetWindowObject(IntGetDesktopWindow());
1677 Children = IntWinListChildren(Desktop);
1678 IntReleaseWindowObject(Desktop);
1679 if (Children)
1680 {
1681 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
1682 {
1683 Child = IntGetWindowObject(*ChildHandle);
1684 if (Child == NULL)
1685 {
1686 continue;
1687 }
1688 if (Child->Parent != Window)
1689 {
1690 IntReleaseWindowObject(Child);
1691 continue;
1692 }
1693 if (IntWndBelongsToThread(Child, PsGetWin32Thread()))
1694 {
1695 IntReleaseWindowObject(Child);
1696 NtUserDestroyWindow(*ChildHandle);
1697 GotOne = TRUE;
1698 continue;
1699 }
1700 if (Child->Owner != NULL)
1701 {
1702 IntReleaseWindowObject(Child->Owner);
1703 Child->Owner = NULL;
1704 }
1705 IntReleaseWindowObject(Child);
1706 }
1707 ExFreePool(Children);
1708 }
1709 if (! GotOne)
1710 {
1711 break;
1712 }
1713 }
1714 }
1715
1716 if (!IntIsWindow(Wnd))
1717 {
1718 return TRUE;
1719 }
1720
1721 /* Unlink now so we won't bother with the children later on */
1722 Parent = Window->Parent;
1723 ExAcquireFastMutexUnsafe(&Parent->ChildrenListLock);
1724 IntUnlinkWindow(Window);
1725 Window->Parent = NULL;
1726 ExReleaseFastMutexUnsafe(&Parent->ChildrenListLock);
1727
1728 /* Destroy the window storage */
1729 IntDestroyWindow(Window, PsGetWin32Process(), PsGetWin32Thread(), TRUE);
1730
1731 IntReleaseWindowObject(Window);
1732 return TRUE;
1733 }
1734
1735
1736 /*
1737 * @unimplemented
1738 */
1739 DWORD
1740 STDCALL
1741 NtUserDrawMenuBarTemp(
1742 HWND hWnd,
1743 HDC hDC,
1744 PRECT hRect,
1745 HMENU hMenu,
1746 HFONT hFont)
1747 {
1748 /* we'll use this function just for caching the menu bar */
1749 UNIMPLEMENTED
1750 return 0;
1751 }
1752
1753
1754 /*
1755 * @unimplemented
1756 */
1757 DWORD STDCALL
1758 NtUserEndDeferWindowPosEx(DWORD Unknown0,
1759 DWORD Unknown1)
1760 {
1761 UNIMPLEMENTED
1762
1763 return 0;
1764 }
1765
1766
1767 /*
1768 * @unimplemented
1769 */
1770 DWORD STDCALL
1771 NtUserFillWindow(DWORD Unknown0,
1772 DWORD Unknown1,
1773 DWORD Unknown2,
1774 DWORD Unknown3)
1775 {
1776 UNIMPLEMENTED
1777
1778 return 0;
1779 }
1780
1781
1782 /*
1783 * FUNCTION:
1784 * Searches a window's children for a window with the specified
1785 * class and name
1786 * ARGUMENTS:
1787 * hwndParent = The window whose childs are to be searched.
1788 * NULL = desktop
1789 *
1790 * hwndChildAfter = Search starts after this child window.
1791 * NULL = start from beginning
1792 *
1793 * ucClassName = Class name to search for
1794 * Reguired parameter.
1795 *
1796 * ucWindowName = Window name
1797 * ->Buffer == NULL = don't care
1798 *
1799 * RETURNS:
1800 * The HWND of the window if it was found, otherwise NULL
1801 *
1802 * FIXME:
1803 * Should use MmCopyFromCaller, we don't want an access violation in here
1804 *
1805 */
1806 /*
1807 * @implemented
1808 */
1809 HWND STDCALL
1810 NtUserFindWindowEx(HWND hwndParent,
1811 HWND hwndChildAfter,
1812 PUNICODE_STRING ucClassName,
1813 PUNICODE_STRING ucWindowName)
1814 {
1815 NTSTATUS status;
1816 HWND windowHandle;
1817 PWINDOW_OBJECT ParentWindow, WndChildAfter, WndChild;
1818 PWNDCLASS_OBJECT classObject;
1819
1820 // Get a pointer to the class
1821 status = ClassReferenceClassByNameOrAtom(&classObject, ucClassName->Buffer);
1822 if (!NT_SUCCESS(status))
1823 {
1824 return NULL;
1825 }
1826
1827 // If hwndParent==NULL use the desktop window instead
1828 if(!hwndParent)
1829 hwndParent = PsGetWin32Thread()->Desktop->DesktopWindow;
1830
1831 // Get the object
1832 ParentWindow = IntGetWindowObject(hwndParent);
1833
1834 if(!ParentWindow)
1835 {
1836 ObmDereferenceObject(classObject);
1837 return NULL;
1838 }
1839
1840 ExAcquireFastMutexUnsafe (&ParentWindow->ChildrenListLock);
1841
1842 if(hwndChildAfter)
1843 {
1844 if (!(WndChildAfter = IntGetWindowObject(hwndChildAfter)))
1845 {
1846 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1847 return NULL;
1848 }
1849
1850 /* must be a direct child (not a decendant child)*/
1851 if (WndChildAfter->Parent != ParentWindow)
1852 {
1853 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1854 return NULL;
1855 }
1856
1857 WndChild = WndChildAfter->NextSibling;
1858 }
1859 else
1860 {
1861 WndChild = ParentWindow->FirstChild;
1862 }
1863
1864 while (WndChild)
1865 {
1866 if (classObject == WndChild->Class && (ucWindowName->Buffer==NULL ||
1867 RtlCompareUnicodeString (ucWindowName, &WndChild->WindowName, TRUE) == 0))
1868 {
1869 windowHandle = WndChild->Self;
1870
1871 ExReleaseFastMutexUnsafe (&ParentWindow->ChildrenListLock);
1872 IntReleaseWindowObject(ParentWindow);
1873 ObmDereferenceObject (classObject);
1874
1875 return windowHandle;
1876 }
1877
1878 WndChild = WndChild->NextSibling;
1879 }
1880
1881 ExReleaseFastMutexUnsafe (&ParentWindow->ChildrenListLock);
1882
1883 IntReleaseWindowObject(ParentWindow);
1884 ObmDereferenceObject (classObject);
1885
1886 return NULL;
1887 }
1888
1889
1890 /*
1891 * @unimplemented
1892 */
1893 DWORD STDCALL
1894 NtUserFlashWindowEx(DWORD Unknown0)
1895 {
1896 UNIMPLEMENTED
1897
1898 return 0;
1899 }
1900
1901
1902 /*
1903 * @implemented
1904 */
1905 HWND STDCALL
1906 NtUserGetAncestor(HWND hWnd, UINT Type)
1907 {
1908 PWINDOW_OBJECT Wnd, WndAncestor;
1909 HWND hWndAncestor = NULL;
1910
1911 if (hWnd == IntGetDesktopWindow())
1912 {
1913 return NULL;
1914 }
1915
1916 IntAcquireWinLockShared();
1917
1918 if (!(Wnd = IntGetWindowObject(hWnd)))
1919 {
1920 IntReleaseWinLock();
1921 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1922 return NULL;
1923 }
1924
1925 switch (Type)
1926 {
1927 case GA_PARENT:
1928 WndAncestor = Wnd->Parent;
1929 break;
1930
1931 case GA_ROOT:
1932 WndAncestor = Wnd;
1933 while (!IntIsDesktopWindow(WndAncestor->Parent))
1934 WndAncestor = WndAncestor->Parent;
1935 break;
1936
1937 case GA_ROOTOWNER:
1938 WndAncestor = Wnd;
1939 for (;;)
1940 {
1941 PWINDOW_OBJECT Parent = IntGetParent(WndAncestor);
1942 if (!Parent) break;
1943 WndAncestor = Parent;
1944 }
1945 break;
1946
1947 default:
1948 WndAncestor = NULL;
1949 }
1950
1951 if (WndAncestor)
1952 {
1953 hWndAncestor = WndAncestor->Self;
1954 }
1955
1956 IntReleaseWindowObject(Wnd);
1957 IntReleaseWinLock();
1958
1959 return hWndAncestor;
1960 }
1961
1962
1963 /*!
1964 * Returns client window rectangle relative to the upper-left corner of client area.
1965 *
1966 * \param hWnd window handle.
1967 * \param Rect pointer to the buffer where the coordinates are returned.
1968 *
1969 */
1970 /*
1971 * @implemented
1972 */
1973 BOOL STDCALL
1974 NtUserGetClientRect(HWND hWnd, LPRECT Rect)
1975 {
1976 PWINDOW_OBJECT WindowObject;
1977 RECT SafeRect;
1978
1979 IntAcquireWinLockShared();
1980 if (!(WindowObject = IntGetWindowObject(hWnd)))
1981 {
1982 IntReleaseWinLock();
1983 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1984 return FALSE;
1985 }
1986
1987 IntGetClientRect(WindowObject, &SafeRect);
1988 IntReleaseWinLock();
1989
1990 if (! NT_SUCCESS(MmCopyToCaller(Rect, &SafeRect, sizeof(RECT))))
1991 {
1992 return(FALSE);
1993 }
1994
1995 return(TRUE);
1996 }
1997
1998
1999 /*
2000 * @implemented
2001 */
2002 HWND STDCALL
2003 NtUserGetDesktopWindow()
2004 {
2005 return IntGetDesktopWindow();
2006 }
2007
2008
2009 /*
2010 * @unimplemented
2011 */
2012 DWORD STDCALL
2013 NtUserGetInternalWindowPos(DWORD Unknown0,
2014 DWORD Unknown1,
2015 DWORD Unknown2)
2016 {
2017 UNIMPLEMENTED
2018
2019 return 0;
2020 }
2021
2022
2023 /*
2024 * @unimplemented
2025 */
2026 HWND STDCALL
2027 NtUserGetLastActivePopup(HWND hWnd)
2028 {
2029 /*
2030 * This code can't work, because hWndLastPopup member of WINDOW_OBJECT is
2031 * not changed anywhere.
2032 * -- Filip, 01/nov/2003
2033 */
2034 #if 0
2035 PWINDOW_OBJECT Wnd;
2036 HWND hWndLastPopup;
2037
2038 IntAcquireWinLockShared();
2039
2040 if (!(Wnd = IntGetWindowObject(hWnd)))
2041 {
2042 IntReleaseWinLock();
2043 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2044 return NULL;
2045 }
2046
2047 hWndLastPopup = Wnd->hWndLastPopup;
2048
2049 IntReleaseWinLock();
2050
2051 return hWndLastPopup;
2052 #else
2053 return NULL;
2054 #endif
2055 }
2056
2057 /*
2058 * NtUserGetParent
2059 *
2060 * The NtUserGetParent function retrieves a handle to the specified window's
2061 * parent or owner.
2062 *
2063 * Remarks
2064 * Note that, despite its name, this function can return an owner window
2065 * instead of a parent window.
2066 *
2067 * Status
2068 * @implemented
2069 */
2070
2071 HWND STDCALL
2072 NtUserGetParent(HWND hWnd)
2073 {
2074 PWINDOW_OBJECT Wnd, WndParent;
2075 HWND hWndParent = NULL;
2076
2077 IntAcquireWinLockShared();
2078
2079 if (!(Wnd = IntGetWindowObject(hWnd)))
2080 {
2081 IntReleaseWinLock();
2082 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2083 return NULL;
2084 }
2085
2086 WndParent = IntGetParent(Wnd);
2087 if (WndParent)
2088 {
2089 hWndParent = WndParent->Self;
2090 }
2091
2092 IntReleaseWindowObject(Wnd);
2093 IntReleaseWinLock();
2094
2095 return hWndParent;
2096 }
2097
2098 /*
2099 * NtUserSetParent
2100 *
2101 * The NtUserSetParent function changes the parent window of the specified
2102 * child window.
2103 *
2104 * Remarks
2105 * The new parent window and the child window must belong to the same
2106 * application. If the window identified by the hWndChild parameter is
2107 * visible, the system performs the appropriate redrawing and repainting.
2108 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
2109 * or WS_POPUP window styles of the window whose parent is being changed.
2110 *
2111 * Status
2112 * @implemented
2113 */
2114
2115 HWND STDCALL
2116 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
2117 {
2118 PWINDOW_OBJECT Wnd = NULL, WndParent = NULL, WndOldParent;
2119 HWND hWndOldParent = NULL;
2120
2121 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
2122 {
2123 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2124 return NULL;
2125 }
2126
2127 if (hWndChild == IntGetDesktopWindow())
2128 {
2129 SetLastWin32Error(ERROR_ACCESS_DENIED);
2130 return NULL;
2131 }
2132
2133 IntAcquireWinLockExclusive();
2134 if (hWndNewParent)
2135 {
2136 if (!(WndParent = IntGetWindowObject(hWndNewParent)))
2137 {
2138 IntReleaseWinLock();
2139 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2140 return NULL;
2141 }
2142 }
2143 else
2144 {
2145 if (!(WndParent = IntGetWindowObject(IntGetDesktopWindow())))
2146 {
2147 IntReleaseWinLock();
2148 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2149 return NULL;
2150 }
2151 }
2152
2153 if (!(Wnd = IntGetWindowObject(hWndChild)))
2154 {
2155 IntReleaseWinLock();
2156 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2157 return NULL;
2158 }
2159
2160 WndOldParent = IntSetParent(Wnd, WndParent);
2161
2162 if (WndOldParent)
2163 {
2164 hWndOldParent = WndOldParent->Self;
2165 }
2166
2167 IntReleaseWindowObject(Wnd);
2168 IntReleaseWindowObject(WndParent);
2169 IntReleaseWinLock();
2170
2171 return hWndOldParent;
2172 }
2173
2174 /*
2175 * NtUserGetShellWindow
2176 *
2177 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
2178 *
2179 * Status
2180 * @implemented
2181 */
2182
2183 HWND STDCALL
2184 NtUserGetShellWindow()
2185 {
2186 PWINSTATION_OBJECT WinStaObject;
2187 HWND Ret;
2188
2189 NTSTATUS Status = IntValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
2190 KernelMode,
2191 0,
2192 &WinStaObject);
2193
2194 if (!NT_SUCCESS(Status))
2195 {
2196 SetLastNtError(Status);
2197 return (HWND)0;
2198 }
2199
2200 Ret = (HWND)WinStaObject->ShellWindow;
2201
2202 ObDereferenceObject(WinStaObject);
2203 return Ret;
2204 }
2205
2206 /*
2207 * NtUserSetShellWindowEx
2208 *
2209 * This is undocumented function to set global shell window. The global
2210 * shell window has special handling of window position.
2211 *
2212 * Status
2213 * @implemented
2214 */
2215
2216 BOOL STDCALL
2217 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
2218 {
2219 PWINSTATION_OBJECT WinStaObject;
2220
2221 NTSTATUS Status = IntValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
2222 KernelMode,
2223 0,
2224 &WinStaObject);
2225
2226 if (!NT_SUCCESS(Status))
2227 {
2228 SetLastNtError(Status);
2229 return FALSE;
2230 }
2231
2232 /*
2233 * Test if we are permitted to change the shell window.
2234 */
2235 if (WinStaObject->ShellWindow)
2236 {
2237 ObDereferenceObject(WinStaObject);
2238 return FALSE;
2239 }
2240
2241 /*
2242 * Move shell window into background.
2243 */
2244 if (hwndListView && hwndListView != hwndShell)
2245 {
2246 /*
2247 * Disabled for now to get Explorer working.
2248 * -- Filip, 01/nov/2003
2249 */
2250 #if 0
2251 WinPosSetWindowPos(hwndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
2252 #endif
2253
2254 if (NtUserGetWindowLong(hwndListView, GWL_EXSTYLE, FALSE) & WS_EX_TOPMOST)
2255 {
2256 ObDereferenceObject(WinStaObject);
2257 return FALSE;
2258 }
2259 }
2260
2261 if (NtUserGetWindowLong(hwndShell, GWL_EXSTYLE, FALSE) & WS_EX_TOPMOST)
2262 {
2263 ObDereferenceObject(WinStaObject);
2264 return FALSE;
2265 }
2266
2267 WinPosSetWindowPos(hwndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
2268
2269 WinStaObject->ShellWindow = hwndShell;
2270 WinStaObject->ShellListView = hwndListView;
2271
2272 ObDereferenceObject(WinStaObject);
2273 return TRUE;
2274 }
2275
2276 /*
2277 * NtUserGetSystemMenu
2278 *
2279 * The NtUserGetSystemMenu function allows the application to access the
2280 * window menu (also known as the system menu or the control menu) for
2281 * copying and modifying.
2282 *
2283 * Parameters
2284 * hWnd
2285 * Handle to the window that will own a copy of the window menu.
2286 * bRevert
2287 * Specifies the action to be taken. If this parameter is FALSE,
2288 * NtUserGetSystemMenu returns a handle to the copy of the window menu
2289 * currently in use. The copy is initially identical to the window menu
2290 * but it can be modified.
2291 * If this parameter is TRUE, GetSystemMenu resets the window menu back
2292 * to the default state. The previous window menu, if any, is destroyed.
2293 *
2294 * Return Value
2295 * If the bRevert parameter is FALSE, the return value is a handle to a
2296 * copy of the window menu. If the bRevert parameter is TRUE, the return
2297 * value is NULL.
2298 *
2299 * Status
2300 * @implemented
2301 */
2302
2303 HMENU STDCALL
2304 NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
2305 {
2306 HMENU Result = 0;
2307 PWINDOW_OBJECT WindowObject;
2308 PMENU_OBJECT MenuObject;
2309
2310 WindowObject = IntGetWindowObject((HWND)hWnd);
2311 if (WindowObject == NULL)
2312 {
2313 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2314 return 0;
2315 }
2316
2317 MenuObject = IntGetSystemMenu(WindowObject, bRevert, FALSE);
2318 if (MenuObject)
2319 {
2320 /*
2321 * Return the handle of the first submenu.
2322 */
2323 ExAcquireFastMutexUnsafe(&MenuObject->MenuItemsLock);
2324 if (MenuObject->MenuItemList)
2325 {
2326 Result = MenuObject->MenuItemList->hSubMenu;
2327 if (!IntIsMenu(Result))
2328 Result = 0;
2329 }
2330 ExReleaseFastMutexUnsafe(&MenuObject->MenuItemsLock);
2331 IntReleaseMenuObject(MenuObject);
2332 }
2333
2334 IntReleaseWindowObject(WindowObject);
2335 return Result;
2336 }
2337
2338 /*
2339 * NtUserSetSystemMenu
2340 *
2341 * Status
2342 * @implemented
2343 */
2344
2345 BOOL STDCALL
2346 NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
2347 {
2348 BOOL Result = FALSE;
2349 PWINDOW_OBJECT WindowObject;
2350 PMENU_OBJECT MenuObject;
2351
2352 WindowObject = IntGetWindowObject(hWnd);
2353 if (!WindowObject)
2354 {
2355 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2356 return FALSE;
2357 }
2358
2359 if (hMenu)
2360 {
2361 /*
2362 * Assign new menu handle.
2363 */
2364 MenuObject = IntGetMenuObject(hMenu);
2365 if (!MenuObject)
2366 {
2367 IntReleaseWindowObject(WindowObject);
2368 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
2369 return FALSE;
2370 }
2371
2372 Result = IntSetSystemMenu(WindowObject, MenuObject);
2373
2374 IntReleaseMenuObject(MenuObject);
2375 }
2376
2377 IntReleaseWindowObject(WindowObject);
2378
2379 return Result;
2380 }
2381
2382 /*
2383 * NtUserGetWindow
2384 *
2385 * The NtUserGetWindow function retrieves a handle to a window that has the
2386 * specified relationship (Z order or owner) to the specified window.
2387 *
2388 * Status
2389 * @implemented
2390 */
2391
2392 HWND STDCALL
2393 NtUserGetWindow(HWND hWnd, UINT Relationship)
2394 {
2395 PWINDOW_OBJECT WindowObject;
2396 HWND hWndResult = NULL;
2397
2398 IntAcquireWinLockShared();
2399
2400 if (!(WindowObject = IntGetWindowObject(hWnd)))
2401 {
2402 IntReleaseWinLock();
2403 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2404 return NULL;
2405 }
2406
2407 switch (Relationship)
2408 {
2409 case GW_HWNDFIRST:
2410 if (WindowObject->Parent && WindowObject->Parent->FirstChild)
2411 hWndResult = WindowObject->Parent->FirstChild->Self;
2412 break;
2413
2414 case GW_HWNDLAST:
2415 if (WindowObject->Parent && WindowObject->Parent->LastChild)
2416 hWndResult = WindowObject->Parent->LastChild->Self;
2417 break;
2418
2419 case GW_HWNDNEXT:
2420 if (WindowObject->NextSibling)
2421 hWndResult = WindowObject->NextSibling->Self;
2422 break;
2423
2424 case GW_HWNDPREV:
2425 if (WindowObject->PrevSibling)
2426 hWndResult = WindowObject->PrevSibling->Self;
2427 break;
2428
2429 case GW_OWNER:
2430 if (WindowObject->Owner)
2431 hWndResult = WindowObject->Owner->Self;
2432 break;
2433 case GW_CHILD:
2434 if (WindowObject->FirstChild)
2435 hWndResult = WindowObject->FirstChild->Self;
2436 break;
2437 }
2438
2439 IntReleaseWindowObject(WindowObject);
2440 IntReleaseWinLock();
2441
2442 return hWndResult;
2443 }
2444
2445 /*
2446 * NtUserGetWindowDC
2447 *
2448 * The NtUserGetWindowDC function retrieves the device context (DC) for the
2449 * entire window, including title bar, menus, and scroll bars. A window device
2450 * context permits painting anywhere in a window, because the origin of the
2451 * device context is the upper-left corner of the window instead of the client
2452 * area.
2453 *
2454 * Status
2455 * @implemented
2456 */
2457
2458 DWORD STDCALL
2459 NtUserGetWindowDC(HWND hWnd)
2460 {
2461 return (DWORD)NtUserGetDCEx(hWnd, 0, DCX_USESTYLE | DCX_WINDOW);
2462 }
2463
2464 /*
2465 * NtUserGetWindowLong
2466 *
2467 * The NtUserGetWindowLong function retrieves information about the specified
2468 * window. The function also retrieves the 32-bit (long) value at the
2469 * specified offset into the extra window memory.
2470 *
2471 * Status
2472 * @implemented
2473 */
2474
2475 LONG STDCALL
2476 NtUserGetWindowLong(HWND hWnd, DWORD Index, BOOL Ansi)
2477 {
2478 PWINDOW_OBJECT WindowObject;
2479 LONG Result;
2480
2481 DPRINT("NtUserGetWindowLong(%x,%d,%d)\n", hWnd, (INT)Index, Ansi);
2482
2483 WindowObject = IntGetWindowObject(hWnd);
2484 if (WindowObject == NULL)
2485 {
2486 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2487 return 0;
2488 }
2489
2490 /*
2491 * Only allow CSRSS to mess with the desktop window
2492 */
2493 if (hWnd == IntGetDesktopWindow()
2494 && WindowObject->OwnerThread->ThreadsProcess != PsGetCurrentProcess())
2495 {
2496 SetLastWin32Error(STATUS_ACCESS_DENIED);
2497 return 0;
2498 }
2499
2500 if ((INT)Index >= 0)
2501 {
2502 if (Index > WindowObject->ExtraDataSize - sizeof(LONG))
2503 {
2504 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2505 return 0;
2506 }
2507 Result = *((LONG *)(WindowObject->ExtraData + Index));
2508 }
2509 else
2510 {
2511 switch (Index)
2512 {
2513 case GWL_EXSTYLE:
2514 Result = WindowObject->ExStyle;
2515 break;
2516
2517 case GWL_STYLE:
2518 Result = WindowObject->Style;
2519 break;
2520
2521 case GWL_WNDPROC:
2522 if (Ansi)
2523 Result = (LONG) WindowObject->WndProcA;
2524 else
2525 Result = (LONG) WindowObject->WndProcW;
2526 break;
2527
2528 case GWL_HINSTANCE:
2529 Result = (LONG) WindowObject->Instance;
2530 break;
2531
2532 case GWL_HWNDPARENT:
2533 if (WindowObject->Parent->Self == IntGetDesktopWindow())
2534 Result = (LONG) NtUserGetWindow(WindowObject->Self, GW_OWNER);
2535 else
2536 Result = (LONG) NtUserGetAncestor(WindowObject->Self, GA_PARENT);
2537 break;
2538
2539 case GWL_ID:
2540 Result = (LONG) WindowObject->IDMenu;
2541 break;
2542
2543 case GWL_USERDATA:
2544 Result = WindowObject->UserData;
2545 break;
2546
2547 default:
2548 DPRINT1("NtUserGetWindowLong(): Unsupported index %d\n", Index);
2549 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2550 Result = 0;
2551 break;
2552 }
2553 }
2554
2555 IntReleaseWindowObject(WindowObject);
2556
2557 return Result;
2558 }
2559
2560 /*
2561 * NtUserSetWindowLong
2562 *
2563 * The NtUserSetWindowLong function changes an attribute of the specified
2564 * window. The function also sets the 32-bit (long) value at the specified
2565 * offset into the extra window memory.
2566 *
2567 * Status
2568 * @implemented
2569 */
2570
2571 LONG STDCALL
2572 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
2573 {
2574 PWINDOW_OBJECT WindowObject;
2575 PW32PROCESS Process;
2576 PWINSTATION_OBJECT WindowStation;
2577 LONG OldValue;
2578 STYLESTRUCT Style;
2579
2580 if (hWnd == IntGetDesktopWindow())
2581 {
2582 SetLastWin32Error(STATUS_ACCESS_DENIED);
2583 return 0;
2584 }
2585
2586 WindowObject = IntGetWindowObject(hWnd);
2587 if (WindowObject == NULL)
2588 {
2589 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2590 return 0;
2591 }
2592
2593 if ((INT)Index >= 0)
2594 {
2595 if (Index > WindowObject->ExtraDataSize - sizeof(LONG))
2596 {
2597 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2598 IntReleaseWindowObject(WindowObject);
2599 return 0;
2600 }
2601 OldValue = *((LONG *)(WindowObject->ExtraData + Index));
2602 *((LONG *)(WindowObject->ExtraData + Index)) = NewValue;
2603 }
2604 else
2605 {
2606 switch (Index)
2607 {
2608 case GWL_EXSTYLE:
2609 OldValue = (LONG) WindowObject->ExStyle;
2610 Style.styleOld = OldValue;
2611 Style.styleNew = NewValue;
2612
2613 /*
2614 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
2615 */
2616 Process = WindowObject->OwnerThread->ThreadsProcess->Win32Process;
2617 WindowStation = Process->WindowStation;
2618 if(WindowStation)
2619 {
2620 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
2621 Style.styleNew &= ~WS_EX_TOPMOST;
2622 }
2623
2624 IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
2625 WindowObject->ExStyle = (DWORD)Style.styleNew;
2626 IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
2627 break;
2628
2629 case GWL_STYLE:
2630 OldValue = (LONG) WindowObject->Style;
2631 Style.styleOld = OldValue;
2632 Style.styleNew = NewValue;
2633 IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
2634 WindowObject->Style = (DWORD)Style.styleNew;
2635 IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
2636 break;
2637
2638 case GWL_WNDPROC:
2639 /* FIXME: should check if window belongs to current process */
2640 if (Ansi)
2641 {
2642 OldValue = (LONG) WindowObject->WndProcA;
2643 WindowObject->WndProcA = (WNDPROC) NewValue;
2644 WindowObject->WndProcW = (WNDPROC) IntAddWndProcHandle((WNDPROC)NewValue,FALSE);
2645 WindowObject->Unicode = FALSE;
2646 }
2647 else
2648 {
2649 OldValue = (LONG) WindowObject->WndProcW;
2650 WindowObject->WndProcW = (WNDPROC) NewValue;
2651 WindowObject->WndProcA = (WNDPROC) IntAddWndProcHandle((WNDPROC)NewValue,TRUE);
2652 WindowObject->Unicode = TRUE;
2653 }
2654 break;
2655
2656 case GWL_HINSTANCE:
2657 OldValue = (LONG) WindowObject->Instance;
2658 WindowObject->Instance = (HINSTANCE) NewValue;
2659 break;
2660
2661 case GWL_HWNDPARENT:
2662 if (WindowObject->Parent->Self == IntGetDesktopWindow())
2663 OldValue = (LONG) IntSetOwner(WindowObject->Self, (HWND) NewValue);
2664 else
2665 OldValue = (LONG) NtUserSetParent(WindowObject->Self, (HWND) NewValue);
2666 break;
2667
2668 case GWL_ID:
2669 OldValue = (LONG) WindowObject->IDMenu;
2670 WindowObject->IDMenu = (UINT) NewValue;
2671 break;
2672
2673 case GWL_USERDATA:
2674 OldValue = WindowObject->UserData;
2675 WindowObject->UserData = NewValue;
2676 break;
2677
2678 default:
2679 DPRINT1("NtUserSetWindowLong(): Unsupported index %d\n", Index);
2680 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2681 OldValue = 0;
2682 break;
2683 }
2684 }
2685
2686 IntReleaseWindowObject(WindowObject);
2687
2688 return OldValue;
2689 }
2690
2691 /*
2692 * NtUserSetWindowWord
2693 *
2694 * Legacy function similar to NtUserSetWindowLong.
2695 *
2696 * Status
2697 * @implemented
2698 */
2699
2700 WORD STDCALL
2701 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
2702 {
2703 PWINDOW_OBJECT WindowObject;
2704 WORD OldValue;
2705
2706 switch (Index)
2707 {
2708 case GWL_ID:
2709 case GWL_HINSTANCE:
2710 case GWL_HWNDPARENT:
2711 return NtUserSetWindowLong(hWnd, Index, (UINT)NewValue, TRUE);
2712 default:
2713 if (Index < 0)
2714 {
2715 SetLastWin32Error(ERROR_INVALID_INDEX);
2716 return 0;
2717 }
2718 }
2719
2720 WindowObject = IntGetWindowObject(hWnd);
2721 if (WindowObject == NULL)
2722 {
2723 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2724 return 0;
2725 }
2726
2727 if (Index > WindowObject->ExtraDataSize - sizeof(WORD))
2728 {
2729 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2730 IntReleaseWindowObject(WindowObject);
2731 return 0;
2732 }
2733
2734 OldValue = *((WORD *)(WindowObject->ExtraData + Index));
2735 *((WORD *)(WindowObject->ExtraData + Index)) = NewValue;
2736
2737 IntReleaseWindowObject(WindowObject);
2738
2739 return OldValue;
2740 }
2741
2742 /*
2743 * @implemented
2744 */
2745 BOOL STDCALL
2746 NtUserGetWindowPlacement(HWND hWnd,
2747 WINDOWPLACEMENT *lpwndpl)
2748 {
2749 PWINDOW_OBJECT WindowObject;
2750 PINTERNALPOS InternalPos;
2751 POINT Size;
2752 WINDOWPLACEMENT Safepl;
2753 NTSTATUS Status;
2754
2755 WindowObject = IntGetWindowObject(hWnd);
2756 if (WindowObject == NULL)
2757 {
2758 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2759 return FALSE;
2760 }
2761
2762 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
2763 if(!NT_SUCCESS(Status))
2764 {
2765 SetLastNtError(Status);
2766 IntReleaseWindowObject(WindowObject);
2767 return FALSE;
2768 }
2769 if(Safepl.length != sizeof(WINDOWPLACEMENT))
2770 {
2771 IntReleaseWindowObject(WindowObject);
2772 return FALSE;
2773 }
2774
2775 Safepl.flags = 0;
2776 Safepl.showCmd = ((WindowObject->Flags & WINDOWOBJECT_RESTOREMAX) ? SW_MAXIMIZE : SW_SHOWNORMAL);
2777
2778 Size.x = WindowObject->WindowRect.left;
2779 Size.y = WindowObject->WindowRect.top;
2780 InternalPos = WinPosInitInternalPos(WindowObject, Size,
2781 &WindowObject->WindowRect);
2782 if (InternalPos)
2783 {
2784 Safepl.rcNormalPosition = InternalPos->NormalRect;
2785 Safepl.ptMinPosition = InternalPos->IconPos;
2786 Safepl.ptMaxPosition = InternalPos->MaxPos;
2787 }
2788 else
2789 {
2790 IntReleaseWindowObject(WindowObject);
2791 return FALSE;
2792 }
2793
2794 Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
2795 if(!NT_SUCCESS(Status))
2796 {
2797 SetLastNtError(Status);
2798 IntReleaseWindowObject(WindowObject);
2799 return FALSE;
2800 }
2801
2802 IntReleaseWindowObject(WindowObject);
2803 return TRUE;
2804 }
2805
2806
2807 /*!
2808 * Return the dimension of the window in the screen coordinates.
2809 * \param hWnd window handle.
2810 * \param Rect pointer to the buffer where the coordinates are returned.
2811 */
2812 /*
2813 * @implemented
2814 */
2815 BOOL STDCALL
2816 NtUserGetWindowRect(HWND hWnd, LPRECT Rect)
2817 {
2818 PWINDOW_OBJECT Wnd;
2819 RECT SafeRect;
2820
2821 IntAcquireWinLockShared();
2822 if (!(Wnd = IntGetWindowObject(hWnd)))
2823 {
2824 IntReleaseWinLock();
2825 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2826 return FALSE;
2827 }
2828
2829 SafeRect = Wnd->WindowRect;
2830 IntReleaseWinLock();
2831
2832 if (! NT_SUCCESS(MmCopyToCaller(Rect, &SafeRect, sizeof(RECT))))
2833 {
2834 return FALSE;
2835 }
2836
2837 return TRUE;
2838 }
2839
2840
2841 /*
2842 * @implemented
2843 */
2844 DWORD STDCALL
2845 NtUserGetWindowThreadProcessId(HWND hWnd, LPDWORD UnsafePid)
2846 {
2847 PWINDOW_OBJECT Wnd;
2848 DWORD tid, pid;
2849
2850 IntAcquireWinLockShared();
2851
2852 if (!(Wnd = IntGetWindowObject(hWnd)))
2853 {
2854 IntReleaseWinLock();
2855 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2856 return 0;
2857 }
2858
2859 tid = IntGetWindowThreadProcessId(Wnd, &pid);
2860 IntReleaseWinLock();
2861
2862 if (UnsafePid) MmCopyToCaller(UnsafePid, &pid, sizeof(DWORD));
2863
2864 return tid;
2865 }
2866
2867
2868 /*
2869 * @unimplemented
2870 */
2871 DWORD STDCALL
2872 NtUserLockWindowUpdate(DWORD Unknown0)
2873 {
2874 UNIMPLEMENTED
2875
2876 return 0;
2877 }
2878
2879
2880 /*
2881 * @implemented
2882 */
2883 BOOL STDCALL
2884 NtUserMoveWindow(
2885 HWND hWnd,
2886 int X,
2887 int Y,
2888 int nWidth,
2889 int nHeight,
2890 BOOL bRepaint)
2891 {
2892 UINT flags = SWP_NOZORDER | SWP_NOACTIVATE;
2893
2894 if(!bRepaint)
2895 flags |= SWP_NOREDRAW;
2896 return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight, flags);
2897 }
2898
2899 /*
2900 QueryWindow based on KJK::Hyperion and James Tabor.
2901
2902 0 = QWUniqueProcessId
2903 1 = QWUniqueThreadId
2904 4 = QWIsHung Implements IsHungAppWindow found
2905 by KJK::Hyperion.
2906
2907 9 = QWKillWindow When I called this with hWnd ==
2908 DesktopWindow, it shutdown the system
2909 and rebooted.
2910 */
2911 /*
2912 * @implemented
2913 */
2914 DWORD STDCALL
2915 NtUserQueryWindow(HWND hWnd, DWORD Index)
2916 {
2917 PWINDOW_OBJECT Window = IntGetWindowObject(hWnd);
2918 DWORD Result;
2919
2920 if (Window == NULL)
2921 {
2922 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2923 return 0;
2924 }
2925
2926 switch(Index)
2927 {
2928 case 0x00:
2929 Result = (DWORD)Window->OwnerThread->ThreadsProcess->UniqueProcessId;
2930 break;
2931
2932 case 0x01:
2933 Result = (DWORD)Window->OwnerThread->Cid.UniqueThread;
2934 break;
2935
2936 default:
2937 Result = (DWORD)NULL;
2938 break;
2939 }
2940
2941 IntReleaseWindowObject(Window);
2942
2943 return Result;
2944 }
2945
2946
2947 /*
2948 * @unimplemented
2949 */
2950 DWORD STDCALL
2951 NtUserRealChildWindowFromPoint(DWORD Unknown0,
2952 DWORD Unknown1,
2953 DWORD Unknown2)
2954 {
2955 UNIMPLEMENTED
2956
2957 return 0;
2958 }
2959
2960
2961 /*
2962 * @implemented
2963 */
2964 UINT STDCALL
2965 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
2966 {
2967 #if 0
2968 PLIST_ENTRY Current;
2969 PREGISTERED_MESSAGE NewMsg, RegMsg;
2970 UINT Msg = REGISTERED_MESSAGE_MIN;
2971 UNICODE_STRING MessageName;
2972 NTSTATUS Status;
2973
2974 Status = MmCopyFromCaller(&MessageName, MessageNameUnsafe, sizeof(UNICODE_STRING));
2975 if (! NT_SUCCESS(Status))
2976 {
2977 SetLastNtError(Status);
2978 return 0;
2979 }
2980
2981 NewMsg = ExAllocatePoolWithTag(PagedPool,
2982 sizeof(REGISTERED_MESSAGE) +
2983 MessageName.Length,
2984 TAG_WNAM);
2985 if (NULL == NewMsg)
2986 {
2987 SetLastNtError(STATUS_NO_MEMORY);
2988 return 0;
2989 }
2990
2991 Status = MmCopyFromCaller(NewMsg->MessageName, MessageName.Buffer, MessageName.Length);
2992 if (! NT_SUCCESS(Status))
2993 {
2994 ExFreePool(NewMsg);
2995 SetLastNtError(Status);
2996 return 0;
2997 }
2998 NewMsg->MessageName[MessageName.Length / sizeof(WCHAR)] = L'\0';
2999 if (wcslen(NewMsg->MessageName) != MessageName.Length / sizeof(WCHAR))
3000 {
3001 ExFreePool(NewMsg);
3002 SetLastNtError(STATUS_INVALID_PARAMETER);
3003 return 0;
3004 }
3005
3006 Current = RegisteredMessageListHead.Flink;
3007 while (Current != &RegisteredMessageListHead)
3008 {
3009 RegMsg = CONTAINING_RECORD(Current, REGISTERED_MESSAGE, ListEntry);
3010 if (0 == wcscmp(NewMsg->MessageName, RegMsg->MessageName))
3011 {
3012 ExFreePool(NewMsg);
3013 return Msg;
3014 }
3015 Msg++;
3016 Current = Current->Flink;
3017 }
3018
3019 if (REGISTERED_MESSAGE_MAX < Msg)
3020 {
3021 ExFreePool(NewMsg);
3022 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
3023 return 0;
3024 }
3025
3026 InsertTailList(&RegisteredMessageListHead, &(NewMsg->ListEntry));
3027
3028 return Msg;
3029 #else
3030 /*
3031 * Notes:
3032 * - There's no need to call MmSafe*, because it should be done in kernel.
3033 * - The passed UNICODE_STRING is expected to be NULL-terminated.
3034 */
3035 return (UINT)IntAddAtom(MessageNameUnsafe->Buffer);
3036 #endif
3037 }
3038
3039
3040 /*
3041 * @unimplemented
3042 */
3043 DWORD STDCALL
3044 NtUserSetImeOwnerWindow(DWORD Unknown0,
3045 DWORD Unknown1)
3046 {
3047 UNIMPLEMENTED
3048
3049 return 0;
3050 }
3051
3052
3053 /*
3054 * @unimplemented
3055 */
3056 DWORD STDCALL
3057 NtUserSetInternalWindowPos(DWORD Unknown0,
3058 DWORD Unknown1,
3059 DWORD Unknown2,
3060 DWORD Unknown3)
3061 {
3062 UNIMPLEMENTED
3063
3064 return 0;
3065
3066 }
3067
3068
3069 /*
3070 * @unimplemented
3071 */
3072 DWORD STDCALL
3073 NtUserSetLayeredWindowAttributes(DWORD Unknown0,
3074 DWORD Unknown1,
3075 DWORD Unknown2,
3076 DWORD Unknown3)
3077 {
3078 UNIMPLEMENTED
3079
3080 return 0;
3081 }
3082
3083
3084 /*
3085 * @unimplemented
3086 */
3087 DWORD STDCALL
3088 NtUserSetLogonNotifyWindow(DWORD Unknown0)
3089 {
3090 UNIMPLEMENTED
3091
3092 return 0;
3093 }
3094
3095
3096 /*
3097 * @implemented
3098 */
3099 BOOL STDCALL
3100 NtUserSetMenu(
3101 HWND Wnd,
3102 HMENU Menu,
3103 BOOL Repaint)
3104 {
3105 PWINDOW_OBJECT WindowObject;
3106 BOOL Changed;
3107
3108 WindowObject = IntGetWindowObject((HWND) Wnd);
3109 if (NULL == WindowObject)
3110 {
3111 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3112 return FALSE;
3113 }
3114
3115 if (! IntSetMenu(WindowObject, Menu, &Changed))
3116 {
3117 IntReleaseWindowObject(WindowObject);
3118 return FALSE;
3119 }
3120
3121 IntReleaseWindowObject(WindowObject);
3122
3123 if (Changed && Repaint)
3124 {
3125 WinPosSetWindowPos(Wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3126 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
3127 }
3128
3129 return TRUE;
3130 }
3131
3132
3133 /*
3134 * @unimplemented
3135 */
3136 DWORD STDCALL
3137 NtUserSetWindowFNID(DWORD Unknown0,
3138 DWORD Unknown1)
3139 {
3140 UNIMPLEMENTED
3141
3142 return 0;
3143 }
3144
3145
3146
3147 /*
3148 * @implemented
3149 */
3150 BOOL STDCALL
3151 NtUserSetWindowPlacement(HWND hWnd,
3152 WINDOWPLACEMENT *lpwndpl)
3153 {
3154 PWINDOW_OBJECT WindowObject;
3155 WINDOWPLACEMENT Safepl;
3156 NTSTATUS Status;
3157
3158 WindowObject = IntGetWindowObject(hWnd);
3159 if (WindowObject == NULL)
3160 {
3161 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3162 return FALSE;
3163 }
3164 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3165 if(!NT_SUCCESS(Status))
3166 {
3167 SetLastNtError(Status);
3168 IntReleaseWindowObject(WindowObject);
3169 return FALSE;
3170 }
3171 if(Safepl.length != sizeof(WINDOWPLACEMENT))
3172 {
3173 IntReleaseWindowObject(WindowObject);
3174 return FALSE;
3175 }
3176
3177 if ((WindowObject->Style & (WS_MAXIMIZE | WS_MINIMIZE)) == 0)
3178 {
3179 WinPosSetWindowPos(WindowObject->Self, NULL,
3180 Safepl.rcNormalPosition.left, Safepl.rcNormalPosition.top,
3181 Safepl.rcNormalPosition.right - Safepl.rcNormalPosition.left,
3182 Safepl.rcNormalPosition.bottom - Safepl.rcNormalPosition.top,
3183 SWP_NOZORDER | SWP_NOACTIVATE);
3184 }
3185
3186 /* FIXME - change window status */
3187 WinPosShowWindow(WindowObject->Self, Safepl.showCmd);
3188
3189 if (WindowObject->InternalPos == NULL)
3190 WindowObject->InternalPos = ExAllocatePoolWithTag(PagedPool, sizeof(INTERNALPOS), TAG_WININTLIST);
3191 WindowObject->InternalPos->NormalRect = Safepl.rcNormalPosition;
3192 WindowObject->InternalPos->IconPos = Safepl.ptMinPosition;
3193 WindowObject->InternalPos->MaxPos = Safepl.ptMaxPosition;
3194
3195 IntReleaseWindowObject(WindowObject);
3196 return TRUE;
3197 }
3198
3199
3200 /*
3201 * @implemented
3202 */
3203 BOOL STDCALL
3204 NtUserSetWindowPos(
3205 HWND hWnd,
3206 HWND hWndInsertAfter,
3207 int X,
3208 int Y,
3209 int cx,
3210 int cy,
3211 UINT uFlags)
3212 {
3213 return WinPosSetWindowPos(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags);
3214 }
3215
3216
3217 /*
3218 * @unimplemented
3219 */
3220 DWORD STDCALL
3221 NtUserSetWindowRgn(DWORD Unknown0,
3222 DWORD Unknown1,
3223 DWORD Unknown2)
3224 {
3225 UNIMPLEMENTED
3226
3227 return 0;
3228 }
3229
3230
3231 /*
3232 * @implemented
3233 */
3234 BOOL STDCALL
3235 NtUserShowWindow(HWND hWnd,
3236 LONG nCmdShow)
3237 {
3238 return WinPosShowWindow(hWnd, nCmdShow);
3239 }
3240
3241
3242 /*
3243 * @unimplemented
3244 */
3245 DWORD STDCALL
3246 NtUserShowWindowAsync(DWORD Unknown0,
3247 DWORD Unknown1)
3248 {
3249 UNIMPLEMENTED
3250
3251 return 0;
3252 }
3253
3254
3255 /*
3256 * @unimplemented
3257 */
3258 DWORD STDCALL
3259 NtUserUpdateLayeredWindow(DWORD Unknown0,
3260 DWORD Unknown1,
3261 DWORD Unknown2,
3262 DWORD Unknown3,
3263 DWORD Unknown4,
3264 DWORD Unknown5,
3265 DWORD Unknown6,
3266 DWORD Unknown7,
3267 DWORD Unknown8)
3268 {
3269 UNIMPLEMENTED
3270
3271 return 0;
3272 }
3273
3274
3275 /*
3276 * @implemented
3277 */
3278 VOID STDCALL
3279 NtUserValidateRect(HWND hWnd, const RECT* Rect)
3280 {
3281 return (VOID)NtUserRedrawWindow(hWnd, Rect, 0, RDW_VALIDATE | RDW_NOCHILDREN);
3282 }
3283
3284 static BOOL IsStaticClass(PWINDOW_OBJECT Window)
3285 {
3286 BOOL rc = FALSE;
3287
3288 ASSERT(0 != Window->Class);
3289 ASSERT(0 != Window->Class->Atom);
3290
3291 DbgPrint("FIXME: Update IsStatic to really check if a window is a static\n");
3292 /*
3293 if (0 == wcscmp((LPWSTR)Window->Class->lpszClassName, L"Static"))
3294 rc = TRUE;
3295 */
3296 return rc;
3297 }
3298
3299 static BOOL IsDisabled(PWINDOW_OBJECT Window)
3300 {
3301 BOOL rc = FALSE;
3302 ASSERT(0 != Window);
3303
3304 rc = (Window->Style & WS_DISABLED);
3305
3306 return rc;
3307 }
3308
3309 static PWINDOW_OBJECT RestrictiveSearchChildWindows(PWINDOW_OBJECT Window, POINT p)
3310 {
3311 PWINDOW_OBJECT ChildWindow = 0;
3312 PWINDOW_OBJECT rc = Window;
3313 ASSERT(0 != Window);
3314
3315 /*
3316 **Aquire a mutex to the Child list.
3317 */
3318 ExAcquireFastMutexUnsafe(&Window->ChildrenListLock);
3319
3320 /*
3321 **Now Find the first non-static window.
3322 */
3323 ChildWindow = Window->FirstChild;
3324
3325 while (0 != ChildWindow)
3326 {
3327 /*
3328 **Test Restrictions on the window.
3329 */
3330 if (!IsStaticClass(ChildWindow) &&
3331 !IsDisabled(ChildWindow) &&
3332 IntIsWindowVisible(ChildWindow->Self))
3333 {
3334 /*
3335 **Now find the deepest child window
3336 */
3337 if (POINT_IN_RECT(p, ChildWindow->WindowRect))
3338 {
3339 rc = RestrictiveSearchChildWindows(ChildWindow, p);
3340 break;
3341 }
3342 }
3343 ChildWindow = ChildWindow->NextSibling;
3344 }
3345
3346 /*
3347 **Release mutex.
3348 */
3349 ExReleaseFastMutexUnsafe(&Window->ChildrenListLock);
3350
3351 return rc;
3352 }
3353
3354 /*
3355 * NtUserWindowFromPoint
3356 *
3357 * Return Value
3358 * The return value is a handle to the window that contains the point.
3359 * If no window exists at the given point, the return value is NULL.
3360 * If the point is over a static text control, the return value is a handle
3361 * to the window under the static text control.
3362 *
3363 * Remarks
3364 * The WindowFromPoint function does not retrieve a handle to a hidden or
3365 * disabled window, even if the point is within the window. An application
3366 * should use the ChildWindowFromPoint function for a nonrestrictive search.
3367 *
3368 * Author
3369 * Mark Tempel
3370 *
3371 * Status
3372 * @implemented
3373 */
3374
3375 HWND STDCALL
3376 NtUserWindowFromPoint(LONG X, LONG Y)
3377 {
3378 HWND hWnd = 0;
3379 PWINDOW_OBJECT DesktopWindow = 0;
3380 PWINDOW_OBJECT TopWindow = 0;
3381 PWINDOW_OBJECT ChildWindow = 0;
3382 POINT pt;
3383
3384 DesktopWindow = IntGetWindowObject(IntGetDesktopWindow());
3385
3386 pt.x = X;
3387 pt.y = Y;
3388
3389 if (DesktopWindow != NULL)
3390 {
3391 /*
3392 * Aquire the mutex to the child window list. (All the topmost windows)
3393 */
3394 ExAcquireFastMutexUnsafe(&DesktopWindow->ChildrenListLock);
3395
3396 /*
3397 * Spin through the windows looking for the window that contains the
3398 * point. The child windows are in Z-order.
3399 */
3400 TopWindow = DesktopWindow->FirstChild;
3401 while (TopWindow != NULL)
3402 {
3403 if (POINT_IN_RECT(pt, TopWindow->WindowRect))
3404 {
3405 break;
3406 }
3407 TopWindow = TopWindow->NextSibling;
3408 }
3409
3410 /*
3411 * Search for the child window that contains the point.
3412 */
3413 if (TopWindow != NULL)
3414 {
3415 ChildWindow = RestrictiveSearchChildWindows(TopWindow, pt);
3416 if (ChildWindow != NULL)
3417 {
3418 hWnd = ChildWindow->Self;
3419 }
3420 }
3421
3422 /*
3423 * Release mutex.
3424 */
3425 ExReleaseFastMutexUnsafe(&DesktopWindow->ChildrenListLock);
3426 }
3427
3428 IntReleaseWindowObject(DesktopWindow);
3429
3430 return hWnd;
3431 }
3432
3433
3434 /*
3435 * NtUserDefSetText
3436 *
3437 * Undocumented function that is called from DefWindowProc to set
3438 * window text.
3439 *
3440 * FIXME: Call this from user32.dll!
3441 *
3442 * Status
3443 * @unimplemented
3444 */
3445
3446 BOOL STDCALL
3447 NtUserDefSetText(HWND WindowHandle, PANSI_STRING Text)
3448 {
3449 PWINDOW_OBJECT WindowObject;
3450 UNICODE_STRING NewWindowName;
3451 BOOL Result = FALSE;
3452
3453 WindowObject = IntGetWindowObject(WindowHandle);
3454 if (!WindowObject)
3455 {
3456 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3457 return FALSE;
3458 }
3459
3460 if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&NewWindowName, Text, TRUE)))
3461 {
3462 RtlFreeUnicodeString(&WindowObject->WindowName);
3463 WindowObject->WindowName.Buffer = NewWindowName.Buffer;
3464 WindowObject->WindowName.Length = NewWindowName.Length;
3465 WindowObject->WindowName.MaximumLength = NewWindowName.MaximumLength;
3466 Result = TRUE;
3467 }
3468
3469 IntReleaseWindowObject(WindowObject);
3470
3471 return Result;
3472 }
3473
3474 /*
3475 * NtUserInternalGetWindowText
3476 *
3477 * FIXME: Call this from user32.dll!
3478 *
3479 * Status
3480 * @implemented
3481 */
3482
3483 DWORD STDCALL
3484 NtUserInternalGetWindowText(HWND WindowHandle, LPWSTR Text, INT MaxCount)
3485 {
3486 PWINDOW_OBJECT WindowObject;
3487 DWORD Result;
3488
3489 WindowObject = IntGetWindowObject(WindowHandle);
3490 if (!WindowObject)
3491 {
3492 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3493 return 0;
3494 }
3495
3496 Result = WindowObject->WindowName.Length / sizeof(WCHAR);
3497 if (Text)
3498 {
3499 /* FIXME: Shouldn't it be always NULL terminated? */
3500 wcsncpy(Text, WindowObject->WindowName.Buffer, MaxCount);
3501 if (MaxCount < Result)
3502 {
3503 Result = MaxCount;
3504 }
3505 }
3506
3507 IntReleaseWindowObject(WindowObject);
3508
3509 return Result;
3510 }
3511
3512 DWORD STDCALL
3513 NtUserDereferenceWndProcHandle(WNDPROC wpHandle, WndProcHandle *Data)
3514 {
3515 WndProcHandle Entry;
3516 if (((DWORD)wpHandle & 0xFFFF0000) == 0xFFFF0000)
3517 {
3518 Entry = WndProcHandlesArray[(DWORD)wpHandle & 0x0000FFFF];
3519 Data->WindowProc = Entry.WindowProc;
3520 Data->IsUnicode = Entry.IsUnicode;
3521 Data->ProcessID = Entry.ProcessID;
3522 return TRUE;
3523 } else {
3524 return FALSE;
3525 }
3526 return FALSE;
3527 }
3528
3529 DWORD
3530 IntAddWndProcHandle(WNDPROC WindowProc, BOOL IsUnicode)
3531 {
3532 WORD i;
3533 WORD FreeSpot;
3534 BOOL found;
3535 WndProcHandle *OldArray;
3536 WORD OldArraySize;
3537 found = FALSE;
3538 for (i = 0;i < WndProcHandlesArraySize;i++)
3539 {
3540 if (WndProcHandlesArray[i].WindowProc == NULL)
3541 {
3542 FreeSpot = i;
3543 found = TRUE;
3544 }
3545 }
3546 if (!found)
3547 {
3548 OldArray = WndProcHandlesArray;
3549 OldArraySize = WndProcHandlesArraySize;
3550 WndProcHandlesArray = ExAllocatePoolWithTag(PagedPool,(OldArraySize + WPH_SIZE) * sizeof(WndProcHandle), TAG_WINPROCLST);
3551 WndProcHandlesArraySize = OldArraySize + WPH_SIZE;
3552 RtlCopyMemory(WndProcHandlesArray,OldArray,OldArraySize * sizeof(WndProcHandle));
3553 ExFreePool(OldArray);
3554 FreeSpot = OldArraySize + 1;
3555 }
3556 WndProcHandlesArray[FreeSpot].WindowProc = WindowProc;
3557 WndProcHandlesArray[FreeSpot].IsUnicode = IsUnicode;
3558 WndProcHandlesArray[FreeSpot].ProcessID = PsGetCurrentProcessId();
3559 return FreeSpot + 0xFFFF0000;
3560 }
3561
3562 DWORD
3563 IntRemoveWndProcHandle(WNDPROC Handle)
3564 {
3565 WORD position;
3566 position = (DWORD)Handle & 0x0000FFFF;
3567 if (position > WndProcHandlesArraySize)
3568 {
3569 return FALSE;
3570 }
3571 WndProcHandlesArray[position].WindowProc = NULL;
3572 WndProcHandlesArray[position].IsUnicode = FALSE;
3573 WndProcHandlesArray[position].ProcessID = NULL;
3574 return TRUE;
3575 }
3576
3577 DWORD
3578 IntRemoveProcessWndProcHandles(HANDLE ProcessID)
3579 {
3580 WORD i;
3581 for (i = 0;i < WndProcHandlesArraySize;i++)
3582 {
3583 if (WndProcHandlesArray[i].ProcessID == ProcessID)
3584 {
3585 WndProcHandlesArray[i].WindowProc = NULL;
3586 WndProcHandlesArray[i].IsUnicode = FALSE;
3587 WndProcHandlesArray[i].ProcessID = NULL;
3588 }
3589 }
3590 return TRUE;
3591 }
3592
3593 /* EOF */