- Fixed very stupid bug with pointer handling in NtUserBuildHwndList.
[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.240 2004/06/20 16:06:05 navaraf Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Windows
24 * FILE: subsys/win32k/ntuser/window.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 06-06-2001 CSH Created
28 */
29 /* INCLUDES ******************************************************************/
30 #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 DPRINT("Sending bogus WM_SIZE\n");
1938
1939 lParam = MAKE_LONG(WindowObject->ClientRect.right -
1940 WindowObject->ClientRect.left,
1941 WindowObject->ClientRect.bottom -
1942 WindowObject->ClientRect.top);
1943 IntSendMessage(WindowObject->Self, WM_SIZE, SIZE_RESTORED,
1944 lParam);
1945
1946 DPRINT("IntCreateWindow(): About to send WM_MOVE\n");
1947
1948 if (0 != (WindowObject->Style & WS_CHILD) && ParentWindow)
1949 {
1950 lParam = MAKE_LONG(WindowObject->ClientRect.left - ParentWindow->ClientRect.left,
1951 WindowObject->ClientRect.top - ParentWindow->ClientRect.top);
1952 }
1953 else
1954 {
1955 lParam = MAKE_LONG(WindowObject->ClientRect.left,
1956 WindowObject->ClientRect.top);
1957 }
1958 IntSendMessage(WindowObject->Self, WM_MOVE, 0, lParam);
1959 }
1960
1961 /* Show or maybe minimize or maximize the window. */
1962 if (WindowObject->Style & (WS_MINIMIZE | WS_MAXIMIZE))
1963 {
1964 RECT NewPos;
1965 UINT16 SwFlag;
1966
1967 SwFlag = (WindowObject->Style & WS_MINIMIZE) ? SW_MINIMIZE :
1968 SW_MAXIMIZE;
1969 WinPosMinMaximize(WindowObject, SwFlag, &NewPos);
1970 SwFlag =
1971 ((WindowObject->Style & WS_CHILD) || NtUserGetActiveWindow()) ?
1972 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED :
1973 SWP_NOZORDER | SWP_FRAMECHANGED;
1974 DPRINT("IntCreateWindow(): About to minimize/maximize\n");
1975 DPRINT("%d,%d %dx%d\n", NewPos.left, NewPos.top, NewPos.right, NewPos.bottom);
1976 WinPosSetWindowPos(WindowObject->Self, 0, NewPos.left, NewPos.top,
1977 NewPos.right, NewPos.bottom, SwFlag);
1978 }
1979
1980 /* Notify the parent window of a new child. */
1981 if ((WindowObject->Style & WS_CHILD) &&
1982 (!(WindowObject->ExStyle & WS_EX_NOPARENTNOTIFY)) && ParentWindow)
1983 {
1984 DPRINT("IntCreateWindow(): About to notify parent\n");
1985 IntSendMessage(ParentWindow->Self,
1986 WM_PARENTNOTIFY,
1987 MAKEWPARAM(WM_CREATE, WindowObject->IDMenu),
1988 (LPARAM)WindowObject->Self);
1989 }
1990
1991 if (NULL != ParentWindow)
1992 {
1993 IntReleaseWindowObject(ParentWindow);
1994 }
1995
1996 /* Initialize and show the window's scrollbars */
1997 if (WindowObject->Style & WS_VSCROLL)
1998 {
1999 NtUserShowScrollBar(WindowObject->Self, SB_VERT, TRUE);
2000 }
2001 if (WindowObject->Style & WS_HSCROLL)
2002 {
2003 NtUserShowScrollBar(WindowObject->Self, SB_HORZ, TRUE);
2004 }
2005
2006 if (dwStyle & WS_VISIBLE)
2007 {
2008 DPRINT("IntCreateWindow(): About to show window\n");
2009 WinPosShowWindow(WindowObject->Self, dwShowMode);
2010 }
2011
2012 DPRINT("IntCreateWindow(): = %X\n", Handle);
2013 DPRINT("WindowObject->SystemMenu = 0x%x\n", WindowObject->SystemMenu);
2014 return((HWND)Handle);
2015 }
2016
2017 HWND STDCALL
2018 NtUserCreateWindowEx(DWORD dwExStyle,
2019 PUNICODE_STRING UnsafeClassName,
2020 PUNICODE_STRING UnsafeWindowName,
2021 DWORD dwStyle,
2022 LONG x,
2023 LONG y,
2024 LONG nWidth,
2025 LONG nHeight,
2026 HWND hWndParent,
2027 HMENU hMenu,
2028 HINSTANCE hInstance,
2029 LPVOID lpParam,
2030 DWORD dwShowMode,
2031 BOOL bUnicodeWindow)
2032 {
2033 NTSTATUS Status;
2034 UNICODE_STRING WindowName;
2035 UNICODE_STRING ClassName;
2036 HWND NewWindow;
2037
2038 DPRINT("NtUserCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, nWidth, nHeight);
2039
2040 /* Get the class name (string or atom) */
2041 Status = MmCopyFromCaller(&ClassName, UnsafeClassName, sizeof(UNICODE_STRING));
2042 if (! NT_SUCCESS(Status))
2043 {
2044 SetLastNtError(Status);
2045 return NULL;
2046 }
2047 if (! IS_ATOM(ClassName.Buffer))
2048 {
2049 Status = IntSafeCopyUnicodeString(&ClassName, UnsafeClassName);
2050 if (! NT_SUCCESS(Status))
2051 {
2052 SetLastNtError(Status);
2053 return NULL;
2054 }
2055 }
2056
2057 /* safely copy the window name */
2058 if (NULL != UnsafeWindowName)
2059 {
2060 Status = IntSafeCopyUnicodeString(&WindowName, UnsafeWindowName);
2061 if (! NT_SUCCESS(Status))
2062 {
2063 if (! IS_ATOM(ClassName.Buffer))
2064 {
2065 RtlFreeUnicodeString(&ClassName);
2066 }
2067 SetLastNtError(Status);
2068 return NULL;
2069 }
2070 }
2071 else
2072 {
2073 RtlInitUnicodeString(&WindowName, NULL);
2074 }
2075
2076 NewWindow = IntCreateWindowEx(dwExStyle, &ClassName, &WindowName, dwStyle, x, y, nWidth, nHeight,
2077 hWndParent, hMenu, hInstance, lpParam, dwShowMode, bUnicodeWindow);
2078
2079 RtlFreeUnicodeString(&WindowName);
2080 if (! IS_ATOM(ClassName.Buffer))
2081 {
2082 RtlFreeUnicodeString(&ClassName);
2083 }
2084
2085 return NewWindow;
2086 }
2087
2088 /*
2089 * @unimplemented
2090 */
2091 HDWP STDCALL
2092 NtUserDeferWindowPos(HDWP WinPosInfo,
2093 HWND Wnd,
2094 HWND WndInsertAfter,
2095 int x,
2096 int y,
2097 int cx,
2098 int cy,
2099 UINT Flags)
2100 {
2101 UNIMPLEMENTED
2102
2103 return 0;
2104 }
2105
2106
2107 /*
2108 * @implemented
2109 */
2110 BOOLEAN STDCALL
2111 NtUserDestroyWindow(HWND Wnd)
2112 {
2113 PWINDOW_OBJECT Window;
2114 BOOLEAN isChild;
2115
2116 Window = IntGetWindowObject(Wnd);
2117 if (Window == NULL)
2118 {
2119 return FALSE;
2120 }
2121
2122 /* Check for owner thread and desktop window */
2123 if ((Window->OwnerThread != PsGetCurrentThread()) || IntIsDesktopWindow(Window))
2124 {
2125 IntReleaseWindowObject(Window);
2126 SetLastWin32Error(ERROR_ACCESS_DENIED);
2127 return FALSE;
2128 }
2129
2130 /* Look whether the focus is within the tree of windows we will
2131 * be destroying.
2132 */
2133 if (!WinPosShowWindow(Wnd, SW_HIDE))
2134 {
2135 if (NtUserGetActiveWindow() == Wnd)
2136 {
2137 WinPosActivateOtherWindow(Window);
2138 }
2139 }
2140 IntLockMessageQueue(Window->MessageQueue);
2141 if (Window->MessageQueue->ActiveWindow == Window->Self)
2142 Window->MessageQueue->ActiveWindow = NULL;
2143 if (Window->MessageQueue->FocusWindow == Window->Self)
2144 Window->MessageQueue->FocusWindow = NULL;
2145 if (Window->MessageQueue->CaptureWindow == Window->Self)
2146 Window->MessageQueue->CaptureWindow = NULL;
2147 IntUnLockMessageQueue(Window->MessageQueue);
2148
2149 /* Call hooks */
2150 #if 0 /* FIXME */
2151 if (HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hwnd, 0, TRUE))
2152 {
2153 return FALSE;
2154 }
2155 #endif
2156
2157 isChild = (0 != (Window->Style & WS_CHILD));
2158
2159 #if 0 /* FIXME */
2160 if (isChild)
2161 {
2162 if (! USER_IsExitingThread(GetCurrentThreadId()))
2163 {
2164 send_parent_notify(hwnd, WM_DESTROY);
2165 }
2166 }
2167 else if (NULL != GetWindow(Wnd, GW_OWNER))
2168 {
2169 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
2170 /* FIXME: clean up palette - see "Internals" p.352 */
2171 }
2172 #endif
2173
2174 if (!IntIsWindow(Wnd))
2175 {
2176 return TRUE;
2177 }
2178
2179 /* Recursively destroy owned windows */
2180 if (! isChild)
2181 {
2182 for (;;)
2183 {
2184 BOOL GotOne = FALSE;
2185 HWND *Children;
2186 HWND *ChildHandle;
2187 PWINDOW_OBJECT Child, Desktop;
2188
2189 Desktop = IntGetWindowObject(IntGetDesktopWindow());
2190 Children = IntWinListChildren(Desktop);
2191 IntReleaseWindowObject(Desktop);
2192 if (Children)
2193 {
2194 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2195 {
2196 Child = IntGetWindowObject(*ChildHandle);
2197 if (Child == NULL)
2198 continue;
2199 IntLockRelatives(Child);
2200 if (Child->Owner != Window->Self)
2201 {
2202 IntUnLockRelatives(Child);
2203 IntReleaseWindowObject(Child);
2204 continue;
2205 }
2206 IntUnLockRelatives(Child);
2207 if (IntWndBelongsToThread(Child, PsGetWin32Thread()))
2208 {
2209 IntReleaseWindowObject(Child);
2210 NtUserDestroyWindow(*ChildHandle);
2211 GotOne = TRUE;
2212 continue;
2213 }
2214 IntLockRelatives(Child);
2215 if (Child->Owner != NULL)
2216 {
2217 Child->Owner = NULL;
2218 }
2219 IntUnLockRelatives(Child);
2220 IntReleaseWindowObject(Child);
2221 }
2222 ExFreePool(Children);
2223 }
2224 if (! GotOne)
2225 {
2226 break;
2227 }
2228 }
2229 }
2230
2231 if (!IntIsWindow(Wnd))
2232 {
2233 IntReleaseWindowObject(Window);
2234 return TRUE;
2235 }
2236
2237 /* Destroy the window storage */
2238 IntDestroyWindow(Window, PsGetWin32Process(), PsGetWin32Thread(), TRUE);
2239
2240 IntReleaseWindowObject(Window);
2241 return TRUE;
2242 }
2243
2244
2245 /*
2246 * @unimplemented
2247 */
2248 DWORD
2249 STDCALL
2250 NtUserDrawMenuBarTemp(
2251 HWND hWnd,
2252 HDC hDC,
2253 PRECT hRect,
2254 HMENU hMenu,
2255 HFONT hFont)
2256 {
2257 /* we'll use this function just for caching the menu bar */
2258 UNIMPLEMENTED
2259 return 0;
2260 }
2261
2262
2263 /*
2264 * @unimplemented
2265 */
2266 DWORD STDCALL
2267 NtUserEndDeferWindowPosEx(DWORD Unknown0,
2268 DWORD Unknown1)
2269 {
2270 UNIMPLEMENTED
2271
2272 return 0;
2273 }
2274
2275
2276 /*
2277 * @unimplemented
2278 */
2279 DWORD STDCALL
2280 NtUserFillWindow(DWORD Unknown0,
2281 DWORD Unknown1,
2282 DWORD Unknown2,
2283 DWORD Unknown3)
2284 {
2285 UNIMPLEMENTED
2286
2287 return 0;
2288 }
2289
2290
2291 HWND FASTCALL
2292 IntFindWindow(PWINDOW_OBJECT Parent,
2293 PWINDOW_OBJECT ChildAfter,
2294 PWNDCLASS_OBJECT ClassObject,
2295 PUNICODE_STRING WindowName)
2296 {
2297 BOOL CheckWindowName;
2298 HWND *List, *phWnd;
2299 HWND Ret = NULL;
2300
2301 ASSERT(Parent);
2302
2303 CheckWindowName = (WindowName && (WindowName->Length > 0));
2304
2305 if((List = IntWinListChildren(Parent)))
2306 {
2307 phWnd = List;
2308 if(ChildAfter)
2309 {
2310 /* skip handles before and including ChildAfter */
2311 while(*phWnd && (*(phWnd++) != ChildAfter->Self));
2312 }
2313
2314 /* search children */
2315 while(*phWnd)
2316 {
2317 PWINDOW_OBJECT Child;
2318 if(!(Child = IntGetWindowObject(*(phWnd++))))
2319 {
2320 continue;
2321 }
2322
2323 /* Do not send WM_GETTEXT messages in the kernel mode version!
2324 The user mode version however calls GetWindowText() which will
2325 send WM_GETTEXT messages to windows belonging to its processes */
2326 if(((!CheckWindowName || (CheckWindowName && !RtlCompareUnicodeString(WindowName, &(Child->WindowName), FALSE))) &&
2327 (!ClassObject || (ClassObject && (Child->Class == ClassObject))))
2328 ||
2329 ((!CheckWindowName || (CheckWindowName && !RtlCompareUnicodeString(WindowName, &(Child->WindowName), FALSE))) &&
2330 (!ClassObject || (ClassObject && (Child->Class == ClassObject)))))
2331 {
2332 Ret = Child->Self;
2333 IntReleaseWindowObject(Child);
2334 break;
2335 }
2336
2337 IntReleaseWindowObject(Child);
2338 }
2339 ExFreePool(List);
2340 }
2341
2342 return Ret;
2343 }
2344
2345 /*
2346 * FUNCTION:
2347 * Searches a window's children for a window with the specified
2348 * class and name
2349 * ARGUMENTS:
2350 * hwndParent = The window whose childs are to be searched.
2351 * NULL = desktop
2352 * HWND_MESSAGE = message-only windows
2353 *
2354 * hwndChildAfter = Search starts after this child window.
2355 * NULL = start from beginning
2356 *
2357 * ucClassName = Class name to search for
2358 * Reguired parameter.
2359 *
2360 * ucWindowName = Window name
2361 * ->Buffer == NULL = don't care
2362 *
2363 * RETURNS:
2364 * The HWND of the window if it was found, otherwise NULL
2365 */
2366 /*
2367 * @implemented
2368 */
2369 HWND STDCALL
2370 NtUserFindWindowEx(HWND hwndParent,
2371 HWND hwndChildAfter,
2372 PUNICODE_STRING ucClassName,
2373 PUNICODE_STRING ucWindowName)
2374 {
2375 PWINDOW_OBJECT Parent, ChildAfter;
2376 UNICODE_STRING ClassName, WindowName;
2377 NTSTATUS Status;
2378 HWND Desktop, Ret = NULL;
2379 PWNDCLASS_OBJECT ClassObject = NULL;
2380 BOOL ClassFound;
2381
2382 Desktop = IntGetDesktopWindow();
2383
2384 if(hwndParent == NULL)
2385 hwndParent = Desktop;
2386 /* FIXME
2387 else if(hwndParent == HWND_MESSAGE)
2388 {
2389 hwndParent = IntGetMessageWindow();
2390 }
2391 */
2392
2393 if(!(Parent = IntGetWindowObject(hwndParent)))
2394 {
2395 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2396 return NULL;
2397 }
2398
2399 ChildAfter = NULL;
2400 if(hwndChildAfter && !(ChildAfter = IntGetWindowObject(hwndChildAfter)))
2401 {
2402 IntReleaseWindowObject(hwndParent);
2403 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2404 return NULL;
2405 }
2406
2407 /* copy the window name */
2408 Status = IntSafeCopyUnicodeString(&WindowName, ucWindowName);
2409 if(!NT_SUCCESS(Status))
2410 {
2411 SetLastNtError(Status);
2412 goto Cleanup3;
2413 }
2414
2415 /* safely copy the class name */
2416 Status = MmCopyFromCaller(&ClassName, ucClassName, sizeof(UNICODE_STRING));
2417 if(!NT_SUCCESS(Status))
2418 {
2419 SetLastNtError(Status);
2420 goto Cleanup2;
2421 }
2422 if(ClassName.Length > 0 && ClassName.Buffer)
2423 {
2424 WCHAR *buf;
2425 /* safely copy the class name string (NULL terminated because class-lookup
2426 depends on it... */
2427 buf = ExAllocatePoolWithTag(PagedPool, ClassName.Length + sizeof(WCHAR), TAG_STRING);
2428 if(!buf)
2429 {
2430 SetLastWin32Error(STATUS_INSUFFICIENT_RESOURCES);
2431 goto Cleanup2;
2432 }
2433 Status = MmCopyFromCaller(buf, ClassName.Buffer, ClassName.Length);
2434 if(!NT_SUCCESS(Status))
2435 {
2436 ExFreePool(buf);
2437 SetLastNtError(Status);
2438 goto Cleanup2;
2439 }
2440 ClassName.Buffer = buf;
2441 /* make sure the string is null-terminated */
2442 buf += ClassName.Length / sizeof(WCHAR);
2443 *buf = L'\0';
2444 }
2445
2446 /* find the class object */
2447 if(ClassName.Buffer)
2448 {
2449 /* this expects the string in ClassName to be NULL-terminated! */
2450 ClassFound = ClassReferenceClassByNameOrAtom(&ClassObject, ClassName.Buffer, NULL);
2451 if(!ClassFound)
2452 {
2453 if (IS_ATOM(ClassName.Buffer))
2454 DPRINT1("Window class not found (%lx)\n", (ULONG_PTR)ClassName.Buffer);
2455 else
2456 DPRINT1("Window class not found (%S)\n", ClassName.Buffer);
2457 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
2458 goto Cleanup;
2459 }
2460 }
2461
2462 if(Parent->Self == Desktop)
2463 {
2464 HWND *List, *phWnd;
2465 PWINDOW_OBJECT TopLevelWindow;
2466 BOOL CheckWindowName;
2467
2468 /* windows searches through all top-level windows if the parent is the desktop
2469 window */
2470
2471 if((List = IntWinListChildren(Parent)))
2472 {
2473 phWnd = List;
2474
2475 if(ChildAfter)
2476 {
2477 /* skip handles before and including ChildAfter */
2478 while(*phWnd && (*(phWnd++) != ChildAfter->Self));
2479 }
2480
2481 CheckWindowName = WindowName.Length > 0;
2482
2483 /* search children */
2484 while(*phWnd)
2485 {
2486 if(!(TopLevelWindow = IntGetWindowObject(*(phWnd++))))
2487 {
2488 continue;
2489 }
2490
2491 /* Do not send WM_GETTEXT messages in the kernel mode version!
2492 The user mode version however calls GetWindowText() which will
2493 send WM_GETTEXT messages to windows belonging to its processes */
2494 if(((!CheckWindowName || (CheckWindowName && !RtlCompareUnicodeString(&WindowName, &(TopLevelWindow->WindowName), FALSE))) &&
2495 (!ClassObject || (ClassObject && (TopLevelWindow->Class == ClassObject))))
2496 ||
2497 ((!CheckWindowName || (CheckWindowName && !RtlCompareUnicodeString(&WindowName, &(TopLevelWindow->WindowName), FALSE))) &&
2498 (!ClassObject || (ClassObject && (TopLevelWindow->Class == ClassObject)))))
2499 {
2500 Ret = TopLevelWindow->Self;
2501 IntReleaseWindowObject(TopLevelWindow);
2502 break;
2503 }
2504
2505 if(IntFindWindow(TopLevelWindow, NULL, ClassObject, &WindowName))
2506 {
2507 /* window returns the handle of the top-level window, in case it found
2508 the child window */
2509 Ret = TopLevelWindow->Self;
2510 IntReleaseWindowObject(TopLevelWindow);
2511 break;
2512 }
2513
2514 IntReleaseWindowObject(TopLevelWindow);
2515 }
2516 ExFreePool(List);
2517 }
2518 }
2519 else
2520 Ret = IntFindWindow(Parent, ChildAfter, ClassObject, &WindowName);
2521
2522 #if 0
2523 if(Ret == NULL && hwndParent == NULL && hwndChildAfter == NULL)
2524 {
2525 /* FIXME - if both hwndParent and hwndChildAfter are NULL, we also should
2526 search the message-only windows. Should this also be done if
2527 Parent is the desktop window??? */
2528 PWINDOW_OBJECT MsgWindows;
2529
2530 if((MsgWindows = IntGetWindowObject(IntGetMessageWindow())))
2531 {
2532 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassObject, &WindowName);
2533 IntReleaseWindowObject(MsgWindows);
2534 }
2535 }
2536 #endif
2537
2538 ClassDereferenceObject(ClassObject);
2539
2540 Cleanup:
2541 if(ClassName.Length > 0 && ClassName.Buffer)
2542 ExFreePool(ClassName.Buffer);
2543
2544 Cleanup2:
2545 RtlFreeUnicodeString(&WindowName);
2546
2547 Cleanup3:
2548 if(ChildAfter)
2549 IntReleaseWindowObject(ChildAfter);
2550 IntReleaseWindowObject(Parent);
2551
2552 return Ret;
2553 }
2554
2555
2556 /*
2557 * @unimplemented
2558 */
2559 DWORD STDCALL
2560 NtUserFlashWindowEx(DWORD Unknown0)
2561 {
2562 UNIMPLEMENTED
2563
2564 return 0;
2565 }
2566
2567
2568 /*
2569 * @implemented
2570 */
2571 HWND STDCALL
2572 NtUserGetAncestor(HWND hWnd, UINT Type)
2573 {
2574 PWINDOW_OBJECT Wnd, WndAncestor, Parent;
2575 HWND hWndAncestor;
2576
2577 if (hWnd == IntGetDesktopWindow())
2578 {
2579 return NULL;
2580 }
2581
2582 if (!(Wnd = IntGetWindowObject(hWnd)))
2583 {
2584 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2585 return NULL;
2586 }
2587
2588 switch (Type)
2589 {
2590 case GA_PARENT:
2591 {
2592 WndAncestor = IntGetParentObject(Wnd);
2593 break;
2594 }
2595
2596 case GA_ROOT:
2597 {
2598 PWINDOW_OBJECT tmp;
2599 WndAncestor = Wnd;
2600 Parent = NULL;
2601
2602 for(;;)
2603 {
2604 tmp = Parent;
2605 if(!(Parent = IntGetParentObject(WndAncestor)))
2606 {
2607 break;
2608 }
2609 if(IntIsDesktopWindow(Parent))
2610 {
2611 IntReleaseWindowObject(Parent);
2612 break;
2613 }
2614 if(tmp)
2615 IntReleaseWindowObject(tmp);
2616 WndAncestor = Parent;
2617 }
2618 break;
2619 }
2620
2621 case GA_ROOTOWNER:
2622 {
2623 WndAncestor = Wnd;
2624 IntReferenceWindowObject(WndAncestor);
2625 for (;;)
2626 {
2627 PWINDOW_OBJECT Old;
2628 Old = WndAncestor;
2629 Parent = IntGetParent(WndAncestor);
2630 IntReleaseWindowObject(Old);
2631 if (!Parent)
2632 {
2633 break;
2634 }
2635 WndAncestor = Parent;
2636 }
2637 break;
2638 }
2639
2640 default:
2641 {
2642 IntReleaseWindowObject(Wnd);
2643 return NULL;
2644 }
2645 }
2646
2647 hWndAncestor = (WndAncestor ? WndAncestor->Self : NULL);
2648 IntReleaseWindowObject(Wnd);
2649
2650 if(WndAncestor && (WndAncestor != Wnd))
2651 IntReleaseWindowObject(WndAncestor);
2652
2653 return hWndAncestor;
2654 }
2655
2656
2657 /*!
2658 * Returns client window rectangle relative to the upper-left corner of client area.
2659 *
2660 * \param hWnd window handle.
2661 * \param Rect pointer to the buffer where the coordinates are returned.
2662 *
2663 */
2664 /*
2665 * @implemented
2666 */
2667 BOOL STDCALL
2668 NtUserGetClientRect(HWND hWnd, LPRECT Rect)
2669 {
2670 PWINDOW_OBJECT WindowObject;
2671 RECT SafeRect;
2672
2673 if(!(WindowObject = IntGetWindowObject(hWnd)))
2674 {
2675 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2676 return FALSE;
2677 }
2678
2679 IntGetClientRect(WindowObject, &SafeRect);
2680 IntReleaseWindowObject(WindowObject);
2681
2682 if(!NT_SUCCESS(MmCopyToCaller(Rect, &SafeRect, sizeof(RECT))))
2683 {
2684 return FALSE;
2685 }
2686 return TRUE;
2687 }
2688
2689
2690 /*
2691 * @implemented
2692 */
2693 HWND STDCALL
2694 NtUserGetDesktopWindow()
2695 {
2696 return IntGetDesktopWindow();
2697 }
2698
2699
2700 /*
2701 * @unimplemented
2702 */
2703 DWORD STDCALL
2704 NtUserGetInternalWindowPos(DWORD Unknown0,
2705 DWORD Unknown1,
2706 DWORD Unknown2)
2707 {
2708 UNIMPLEMENTED
2709
2710 return 0;
2711 }
2712
2713
2714 /*
2715 * @unimplemented
2716 */
2717 HWND STDCALL
2718 NtUserGetLastActivePopup(HWND hWnd)
2719 {
2720 /*
2721 * This code can't work, because hWndLastPopup member of WINDOW_OBJECT is
2722 * not changed anywhere.
2723 * -- Filip, 01/nov/2003
2724 */
2725 #if 0
2726 PWINDOW_OBJECT Wnd;
2727 HWND hWndLastPopup;
2728
2729 IntAcquireWinLockShared();
2730
2731 if (!(Wnd = IntGetWindowObject(hWnd)))
2732 {
2733 IntReleaseWinLock();
2734 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2735 return NULL;
2736 }
2737
2738 hWndLastPopup = Wnd->hWndLastPopup;
2739
2740 IntReleaseWinLock();
2741
2742 return hWndLastPopup;
2743 #else
2744 return NULL;
2745 #endif
2746 }
2747
2748 /*
2749 * NtUserGetParent
2750 *
2751 * The NtUserGetParent function retrieves a handle to the specified window's
2752 * parent or owner.
2753 *
2754 * Remarks
2755 * Note that, despite its name, this function can return an owner window
2756 * instead of a parent window.
2757 *
2758 * Status
2759 * @implemented
2760 */
2761
2762 HWND STDCALL
2763 NtUserGetParent(HWND hWnd)
2764 {
2765 PWINDOW_OBJECT Wnd, WndParent;
2766 HWND hWndParent = NULL;
2767
2768 if (!(Wnd = IntGetWindowObject(hWnd)))
2769 {
2770 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2771 return NULL;
2772 }
2773
2774 WndParent = IntGetParent(Wnd);
2775 if (WndParent)
2776 {
2777 hWndParent = WndParent->Self;
2778 IntReleaseWindowObject(WndParent);
2779 }
2780
2781 IntReleaseWindowObject(Wnd);
2782
2783 return hWndParent;
2784 }
2785
2786 /*
2787 * NtUserSetParent
2788 *
2789 * The NtUserSetParent function changes the parent window of the specified
2790 * child window.
2791 *
2792 * Remarks
2793 * The new parent window and the child window must belong to the same
2794 * application. If the window identified by the hWndChild parameter is
2795 * visible, the system performs the appropriate redrawing and repainting.
2796 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
2797 * or WS_POPUP window styles of the window whose parent is being changed.
2798 *
2799 * Status
2800 * @implemented
2801 */
2802
2803 HWND STDCALL
2804 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
2805 {
2806 PWINDOW_OBJECT Wnd = NULL, WndParent = NULL, WndOldParent;
2807 HWND hWndOldParent = NULL;
2808
2809 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
2810 {
2811 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2812 return NULL;
2813 }
2814
2815 if (hWndChild == IntGetDesktopWindow())
2816 {
2817 SetLastWin32Error(ERROR_ACCESS_DENIED);
2818 return NULL;
2819 }
2820
2821 if (hWndNewParent)
2822 {
2823 if (!(WndParent = IntGetWindowObject(hWndNewParent)))
2824 {
2825 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2826 return NULL;
2827 }
2828 }
2829 else
2830 {
2831 if (!(WndParent = IntGetWindowObject(IntGetDesktopWindow())))
2832 {
2833 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2834 return NULL;
2835 }
2836 }
2837
2838 if (!(Wnd = IntGetWindowObject(hWndChild)))
2839 {
2840 IntReleaseWindowObject(WndParent);
2841 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2842 return NULL;
2843 }
2844
2845 WndOldParent = IntSetParent(Wnd, WndParent);
2846
2847 if (WndOldParent)
2848 {
2849 hWndOldParent = WndOldParent->Self;
2850 IntReleaseWindowObject(WndOldParent);
2851 }
2852
2853 IntReleaseWindowObject(Wnd);
2854 IntReleaseWindowObject(WndParent);
2855
2856 return hWndOldParent;
2857 }
2858
2859 /*
2860 * NtUserGetShellWindow
2861 *
2862 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
2863 *
2864 * Status
2865 * @implemented
2866 */
2867
2868 HWND STDCALL
2869 NtUserGetShellWindow()
2870 {
2871 PWINSTATION_OBJECT WinStaObject;
2872 HWND Ret;
2873
2874 NTSTATUS Status = IntValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
2875 KernelMode,
2876 0,
2877 &WinStaObject);
2878
2879 if (!NT_SUCCESS(Status))
2880 {
2881 SetLastNtError(Status);
2882 return (HWND)0;
2883 }
2884
2885 Ret = (HWND)WinStaObject->ShellWindow;
2886
2887 ObDereferenceObject(WinStaObject);
2888 return Ret;
2889 }
2890
2891 /*
2892 * NtUserSetShellWindowEx
2893 *
2894 * This is undocumented function to set global shell window. The global
2895 * shell window has special handling of window position.
2896 *
2897 * Status
2898 * @implemented
2899 */
2900
2901 BOOL STDCALL
2902 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
2903 {
2904 PWINSTATION_OBJECT WinStaObject;
2905
2906 NTSTATUS Status = IntValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
2907 KernelMode,
2908 0,
2909 &WinStaObject);
2910
2911 if (!NT_SUCCESS(Status))
2912 {
2913 SetLastNtError(Status);
2914 return FALSE;
2915 }
2916
2917 /*
2918 * Test if we are permitted to change the shell window.
2919 */
2920 if (WinStaObject->ShellWindow)
2921 {
2922 ObDereferenceObject(WinStaObject);
2923 return FALSE;
2924 }
2925
2926 /*
2927 * Move shell window into background.
2928 */
2929 if (hwndListView && hwndListView != hwndShell)
2930 {
2931 /*
2932 * Disabled for now to get Explorer working.
2933 * -- Filip, 01/nov/2003
2934 */
2935 #if 0
2936 WinPosSetWindowPos(hwndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
2937 #endif
2938
2939 if (NtUserGetWindowLong(hwndListView, GWL_EXSTYLE, FALSE) & WS_EX_TOPMOST)
2940 {
2941 ObDereferenceObject(WinStaObject);
2942 return FALSE;
2943 }
2944 }
2945
2946 if (NtUserGetWindowLong(hwndShell, GWL_EXSTYLE, FALSE) & WS_EX_TOPMOST)
2947 {
2948 ObDereferenceObject(WinStaObject);
2949 return FALSE;
2950 }
2951
2952 WinPosSetWindowPos(hwndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
2953
2954 WinStaObject->ShellWindow = hwndShell;
2955 WinStaObject->ShellListView = hwndListView;
2956
2957 ObDereferenceObject(WinStaObject);
2958 return TRUE;
2959 }
2960
2961 /*
2962 * NtUserGetSystemMenu
2963 *
2964 * The NtUserGetSystemMenu function allows the application to access the
2965 * window menu (also known as the system menu or the control menu) for
2966 * copying and modifying.
2967 *
2968 * Parameters
2969 * hWnd
2970 * Handle to the window that will own a copy of the window menu.
2971 * bRevert
2972 * Specifies the action to be taken. If this parameter is FALSE,
2973 * NtUserGetSystemMenu returns a handle to the copy of the window menu
2974 * currently in use. The copy is initially identical to the window menu
2975 * but it can be modified.
2976 * If this parameter is TRUE, GetSystemMenu resets the window menu back
2977 * to the default state. The previous window menu, if any, is destroyed.
2978 *
2979 * Return Value
2980 * If the bRevert parameter is FALSE, the return value is a handle to a
2981 * copy of the window menu. If the bRevert parameter is TRUE, the return
2982 * value is NULL.
2983 *
2984 * Status
2985 * @implemented
2986 */
2987
2988 HMENU STDCALL
2989 NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
2990 {
2991 HMENU Result = 0;
2992 PWINDOW_OBJECT WindowObject;
2993 PMENU_OBJECT MenuObject;
2994
2995 WindowObject = IntGetWindowObject((HWND)hWnd);
2996 if (WindowObject == NULL)
2997 {
2998 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2999 return 0;
3000 }
3001
3002 MenuObject = IntGetSystemMenu(WindowObject, bRevert, FALSE);
3003 if (MenuObject)
3004 {
3005 Result = MenuObject->MenuInfo.Self;
3006 IntReleaseMenuObject(MenuObject);
3007 }
3008
3009 IntReleaseWindowObject(WindowObject);
3010 return Result;
3011 }
3012
3013 /*
3014 * NtUserSetSystemMenu
3015 *
3016 * Status
3017 * @implemented
3018 */
3019
3020 BOOL STDCALL
3021 NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
3022 {
3023 BOOL Result = FALSE;
3024 PWINDOW_OBJECT WindowObject;
3025 PMENU_OBJECT MenuObject;
3026
3027 WindowObject = IntGetWindowObject(hWnd);
3028 if (!WindowObject)
3029 {
3030 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3031 return FALSE;
3032 }
3033
3034 if (hMenu)
3035 {
3036 /*
3037 * Assign new menu handle.
3038 */
3039 MenuObject = IntGetMenuObject(hMenu);
3040 if (!MenuObject)
3041 {
3042 IntReleaseWindowObject(WindowObject);
3043 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
3044 return FALSE;
3045 }
3046
3047 Result = IntSetSystemMenu(WindowObject, MenuObject);
3048
3049 IntReleaseMenuObject(MenuObject);
3050 }
3051
3052 IntReleaseWindowObject(WindowObject);
3053
3054 return Result;
3055 }
3056
3057 /*
3058 * NtUserGetWindow
3059 *
3060 * The NtUserGetWindow function retrieves a handle to a window that has the
3061 * specified relationship (Z order or owner) to the specified window.
3062 *
3063 * Status
3064 * @implemented
3065 */
3066
3067 HWND STDCALL
3068 NtUserGetWindow(HWND hWnd, UINT Relationship)
3069 {
3070 PWINDOW_OBJECT WindowObject, Parent;
3071 HWND hWndResult = NULL;
3072
3073 if (!(WindowObject = IntGetWindowObject(hWnd)))
3074 {
3075 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3076 return NULL;
3077 }
3078
3079 switch (Relationship)
3080 {
3081 case GW_HWNDFIRST:
3082 if((Parent = IntGetParentObject(WindowObject)))
3083 {
3084 IntLockRelatives(Parent);
3085 if (Parent->FirstChild)
3086 hWndResult = Parent->FirstChild->Self;
3087 IntUnLockRelatives(Parent);
3088 IntReleaseWindowObject(Parent);
3089 }
3090 break;
3091
3092 case GW_HWNDLAST:
3093 if((Parent = IntGetParentObject(WindowObject)))
3094 {
3095 IntLockRelatives(Parent);
3096 if (Parent->LastChild)
3097 hWndResult = Parent->LastChild->Self;
3098 IntUnLockRelatives(Parent);
3099 IntReleaseWindowObject(Parent);
3100 }
3101 break;
3102
3103 case GW_HWNDNEXT:
3104 IntLockRelatives(WindowObject);
3105 if (WindowObject->NextSibling)
3106 hWndResult = WindowObject->NextSibling->Self;
3107 IntUnLockRelatives(WindowObject);
3108 break;
3109
3110 case GW_HWNDPREV:
3111 IntLockRelatives(WindowObject);
3112 if (WindowObject->PrevSibling)
3113 hWndResult = WindowObject->PrevSibling->Self;
3114 IntUnLockRelatives(WindowObject);
3115 break;
3116
3117 case GW_OWNER:
3118 IntLockRelatives(WindowObject);
3119 if((Parent = IntGetWindowObject(WindowObject->Owner)))
3120 {
3121 hWndResult = Parent->Self;
3122 IntReleaseWindowObject(Parent);
3123 }
3124 IntUnLockRelatives(WindowObject);
3125 break;
3126 case GW_CHILD:
3127 IntLockRelatives(WindowObject);
3128 if (WindowObject->FirstChild)
3129 hWndResult = WindowObject->FirstChild->Self;
3130 IntUnLockRelatives(WindowObject);
3131 break;
3132 }
3133
3134 IntReleaseWindowObject(WindowObject);
3135
3136 return hWndResult;
3137 }
3138
3139 /*
3140 * NtUserGetWindowLong
3141 *
3142 * The NtUserGetWindowLong function retrieves information about the specified
3143 * window. The function also retrieves the 32-bit (long) value at the
3144 * specified offset into the extra window memory.
3145 *
3146 * Status
3147 * @implemented
3148 */
3149
3150 LONG STDCALL
3151 NtUserGetWindowLong(HWND hWnd, DWORD Index, BOOL Ansi)
3152 {
3153 PWINDOW_OBJECT WindowObject, Parent;
3154 LONG Result;
3155
3156 DPRINT("NtUserGetWindowLong(%x,%d,%d)\n", hWnd, (INT)Index, Ansi);
3157
3158 WindowObject = IntGetWindowObject(hWnd);
3159 if (WindowObject == NULL)
3160 {
3161 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3162 return 0;
3163 }
3164
3165 /*
3166 * Only allow CSRSS to mess with the desktop window
3167 */
3168 if (hWnd == IntGetDesktopWindow()
3169 && WindowObject->OwnerThread->ThreadsProcess != PsGetCurrentProcess())
3170 {
3171 SetLastWin32Error(STATUS_ACCESS_DENIED);
3172 return 0;
3173 }
3174
3175 if ((INT)Index >= 0)
3176 {
3177 if ((Index + sizeof(LONG)) > WindowObject->ExtraDataSize)
3178 {
3179 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3180 return 0;
3181 }
3182 Result = *((LONG *)(WindowObject->ExtraData + Index));
3183 }
3184 else
3185 {
3186 switch (Index)
3187 {
3188 case GWL_EXSTYLE:
3189 Result = WindowObject->ExStyle;
3190 break;
3191
3192 case GWL_STYLE:
3193 Result = WindowObject->Style;
3194 break;
3195
3196 case GWL_WNDPROC:
3197 if (Ansi)
3198 Result = (LONG) WindowObject->WndProcA;
3199 else
3200 Result = (LONG) WindowObject->WndProcW;
3201 break;
3202
3203 case GWL_HINSTANCE:
3204 Result = (LONG) WindowObject->Instance;
3205 break;
3206
3207 case GWL_HWNDPARENT:
3208 IntLockRelatives(WindowObject);
3209 Parent = IntGetWindowObject(WindowObject->Parent);
3210 IntUnLockRelatives(WindowObject);
3211 if(Parent)
3212 {
3213 if (Parent && Parent->Self == IntGetDesktopWindow())
3214 Result = (LONG) NtUserGetWindow(WindowObject->Self, GW_OWNER);
3215 else
3216 Result = (LONG) Parent->Self;
3217 IntReleaseWindowObject(Parent);
3218 }
3219 break;
3220
3221 case GWL_ID:
3222 Result = (LONG) WindowObject->IDMenu;
3223 break;
3224
3225 case GWL_USERDATA:
3226 Result = WindowObject->UserData;
3227 break;
3228
3229 default:
3230 DPRINT1("NtUserGetWindowLong(): Unsupported index %d\n", Index);
3231 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3232 Result = 0;
3233 break;
3234 }
3235 }
3236
3237 IntReleaseWindowObject(WindowObject);
3238
3239 return Result;
3240 }
3241
3242 /*
3243 * NtUserSetWindowLong
3244 *
3245 * The NtUserSetWindowLong function changes an attribute of the specified
3246 * window. The function also sets the 32-bit (long) value at the specified
3247 * offset into the extra window memory.
3248 *
3249 * Status
3250 * @implemented
3251 */
3252
3253 LONG STDCALL
3254 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3255 {
3256 PWINDOW_OBJECT WindowObject, Parent;
3257 PW32PROCESS Process;
3258 PWINSTATION_OBJECT WindowStation;
3259 LONG OldValue;
3260 STYLESTRUCT Style;
3261
3262 if (hWnd == IntGetDesktopWindow())
3263 {
3264 SetLastWin32Error(STATUS_ACCESS_DENIED);
3265 return 0;
3266 }
3267
3268 WindowObject = IntGetWindowObject(hWnd);
3269 if (WindowObject == NULL)
3270 {
3271 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3272 return 0;
3273 }
3274
3275 if ((INT)Index >= 0)
3276 {
3277 if ((Index + sizeof(LONG)) > WindowObject->ExtraDataSize)
3278 {
3279 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3280 IntReleaseWindowObject(WindowObject);
3281 return 0;
3282 }
3283 OldValue = *((LONG *)(WindowObject->ExtraData + Index));
3284 *((LONG *)(WindowObject->ExtraData + Index)) = NewValue;
3285 }
3286 else
3287 {
3288 switch (Index)
3289 {
3290 case GWL_EXSTYLE:
3291 OldValue = (LONG) WindowObject->ExStyle;
3292 Style.styleOld = OldValue;
3293 Style.styleNew = NewValue;
3294
3295 /*
3296 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3297 */
3298 Process = WindowObject->OwnerThread->ThreadsProcess->Win32Process;
3299 WindowStation = Process->WindowStation;
3300 if(WindowStation)
3301 {
3302 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3303 Style.styleNew &= ~WS_EX_TOPMOST;
3304 }
3305
3306 IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3307 WindowObject->ExStyle = (DWORD)Style.styleNew;
3308 IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3309 break;
3310
3311 case GWL_STYLE:
3312 OldValue = (LONG) WindowObject->Style;
3313 Style.styleOld = OldValue;
3314 Style.styleNew = NewValue;
3315 IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3316 WindowObject->Style = (DWORD)Style.styleNew;
3317 IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3318 break;
3319
3320 case GWL_WNDPROC:
3321 /* FIXME: should check if window belongs to current process */
3322 if (Ansi)
3323 {
3324 OldValue = (LONG) WindowObject->WndProcA;
3325 WindowObject->WndProcA = (WNDPROC) NewValue;
3326 WindowObject->WndProcW = (WNDPROC) IntAddWndProcHandle((WNDPROC)NewValue,FALSE);
3327 WindowObject->Unicode = FALSE;
3328 }
3329 else
3330 {
3331 OldValue = (LONG) WindowObject->WndProcW;
3332 WindowObject->WndProcW = (WNDPROC) NewValue;
3333 WindowObject->WndProcA = (WNDPROC) IntAddWndProcHandle((WNDPROC)NewValue,TRUE);
3334 WindowObject->Unicode = TRUE;
3335 }
3336 break;
3337
3338 case GWL_HINSTANCE:
3339 OldValue = (LONG) WindowObject->Instance;
3340 WindowObject->Instance = (HINSTANCE) NewValue;
3341 break;
3342
3343 case GWL_HWNDPARENT:
3344 Parent = IntGetParentObject(WindowObject);
3345 if (Parent && (Parent->Self == IntGetDesktopWindow()))
3346 OldValue = (LONG) IntSetOwner(WindowObject->Self, (HWND) NewValue);
3347 else
3348 OldValue = (LONG) NtUserSetParent(WindowObject->Self, (HWND) NewValue);
3349 if(Parent)
3350 IntReleaseWindowObject(Parent);
3351 break;
3352
3353 case GWL_ID:
3354 OldValue = (LONG) WindowObject->IDMenu;
3355 WindowObject->IDMenu = (UINT) NewValue;
3356 break;
3357
3358 case GWL_USERDATA:
3359 OldValue = WindowObject->UserData;
3360 WindowObject->UserData = NewValue;
3361 break;
3362
3363 default:
3364 DPRINT1("NtUserSetWindowLong(): Unsupported index %d\n", Index);
3365 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3366 OldValue = 0;
3367 break;
3368 }
3369 }
3370
3371 IntReleaseWindowObject(WindowObject);
3372
3373 return OldValue;
3374 }
3375
3376 /*
3377 * NtUserSetWindowWord
3378 *
3379 * Legacy function similar to NtUserSetWindowLong.
3380 *
3381 * Status
3382 * @implemented
3383 */
3384
3385 WORD STDCALL
3386 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
3387 {
3388 PWINDOW_OBJECT WindowObject;
3389 WORD OldValue;
3390
3391 switch (Index)
3392 {
3393 case GWL_ID:
3394 case GWL_HINSTANCE:
3395 case GWL_HWNDPARENT:
3396 return NtUserSetWindowLong(hWnd, Index, (UINT)NewValue, TRUE);
3397 default:
3398 if (Index < 0)
3399 {
3400 SetLastWin32Error(ERROR_INVALID_INDEX);
3401 return 0;
3402 }
3403 }
3404
3405 WindowObject = IntGetWindowObject(hWnd);
3406 if (WindowObject == NULL)
3407 {
3408 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3409 return 0;
3410 }
3411
3412 if (Index > WindowObject->ExtraDataSize - sizeof(WORD))
3413 {
3414 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3415 IntReleaseWindowObject(WindowObject);
3416 return 0;
3417 }
3418
3419 OldValue = *((WORD *)(WindowObject->ExtraData + Index));
3420 *((WORD *)(WindowObject->ExtraData + Index)) = NewValue;
3421
3422 IntReleaseWindowObject(WindowObject);
3423
3424 return OldValue;
3425 }
3426
3427 /*
3428 * @implemented
3429 */
3430 BOOL STDCALL
3431 NtUserGetWindowPlacement(HWND hWnd,
3432 WINDOWPLACEMENT *lpwndpl)
3433 {
3434 PWINDOW_OBJECT WindowObject;
3435 PINTERNALPOS InternalPos;
3436 POINT Size;
3437 WINDOWPLACEMENT Safepl;
3438 NTSTATUS Status;
3439
3440 WindowObject = IntGetWindowObject(hWnd);
3441 if (WindowObject == NULL)
3442 {
3443 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3444 return FALSE;
3445 }
3446
3447 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3448 if(!NT_SUCCESS(Status))
3449 {
3450 SetLastNtError(Status);
3451 IntReleaseWindowObject(WindowObject);
3452 return FALSE;
3453 }
3454 if(Safepl.length != sizeof(WINDOWPLACEMENT))
3455 {
3456 IntReleaseWindowObject(WindowObject);
3457 return FALSE;
3458 }
3459
3460 Safepl.flags = 0;
3461 Safepl.showCmd = ((WindowObject->Flags & WINDOWOBJECT_RESTOREMAX) ? SW_MAXIMIZE : SW_SHOWNORMAL);
3462
3463 Size.x = WindowObject->WindowRect.left;
3464 Size.y = WindowObject->WindowRect.top;
3465 InternalPos = WinPosInitInternalPos(WindowObject, &Size,
3466 &WindowObject->WindowRect);
3467 if (InternalPos)
3468 {
3469 Safepl.rcNormalPosition = InternalPos->NormalRect;
3470 Safepl.ptMinPosition = InternalPos->IconPos;
3471 Safepl.ptMaxPosition = InternalPos->MaxPos;
3472 }
3473 else
3474 {
3475 IntReleaseWindowObject(WindowObject);
3476 return FALSE;
3477 }
3478
3479 Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
3480 if(!NT_SUCCESS(Status))
3481 {
3482 SetLastNtError(Status);
3483 IntReleaseWindowObject(WindowObject);
3484 return FALSE;
3485 }
3486
3487 IntReleaseWindowObject(WindowObject);
3488 return TRUE;
3489 }
3490
3491
3492 /*!
3493 * Return the dimension of the window in the screen coordinates.
3494 * \param hWnd window handle.
3495 * \param Rect pointer to the buffer where the coordinates are returned.
3496 */
3497 /*
3498 * @implemented
3499 */
3500 BOOL STDCALL
3501 NtUserGetWindowRect(HWND hWnd, LPRECT Rect)
3502 {
3503 PWINDOW_OBJECT Wnd;
3504 NTSTATUS Status;
3505
3506 if (!(Wnd = IntGetWindowObject(hWnd)))
3507 {
3508 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3509 return FALSE;
3510 }
3511 Status = MmCopyToCaller(Rect, &Wnd->WindowRect, sizeof(RECT));
3512 if (!NT_SUCCESS(Status))
3513 {
3514 IntReleaseWindowObject(Wnd);
3515 SetLastNtError(Status);
3516 return FALSE;
3517 }
3518
3519 IntReleaseWindowObject(Wnd);
3520 return TRUE;
3521 }
3522
3523
3524 /*
3525 * @implemented
3526 */
3527 DWORD STDCALL
3528 NtUserGetWindowThreadProcessId(HWND hWnd, LPDWORD UnsafePid)
3529 {
3530 PWINDOW_OBJECT Wnd;
3531 DWORD tid, pid;
3532
3533 if (!(Wnd = IntGetWindowObject(hWnd)))
3534 {
3535 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3536 return 0;
3537 }
3538
3539 tid = (DWORD)IntGetWndThreadId(Wnd);
3540 pid = (DWORD)IntGetWndProcessId(Wnd);
3541
3542 if (UnsafePid) MmCopyToCaller(UnsafePid, &pid, sizeof(DWORD));
3543
3544 return tid;
3545 }
3546
3547
3548 /*
3549 * @unimplemented
3550 */
3551 DWORD STDCALL
3552 NtUserLockWindowUpdate(DWORD Unknown0)
3553 {
3554 UNIMPLEMENTED
3555
3556 return 0;
3557 }
3558
3559
3560 /*
3561 * @implemented
3562 */
3563 BOOL STDCALL
3564 NtUserMoveWindow(
3565 HWND hWnd,
3566 int X,
3567 int Y,
3568 int nWidth,
3569 int nHeight,
3570 BOOL bRepaint)
3571 {
3572 return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight,
3573 (bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE :
3574 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW));
3575 }
3576
3577 /*
3578 QueryWindow based on KJK::Hyperion and James Tabor.
3579
3580 0 = QWUniqueProcessId
3581 1 = QWUniqueThreadId
3582 4 = QWIsHung Implements IsHungAppWindow found
3583 by KJK::Hyperion.
3584
3585 9 = QWKillWindow When I called this with hWnd ==
3586 DesktopWindow, it shutdown the system
3587 and rebooted.
3588 */
3589 /*
3590 * @implemented
3591 */
3592 DWORD STDCALL
3593 NtUserQueryWindow(HWND hWnd, DWORD Index)
3594 {
3595 PWINDOW_OBJECT Window = IntGetWindowObject(hWnd);
3596 DWORD Result;
3597
3598 if (Window == NULL)
3599 {
3600 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3601 return 0;
3602 }
3603
3604 switch(Index)
3605 {
3606 case QUERY_WINDOW_UNIQUE_PROCESS_ID:
3607 Result = (DWORD)IntGetWndProcessId(Window);
3608 break;
3609
3610 case QUERY_WINDOW_UNIQUE_THREAD_ID:
3611 Result = (DWORD)IntGetWndThreadId(Window);
3612 break;
3613
3614 case QUERY_WINDOW_ISHUNG:
3615 Result = (DWORD)MsqIsHung(Window->MessageQueue);
3616 break;
3617
3618 default:
3619 Result = (DWORD)NULL;
3620 break;
3621 }
3622
3623 IntReleaseWindowObject(Window);
3624
3625 return Result;
3626 }
3627
3628
3629 /*
3630 * @unimplemented
3631 */
3632 DWORD STDCALL
3633 NtUserRealChildWindowFromPoint(DWORD Unknown0,
3634 DWORD Unknown1,
3635 DWORD Unknown2)
3636 {
3637 UNIMPLEMENTED
3638
3639 return 0;
3640 }
3641
3642
3643 /*
3644 * @implemented
3645 */
3646 UINT STDCALL
3647 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
3648 {
3649 UNICODE_STRING SafeMessageName;
3650 NTSTATUS Status;
3651 UINT Ret;
3652
3653 if(MessageNameUnsafe == NULL)
3654 {
3655 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3656 return 0;
3657 }
3658
3659 Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
3660 if(!NT_SUCCESS(Status))
3661 {
3662 SetLastNtError(Status);
3663 return 0;
3664 }
3665
3666 Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
3667
3668 RtlFreeUnicodeString(&SafeMessageName);
3669 return Ret;
3670 }
3671
3672
3673 /*
3674 * @unimplemented
3675 */
3676 DWORD STDCALL
3677 NtUserSetImeOwnerWindow(DWORD Unknown0,
3678 DWORD Unknown1)
3679 {
3680 UNIMPLEMENTED
3681
3682 return 0;
3683 }
3684
3685
3686 /*
3687 * @unimplemented
3688 */
3689 DWORD STDCALL
3690 NtUserSetInternalWindowPos(DWORD Unknown0,
3691 DWORD Unknown1,
3692 DWORD Unknown2,
3693 DWORD Unknown3)
3694 {
3695 UNIMPLEMENTED
3696
3697 return 0;
3698
3699 }
3700
3701
3702 /*
3703 * @unimplemented
3704 */
3705 DWORD STDCALL
3706 NtUserSetLayeredWindowAttributes(DWORD Unknown0,
3707 DWORD Unknown1,
3708 DWORD Unknown2,
3709 DWORD Unknown3)
3710 {
3711 UNIMPLEMENTED
3712
3713 return 0;
3714 }
3715
3716
3717 /*
3718 * @unimplemented
3719 */
3720 DWORD STDCALL
3721 NtUserSetLogonNotifyWindow(DWORD Unknown0)
3722 {
3723 UNIMPLEMENTED
3724
3725 return 0;
3726 }
3727
3728
3729 /*
3730 * @implemented
3731 */
3732 BOOL STDCALL
3733 NtUserSetMenu(
3734 HWND Wnd,
3735 HMENU Menu,
3736 BOOL Repaint)
3737 {
3738 PWINDOW_OBJECT WindowObject;
3739 BOOL Changed;
3740
3741 WindowObject = IntGetWindowObject((HWND) Wnd);
3742 if (NULL == WindowObject)
3743 {
3744 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3745 return FALSE;
3746 }
3747
3748 if (! IntSetMenu(WindowObject, Menu, &Changed))
3749 {
3750 IntReleaseWindowObject(WindowObject);
3751 return FALSE;
3752 }
3753
3754 IntReleaseWindowObject(WindowObject);
3755
3756 if (Changed && Repaint)
3757 {
3758 WinPosSetWindowPos(Wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3759 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
3760 }
3761
3762 return TRUE;
3763 }
3764
3765
3766 /*
3767 * @unimplemented
3768 */
3769 DWORD STDCALL
3770 NtUserSetWindowFNID(DWORD Unknown0,
3771 DWORD Unknown1)
3772 {
3773 UNIMPLEMENTED
3774
3775 return 0;
3776 }
3777
3778
3779
3780 /*
3781 * @implemented
3782 */
3783 BOOL STDCALL
3784 NtUserSetWindowPlacement(HWND hWnd,
3785 WINDOWPLACEMENT *lpwndpl)
3786 {
3787 PWINDOW_OBJECT WindowObject;
3788 WINDOWPLACEMENT Safepl;
3789 NTSTATUS Status;
3790
3791 WindowObject = IntGetWindowObject(hWnd);
3792 if (WindowObject == NULL)
3793 {
3794 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3795 return FALSE;
3796 }
3797 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
3798 if(!NT_SUCCESS(Status))
3799 {
3800 SetLastNtError(Status);
3801 IntReleaseWindowObject(WindowObject);
3802 return FALSE;
3803 }
3804 if(Safepl.length != sizeof(WINDOWPLACEMENT))
3805 {
3806 IntReleaseWindowObject(WindowObject);
3807 return FALSE;
3808 }
3809
3810 if ((WindowObject->Style & (WS_MAXIMIZE | WS_MINIMIZE)) == 0)
3811 {
3812 WinPosSetWindowPos(WindowObject->Self, NULL,
3813 Safepl.rcNormalPosition.left, Safepl.rcNormalPosition.top,
3814 Safepl.rcNormalPosition.right - Safepl.rcNormalPosition.left,
3815 Safepl.rcNormalPosition.bottom - Safepl.rcNormalPosition.top,
3816 SWP_NOZORDER | SWP_NOACTIVATE);
3817 }
3818
3819 /* FIXME - change window status */
3820 WinPosShowWindow(WindowObject->Self, Safepl.showCmd);
3821
3822 if (WindowObject->InternalPos == NULL)
3823 WindowObject->InternalPos = ExAllocatePoolWithTag(PagedPool, sizeof(INTERNALPOS), TAG_WININTLIST);
3824 WindowObject->InternalPos->NormalRect = Safepl.rcNormalPosition;
3825 WindowObject->InternalPos->IconPos = Safepl.ptMinPosition;
3826 WindowObject->InternalPos->MaxPos = Safepl.ptMaxPosition;
3827
3828 IntReleaseWindowObject(WindowObject);
3829 return TRUE;
3830 }
3831
3832
3833 /*
3834 * @implemented
3835 */
3836 BOOL STDCALL
3837 NtUserSetWindowPos(
3838 HWND hWnd,
3839 HWND hWndInsertAfter,
3840 int X,
3841 int Y,
3842 int cx,
3843 int cy,
3844 UINT uFlags)
3845 {
3846 return WinPosSetWindowPos(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags);
3847 }
3848
3849
3850 INT FASTCALL
3851 IntGetWindowRgn(HWND hWnd, HRGN hRgn)
3852 {
3853 INT Ret;
3854 PWINDOW_OBJECT WindowObject;
3855 HRGN VisRgn;
3856 ROSRGNDATA *pRgn;
3857
3858 if(!(WindowObject = IntGetWindowObject(hWnd)))
3859 {
3860 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3861 return ERROR;
3862 }
3863 if(!hRgn)
3864 {
3865 IntReleaseWindowObject(WindowObject);
3866 return ERROR;
3867 }
3868
3869 /* Create a new window region using the window rectangle */
3870 VisRgn = UnsafeIntCreateRectRgnIndirect(&WindowObject->WindowRect);
3871 NtGdiOffsetRgn(VisRgn, -WindowObject->WindowRect.left, -WindowObject->WindowRect.top);
3872 /* if there's a region assigned to the window, combine them both */
3873 if(WindowObject->WindowRegion && !(WindowObject->Style & WS_MINIMIZE))
3874 NtGdiCombineRgn(VisRgn, VisRgn, WindowObject->WindowRegion, RGN_AND);
3875 /* Copy the region into hRgn */
3876 NtGdiCombineRgn(hRgn, VisRgn, NULL, RGN_COPY);
3877
3878 if((pRgn = RGNDATA_LockRgn(hRgn)))
3879 {
3880 Ret = pRgn->rdh.iType;
3881 RGNDATA_UnlockRgn(hRgn);
3882 }
3883 else
3884 Ret = ERROR;
3885
3886 NtGdiDeleteObject(VisRgn);
3887
3888 IntReleaseWindowObject(WindowObject);
3889 return Ret;
3890 }
3891
3892 INT FASTCALL
3893 IntGetWindowRgnBox(HWND hWnd, RECT *Rect)
3894 {
3895 INT Ret;
3896 PWINDOW_OBJECT WindowObject;
3897 HRGN VisRgn;
3898 ROSRGNDATA *pRgn;
3899
3900 if(!(WindowObject = IntGetWindowObject(hWnd)))
3901 {
3902 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3903 return ERROR;
3904 }
3905 if(!Rect)
3906 {
3907 IntReleaseWindowObject(WindowObject);
3908 return ERROR;
3909 }
3910
3911 /* Create a new window region using the window rectangle */
3912 VisRgn = UnsafeIntCreateRectRgnIndirect(&WindowObject->WindowRect);
3913 NtGdiOffsetRgn(VisRgn, -WindowObject->WindowRect.left, -WindowObject->WindowRect.top);
3914 /* if there's a region assigned to the window, combine them both */
3915 if(WindowObject->WindowRegion && !(WindowObject->Style & WS_MINIMIZE))
3916 NtGdiCombineRgn(VisRgn, VisRgn, WindowObject->WindowRegion, RGN_AND);
3917
3918 if((pRgn = RGNDATA_LockRgn(VisRgn)))
3919 {
3920 Ret = pRgn->rdh.iType;
3921 *Rect = pRgn->rdh.rcBound;
3922 RGNDATA_UnlockRgn(VisRgn);
3923 }
3924 else
3925 Ret = ERROR;
3926
3927 NtGdiDeleteObject(VisRgn);
3928
3929 IntReleaseWindowObject(WindowObject);
3930 return Ret;
3931 }
3932
3933
3934 /*
3935 * @implemented
3936 */
3937 INT STDCALL
3938 NtUserSetWindowRgn(
3939 HWND hWnd,
3940 HRGN hRgn,
3941 BOOL bRedraw)
3942 {
3943 PWINDOW_OBJECT WindowObject;
3944
3945 WindowObject = IntGetWindowObject(hWnd);
3946 if (WindowObject == NULL)
3947 {
3948 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3949 return 0;
3950 }
3951
3952 /* FIXME - Verify if hRgn is a valid handle!!!!
3953 Propably make this operation thread-safe, but maybe it's not necessary */
3954
3955 if(WindowObject->WindowRegion)
3956 {
3957 /* Delete no longer needed region handle */
3958 NtGdiDeleteObject(WindowObject->WindowRegion);
3959 }
3960 WindowObject->WindowRegion = hRgn;
3961
3962 /* FIXME - send WM_WINDOWPOSCHANGING and WM_WINDOWPOSCHANGED messages to the window */
3963
3964 if(bRedraw)
3965 {
3966 IntRedrawWindow(WindowObject, NULL, NULL, RDW_INVALIDATE);
3967 }
3968
3969 IntReleaseWindowObject(WindowObject);
3970 return (INT)hRgn;
3971 }
3972
3973
3974 /*
3975 * @implemented
3976 */
3977 BOOL STDCALL
3978 NtUserShowWindow(HWND hWnd,
3979 LONG nCmdShow)
3980 {
3981 return WinPosShowWindow(hWnd, nCmdShow);
3982 }
3983
3984
3985 /*
3986 * @unimplemented
3987 */
3988 DWORD STDCALL
3989 NtUserShowWindowAsync(DWORD Unknown0,
3990 DWORD Unknown1)
3991 {
3992 UNIMPLEMENTED
3993
3994 return 0;
3995 }
3996
3997
3998 /*
3999 * @unimplemented
4000 */
4001 DWORD STDCALL
4002 NtUserUpdateLayeredWindow(DWORD Unknown0,
4003 DWORD Unknown1,
4004 DWORD Unknown2,
4005 DWORD Unknown3,
4006 DWORD Unknown4,
4007 DWORD Unknown5,
4008 DWORD Unknown6,
4009 DWORD Unknown7,
4010 DWORD Unknown8)
4011 {
4012 UNIMPLEMENTED
4013
4014 return 0;
4015 }
4016
4017
4018 /*
4019 * @implemented
4020 */
4021 VOID STDCALL
4022 NtUserValidateRect(HWND hWnd, const RECT* Rect)
4023 {
4024 return (VOID)NtUserRedrawWindow(hWnd, Rect, 0, RDW_VALIDATE | RDW_NOCHILDREN);
4025 }
4026
4027
4028 /*
4029 * @implemented
4030 */
4031 HWND STDCALL
4032 NtUserWindowFromPoint(LONG X, LONG Y)
4033 {
4034 POINT pt;
4035 HWND Ret;
4036 PWINDOW_OBJECT DesktopWindow, Window = NULL;
4037
4038 if ((DesktopWindow = IntGetWindowObject(IntGetDesktopWindow())))
4039 {
4040 USHORT Hit;
4041
4042 pt.x = X;
4043 pt.y = Y;
4044
4045 Hit = WinPosWindowFromPoint(DesktopWindow, PsGetWin32Thread()->MessageQueue, &pt, &Window);
4046
4047 if(Window)
4048 {
4049 Ret = Window->Self;
4050 IntReleaseWindowObject(Window);
4051 IntReleaseWindowObject(DesktopWindow);
4052 return Ret;
4053 }
4054
4055 IntReleaseWindowObject(DesktopWindow);
4056 }
4057
4058 return NULL;
4059 }
4060
4061
4062 /*
4063 * NtUserDefSetText
4064 *
4065 * Undocumented function that is called from DefWindowProc to set
4066 * window text.
4067 *
4068 * Status
4069 * @implemented
4070 */
4071
4072 BOOL STDCALL
4073 NtUserDefSetText(HWND WindowHandle, PUNICODE_STRING WindowText)
4074 {
4075 PWINDOW_OBJECT WindowObject;
4076 UNICODE_STRING SafeText;
4077 NTSTATUS Status;
4078
4079 WindowObject = IntGetWindowObject(WindowHandle);
4080 if(!WindowObject)
4081 {
4082 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
4083 return FALSE;
4084 }
4085
4086 if(WindowText)
4087 {
4088 Status = IntSafeCopyUnicodeString(&SafeText, WindowText);
4089 if(!NT_SUCCESS(Status))
4090 {
4091 SetLastNtError(Status);
4092 IntReleaseWindowObject(WindowObject);
4093 return FALSE;
4094 }
4095 }
4096 else
4097 {
4098 RtlInitUnicodeString(&SafeText, NULL);
4099 }
4100
4101 /* FIXME - do this thread-safe! otherwise one could crash here! */
4102 RtlFreeUnicodeString(&WindowObject->WindowName);
4103
4104 WindowObject->WindowName = SafeText;
4105
4106 IntReleaseWindowObject(WindowObject);
4107 return TRUE;
4108 }
4109
4110 /*
4111 * NtUserInternalGetWindowText
4112 *
4113 * Status
4114 * @implemented
4115 */
4116
4117 INT STDCALL
4118 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount)
4119 {
4120 PWINDOW_OBJECT WindowObject;
4121 NTSTATUS Status;
4122 INT Result;
4123
4124 if(lpString && (nMaxCount <= 1))
4125 {
4126 SetLastWin32Error(ERROR_INVALID_PARAMETER);
4127 return 0;
4128 }
4129
4130 WindowObject = IntGetWindowObject(hWnd);
4131 if(!WindowObject)
4132 {
4133 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
4134 return 0;
4135 }
4136
4137 /* FIXME - do this thread-safe! otherwise one could crash here! */
4138 Result = WindowObject->WindowName.Length / sizeof(WCHAR);
4139 if(lpString)
4140 {
4141 const WCHAR Terminator = L'\0';
4142 INT Copy;
4143 WCHAR *Buffer = (WCHAR*)lpString;
4144
4145 Copy = min(nMaxCount - 1, Result);
4146 if(Copy > 0)
4147 {
4148 Status = MmCopyToCaller(Buffer, WindowObject->WindowName.Buffer, Copy * sizeof(WCHAR));
4149 if(!NT_SUCCESS(Status))
4150 {
4151 SetLastNtError(Status);
4152 IntReleaseWindowObject(WindowObject);
4153 return 0;
4154 }
4155 Buffer += Copy;
4156 }
4157
4158 Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
4159 if(!NT_SUCCESS(Status))
4160 {
4161 SetLastNtError(Status);
4162 IntReleaseWindowObject(WindowObject);
4163 return 0;
4164 }
4165
4166 Result = Copy;
4167 }
4168
4169 IntReleaseWindowObject(WindowObject);
4170 return Result;
4171 }
4172
4173 DWORD STDCALL
4174 NtUserDereferenceWndProcHandle(WNDPROC wpHandle, WndProcHandle *Data)
4175 {
4176 WndProcHandle Entry;
4177 if (((DWORD)wpHandle & 0xFFFF0000) == 0xFFFF0000)
4178 {
4179 Entry = WndProcHandlesArray[(DWORD)wpHandle & 0x0000FFFF];
4180 Data->WindowProc = Entry.WindowProc;
4181 Data->IsUnicode = Entry.IsUnicode;
4182 Data->ProcessID = Entry.ProcessID;
4183 return TRUE;
4184 } else {
4185 return FALSE;
4186 }
4187 return FALSE;
4188 }
4189
4190 DWORD
4191 IntAddWndProcHandle(WNDPROC WindowProc, BOOL IsUnicode)
4192 {
4193 WORD i;
4194 WORD FreeSpot;
4195 BOOL found;
4196 WndProcHandle *OldArray;
4197 WORD OldArraySize;
4198 found = FALSE;
4199 for (i = 0;i < WndProcHandlesArraySize;i++)
4200 {
4201 if (WndProcHandlesArray[i].WindowProc == NULL)
4202 {
4203 FreeSpot = i;
4204 found = TRUE;
4205 }
4206 }
4207 if (!found)
4208 {
4209 OldArray = WndProcHandlesArray;
4210 OldArraySize = WndProcHandlesArraySize;
4211 WndProcHandlesArray = ExAllocatePoolWithTag(PagedPool,(OldArraySize + WPH_SIZE) * sizeof(WndProcHandle), TAG_WINPROCLST);
4212 WndProcHandlesArraySize = OldArraySize + WPH_SIZE;
4213 RtlCopyMemory(WndProcHandlesArray,OldArray,OldArraySize * sizeof(WndProcHandle));
4214 ExFreePool(OldArray);
4215 FreeSpot = OldArraySize + 1;
4216 }
4217 WndProcHandlesArray[FreeSpot].WindowProc = WindowProc;
4218 WndProcHandlesArray[FreeSpot].IsUnicode = IsUnicode;
4219 WndProcHandlesArray[FreeSpot].ProcessID = PsGetCurrentProcessId();
4220 return FreeSpot + 0xFFFF0000;
4221 }
4222
4223 DWORD
4224 IntRemoveWndProcHandle(WNDPROC Handle)
4225 {
4226 WORD position;
4227 position = (DWORD)Handle & 0x0000FFFF;
4228 if (position > WndProcHandlesArraySize)
4229 {
4230 return FALSE;
4231 }
4232 WndProcHandlesArray[position].WindowProc = NULL;
4233 WndProcHandlesArray[position].IsUnicode = FALSE;
4234 WndProcHandlesArray[position].ProcessID = NULL;
4235 return TRUE;
4236 }
4237
4238 DWORD
4239 IntRemoveProcessWndProcHandles(HANDLE ProcessID)
4240 {
4241 WORD i;
4242 for (i = 0;i < WndProcHandlesArraySize;i++)
4243 {
4244 if (WndProcHandlesArray[i].ProcessID == ProcessID)
4245 {
4246 WndProcHandlesArray[i].WindowProc = NULL;
4247 WndProcHandlesArray[i].IsUnicode = FALSE;
4248 WndProcHandlesArray[i].ProcessID = NULL;
4249 }
4250 }
4251 return TRUE;
4252 }
4253
4254 /* EOF */