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