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