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