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