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