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