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