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