small bugfix - debug/release inconsistency - found by Thomas Weidenmueller
[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.241 2004/06/22 12:43:49 royce Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Windows
24 * FILE: subsys/win32k/ntuser/window.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 06-06-2001 CSH Created
28 */
29 /* INCLUDES ******************************************************************/
30 #include <w32k.h>
31
32 static WndProcHandle *WndProcHandlesArray = 0;
33 static WORD WndProcHandlesArraySize = 0;
34 #define WPH_SIZE 0x40 /* the size to add to the WndProcHandle array each time */
35
36 /* dialog resources appear to pass this in 16 bits, handle them properly */
37 #define CW_USEDEFAULT16 (0x8000)
38
39 #define POINT_IN_RECT(p, r) (((r.bottom >= p.y) && (r.top <= p.y))&&((r.left <= p.x )&&( r.right >= p.x )))
40
41 /* PRIVATE FUNCTIONS **********************************************************/
42
43 /*
44 * InitWindowImpl
45 *
46 * Initialize windowing implementation.
47 */
48
49 NTSTATUS FASTCALL
50 InitWindowImpl(VOID)
51 {
52 WndProcHandlesArray = ExAllocatePoolWithTag(PagedPool,WPH_SIZE * sizeof(WndProcHandle), TAG_WINPROCLST);
53 WndProcHandlesArraySize = WPH_SIZE;
54 return STATUS_SUCCESS;
55 }
56
57 /*
58 * CleanupWindowImpl
59 *
60 * Cleanup windowing implementation.
61 */
62
63 NTSTATUS FASTCALL
64 CleanupWindowImpl(VOID)
65 {
66 ExFreePool(WndProcHandlesArray);
67 WndProcHandlesArray = 0;
68 WndProcHandlesArraySize = 0;
69 return STATUS_SUCCESS;
70 }
71
72 /* HELPER FUNCTIONS ***********************************************************/
73
74 /*
75 * IntIsWindow
76 *
77 * The function determines whether the specified window handle identifies
78 * an existing window.
79 *
80 * Parameters
81 * hWnd
82 * Handle to the window to test.
83 *
84 * Return Value
85 * If the window handle identifies an existing window, the return value
86 * is TRUE. If the window handle does not identify an existing window,
87 * the return value is FALSE.
88 */
89
90 BOOL FASTCALL
91 IntIsWindow(HWND hWnd)
92 {
93 PWINDOW_OBJECT Window;
94
95 if (!(Window = IntGetWindowObject(hWnd)))
96 return FALSE;
97
98 IntReleaseWindowObject(Window);
99 return TRUE;
100 }
101
102 /*
103 * IntGetProcessWindowObject
104 *
105 * Get window object from handle of specified process.
106 */
107
108 PWINDOW_OBJECT FASTCALL
109 IntGetProcessWindowObject(PW32PROCESS ProcessData, HWND hWnd)
110 {
111 PWINDOW_OBJECT WindowObject;
112 NTSTATUS Status;
113
114 Status = ObmReferenceObjectByHandle(ProcessData->WindowStation->HandleTable,
115 hWnd, otWindow, (PVOID*)&WindowObject);
116 if (!NT_SUCCESS(Status))
117 {
118 return NULL;
119 }
120 return WindowObject;
121 }
122
123
124 PWINDOW_OBJECT FASTCALL
125 IntGetParent(PWINDOW_OBJECT Wnd)
126 {
127 HWND hWnd;
128
129 if (Wnd->Style & WS_POPUP)
130 {
131 IntLockRelatives(Wnd);
132 hWnd = Wnd->Owner;
133 IntUnLockRelatives(Wnd);
134 return IntGetWindowObject(hWnd);
135 }
136 else if (Wnd->Style & WS_CHILD)
137 {
138 IntLockRelatives(Wnd);
139 hWnd = Wnd->Parent;
140 IntUnLockRelatives(Wnd);
141 return IntGetWindowObject(hWnd);
142 }
143
144 return NULL;
145 }
146
147
148 PWINDOW_OBJECT FASTCALL
149 IntGetParentObject(PWINDOW_OBJECT Wnd)
150 {
151 HWND hParent;
152
153 IntLockRelatives(Wnd);
154 hParent = Wnd->Parent;
155 IntUnLockRelatives(Wnd);
156 return IntGetWindowObject(hParent);
157 }
158
159 /*
160 * IntWinListChildren
161 *
162 * Compile a list of all child window handles from given window.
163 *
164 * Remarks
165 * This function is similar to Wine WIN_ListChildren. The caller
166 * must free the returned list with ExFreePool.
167 */
168
169 HWND* FASTCALL
170 IntWinListChildren(PWINDOW_OBJECT Window)
171 {
172 PWINDOW_OBJECT Child;
173 HWND *List;
174 UINT Index, NumChildren = 0;
175
176 IntLockRelatives(Window);
177
178 for (Child = Window->FirstChild; Child; Child = Child->NextSibling)
179 ++NumChildren;
180
181 List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), TAG_WINLIST);
182 if(!List)
183 {
184 DPRINT1("Failed to allocate memory for children array\n");
185 IntUnLockRelatives(Window);
186 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
187 return NULL;
188 }
189 for (Child = Window->FirstChild, Index = 0;
190 Child != NULL;
191 Child = Child->NextSibling, ++Index)
192 List[Index] = Child->Self;
193 List[Index] = NULL;
194
195 IntUnLockRelatives(Window);
196
197 return List;
198 }
199
200 /***********************************************************************
201 * IntSendDestroyMsg
202 */
203 static void IntSendDestroyMsg(HWND Wnd)
204 {
205 #if 0 /* FIXME */
206 GUITHREADINFO info;
207
208 if (GetGUIThreadInfo(GetCurrentThreadId(), &info))
209 {
210 if (Wnd == info.hwndCaret)
211 {
212 DestroyCaret();
213 }
214 }
215 #endif
216
217 /*
218 * Send the WM_DESTROY to the window.
219 */
220 IntSendMessage(Wnd, WM_DESTROY, 0, 0);
221
222 /*
223 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
224 * make sure that the window still exists when we come back.
225 */
226 #if 0 /* FIXME */
227 if (IsWindow(Wnd))
228 {
229 HWND* pWndArray;
230 int i;
231
232 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
233
234 /* start from the end (FIXME: is this needed?) */
235 for (i = 0; pWndArray[i]; i++) ;
236
237 while (--i >= 0)
238 {
239 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
240 }
241 HeapFree(GetProcessHeap(), 0, pWndArray);
242 }
243 else
244 {
245 DPRINT("destroyed itself while in WM_DESTROY!\n");
246 }
247 #endif
248 }
249
250 /***********************************************************************
251 * IntDestroyWindow
252 *
253 * Destroy storage associated to a window. "Internals" p.358
254 */
255 static LRESULT IntDestroyWindow(PWINDOW_OBJECT Window,
256 PW32PROCESS ProcessData,
257 PW32THREAD ThreadData,
258 BOOLEAN SendMessages)
259 {
260 HWND *Children;
261 HWND *ChildHandle;
262 PWINDOW_OBJECT Child;
263 PMENU_OBJECT Menu;
264 BOOL BelongsToThreadData;
265
266 ASSERT(Window);
267
268 RemoveTimersWindow(Window->Self);
269
270 IntLockThreadWindows(Window->OwnerThread->Win32Thread);
271 if(Window->Status & WINDOWSTATUS_DESTROYING)
272 {
273 IntUnLockThreadWindows(Window->OwnerThread->Win32Thread);
274 DPRINT("Tried to call IntDestroyWindow() twice\n");
275 return 0;
276 }
277 Window->Status |= WINDOWSTATUS_DESTROYING;
278 /* remove the window already at this point from the thread window list so we
279 don't get into trouble when destroying the thread windows while we're still
280 in IntDestroyWindow() */
281 RemoveEntryList(&Window->ThreadListEntry);
282 IntUnLockThreadWindows(Window->OwnerThread->Win32Thread);
283
284 BelongsToThreadData = IntWndBelongsToThread(Window, ThreadData);
285
286 if(SendMessages)
287 {
288 /* Send destroy messages */
289 IntSendDestroyMsg(Window->Self);
290 }
291
292 /* free child windows */
293 Children = IntWinListChildren(Window);
294 if (Children)
295 {
296 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
297 {
298 if ((Child = IntGetWindowObject(*ChildHandle)))
299 {
300 if(!IntWndBelongsToThread(Child, ThreadData))
301 {
302 /* send WM_DESTROY messages to windows not belonging to the same thread */
303 IntSendDestroyMsg(Child->Self);
304 }
305 else
306 IntDestroyWindow(Child, ProcessData, ThreadData, SendMessages);
307 IntReleaseWindowObject(Child);
308 }
309 }
310 ExFreePool(Children);
311 }
312
313 if (SendMessages)
314 {
315 /*
316 * Clear the update region to make sure no WM_PAINT messages will be
317 * generated for this window while processing the WM_NCDESTROY.
318 */
319 IntRedrawWindow(Window, NULL, 0,
320 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
321 RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
322
323 /*
324 * Send the WM_NCDESTROY to the window being destroyed.
325 */
326 if(BelongsToThreadData)
327 IntSendMessage(Window->Self, WM_NCDESTROY, 0, 0);
328 }
329
330 /* reset shell window handles */
331 if(ProcessData->WindowStation)
332 {
333 if (Window->Self == ProcessData->WindowStation->ShellWindow)
334 ProcessData->WindowStation->ShellWindow = NULL;
335
336 if (Window->Self == ProcessData->WindowStation->ShellListView)
337 ProcessData->WindowStation->ShellListView = NULL;
338 }
339
340 /* Unregister hot keys */
341 UnregisterWindowHotKeys (Window);
342
343 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
344
345 #if 0 /* FIXME */
346 WinPosCheckInternalPos(Window->Self);
347 if (Window->Self == GetCapture())
348 {
349 ReleaseCapture();
350 }
351
352 /* free resources associated with the window */
353 TIMER_RemoveWindowTimers(Window->Self);
354 #endif
355
356 if (!(Window->Style & WS_CHILD) && Window->IDMenu
357 && (Menu = IntGetMenuObject((HMENU)Window->IDMenu)))
358 {
359 IntDestroyMenuObject(Menu, TRUE, TRUE);
360 Window->IDMenu = 0;
361 IntReleaseMenuObject(Menu);
362 }
363
364 if(Window->SystemMenu
365 && (Menu = IntGetMenuObject(Window->SystemMenu)))
366 {
367 IntDestroyMenuObject(Menu, TRUE, TRUE);
368 Window->SystemMenu = (HMENU)0;
369 IntReleaseMenuObject(Menu);
370 }
371
372 DceFreeWindowDCE(Window); /* Always do this to catch orphaned DCs */
373 #if 0 /* FIXME */
374 WINPROC_FreeProc(Window->winproc, WIN_PROC_WINDOW);
375 CLASS_RemoveWindow(Window->Class);
376 #endif
377
378 IntUnlinkWindow(Window);
379
380 IntReferenceWindowObject(Window);
381 ObmCloseHandle(ProcessData->WindowStation->HandleTable, Window->Self);
382
383 IntDestroyScrollBars(Window);
384
385 IntLockThreadWindows(Window->OwnerThread->Win32Thread);
386 Window->Status |= WINDOWSTATUS_DESTROYED;
387 /* don't remove the WINDOWSTATUS_DESTROYING bit */
388 IntUnLockThreadWindows(Window->OwnerThread->Win32Thread);
389
390 /* 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;
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->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->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 && (Window->Style & WS_CHILD))
1185 {
1186 Status = MmCopyToCaller(pWnd++, &Window->Self, sizeof(HWND));
1187 if(!NT_SUCCESS(Status))
1188 {
1189 SetLastNtError(Status);
1190 break;
1191 }
1192 }
1193
1194 if(!(Window->Style & WS_CHILD))
1195 {
1196 dwCount++;
1197 }
1198
1199 Current = Current->Flink;
1200 }
1201 IntUnLockThreadWindows(W32Thread);
1202
1203 ObDereferenceObject(Thread);
1204 }
1205 else
1206 {
1207 PDESKTOP_OBJECT Desktop;
1208 PWINDOW_OBJECT Window, Child;
1209
1210 if(hDesktop == NULL && !(Desktop = IntGetActiveDesktop()))
1211 {
1212 SetLastWin32Error(ERROR_INVALID_HANDLE);
1213 return 0;
1214 }
1215
1216 if(hDesktop)
1217 {
1218 Status = IntValidateDesktopHandle(hDesktop,
1219 UserMode,
1220 0,
1221 &Desktop);
1222 if(!NT_SUCCESS(Status))
1223 {
1224 SetLastWin32Error(ERROR_INVALID_HANDLE);
1225 return 0;
1226 }
1227 }
1228 if(!(Window = IntGetWindowObject(Desktop->DesktopWindow)))
1229 {
1230 if(hDesktop)
1231 ObDereferenceObject(Desktop);
1232 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1233 return 0;
1234 }
1235
1236 IntLockRelatives(Window);
1237 for(Child = Window->FirstChild; Child != NULL; Child = Child->NextSibling)
1238 {
1239 if(dwCount++ < nBufSize && pWnd)
1240 {
1241 Status = MmCopyToCaller(pWnd++, &Child->Self, sizeof(HWND));
1242 if(!NT_SUCCESS(Status))
1243 {
1244 SetLastNtError(Status);
1245 break;
1246 }
1247 }
1248 }
1249 IntUnLockRelatives(Window);
1250
1251 IntReleaseWindowObject(Window);
1252 if(hDesktop)
1253 ObDereferenceObject(Desktop);
1254 }
1255
1256 return dwCount;
1257 }
1258
1259
1260 /*
1261 * @implemented
1262 */
1263 HWND STDCALL
1264 NtUserChildWindowFromPointEx(HWND hwndParent,
1265 LONG x,
1266 LONG y,
1267 UINT uiFlags)
1268 {
1269 PWINDOW_OBJECT Parent;
1270 POINTL Pt;
1271 HWND Ret;
1272 HWND *List, *phWnd;
1273
1274 if(!(Parent = IntGetWindowObject(hwndParent)))
1275 {
1276 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1277 return NULL;
1278 }
1279
1280 Pt.x = x;
1281 Pt.y = y;
1282
1283 if(Parent->Self != IntGetDesktopWindow())
1284 {
1285 Pt.x += Parent->ClientRect.left;
1286 Pt.y += Parent->ClientRect.top;
1287 }
1288
1289 if(!IntPtInWindow(Parent, Pt.x, Pt.y))
1290 {
1291 IntReleaseWindowObject(Parent);
1292 return NULL;
1293 }
1294
1295 Ret = Parent->Self;
1296 if((List = IntWinListChildren(Parent)))
1297 {
1298 for(phWnd = List; *phWnd; phWnd++)
1299 {
1300 PWINDOW_OBJECT Child;
1301 if((Child = IntGetWindowObject(*phWnd)))
1302 {
1303 if(!(Child->Style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE))
1304 {
1305 IntReleaseWindowObject(Child);
1306 continue;
1307 }
1308 if((Child->Style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED))
1309 {
1310 IntReleaseWindowObject(Child);
1311 continue;
1312 }
1313 if((Child->ExStyle & WS_EX_TRANSPARENT) && (uiFlags & CWP_SKIPTRANSPARENT))
1314 {
1315 IntReleaseWindowObject(Child);
1316 continue;
1317 }
1318 if(IntPtInWindow(Child, Pt.x, Pt.y))
1319 {
1320 Ret = Child->Self;
1321 IntReleaseWindowObject(Child);
1322 break;
1323 }
1324 IntReleaseWindowObject(Child);
1325 }
1326 }
1327 ExFreePool(List);
1328 }
1329
1330 IntReleaseWindowObject(Parent);
1331 return Ret;
1332 }
1333
1334
1335 /*
1336 * calculates the default position of a window
1337 */
1338 BOOL FASTCALL
1339 IntCalcDefPosSize(PWINDOW_OBJECT Parent, PWINDOW_OBJECT WindowObject, RECT *rc, BOOL IncPos)
1340 {
1341 SIZE Sz;
1342 POINT Pos;
1343
1344 if(Parent != NULL)
1345 {
1346 NtGdiIntersectRect(rc, rc, &Parent->ClientRect);
1347
1348 if(IncPos)
1349 {
1350 Pos.x = Parent->TiledCounter * (NtUserGetSystemMetrics(SM_CXSIZE) + NtUserGetSystemMetrics(SM_CXFRAME));
1351 Pos.y = Parent->TiledCounter * (NtUserGetSystemMetrics(SM_CYSIZE) + NtUserGetSystemMetrics(SM_CYFRAME));
1352 if(Pos.x > ((rc->right - rc->left) / 4) ||
1353 Pos.y > ((rc->bottom - rc->top) / 4))
1354 {
1355 /* reset counter and position */
1356 Pos.x = 0;
1357 Pos.y = 0;
1358 Parent->TiledCounter = 0;
1359 }
1360 Parent->TiledCounter++;
1361 }
1362 Pos.x += rc->left;
1363 Pos.y += rc->top;
1364 }
1365 else
1366 {
1367 Pos.x = rc->left;
1368 Pos.y = rc->top;
1369 }
1370
1371 Sz.cx = EngMulDiv(rc->right - rc->left, 3, 4);
1372 Sz.cy = EngMulDiv(rc->bottom - rc->top, 3, 4);
1373
1374 rc->left = Pos.x;
1375 rc->top = Pos.y;
1376 rc->right = rc->left + Sz.cx;
1377 rc->bottom = rc->top + Sz.cy;
1378 return TRUE;
1379 }
1380
1381
1382 /*
1383 * @implemented
1384 */
1385 HWND STDCALL
1386 IntCreateWindowEx(DWORD dwExStyle,
1387 PUNICODE_STRING ClassName,
1388 PUNICODE_STRING WindowName,
1389 DWORD dwStyle,
1390 LONG x,
1391 LONG y,
1392 LONG nWidth,
1393 LONG nHeight,
1394 HWND hWndParent,
1395 HMENU hMenu,
1396 HINSTANCE hInstance,
1397 LPVOID lpParam,
1398 DWORD dwShowMode,
1399 BOOL bUnicodeWindow)
1400 {
1401 PWINSTATION_OBJECT WinStaObject;
1402 PWNDCLASS_OBJECT ClassObject;
1403 PWINDOW_OBJECT WindowObject;
1404 PWINDOW_OBJECT ParentWindow, OwnerWindow;
1405 HWND ParentWindowHandle;
1406 HWND OwnerWindowHandle;
1407 PMENU_OBJECT SystemMenu;
1408 NTSTATUS Status;
1409 HANDLE Handle;
1410 POINT Pos;
1411 SIZE Size;
1412 #if 0
1413 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
1414 #else
1415 POINT MaxPos;
1416 #endif
1417 CREATESTRUCTW Cs;
1418 CBT_CREATEWNDW CbtCreate;
1419 LRESULT Result;
1420 BOOL MenuChanged;
1421 BOOL ClassFound;
1422 PWSTR ClassNameString;
1423
1424 ParentWindowHandle = PsGetWin32Thread()->Desktop->DesktopWindow;
1425 OwnerWindowHandle = NULL;
1426
1427 if (hWndParent == HWND_MESSAGE)
1428 {
1429 /*
1430 * native ole32.OleInitialize uses HWND_MESSAGE to create the
1431 * message window (style: WS_POPUP|WS_DISABLED)
1432 */
1433 UNIMPLEMENTED;
1434 }
1435 else if (hWndParent)
1436 {
1437 if ((dwStyle & (WS_CHILD | WS_POPUP)) == WS_CHILD)
1438 ParentWindowHandle = hWndParent;
1439 else
1440 OwnerWindowHandle = NtUserGetAncestor(hWndParent, GA_ROOT);
1441 }
1442 else if ((dwStyle & (WS_CHILD | WS_POPUP)) == WS_CHILD)
1443 {
1444 return (HWND)0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1445 }
1446
1447 if (NULL != ParentWindowHandle)
1448 {
1449 ParentWindow = IntGetWindowObject(ParentWindowHandle);
1450 }
1451 else
1452 {
1453 ParentWindow = NULL;
1454 }
1455
1456 /* FIXME: parent must belong to the current process */
1457
1458 /* Check the class. */
1459 if (IS_ATOM(ClassName->Buffer))
1460 {
1461 ClassFound = ClassReferenceClassByNameOrAtom(&ClassObject, ClassName->Buffer, hInstance);
1462 }
1463 else
1464 {
1465 Status = IntUnicodeStringToNULLTerminated(&ClassNameString, ClassName);
1466 if (! NT_SUCCESS(Status))
1467 {
1468 if (NULL != ParentWindow)
1469 {
1470 IntReleaseWindowObject(ParentWindow);
1471 }
1472 return NULL;
1473 }
1474 ClassFound = ClassReferenceClassByNameOrAtom(&ClassObject, ClassNameString, hInstance);
1475 IntFreeNULLTerminatedFromUnicodeString(ClassNameString, ClassName);
1476 }
1477 if (!ClassFound)
1478 {
1479 if (IS_ATOM(ClassName->Buffer))
1480 {
1481 DPRINT1("Class 0x%x not found\n", (DWORD_PTR) ClassName->Buffer);
1482 }
1483 else
1484 {
1485 DPRINT1("Class %wZ not found\n", ClassName);
1486 }
1487 if (NULL != ParentWindow)
1488 {
1489 IntReleaseWindowObject(ParentWindow);
1490 }
1491 return((HWND)0);
1492 }
1493
1494 /* Check the window station. */
1495 DPRINT("IoGetCurrentProcess() %X\n", IoGetCurrentProcess());
1496 DPRINT("PROCESS_WINDOW_STATION %X\n", PROCESS_WINDOW_STATION());
1497 Status = IntValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
1498 KernelMode,
1499 0,
1500 &WinStaObject);
1501 if (!NT_SUCCESS(Status))
1502 {
1503 ClassDereferenceObject(ClassObject);
1504 if (NULL != ParentWindow)
1505 {
1506 IntReleaseWindowObject(ParentWindow);
1507 }
1508 DPRINT("Validation of window station handle (0x%X) failed\n",
1509 PROCESS_WINDOW_STATION());
1510 return (HWND)0;
1511 }
1512
1513 /* Create the window object. */
1514 WindowObject = (PWINDOW_OBJECT)
1515 ObmCreateObject(PsGetWin32Process()->WindowStation->HandleTable, &Handle,
1516 otWindow, sizeof(WINDOW_OBJECT) + ClassObject->cbWndExtra
1517 );
1518
1519 DPRINT("Created object with handle %X\n", Handle);
1520 if (!WindowObject)
1521 {
1522 ObDereferenceObject(WinStaObject);
1523 ClassDereferenceObject(ClassObject);
1524 if (NULL != ParentWindow)
1525 {
1526 IntReleaseWindowObject(ParentWindow);
1527 }
1528 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1529 return (HWND)0;
1530 }
1531 ObDereferenceObject(WinStaObject);
1532
1533 if (NULL == PsGetWin32Thread()->Desktop->DesktopWindow)
1534 {
1535 /* If there is no desktop window yet, we must be creating it */
1536 PsGetWin32Thread()->Desktop->DesktopWindow = Handle;
1537 }
1538
1539 /*
1540 * Fill out the structure describing it.
1541 */
1542 WindowObject->Class = ClassObject;
1543 IntLockClassWindows(ClassObject);
1544 InsertTailList(&ClassObject->ClassWindowsListHead, &WindowObject->ClassListEntry);
1545 IntUnLockClassWindows(ClassObject);
1546
1547 WindowObject->ExStyle = dwExStyle;
1548 WindowObject->Style = dwStyle & ~WS_VISIBLE;
1549 DPRINT("1: Style is now %lx\n", WindowObject->Style);
1550
1551 WindowObject->SystemMenu = (HMENU)0;
1552 WindowObject->ContextHelpId = 0;
1553 WindowObject->IDMenu = 0;
1554 WindowObject->Instance = hInstance;
1555 WindowObject->Self = Handle;
1556 if (0 != (dwStyle & WS_CHILD))
1557 {
1558 WindowObject->IDMenu = (UINT) hMenu;
1559 }
1560 else
1561 {
1562 IntSetMenu(WindowObject, hMenu, &MenuChanged);
1563 }
1564 WindowObject->MessageQueue = PsGetWin32Thread()->MessageQueue;
1565 WindowObject->Parent = (ParentWindow ? ParentWindow->Self : NULL);
1566 if((OwnerWindow = IntGetWindowObject(OwnerWindowHandle)))
1567 {
1568 WindowObject->Owner = OwnerWindowHandle;
1569 IntReleaseWindowObject(OwnerWindow);
1570 }
1571 else
1572 WindowObject->Owner = NULL;
1573 WindowObject->UserData = 0;
1574 if ((((DWORD)ClassObject->lpfnWndProcA & 0xFFFF0000) != 0xFFFF0000)
1575 && (((DWORD)ClassObject->lpfnWndProcW & 0xFFFF0000) != 0xFFFF0000))
1576 {
1577 WindowObject->Unicode = bUnicodeWindow;
1578 }
1579 else
1580 {
1581 WindowObject->Unicode = ClassObject->Unicode;
1582 }
1583 WindowObject->WndProcA = ClassObject->lpfnWndProcA;
1584 WindowObject->WndProcW = ClassObject->lpfnWndProcW;
1585 WindowObject->OwnerThread = PsGetCurrentThread();
1586 WindowObject->FirstChild = NULL;
1587 WindowObject->LastChild = NULL;
1588 WindowObject->PrevSibling = NULL;
1589 WindowObject->NextSibling = NULL;
1590
1591 /* extra window data */
1592 if (ClassObject->cbWndExtra != 0)
1593 {
1594 WindowObject->ExtraData = (PCHAR)(WindowObject + 1);
1595 WindowObject->ExtraDataSize = ClassObject->cbWndExtra;
1596 RtlZeroMemory(WindowObject->ExtraData, WindowObject->ExtraDataSize);
1597 }
1598 else
1599 {
1600 WindowObject->ExtraData = NULL;
1601 WindowObject->ExtraDataSize = 0;
1602 }
1603
1604 InitializeListHead(&WindowObject->PropListHead);
1605 ExInitializeFastMutex(&WindowObject->PropListLock);
1606 ExInitializeFastMutex(&WindowObject->RelativesLock);
1607 ExInitializeFastMutex(&WindowObject->UpdateLock);
1608
1609 if (NULL != WindowName->Buffer)
1610 {
1611 WindowObject->WindowName.MaximumLength = WindowName->MaximumLength;
1612 WindowObject->WindowName.Length = WindowName->Length;
1613 WindowObject->WindowName.Buffer = ExAllocatePoolWithTag(PagedPool, WindowName->MaximumLength,
1614 TAG_STRING);
1615 if (NULL == WindowObject->WindowName.Buffer)
1616 {
1617 ClassDereferenceObject(ClassObject);
1618 DPRINT1("Failed to allocate mem for window name\n");
1619 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
1620 return NULL;
1621 }
1622 RtlCopyMemory(WindowObject->WindowName.Buffer, WindowName->Buffer, WindowName->MaximumLength);
1623 }
1624 else
1625 {
1626 RtlInitUnicodeString(&WindowObject->WindowName, NULL);
1627 }
1628
1629
1630 /* Correct the window style. */
1631 if (!(dwStyle & WS_CHILD))
1632 {
1633 WindowObject->Style |= WS_CLIPSIBLINGS;
1634 DPRINT("3: Style is now %lx\n", WindowObject->Style);
1635 if (!(dwStyle & WS_POPUP))
1636 {
1637 WindowObject->Style |= WS_CAPTION;
1638 WindowObject->Flags |= WINDOWOBJECT_NEED_SIZE;
1639 DPRINT("4: Style is now %lx\n", WindowObject->Style);
1640 /* FIXME: Note the window needs a size. */
1641 }
1642 }
1643
1644 if(!(WindowObject->Style & (WS_POPUP | WS_CHILD)))
1645 {
1646 /* Automatically assign the caption and border style. Also always
1647 clip siblings for overlapped windows. */
1648 WindowObject->Style |= (WS_CAPTION | WS_BORDER | WS_CLIPSIBLINGS);
1649 }
1650
1651 /* create system menu */
1652 if((WindowObject->Style & WS_SYSMENU) && (WindowObject->Style & WS_CAPTION))
1653 {
1654 SystemMenu = IntGetSystemMenu(WindowObject, TRUE, TRUE);
1655 if(SystemMenu)
1656 {
1657 WindowObject->SystemMenu = SystemMenu->MenuInfo.Self;
1658 IntReleaseMenuObject(SystemMenu);
1659 }
1660 }
1661
1662 /* Insert the window into the thread's window list. */
1663 IntLockThreadWindows(PsGetWin32Thread());
1664 InsertTailList (&PsGetWin32Thread()->WindowListHead,
1665 &WindowObject->ThreadListEntry);
1666 IntUnLockThreadWindows(PsGetWin32Thread());
1667
1668 /* Allocate a DCE for this window. */
1669 if (dwStyle & CS_OWNDC)
1670 {
1671 WindowObject->Dce = DceAllocDCE(WindowObject->Self, DCE_WINDOW_DC);
1672 }
1673 /* FIXME: Handle "CS_CLASSDC" */
1674
1675 Pos.x = x;
1676 Pos.y = y;
1677 Size.cx = nWidth;
1678 Size.cy = nHeight;
1679
1680 /* call hook */
1681 Cs.lpCreateParams = lpParam;
1682 Cs.hInstance = hInstance;
1683 Cs.hMenu = hMenu;
1684 Cs.hwndParent = ParentWindowHandle;
1685 Cs.cx = Size.cx;
1686 Cs.cy = Size.cy;
1687 Cs.x = Pos.x;
1688 Cs.y = Pos.y;
1689 Cs.style = dwStyle;
1690 Cs.lpszName = (LPCWSTR) WindowName;
1691 Cs.lpszClass = (LPCWSTR) ClassName;
1692 Cs.dwExStyle = dwExStyle;
1693 CbtCreate.lpcs = &Cs;
1694 CbtCreate.hwndInsertAfter = HWND_TOP;
1695 if (HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) Handle, (LPARAM) &CbtCreate))
1696 {
1697 if (NULL != ParentWindow)
1698 {
1699 IntReleaseWindowObject(ParentWindow);
1700 }
1701
1702 /* FIXME - Delete window object and remove it from the thread windows list */
1703 /* FIXME - delete allocated DCE */
1704
1705 ClassDereferenceObject(ClassObject);
1706 DPRINT1("CBT-hook returned !0\n");
1707 return (HWND) NULL;
1708 }
1709
1710 x = Cs.x;
1711 y = Cs.y;
1712 nWidth = Cs.cx;
1713 nHeight = Cs.cy;
1714
1715 /* default positioning for overlapped windows */
1716 if(!(WindowObject->Style & (WS_POPUP | WS_CHILD)))
1717 {
1718 RECT rc, WorkArea;
1719 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
1720 BOOL CalculatedDefPosSize = FALSE;
1721
1722 IntGetDesktopWorkArea(WindowObject->OwnerThread->Win32Thread->Desktop, &WorkArea);
1723
1724 rc = WorkArea;
1725 ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
1726
1727 if(x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
1728 {
1729 CalculatedDefPosSize = IntCalcDefPosSize(ParentWindow, WindowObject, &rc, TRUE);
1730
1731 if(ProcessParams->dwFlags & STARTF_USEPOSITION)
1732 {
1733 ProcessParams->dwFlags &= ~STARTF_USEPOSITION;
1734 Pos.x = WorkArea.left + ProcessParams->dwX;
1735 Pos.y = WorkArea.top + ProcessParams->dwY;
1736 }
1737 else
1738 {
1739 Pos.x = rc.left;
1740 Pos.y = rc.top;
1741 }
1742
1743 /* According to wine, the ShowMode is set to y if x == CW_USEDEFAULT(16) and
1744 y is something else */
1745 if(y != CW_USEDEFAULT && y != CW_USEDEFAULT16)
1746 {
1747 dwShowMode = y;
1748 }
1749 }
1750 if(nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16)
1751 {
1752 if(!CalculatedDefPosSize)
1753 {
1754 IntCalcDefPosSize(ParentWindow, WindowObject, &rc, FALSE);
1755 }
1756 if(ProcessParams->dwFlags & STARTF_USESIZE)
1757 {
1758 ProcessParams->dwFlags &= ~STARTF_USESIZE;
1759 Size.cx = ProcessParams->dwXSize;
1760 Size.cy = ProcessParams->dwYSize;
1761 }
1762 else
1763 {
1764 Size.cx = rc.right - rc.left;
1765 Size.cy = rc.bottom - rc.top;
1766 }
1767
1768 /* move the window if necessary */
1769 if(Pos.x > rc.left)
1770 Pos.x = max(rc.left, 0);
1771 if(Pos.y > rc.top)
1772 Pos.y = max(rc.top, 0);
1773 }
1774 }
1775 else
1776 {
1777 /* if CW_USEDEFAULT(16) is set for non-overlapped windows, both values are set to zero) */
1778 if(x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
1779 {
1780 Pos.x = 0;
1781 Pos.y = 0;
1782 }
1783 if(nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16)
1784 {
1785 Size.cx = 0;
1786 Size.cy = 0;
1787 }
1788 }
1789
1790 /* Initialize the window dimensions. */
1791 WindowObject->WindowRect.left = Pos.x;
1792 WindowObject->WindowRect.top = Pos.y;
1793 WindowObject->WindowRect.right = Pos.x + Size.cx;
1794 WindowObject->WindowRect.bottom = Pos.y + Size.cy;
1795 if (0 != (WindowObject->Style & WS_CHILD) && ParentWindow)
1796 {
1797 NtGdiOffsetRect(&(WindowObject->WindowRect), ParentWindow->ClientRect.left,
1798 ParentWindow->ClientRect.top);
1799 }
1800 WindowObject->ClientRect = WindowObject->WindowRect;
1801
1802 /*
1803 * Get the size and position of the window.
1804 */
1805 if ((dwStyle & WS_THICKFRAME) || !(dwStyle & (WS_POPUP | WS_CHILD)))
1806 {
1807 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
1808
1809 /* WinPosGetMinMaxInfo sends the WM_GETMINMAXINFO message */
1810 WinPosGetMinMaxInfo(WindowObject, &MaxSize, &MaxPos, &MinTrack,
1811 &MaxTrack);
1812 if (MaxSize.x < nWidth) nWidth = MaxSize.x;
1813 if (MaxSize.y < nHeight) nHeight = MaxSize.y;
1814 if (nWidth < MinTrack.x ) nWidth = MinTrack.x;
1815 if (nHeight < MinTrack.y ) nHeight = MinTrack.y;
1816 if (nWidth < 0) nWidth = 0;
1817 if (nHeight < 0) nHeight = 0;
1818 }
1819
1820 WindowObject->WindowRect.left = Pos.x;
1821 WindowObject->WindowRect.top = Pos.y;
1822 WindowObject->WindowRect.right = Pos.x + Size.cx;
1823 WindowObject->WindowRect.bottom = Pos.y + Size.cy;
1824 if (0 != (WindowObject->Style & WS_CHILD) && ParentWindow)
1825 {
1826 NtGdiOffsetRect(&(WindowObject->WindowRect), ParentWindow->ClientRect.left,
1827 ParentWindow->ClientRect.top);
1828 }
1829 WindowObject->ClientRect = WindowObject->WindowRect;
1830
1831 /* FIXME: Initialize the window menu. */
1832
1833 /* Send a NCCREATE message. */
1834 Cs.cx = Size.cx;
1835 Cs.cy = Size.cy;
1836 Cs.x = Pos.x;
1837 Cs.y = Pos.y;
1838
1839 DPRINT("[win32k.window] IntCreateWindowEx style %d, exstyle %d, parent %d\n", Cs.style, Cs.dwExStyle, Cs.hwndParent);
1840 DPRINT("IntCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, nWidth, nHeight);
1841 DPRINT("IntCreateWindowEx(): About to send NCCREATE message.\n");
1842 Result = IntSendMessage(WindowObject->Self, WM_NCCREATE, 0, (LPARAM) &Cs);
1843 if (!Result)
1844 {
1845 /* FIXME: Cleanup. */
1846 if (NULL != ParentWindow)
1847 {
1848 IntReleaseWindowObject(ParentWindow);
1849 }
1850 DPRINT("IntCreateWindowEx(): NCCREATE message failed.\n");
1851 return((HWND)0);
1852 }
1853
1854 /* Calculate the non-client size. */
1855 MaxPos.x = WindowObject->WindowRect.left;
1856 MaxPos.y = WindowObject->WindowRect.top;
1857 DPRINT("IntCreateWindowEx(): About to get non-client size.\n");
1858 /* WinPosGetNonClientSize SENDS THE WM_NCCALCSIZE message */
1859 Result = WinPosGetNonClientSize(WindowObject->Self,
1860 &WindowObject->WindowRect,
1861 &WindowObject->ClientRect);
1862 NtGdiOffsetRect(&WindowObject->WindowRect,
1863 MaxPos.x - WindowObject->WindowRect.left,
1864 MaxPos.y - WindowObject->WindowRect.top);
1865
1866 if (NULL != ParentWindow)
1867 {
1868 /* link the window into the parent's child list */
1869 if ((dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
1870 {
1871 PWINDOW_OBJECT PrevSibling;
1872 IntLockRelatives(ParentWindow);
1873 if((PrevSibling = ParentWindow->LastChild))
1874 IntReferenceWindowObject(PrevSibling);
1875 IntUnLockRelatives(ParentWindow);
1876 /* link window as bottom sibling */
1877 IntLinkWindow(WindowObject, ParentWindow, PrevSibling /*prev sibling*/);
1878 if(PrevSibling)
1879 IntReleaseWindowObject(PrevSibling);
1880 }
1881 else
1882 {
1883 /* link window as top sibling (but after topmost siblings) */
1884 PWINDOW_OBJECT InsertAfter, Sibling;
1885 if (0 == (dwExStyle & WS_EX_TOPMOST))
1886 {
1887 IntLockRelatives(ParentWindow);
1888 InsertAfter = NULL;
1889 Sibling = ParentWindow->FirstChild;
1890 while (NULL != Sibling && 0 != (Sibling->ExStyle & WS_EX_TOPMOST))
1891 {
1892 InsertAfter = Sibling;
1893 Sibling = Sibling->NextSibling;
1894 }
1895 IntUnLockRelatives(ParentWindow);
1896 }
1897 else
1898 {
1899 InsertAfter = NULL;
1900 }
1901 if (NULL != InsertAfter)
1902 {
1903 IntReferenceWindowObject(InsertAfter);
1904 }
1905 IntLinkWindow(WindowObject, ParentWindow, InsertAfter /* prev sibling */);
1906 if (NULL != InsertAfter)
1907 {
1908 IntReleaseWindowObject(InsertAfter);
1909 }
1910 }
1911 }
1912
1913 /* Send the WM_CREATE message. */
1914 DPRINT("IntCreateWindowEx(): about to send CREATE message.\n");
1915 Result = IntSendMessage(WindowObject->Self, WM_CREATE, 0, (LPARAM) &Cs);
1916 if (Result == (LRESULT)-1)
1917 {
1918 /* FIXME: Cleanup. */
1919 if (NULL != ParentWindow)
1920 {
1921 IntReleaseWindowObject(ParentWindow);
1922 }
1923 ClassDereferenceObject(ClassObject);
1924 DPRINT("IntCreateWindowEx(): send CREATE message failed.\n");
1925 return((HWND)0);
1926 }
1927
1928 /* Send move and size messages. */
1929 if (!(WindowObject->Flags & WINDOWOBJECT_NEED_SIZE))
1930 {
1931 LONG lParam;
1932
1933 DPRINT("IntCreateWindow(): About to send WM_SIZE\n");
1934
1935 if ((WindowObject->ClientRect.right - WindowObject->ClientRect.left) < 0 ||
1936 (WindowObject->ClientRect.bottom - WindowObject->ClientRect.top) < 0)
1937 {
1938 DPRINT("Sending bogus WM_SIZE\n");
1939 }
1940
1941 lParam = MAKE_LONG(WindowObject->ClientRect.right -
1942 WindowObject->ClientRect.left,
1943 WindowObject->ClientRect.bottom -
1944 WindowObject->ClientRect.top);
1945 IntSendMessage(WindowObject->Self, WM_SIZE, SIZE_RESTORED,
1946 lParam);
1947
1948 DPRINT("IntCreateWindow(): About to send WM_MOVE\n");
1949
1950 if (0 != (WindowObject->Style & WS_CHILD) && ParentWindow)
1951 {
1952 lParam = MAKE_LONG(WindowObject->ClientRect.left - ParentWindow->ClientRect.left,
1953 WindowObject->ClientRect.top - ParentWindow->ClientRect.top);
1954 }
1955 else
1956 {
1957 lParam = MAKE_LONG(WindowObject->ClientRect.left,
1958 WindowObject->ClientRect.top);
1959 }
1960 IntSendMessage(WindowObject->Self, WM_MOVE, 0, lParam);
1961 }
1962
1963 /* Show or maybe minimize or maximize the window. */
1964 if (WindowObject->Style & (WS_MINIMIZE | WS_MAXIMIZE))
1965 {
1966 RECT NewPos;
1967 UINT16 SwFlag;
1968
1969 SwFlag = (WindowObject->Style & WS_MINIMIZE) ? SW_MINIMIZE :
1970 SW_MAXIMIZE;
1971 WinPosMinMaximize(WindowObject, SwFlag, &NewPos);
1972 SwFlag =
1973 ((WindowObject->Style & WS_CHILD) || NtUserGetActiveWindow()) ?
1974 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED :
1975 SWP_NOZORDER | SWP_FRAMECHANGED;
1976 DPRINT("IntCreateWindow(): About to minimize/maximize\n");
1977 DPRINT("%d,%d %dx%d\n", NewPos.left, NewPos.top, NewPos.right, NewPos.bottom);
1978 WinPosSetWindowPos(WindowObject->Self, 0, NewPos.left, NewPos.top,
1979 NewPos.right, NewPos.bottom, SwFlag);
1980 }
1981
1982 /* Notify the parent window of a new child. */
1983 if ((WindowObject->Style & WS_CHILD) &&
1984 (!(WindowObject->ExStyle & WS_EX_NOPARENTNOTIFY)) && ParentWindow)
1985 {
1986 DPRINT("IntCreateWindow(): About to notify parent\n");
1987 IntSendMessage(ParentWindow->Self,
1988 WM_PARENTNOTIFY,
1989 MAKEWPARAM(WM_CREATE, WindowObject->IDMenu),
1990 (LPARAM)WindowObject->Self);
1991 }
1992
1993 if (NULL != ParentWindow)
1994 {
1995 IntReleaseWindowObject(ParentWindow);
1996 }
1997
1998 /* Initialize and show the window's scrollbars */
1999 if (WindowObject->Style & WS_VSCROLL)
2000 {
2001 NtUserShowScrollBar(WindowObject->Self, SB_VERT, TRUE);
2002 }
2003 if (WindowObject->Style & WS_HSCROLL)
2004 {
2005 NtUserShowScrollBar(WindowObject->Self, SB_HORZ, TRUE);
2006 }
2007
2008 if (dwStyle & WS_VISIBLE)
2009 {
2010 DPRINT("IntCreateWindow(): About to show window\n");
2011 WinPosShowWindow(WindowObject->Self, dwShowMode);
2012 }
2013
2014 DPRINT("IntCreateWindow(): = %X\n", Handle);
2015 DPRINT("WindowObject->SystemMenu = 0x%x\n", WindowObject->SystemMenu);
2016 return((HWND)Handle);
2017 }
2018
2019 HWND STDCALL
2020 NtUserCreateWindowEx(DWORD dwExStyle,
2021 PUNICODE_STRING UnsafeClassName,
2022 PUNICODE_STRING UnsafeWindowName,
2023 DWORD dwStyle,
2024 LONG x,
2025 LONG y,
2026 LONG nWidth,
2027 LONG nHeight,
2028 HWND hWndParent,
2029 HMENU hMenu,
2030 HINSTANCE hInstance,
2031 LPVOID lpParam,
2032 DWORD dwShowMode,
2033 BOOL bUnicodeWindow)
2034 {
2035 NTSTATUS Status;
2036 UNICODE_STRING WindowName;
2037 UNICODE_STRING ClassName;
2038 HWND NewWindow;
2039
2040 DPRINT("NtUserCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, nWidth, nHeight);
2041
2042 /* Get the class name (string or atom) */
2043 Status = MmCopyFromCaller(&ClassName, UnsafeClassName, sizeof(UNICODE_STRING));
2044 if (! NT_SUCCESS(Status))
2045 {
2046 SetLastNtError(Status);
2047 return NULL;
2048 }
2049 if (! IS_ATOM(ClassName.Buffer))
2050 {
2051 Status = IntSafeCopyUnicodeString(&ClassName, UnsafeClassName);
2052 if (! NT_SUCCESS(Status))
2053 {
2054 SetLastNtError(Status);
2055 return NULL;
2056 }
2057 }
2058
2059 /* safely copy the window name */
2060 if (NULL != UnsafeWindowName)
2061 {
2062 Status = IntSafeCopyUnicodeString(&WindowName, UnsafeWindowName);
2063 if (! NT_SUCCESS(Status))
2064 {
2065 if (! IS_ATOM(ClassName.Buffer))
2066 {
2067 RtlFreeUnicodeString(&ClassName);
2068 }
2069 SetLastNtError(Status);
2070 return NULL;
2071 }
2072 }
2073 else
2074 {
2075 RtlInitUnicodeString(&WindowName, NULL);
2076 }
2077
2078 NewWindow = IntCreateWindowEx(dwExStyle, &ClassName, &WindowName, dwStyle, x, y, nWidth, nHeight,
2079 hWndParent, hMenu, hInstance, lpParam, dwShowMode, bUnicodeWindow);
2080
2081 RtlFreeUnicodeString(&WindowName);
2082 if (! IS_ATOM(ClassName.Buffer))
2083 {
2084 RtlFreeUnicodeString(&ClassName);
2085 }
2086
2087 return NewWindow;
2088 }
2089
2090 /*
2091 * @unimplemented
2092 */
2093 HDWP STDCALL
2094 NtUserDeferWindowPos(HDWP WinPosInfo,
2095 HWND Wnd,
2096 HWND WndInsertAfter,
2097 int x,
2098 int y,
2099 int cx,
2100 int cy,
2101 UINT Flags)
2102 {
2103 UNIMPLEMENTED
2104
2105 return 0;
2106 }
2107
2108
2109 /*
2110 * @implemented
2111 */
2112 BOOLEAN STDCALL
2113 NtUserDestroyWindow(HWND Wnd)
2114 {
2115 PWINDOW_OBJECT Window;
2116 BOOLEAN isChild;
2117
2118 Window = IntGetWindowObject(Wnd);
2119 if (Window == NULL)
2120 {
2121 return FALSE;
2122 }
2123
2124 /* Check for owner thread and desktop window */
2125 if ((Window->OwnerThread != PsGetCurrentThread()) || IntIsDesktopWindow(Window))
2126 {
2127 IntReleaseWindowObject(Window);
2128 SetLastWin32Error(ERROR_ACCESS_DENIED);
2129 return FALSE;
2130 }
2131
2132 /* Look whether the focus is within the tree of windows we will
2133 * be destroying.
2134 */
2135 if (!WinPosShowWindow(Wnd, SW_HIDE))
2136 {
2137 if (NtUserGetActiveWindow() == Wnd)
2138 {
2139 WinPosActivateOtherWindow(Window);
2140 }
2141 }
2142 IntLockMessageQueue(Window->MessageQueue);
2143 if (Window->MessageQueue->ActiveWindow == Window->Self)
2144 Window->MessageQueue->ActiveWindow = NULL;
2145 if (Window->MessageQueue->FocusWindow == Window->Self)
2146 Window->MessageQueue->FocusWindow = NULL;
2147 if (Window->MessageQueue->CaptureWindow == Window->Self)
2148 Window->MessageQueue->CaptureWindow = NULL;
2149 IntUnLockMessageQueue(Window->MessageQueue);
2150
2151 /* Call hooks */
2152 #if 0 /* FIXME */
2153 if (HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hwnd, 0, TRUE))
2154 {
2155 return FALSE;
2156 }
2157 #endif
2158
2159 isChild = (0 != (Window->Style & WS_CHILD));
2160
2161 #if 0 /* FIXME */
2162 if (isChild)
2163 {
2164 if (! USER_IsExitingThread(GetCurrentThreadId()))
2165 {
2166 send_parent_notify(hwnd, WM_DESTROY);
2167 }
2168 }
2169 else if (NULL != GetWindow(Wnd, GW_OWNER))
2170 {
2171 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
2172 /* FIXME: clean up palette - see "Internals" p.352 */
2173 }
2174 #endif
2175
2176 if (!IntIsWindow(Wnd))
2177 {
2178 return TRUE;
2179 }
2180
2181 /* Recursively destroy owned windows */
2182 if (! isChild)
2183 {
2184 for (;;)
2185 {
2186 BOOL GotOne = FALSE;
2187 HWND *Children;
2188 HWND *ChildHandle;
2189 PWINDOW_OBJECT Child, Desktop;
2190
2191 Desktop = IntGetWindowObject(IntGetDesktopWindow());
2192 Children = IntWinListChildren(Desktop);
2193 IntReleaseWindowObject(Desktop);
2194 if (Children)
2195 {
2196 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2197 {
2198 Child = IntGetWindowObject(*ChildHandle);
2199 if (Child == NULL)
2200 continue;
2201 IntLockRelatives(Child);
2202 if (Child->Owner != Window->Self)
2203 {
2204 IntUnLockRelatives(Child);
2205 IntReleaseWindowObject(Child);
2206 continue;
2207 }
2208 IntUnLockRelatives(Child);
2209 if (IntWndBelongsToThread(Child, PsGetWin32Thread()))
2210 {
2211 IntReleaseWindowObject(Child);
2212 NtUserDestroyWindow(*ChildHandle);
2213 GotOne = TRUE;
2214 continue;
2215 }
2216 IntLockRelatives(Child);
2217 if (Child->Owner != NULL)
2218 {
2219 Child->Owner = NULL;
2220 }
2221 IntUnLockRelatives(Child);
2222 IntReleaseWindowObject(Child);
2223 }
2224 ExFreePool(Children);
2225 }
2226 if (! GotOne)
2227 {
2228 break;
2229 }
2230 }
2231 }
2232
2233 if (!IntIsWindow(Wnd))
2234 {
2235 IntReleaseWindowObject(Window);
2236 return TRUE;
2237 }
2238
2239 /* Destroy the window storage */
2240 IntDestroyWindow(Window, PsGetWin32Process(), PsGetWin32Thread(), TRUE);
2241
2242 IntReleaseWindowObject(Window);
2243 return TRUE;
2244 }
2245
2246
2247 /*
2248 * @unimplemented
2249 */
2250 DWORD
2251 STDCALL
2252 NtUserDrawMenuBarTemp(
2253 HWND hWnd,
2254 HDC hDC,
2255 PRECT hRect,
2256 HMENU hMenu,
2257 HFONT hFont)
2258 {
2259 /* we'll use this function just for caching the menu bar */
2260 UNIMPLEMENTED
2261 return 0;
2262 }
2263
2264
2265 /*
2266 * @unimplemented
2267 */
2268 DWORD STDCALL
2269 NtUserEndDeferWindowPosEx(DWORD Unknown0,
2270 DWORD Unknown1)
2271 {
2272 UNIMPLEMENTED
2273
2274 return 0;
2275 }
2276
2277
2278 /*
2279 * @unimplemented
2280 */
2281 DWORD STDCALL
2282 NtUserFillWindow(DWORD Unknown0,
2283 DWORD Unknown1,
2284 DWORD Unknown2,
2285 DWORD Unknown3)
2286 {
2287 UNIMPLEMENTED
2288
2289 return 0;
2290 }
2291
2292
2293 HWND FASTCALL
2294 IntFindWindow(PWINDOW_OBJECT Parent,
2295 PWINDOW_OBJECT ChildAfter,
2296 PWNDCLASS_OBJECT ClassObject,
2297 PUNICODE_STRING WindowName)
2298 {
2299 BOOL CheckWindowName;
2300 HWND *List, *phWnd;
2301 HWND Ret = NULL;
2302
2303 ASSERT(Parent);
2304
2305 CheckWindowName = (WindowName && (WindowName->Length > 0));
2306
2307 if((List = IntWinListChildren(Parent)))
2308 {
2309 phWnd = List;
2310 if(ChildAfter)
2311 {
2312 /* skip handles before and including ChildAfter */
2313 while(*phWnd && (*(phWnd++) != ChildAfter->Self));
2314 }
2315
2316 /* search children */
2317 while(*phWnd)
2318 {
2319 PWINDOW_OBJECT Child;
2320 if(!(Child = IntGetWindowObject(*(phWnd++))))
2321 {
2322 continue;
2323 }
2324
2325 /* Do not send WM_GETTEXT messages in the kernel mode version!
2326 The user mode version however calls GetWindowText() which will
2327 send WM_GETTEXT messages to windows belonging to its processes */
2328 if(((!CheckWindowName || (CheckWindowName && !RtlCompareUnicodeString(WindowName, &(Child->WindowName), FALSE))) &&
2329 (!ClassObject || (ClassObject && (Child->Class == ClassObject))))
2330 ||
2331 ((!CheckWindowName || (CheckWindowName && !RtlCompareUnicodeString(WindowName, &(Child->WindowName), FALSE))) &&
2332 (!ClassObject || (ClassObject && (Child->Class == ClassObject)))))
2333 {
2334 Ret = Child->Self;
2335 IntReleaseWindowObject(Child);
2336 break;
2337 }
2338
2339 IntReleaseWindowObject(Child);
2340 }
2341 ExFreePool(List);
2342 }
2343
2344 return Ret;
2345 }
2346
2347 /*
2348 * FUNCTION:
2349 * Searches a window's children for a window with the specified
2350 * class and name
2351 * ARGUMENTS:
2352 * hwndParent = The window whose childs are to be searched.
2353 * NULL = desktop
2354 * HWND_MESSAGE = message-only windows
2355 *
2356 * hwndChildAfter = Search starts after this child window.
2357 * NULL = start from beginning
2358 *
2359 * ucClassName = Class name to search for
2360 * Reguired parameter.
2361 *
2362 * ucWindowName = Window name
2363 * ->Buffer == NULL = don't care
2364 *
2365 * RETURNS:
2366 * The HWND of the window if it was found, otherwise NULL
2367 */
2368 /*
2369 * @implemented
2370 */
2371 HWND STDCALL
2372 NtUserFindWindowEx(HWND hwndParent,
2373 HWND hwndChildAfter,
2374 PUNICODE_STRING ucClassName,
2375 PUNICODE_STRING ucWindowName)
2376 {
2377 PWINDOW_OBJECT Parent, ChildAfter;
2378 UNICODE_STRING ClassName, WindowName;
2379 NTSTATUS Status;
2380 HWND Desktop, Ret = NULL;
2381 PWNDCLASS_OBJECT ClassObject = NULL;
2382 BOOL ClassFound;
2383
2384 Desktop = IntGetDesktopWindow();
2385
2386 if(hwndParent == NULL)
2387 hwndParent = Desktop;
2388 /* FIXME
2389 else if(hwndParent == HWND_MESSAGE)
2390 {
2391 hwndParent = IntGetMessageWindow();
2392 }
2393 */
2394
2395 if(!(Parent = IntGetWindowObject(hwndParent)))
2396 {
2397 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2398 return NULL;
2399 }
2400
2401 ChildAfter = NULL;
2402 if(hwndChildAfter && !(ChildAfter = IntGetWindowObject(hwndChildAfter)))
2403 {
2404 IntReleaseWindowObject(hwndParent);
2405 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2406 return NULL;
2407 }
2408
2409 /* copy the window name */
2410 Status = IntSafeCopyUnicodeString(&WindowName, ucWindowName);
2411 if(!NT_SUCCESS(Status))
2412 {
2413 SetLastNtError(Status);
2414 goto Cleanup3;
2415 }
2416
2417 /* safely copy the class name */
2418 Status = MmCopyFromCaller(&ClassName, ucClassName, sizeof(UNICODE_STRING));
2419 if(!NT_SUCCESS(Status))
2420 {
2421 SetLastNtError(Status);
2422 goto Cleanup2;
2423 }
2424 if(ClassName.Length > 0 && ClassName.Buffer)
2425 {
2426 WCHAR *buf;
2427 /* safely copy the class name string (NULL terminated because class-lookup
2428 depends on it... */
2429 buf = ExAllocatePoolWithTag(PagedPool, ClassName.Length + sizeof(WCHAR), TAG_STRING);
2430 if(!buf)
2431 {
2432 SetLastWin32Error(STATUS_INSUFFICIENT_RESOURCES);
2433 goto Cleanup2;
2434 }
2435 Status = MmCopyFromCaller(buf, ClassName.Buffer, ClassName.Length);
2436 if(!NT_SUCCESS(Status))
2437 {
2438 ExFreePool(buf);
2439 SetLastNtError(Status);
2440 goto Cleanup2;
2441 }
2442 ClassName.Buffer = buf;
2443 /* make sure the string is null-terminated */
2444 buf += ClassName.Length / sizeof(WCHAR);
2445 *buf = L'\0';
2446 }
2447
2448 /* find the class object */
2449 if(ClassName.Buffer)
2450 {
2451 /* this expects the string in ClassName to be NULL-terminated! */
2452 ClassFound = ClassReferenceClassByNameOrAtom(&ClassObject, ClassName.Buffer, NULL);
2453 if(!ClassFound)
2454 {
2455 if (IS_ATOM(ClassName.Buffer))
2456 DPRINT1("Window class not found (%lx)\n", (ULONG_PTR)ClassName.Buffer);
2457 else
2458 DPRINT1("Window class not found (%S)\n", ClassName.Buffer);
2459 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
2460 goto Cleanup;
2461 }
2462 }
2463
2464 if(Parent->Self == Desktop)
2465 {
2466 HWND *List, *phWnd;
2467 PWINDOW_OBJECT TopLevelWindow;
2468 BOOL CheckWindowName;
2469
2470 /* windows searches through all top-level windows if the parent is the desktop
2471 window */
2472
2473 if((List = IntWinListChildren(Parent)))
2474 {
2475 phWnd = List;
2476
2477 if(ChildAfter)
2478 {
2479 /* skip handles before and including ChildAfter */
2480 while(*phWnd && (*(phWnd++) != ChildAfter->Self));
2481 }
2482
2483 CheckWindowName = WindowName.Length > 0;
2484
2485 /* search children */
2486 while(*phWnd)
2487 {
2488 if(!(TopLevelWindow = IntGetWindowObject(*(phWnd++))))
2489 {
2490 continue;
2491 }
2492
2493 /* Do not send WM_GETTEXT messages in the kernel mode version!
2494 The user mode version however calls GetWindowText() which will
2495 send WM_GETTEXT messages to windows belonging to its processes */
2496 if(((!CheckWindowName || (CheckWindowName && !RtlCompareUnicodeString(&WindowName, &(TopLevelWindow->WindowName), FALSE))) &&
2497 (!ClassObject || (ClassObject && (TopLevelWindow->Class == ClassObject))))
2498 ||
2499 ((!CheckWindowName || (CheckWindowName && !RtlCompareUnicodeString(&WindowName, &(TopLevelWindow->WindowName), FALSE))) &&
2500 (!ClassObject || (ClassObject && (TopLevelWindow->Class == ClassObject)))))
2501 {
2502 Ret = TopLevelWindow->Self;
2503 IntReleaseWindowObject(TopLevelWindow);
2504 break;
2505 }
2506
2507 if(IntFindWindow(TopLevelWindow, NULL, ClassObject, &WindowName))
2508 {
2509 /* window returns the handle of the top-level window, in case it found
2510 the child window */
2511 Ret = TopLevelWindow->Self;
2512 IntReleaseWindowObject(TopLevelWindow);
2513 break;
2514 }
2515
2516 IntReleaseWindowObject(TopLevelWindow);
2517 }
2518 ExFreePool(List);
2519 }
2520 }
2521 else
2522 Ret = IntFindWindow(Parent, ChildAfter, ClassObject, &WindowName);
2523
2524 #if 0
2525 if(Ret == NULL && hwndParent == NULL && hwndChildAfter == NULL)
2526 {
2527 /* FIXME - if both hwndParent and hwndChildAfter are NULL, we also should
2528 search the message-only windows. Should this also be done if
2529 Parent is the desktop window??? */
2530 PWINDOW_OBJECT MsgWindows;
2531
2532 if((MsgWindows = IntGetWindowObject(IntGetMessageWindow())))
2533 {
2534 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassObject, &WindowName);
2535 IntReleaseWindowObject(MsgWindows);
2536 }
2537 }
2538 #endif
2539
2540 ClassDereferenceObject(ClassObject);
2541
2542 Cleanup:
2543 if(ClassName.Length > 0 && ClassName.Buffer)
2544 ExFreePool(ClassName.Buffer);
2545
2546 Cleanup2:
2547 RtlFreeUnicodeString(&WindowName);
2548
2549 Cleanup3:
2550 if(ChildAfter)
2551 IntReleaseWindowObject(ChildAfter);
2552 IntReleaseWindowObject(Parent);
2553
2554 return Ret;
2555 }
2556
2557
2558 /*
2559 * @unimplemented
2560 */
2561 DWORD STDCALL
2562 NtUserFlashWindowEx(DWORD Unknown0)
2563 {
2564 UNIMPLEMENTED
2565
2566 return 0;
2567 }
2568
2569
2570 /*
2571 * @implemented
2572 */
2573 HWND STDCALL
2574 NtUserGetAncestor(HWND hWnd, UINT Type)
2575 {
2576 PWINDOW_OBJECT Wnd, WndAncestor, Parent;
2577 HWND hWndAncestor;
2578
2579 if (hWnd == IntGetDesktopWindow())
2580 {
2581 return NULL;
2582 }
2583
2584 if (!(Wnd = IntGetWindowObject(hWnd)))
2585 {
2586 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2587 return NULL;
2588 }
2589
2590 switch (Type)
2591 {
2592 case GA_PARENT:
2593 {
2594 WndAncestor = IntGetParentObject(Wnd);
2595 break;
2596 }
2597
2598 case GA_ROOT:
2599 {
2600 PWINDOW_OBJECT tmp;
2601 WndAncestor = Wnd;
2602 Parent = NULL;
2603
2604 for(;;)
2605 {
2606 tmp = Parent;
2607 if(!(Parent = IntGetParentObject(WndAncestor)))
2608 {
2609 break;
2610 }
2611 if(IntIsDesktopWindow(Parent))
2612 {
2613 IntReleaseWindowObject(Parent);
2614 break;
2615 }
2616 if(tmp)
2617 IntReleaseWindowObject(tmp);
2618 WndAncestor = Parent;
2619 }
2620 break;
2621 }
2622
2623 case GA_ROOTOWNER:
2624 {
2625 WndAncestor = Wnd;
2626 IntReferenceWindowObject(WndAncestor);
2627 for (;;)
2628 {
2629 PWINDOW_OBJECT Old;
2630 Old = WndAncestor;
2631 Parent = IntGetParent(WndAncestor);
2632 IntReleaseWindowObject(Old);
2633 if (!Parent)
2634 {
2635 break;
2636 }
2637 WndAncestor = Parent;
2638 }
2639 break;
2640 }
2641
2642 default:
2643 {
2644 IntReleaseWindowObject(Wnd);
2645 return NULL;
2646 }
2647 }
2648
2649 hWndAncestor = (WndAncestor ? WndAncestor->Self : NULL);
2650 IntReleaseWindowObject(Wnd);
2651
2652 if(WndAncestor && (WndAncestor != Wnd))
2653 IntReleaseWindowObject(WndAncestor);
2654
2655 return hWndAncestor;
2656 }
2657
2658
2659 /*!
2660 * Returns client window rectangle relative to the upper-left corner of client area.
2661 *
2662 * \param hWnd window handle.
2663 * \param Rect pointer to the buffer where the coordinates are returned.
2664 *
2665 */
2666 /*
2667 * @implemented
2668 */
2669 BOOL STDCALL
2670 NtUserGetClientRect(HWND hWnd, LPRECT Rect)
2671 {
2672 PWINDOW_OBJECT WindowObject;
2673 RECT SafeRect;
2674
2675 if(!(WindowObject = IntGetWindowObject(hWnd)))
2676 {
2677 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2678 return FALSE;
2679 }
2680
2681 IntGetClientRect(WindowObject, &SafeRect);
2682 IntReleaseWindowObject(WindowObject);
2683
2684 if(!NT_SUCCESS(MmCopyToCaller(Rect, &SafeRect, sizeof(RECT))))
2685 {
2686 return FALSE;
2687 }
2688 return TRUE;
2689 }
2690
2691
2692 /*
2693 * @implemented
2694 */
2695 HWND STDCALL
2696 NtUserGetDesktopWindow()
2697 {
2698 return IntGetDesktopWindow();
2699 }
2700
2701
2702 /*
2703 * @unimplemented
2704 */
2705 DWORD STDCALL
2706 NtUserGetInternalWindowPos(DWORD Unknown0,
2707 DWORD Unknown1,
2708 DWORD Unknown2)
2709 {
2710 UNIMPLEMENTED
2711
2712 return 0;
2713 }
2714
2715
2716 /*
2717 * @unimplemented
2718 */
2719 HWND STDCALL
2720 NtUserGetLastActivePopup(HWND hWnd)
2721 {
2722 /*
2723 * This code can't work, because hWndLastPopup member of WINDOW_OBJECT is
2724 * not changed anywhere.
2725 * -- Filip, 01/nov/2003
2726 */
2727 #if 0
2728 PWINDOW_OBJECT Wnd;
2729 HWND hWndLastPopup;
2730
2731 IntAcquireWinLockShared();
2732
2733 if (!(Wnd = IntGetWindowObject(hWnd)))
2734 {
2735 IntReleaseWinLock();
2736 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2737 return NULL;
2738 }
2739
2740 hWndLastPopup = Wnd->hWndLastPopup;
2741
2742 IntReleaseWinLock();
2743
2744 return hWndLastPopup;
2745 #else
2746 return NULL;
2747 #endif
2748 }
2749
2750 /*
2751 * NtUserGetParent
2752 *
2753 * The NtUserGetParent function retrieves a handle to the specified window's
2754 * parent or owner.
2755 *
2756 * Remarks
2757 * Note that, despite its name, this function can return an owner window
2758 * instead of a parent window.
2759 *
2760 * Status
2761 * @implemented
2762 */
2763
2764 HWND STDCALL
2765 NtUserGetParent(HWND hWnd)
2766 {
2767 PWINDOW_OBJECT Wnd, WndParent;
2768 HWND hWndParent = NULL;
2769
2770 if (!(Wnd = IntGetWindowObject(hWnd)))
2771 {
2772 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2773 return NULL;
2774 }
2775
2776 WndParent = IntGetParent(Wnd);
2777 if (WndParent)
2778 {
2779 hWndParent = WndParent->Self;
2780 IntReleaseWindowObject(WndParent);
2781 }
2782
2783 IntReleaseWindowObject(Wnd);
2784
2785 return hWndParent;
2786 }
2787
2788 /*
2789 * NtUserSetParent
2790 *
2791 * The NtUserSetParent function changes the parent window of the specified
2792 * child window.
2793 *
2794 * Remarks
2795 * The new parent window and the child window must belong to the same
2796 * application. If the window identified by the hWndChild parameter is
2797 * visible, the system performs the appropriate redrawing and repainting.
2798 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
2799 * or WS_POPUP window styles of the window whose parent is being changed.
2800 *
2801 * Status
2802 * @implemented
2803 */
2804
2805 HWND STDCALL
2806 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
2807 {
2808 PWINDOW_OBJECT Wnd = NULL, WndParent = NULL, WndOldParent;
2809 HWND hWndOldParent = NULL;
2810
2811 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
2812 {
2813 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2814 return NULL;
2815 }
2816
2817 if (hWndChild == IntGetDesktopWindow())
2818 {
2819 SetLastWin32Error(ERROR_ACCESS_DENIED);
2820 return NULL;
2821 }
2822
2823 if (hWndNewParent)
2824 {
2825 if (!(WndParent = IntGetWindowObject(hWndNewParent)))
2826 {
2827 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2828 return NULL;
2829 }
2830 }
2831 else
2832 {
2833 if (!(WndParent = IntGetWindowObject(IntGetDesktopWindow())))
2834 {
2835 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2836 return NULL;
2837 }
2838 }
2839
2840 if (!(Wnd = IntGetWindowObject(hWndChild)))
2841 {
2842 IntReleaseWindowObject(WndParent);
2843 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2844 return NULL;
2845 }
2846
2847 WndOldParent = IntSetParent(Wnd, WndParent);
2848
2849 if (WndOldParent)
2850 {
2851 hWndOldParent = WndOldParent->Self;
2852 IntReleaseWindowObject(WndOldParent);
2853 }
2854
2855 IntReleaseWindowObject(Wnd);
2856 IntReleaseWindowObject(WndParent);
2857
2858 return hWndOldParent;
2859 }
2860
2861 /*
2862 * NtUserGetShellWindow
2863 *
2864 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
2865 *
2866 * Status
2867 * @implemented
2868 */
2869
2870 HWND STDCALL
2871 NtUserGetShellWindow()
2872 {
2873 PWINSTATION_OBJECT WinStaObject;
2874 HWND Ret;
2875
2876 NTSTATUS Status = IntValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
2877 KernelMode,
2878 0,
2879 &WinStaObject);
2880
2881 if (!NT_SUCCESS(Status))
2882 {
2883 SetLastNtError(Status);
2884 return (HWND)0;
2885 }
2886
2887 Ret = (HWND)WinStaObject->ShellWindow;
2888
2889 ObDereferenceObject(WinStaObject);
2890 return Ret;
2891 }
2892
2893 /*
2894 * NtUserSetShellWindowEx
2895 *
2896 * This is undocumented function to set global shell window. The global
2897 * shell window has special handling of window position.
2898 *
2899 * Status
2900 * @implemented
2901 */
2902
2903 BOOL STDCALL
2904 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
2905 {
2906 PWINSTATION_OBJECT WinStaObject;
2907
2908 NTSTATUS Status = IntValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
2909 KernelMode,
2910 0,
2911 &WinStaObject);
2912
2913 if (!NT_SUCCESS(Status))
2914 {
2915 SetLastNtError(Status);
2916 return FALSE;
2917 }
2918
2919 /*
2920 * Test if we are permitted to change the shell window.
2921 */
2922 if (WinStaObject->ShellWindow)
2923 {
2924 ObDereferenceObject(WinStaObject);
2925 return FALSE;
2926 }
2927
2928 /*
2929 * Move shell window into background.
2930 */
2931 if (hwndListView && hwndListView != hwndShell)
2932 {
2933 /*
2934 * Disabled for now to get Explorer working.
2935 * -- Filip, 01/nov/2003
2936 */
2937 #if 0
2938 WinPosSetWindowPos(hwndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
2939 #endif
2940
2941 if (NtUserGetWindowLong(hwndListView, GWL_EXSTYLE, FALSE) & WS_EX_TOPMOST)
2942 {
2943 ObDereferenceObject(WinStaObject);
2944 return FALSE;
2945 }
2946 }
2947
2948 if (NtUserGetWindowLong(hwndShell, GWL_EXSTYLE, FALSE) & WS_EX_TOPMOST)
2949 {
2950 ObDereferenceObject(WinStaObject);
2951 return FALSE;
2952 }
2953
2954 WinPosSetWindowPos(hwndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
2955
2956 WinStaObject->ShellWindow = hwndShell;
2957 WinStaObject->ShellListView = hwndListView;
2958
2959 ObDereferenceObject(WinStaObject);
2960 return TRUE;
2961 }
2962
2963 /*
2964 * NtUserGetSystemMenu
2965 *
2966 * The NtUserGetSystemMenu function allows the application to access the
2967 * window menu (also known as the system menu or the control menu) for
2968 * copying and modifying.
2969 *
2970 * Parameters
2971 * hWnd
2972 * Handle to the window that will own a copy of the window menu.
2973 * bRevert
2974 * Specifies the action to be taken. If this parameter is FALSE,
2975 * NtUserGetSystemMenu returns a handle to the copy of the window menu
2976 * currently in use. The copy is initially identical to the window menu
2977 * but it can be modified.
2978 * If this parameter is TRUE, GetSystemMenu resets the window menu back
2979 * to the default state. The previous window menu, if any, is destroyed.
2980 *
2981 * Return Value
2982 * If the bRevert parameter is FALSE, the return value is a handle to a
2983 * copy of the window menu. If the bRevert parameter is TRUE, the return
2984 * value is NULL.
2985 *
2986 * Status
2987 * @implemented
2988 */
2989
2990 HMENU STDCALL
2991 NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
2992 {
2993 HMENU Result = 0;
2994 PWINDOW_OBJECT WindowObject;
2995 PMENU_OBJECT MenuObject;
2996
2997 WindowObject = IntGetWindowObject((HWND)hWnd);
2998 if (WindowObject == NULL)
2999 {
3000 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3001 return 0;
3002 }
3003
3004 MenuObject = IntGetSystemMenu(WindowObject, bRevert, FALSE);
3005 if (MenuObject)
3006 {
3007 Result = MenuObject->MenuInfo.Self;
3008 IntReleaseMenuObject(MenuObject);
3009 }
3010
3011 IntReleaseWindowObject(WindowObject);
3012 return Result;
3013 }
3014
3015 /*
3016 * NtUserSetSystemMenu
3017 *
3018 * Status
3019 * @implemented
3020 */
3021
3022 BOOL STDCALL
3023 NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
3024 {
3025 BOOL Result = FALSE;
3026 PWINDOW_OBJECT WindowObject;
3027 PMENU_OBJECT MenuObject;
3028
3029 WindowObject = IntGetWindowObject(hWnd);
3030 if (!WindowObject)
3031 {
3032 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3033 return FALSE;
3034 }
3035
3036 if (hMenu)
3037 {
3038 /*
3039 * Assign new menu handle.
3040 */
3041 MenuObject = IntGetMenuObject(hMenu);
3042 if (!MenuObject)
3043 {
3044 IntReleaseWindowObject(WindowObject);
3045 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
3046 return FALSE;
3047 }
3048
3049 Result = IntSetSystemMenu(WindowObject, MenuObject);
3050
3051 IntReleaseMenuObject(MenuObject);
3052 }
3053
3054 IntReleaseWindowObject(WindowObject);
3055
3056 return Result;
3057 }
3058
3059 /*
3060 * NtUserGetWindow
3061 *
3062 * The NtUserGetWindow function retrieves a handle to a window that has the
3063 * specified relationship (Z order or owner) to the specified window.
3064 *
3065 * Status
3066 * @implemented
3067 */
3068
3069 HWND STDCALL
3070 NtUserGetWindow(HWND hWnd, UINT Relationship)
3071 {
3072 PWINDOW_OBJECT WindowObject, Parent;
3073 HWND hWndResult = NULL;
3074
3075 if (!(WindowObject = IntGetWindowObject(hWnd)))
3076 {
3077 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3078 return NULL;
3079 }
3080
3081 switch (Relationship)
3082 {
3083 case GW_HWNDFIRST:
3084 if((Parent = IntGetParentObject(WindowObject)))
3085 {
3086 IntLockRelatives(Parent);
3087 if (Parent->FirstChild)
3088 hWndResult = Parent->FirstChild->Self;
3089 IntUnLockRelatives(Parent);
3090 IntReleaseWindowObject(Parent);
3091 }
3092 break;
3093
3094 case GW_HWNDLAST:
3095 if((Parent = IntGetParentObject(WindowObject)))
3096 {
3097 IntLockRelatives(Parent);
3098 if (Parent->LastChild)
3099 hWndResult = Parent->LastChild->Self;
3100 IntUnLockRelatives(Parent);
3101 IntReleaseWindowObject(Parent);
3102 }
3103 break;
3104
3105 case GW_HWNDNEXT:
3106 IntLockRelatives(WindowObject);
3107 if (WindowObject->NextSibling)
3108 hWndResult = WindowObject->NextSibling->Self;
3109 IntUnLockRelatives(WindowObject);
3110 break;
3111
3112 case GW_HWNDPREV:
3113 IntLockRelatives(WindowObject);
3114 if (WindowObject->PrevSibling)
3115 hWndResult = WindowObject->PrevSibling->Self;
3116 IntUnLockRelatives(WindowObject);
3117 break;
3118
3119 case GW_OWNER:
3120 IntLockRelatives(WindowObject);
3121 if((Parent = IntGetWindowObject(WindowObject->Owner)))
3122 {
3123 hWndResult = Parent->Self;
3124 IntReleaseWindowObject(Parent);
3125 }
3126 IntUnLockRelatives(WindowObject);
3127 break;
3128 case GW_CHILD:
3129 IntLockRelatives(WindowObject);
3130 if (WindowObject->FirstChild)
3131 hWndResult = WindowObject->FirstChild->Self;
3132 IntUnLockRelatives(WindowObject);
3133 break;
3134 }
3135
3136 IntReleaseWindowObject(WindowObject);
3137
3138 return hWndResult;
3139 }
3140
3141 /*
3142 * NtUserGetWindowLong
3143 *
3144 * The NtUserGetWindowLong function retrieves information about the specified
3145 * window. The function also retrieves the 32-bit (long) value at the
3146 * specified offset into the extra window memory.
3147 *
3148 * Status
3149 * @implemented
3150 */
3151
3152 LONG STDCALL
3153 NtUserGetWindowLong(HWND hWnd, DWORD Index, BOOL Ansi)
3154 {
3155 PWINDOW_OBJECT WindowObject, Parent;
3156 LONG Result;
3157
3158 DPRINT("NtUserGetWindowLong(%x,%d,%d)\n", hWnd, (INT)Index, Ansi);
3159
3160 WindowObject = IntGetWindowObject(hWnd);
3161 if (WindowObject == NULL)
3162 {
3163 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3164 return 0;
3165 }
3166
3167 /*
3168 * Only allow CSRSS to mess with the desktop window
3169 */
3170 if (hWnd == IntGetDesktopWindow()
3171 && WindowObject->OwnerThread->ThreadsProcess != PsGetCurrentProcess())
3172 {
3173 SetLastWin32Error(STATUS_ACCESS_DENIED);
3174 return 0;
3175 }
3176
3177 if ((INT)Index >= 0)
3178 {
3179 if ((Index + sizeof(LONG)) > WindowObject->ExtraDataSize)
3180 {
3181 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3182 return 0;
3183 }
3184 Result = *((LONG *)(WindowObject->ExtraData + Index));
3185 }
3186 else
3187 {
3188 switch (Index)
3189 {
3190 case GWL_EXSTYLE:
3191 Result = WindowObject->ExStyle;
3192 break;
3193
3194 case GWL_STYLE:
3195 Result = WindowObject->Style;
3196 break;
3197
3198 case GWL_WNDPROC:
3199 if (Ansi)
3200 Result = (LONG) WindowObject->WndProcA;
3201 else
3202 Result = (LONG) WindowObject->WndProcW;
3203 break;
3204
3205 case GWL_HINSTANCE:
3206 Result = (LONG) WindowObject->Instance;
3207 break;
3208
3209 case GWL_HWNDPARENT:
3210 IntLockRelatives(WindowObject);
3211 Parent = IntGetWindowObject(WindowObject->Parent);
3212 IntUnLockRelatives(WindowObject);
3213 if(Parent)
3214 {
3215 if (Parent && Parent->Self == IntGetDesktopWindow())
3216 Result = (LONG) NtUserGetWindow(WindowObject->Self, GW_OWNER);
3217 else
3218 Result = (LONG) Parent->Self;
3219 IntReleaseWindowObject(Parent);
3220 }
3221 break;
3222
3223 case GWL_ID:
3224 Result = (LONG) WindowObject->IDMenu;
3225 break;
3226
3227 case GWL_USERDATA:
3228 Result = WindowObject->UserData;
3229 break;
3230
3231 default:
3232 DPRINT1("NtUserGetWindowLong(): Unsupported index %d\n", Index);
3233 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3234 Result = 0;
3235 break;
3236 }
3237 }
3238
3239 IntReleaseWindowObject(WindowObject);
3240
3241 return Result;
3242 }
3243
3244 /*
3245 * NtUserSetWindowLong
3246 *
3247 * The NtUserSetWindowLong function changes an attribute of the specified
3248 * window. The function also sets the 32-bit (long) value at the specified
3249 * offset into the extra window memory.
3250 *
3251 * Status
3252 * @implemented
3253 */
3254
3255 LONG STDCALL
3256 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3257 {
3258 PWINDOW_OBJECT WindowObject, Parent;
3259 PW32PROCESS Process;
3260 PWINSTATION_OBJECT WindowStation;
3261 LONG OldValue;
3262 STYLESTRUCT Style;
3263
3264 if (hWnd == IntGetDesktopWindow())
3265 {
3266 SetLastWin32Error(STATUS_ACCESS_DENIED);
3267 return 0;
3268 }
3269
3270 WindowObject = IntGetWindowObject(hWnd);
3271 if (WindowObject == NULL)
3272 {
3273 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3274 return 0;
3275 }
3276
3277 if ((INT)Index >= 0)
3278 {
3279 if ((Index + sizeof(LONG)) > WindowObject->ExtraDataSize)
3280 {
3281 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3282 IntReleaseWindowObject(WindowObject);
3283 return 0;
3284 }
3285 OldValue = *((LONG *)(WindowObject->ExtraData + Index));
3286 *((LONG *)(WindowObject->ExtraData + Index)) = NewValue;
3287 }
3288 else
3289 {
3290 switch (Index)
3291 {
3292 case GWL_EXSTYLE:
3293 OldValue = (LONG) WindowObject->ExStyle;
3294 Style.styleOld = OldValue;
3295 Style.styleNew = NewValue;
3296
3297 /*
3298 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3299 */
3300 Process = WindowObject->OwnerThread->ThreadsProcess->Win32Process;
3301 WindowStation = Process->WindowStation;
3302 if(WindowStation)
3303 {
3304 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3305 Style.styleNew &= ~WS_EX_TOPMOST;
3306 }
3307
3308 IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3309 WindowObject->ExStyle = (DWORD)Style.styleNew;
3310 IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3311 break;
3312
3313 case GWL_STYLE:
3314 OldValue = (LONG) WindowObject->Style;
3315 Style.styleOld = OldValue;
3316 Style.styleNew = NewValue;
3317 IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3318 WindowObject->Style = (DWORD)Style.styleNew;
3319 IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3320 break;
3321
3322 case GWL_WNDPROC:
3323 /* FIXME: should check if window belongs to current process */
3324 if (Ansi)
3325 {
3326 OldValue = (LONG) WindowObject->WndProcA;
3327 WindowObject->WndProcA = (WNDPROC) NewValue;
3328 WindowObject->WndProcW = (WNDPROC) IntAddWndProcHandle((WNDPROC)NewValue,FALSE);
3329 WindowObject->Unicode = FALSE;
3330 }
3331 else
3332 {
3333 OldValue = (LONG) WindowObject->WndProcW;
3334 WindowObject->WndProcW = (WNDPROC) NewValue;
3335 WindowObject->WndProcA = (WNDPROC) IntAddWndProcHandle((WNDPROC)NewValue,TRUE);
3336 WindowObject->Unicode = TRUE;
3337 }
3338 break;
3339
3340 case GWL_HINSTANCE