scrollbar:
[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 UserGetWindowObject(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, 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 = UserGetWindowObject(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 //faxme:temp hack
1977 UserReferenceWindowObjectCo(Window);
1978 /* Initialize and show the window's scrollbars */
1979 if (Window->Style & WS_VSCROLL)
1980 {
1981 co_UserShowScrollBar(Window, SB_VERT, TRUE);
1982 }
1983 if (Window->Style & WS_HSCROLL)
1984 {
1985 co_UserShowScrollBar(Window, SB_HORZ, TRUE);
1986 }
1987 UserDereferenceWindowObjectCo(Window);
1988
1989 if (dwStyle & WS_VISIBLE)
1990 {
1991 DPRINT("IntCreateWindow(): About to show window\n");
1992 co_WinPosShowWindow(Window->hSelf, dwShowMode);
1993 }
1994
1995 DPRINT("IntCreateWindow(): = %X\n", Handle);
1996 DPRINT("WindowObject->SystemMenu = 0x%x\n", Window->SystemMenu);
1997 return((HWND)Handle);
1998 }
1999
2000 HWND STDCALL
2001 NtUserCreateWindowEx(DWORD dwExStyle,
2002 PUNICODE_STRING UnsafeClassName,
2003 PUNICODE_STRING UnsafeWindowName,
2004 DWORD dwStyle,
2005 LONG x,
2006 LONG y,
2007 LONG nWidth,
2008 LONG nHeight,
2009 HWND hWndParent,
2010 HMENU hMenu,
2011 HINSTANCE hInstance,
2012 LPVOID lpParam,
2013 DWORD dwShowMode,
2014 BOOL bUnicodeWindow)
2015 {
2016 NTSTATUS Status;
2017 UNICODE_STRING WindowName;
2018 UNICODE_STRING ClassName;
2019 HWND NewWindow;
2020 DECLARE_RETURN(HWND);
2021
2022 DPRINT("Enter NtUserCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, nWidth, nHeight);
2023 UserEnterExclusive();
2024
2025 /* Get the class name (string or atom) */
2026 Status = MmCopyFromCaller(&ClassName, UnsafeClassName, sizeof(UNICODE_STRING));
2027 if (! NT_SUCCESS(Status))
2028 {
2029 SetLastNtError(Status);
2030 RETURN( NULL);
2031 }
2032 if (! IS_ATOM(ClassName.Buffer))
2033 {
2034 Status = IntSafeCopyUnicodeStringTerminateNULL(&ClassName, UnsafeClassName);
2035 if (! NT_SUCCESS(Status))
2036 {
2037 SetLastNtError(Status);
2038 RETURN( NULL);
2039 }
2040 }
2041
2042 /* safely copy the window name */
2043 if (NULL != UnsafeWindowName)
2044 {
2045 Status = IntSafeCopyUnicodeString(&WindowName, UnsafeWindowName);
2046 if (! NT_SUCCESS(Status))
2047 {
2048 if (! IS_ATOM(ClassName.Buffer))
2049 {
2050 RtlFreeUnicodeString(&ClassName);
2051 }
2052 SetLastNtError(Status);
2053 RETURN( NULL);
2054 }
2055 }
2056 else
2057 {
2058 RtlInitUnicodeString(&WindowName, NULL);
2059 }
2060
2061 NewWindow = co_IntCreateWindowEx(dwExStyle, &ClassName, &WindowName, dwStyle, x, y, nWidth, nHeight,
2062 hWndParent, hMenu, hInstance, lpParam, dwShowMode, bUnicodeWindow);
2063
2064 RtlFreeUnicodeString(&WindowName);
2065 if (! IS_ATOM(ClassName.Buffer))
2066 {
2067 RtlFreeUnicodeString(&ClassName);
2068 }
2069
2070 RETURN( NewWindow);
2071
2072 CLEANUP:
2073 DPRINT("Leave NtUserCreateWindowEx, ret=%i\n",_ret_);
2074 UserLeave();
2075 END_CLEANUP;
2076 }
2077
2078 /*
2079 * @unimplemented
2080 */
2081 HDWP STDCALL
2082 NtUserDeferWindowPos(HDWP WinPosInfo,
2083 HWND Wnd,
2084 HWND WndInsertAfter,
2085 int x,
2086 int y,
2087 int cx,
2088 int cy,
2089 UINT Flags)
2090 {
2091 UNIMPLEMENTED
2092
2093 return 0;
2094 }
2095
2096
2097 BOOLEAN FASTCALL co_UserDestroyWindow(PWINDOW_OBJECT Window)
2098 {
2099 BOOLEAN isChild;
2100
2101 if (Window == NULL)
2102 {
2103 return FALSE;
2104 }
2105
2106 /* Check for owner thread and desktop window */
2107 if ((Window->OwnerThread != PsGetCurrentThread()) || IntIsDesktopWindow(Window))
2108 {
2109 SetLastWin32Error(ERROR_ACCESS_DENIED);
2110 return FALSE;
2111 }
2112
2113 /* Look whether the focus is within the tree of windows we will
2114 * be destroying.
2115 */
2116 if (!co_WinPosShowWindow(Window->hSelf, SW_HIDE))
2117 {
2118 if (UserGetActiveWindow() == Window->hSelf)
2119 {
2120 co_WinPosActivateOtherWindow(Window);
2121 }
2122 }
2123
2124 if (Window->MessageQueue->ActiveWindow == Window->hSelf)
2125 Window->MessageQueue->ActiveWindow = NULL;
2126 if (Window->MessageQueue->FocusWindow == Window->hSelf)
2127 Window->MessageQueue->FocusWindow = NULL;
2128 if (Window->MessageQueue->CaptureWindow == Window->hSelf)
2129 Window->MessageQueue->CaptureWindow = NULL;
2130
2131 IntDereferenceMessageQueue(Window->MessageQueue);
2132 /* Call hooks */
2133 #if 0 /* FIXME */
2134 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hwnd, 0, TRUE))
2135 {
2136 return FALSE;
2137 }
2138 #endif
2139
2140 IntEngWindowChanged(Window, WOC_DELETE);
2141 isChild = (0 != (Window->Style & WS_CHILD));
2142
2143 #if 0 /* FIXME */
2144 if (isChild)
2145 {
2146 if (! USER_IsExitingThread(GetCurrentThreadId()))
2147 {
2148 send_parent_notify(hwnd, WM_DESTROY);
2149 }
2150 }
2151 else if (NULL != GetWindow(Wnd, GW_OWNER))
2152 {
2153 co_HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
2154 /* FIXME: clean up palette - see "Internals" p.352 */
2155 }
2156 #endif
2157
2158 if (!IntIsWindow(Window->hSelf))
2159 {
2160 return TRUE;
2161 }
2162
2163 /* Recursively destroy owned windows */
2164 if (! isChild)
2165 {
2166 for (;;)
2167 {
2168 BOOL GotOne = FALSE;
2169 HWND *Children;
2170 HWND *ChildHandle;
2171 PWINDOW_OBJECT Child, Desktop;
2172
2173 Desktop = IntGetWindowObject(IntGetDesktopWindow());
2174 Children = IntWinListChildren(Desktop);
2175 IntReleaseWindowObject(Desktop);
2176 if (Children)
2177 {
2178 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2179 {
2180 Child = IntGetWindowObject(*ChildHandle);
2181 if (Child == NULL)
2182 continue;
2183 if (Child->hOwner != Window->hSelf)
2184 {
2185 IntReleaseWindowObject(Child);
2186 continue;
2187 }
2188
2189 if (IntWndBelongsToThread(Child, PsGetWin32Thread()))
2190 {
2191 co_UserDestroyWindow(Child);
2192 IntReleaseWindowObject(Child);
2193 GotOne = TRUE;
2194 continue;
2195 }
2196
2197 if (Child->hOwner != NULL)
2198 {
2199 Child->hOwner = NULL;
2200 }
2201
2202 IntReleaseWindowObject(Child);
2203 }
2204 ExFreePool(Children);
2205 }
2206 if (! GotOne)
2207 {
2208 break;
2209 }
2210 }
2211 }
2212
2213 if (!IntIsWindow(Window->hSelf))
2214 {
2215 return TRUE;
2216 }
2217
2218 /* Destroy the window storage */
2219 co_IntDestroyWindow(Window, PsGetWin32Process(), PsGetWin32Thread(), TRUE);
2220
2221 return TRUE;
2222 }
2223
2224
2225
2226
2227 /*
2228 * @implemented
2229 */
2230 BOOLEAN STDCALL
2231 NtUserDestroyWindow(HWND Wnd)
2232 {
2233 PWINDOW_OBJECT Window;
2234 DECLARE_RETURN(BOOLEAN);
2235
2236 DPRINT("Enter NtUserDestroyWindow\n");
2237 UserEnterExclusive();
2238
2239 Window = IntGetWindowObject(Wnd);
2240 if (Window == NULL)
2241 {
2242 RETURN(FALSE);
2243 }
2244
2245 RETURN(co_UserDestroyWindow(Window));
2246
2247 CLEANUP:
2248 DPRINT("Leave NtUserDestroyWindow, ret=%i\n",_ret_);
2249 UserLeave();
2250 END_CLEANUP;
2251 }
2252
2253
2254
2255 /*
2256 * @unimplemented
2257 */
2258 DWORD
2259 STDCALL
2260 NtUserDrawMenuBarTemp(
2261 HWND hWnd,
2262 HDC hDC,
2263 PRECT hRect,
2264 HMENU hMenu,
2265 HFONT hFont)
2266 {
2267 /* we'll use this function just for caching the menu bar */
2268 UNIMPLEMENTED
2269 return 0;
2270 }
2271
2272
2273 /*
2274 * @unimplemented
2275 */
2276 DWORD STDCALL
2277 NtUserEndDeferWindowPosEx(DWORD Unknown0,
2278 DWORD Unknown1)
2279 {
2280 UNIMPLEMENTED
2281
2282 return 0;
2283 }
2284
2285
2286 /*
2287 * @unimplemented
2288 */
2289 DWORD STDCALL
2290 NtUserFillWindow(DWORD Unknown0,
2291 DWORD Unknown1,
2292 DWORD Unknown2,
2293 DWORD Unknown3)
2294 {
2295 UNIMPLEMENTED
2296
2297 return 0;
2298 }
2299
2300
2301 HWND FASTCALL
2302 IntFindWindow(PWINDOW_OBJECT Parent,
2303 PWINDOW_OBJECT ChildAfter,
2304 RTL_ATOM ClassAtom,
2305 PUNICODE_STRING WindowName)
2306 {
2307 BOOL CheckWindowName;
2308 HWND *List, *phWnd;
2309 HWND Ret = NULL;
2310
2311 ASSERT(Parent);
2312
2313 CheckWindowName = (WindowName && (WindowName->Length > 0));
2314
2315 if((List = IntWinListChildren(Parent)))
2316 {
2317 phWnd = List;
2318 if(ChildAfter)
2319 {
2320 /* skip handles before and including ChildAfter */
2321 while(*phWnd && (*(phWnd++) != ChildAfter->hSelf));
2322 }
2323
2324 /* search children */
2325 while(*phWnd)
2326 {
2327 PWINDOW_OBJECT Child;
2328 if(!(Child = IntGetWindowObject(*(phWnd++))))
2329 {
2330 continue;
2331 }
2332
2333 /* Do not send WM_GETTEXT messages in the kernel mode version!
2334 The user mode version however calls GetWindowText() which will
2335 send WM_GETTEXT messages to windows belonging to its processes */
2336 if((!CheckWindowName || !RtlCompareUnicodeString(WindowName, &(Child->WindowName), FALSE)) &&
2337 (!ClassAtom || Child->Class->Atom == ClassAtom))
2338 {
2339 Ret = Child->hSelf;
2340 IntReleaseWindowObject(Child);
2341 break;
2342 }
2343
2344 IntReleaseWindowObject(Child);
2345 }
2346 ExFreePool(List);
2347 }
2348
2349 return Ret;
2350 }
2351
2352 /*
2353 * FUNCTION:
2354 * Searches a window's children for a window with the specified
2355 * class and name
2356 * ARGUMENTS:
2357 * hwndParent = The window whose childs are to be searched.
2358 * NULL = desktop
2359 * HWND_MESSAGE = message-only windows
2360 *
2361 * hwndChildAfter = Search starts after this child window.
2362 * NULL = start from beginning
2363 *
2364 * ucClassName = Class name to search for
2365 * Reguired parameter.
2366 *
2367 * ucWindowName = Window name
2368 * ->Buffer == NULL = don't care
2369 *
2370 * RETURNS:
2371 * The HWND of the window if it was found, otherwise NULL
2372 */
2373 /*
2374 * @implemented
2375 */
2376 HWND STDCALL
2377 NtUserFindWindowEx(HWND hwndParent,
2378 HWND hwndChildAfter,
2379 PUNICODE_STRING ucClassName,
2380 PUNICODE_STRING ucWindowName)
2381 {
2382 PWINDOW_OBJECT Parent, ChildAfter;
2383 UNICODE_STRING ClassName, WindowName;
2384 NTSTATUS Status;
2385 HWND Desktop, Ret = NULL;
2386 RTL_ATOM ClassAtom;
2387 DECLARE_RETURN(HWND);
2388
2389 DPRINT("Enter NtUserFindWindowEx\n");
2390 UserEnterShared();
2391
2392 Desktop = IntGetCurrentThreadDesktopWindow();
2393
2394 if(hwndParent == NULL)
2395 hwndParent = Desktop;
2396 /* FIXME
2397 else if(hwndParent == HWND_MESSAGE)
2398 {
2399 hwndParent = IntGetMessageWindow();
2400 }
2401 */
2402
2403 if(!(Parent = IntGetWindowObject(hwndParent)))
2404 {
2405 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2406 RETURN( NULL);
2407 }
2408
2409 ChildAfter = NULL;
2410 if(hwndChildAfter && !(ChildAfter = IntGetWindowObject(hwndChildAfter)))
2411 {
2412 IntReleaseWindowObject(Parent);
2413 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2414 RETURN( NULL);
2415 }
2416
2417 /* copy the window name */
2418 Status = IntSafeCopyUnicodeString(&WindowName, ucWindowName);
2419 if(!NT_SUCCESS(Status))
2420 {
2421 SetLastNtError(Status);
2422 goto Cleanup3;
2423 }
2424
2425 /* safely copy the class name */
2426 Status = MmCopyFromCaller(&ClassName, ucClassName, sizeof(UNICODE_STRING));
2427 if(!NT_SUCCESS(Status))
2428 {
2429 SetLastNtError(Status);
2430 goto Cleanup2;
2431 }
2432 if(ClassName.Length > 0 && ClassName.Buffer)
2433 {
2434 WCHAR *buf;
2435 /* safely copy the class name string (NULL terminated because class-lookup
2436 depends on it... */
2437 buf = ExAllocatePoolWithTag(PagedPool, ClassName.Length + sizeof(WCHAR), TAG_STRING);
2438 if(!buf)
2439 {
2440 SetLastWin32Error(STATUS_INSUFFICIENT_RESOURCES);
2441 goto Cleanup2;
2442 }
2443 Status = MmCopyFromCaller(buf, ClassName.Buffer, ClassName.Length);
2444 if(!NT_SUCCESS(Status))
2445 {
2446 ExFreePool(buf);
2447 SetLastNtError(Status);
2448 goto Cleanup2;
2449 }
2450 ClassName.Buffer = buf;
2451 /* make sure the string is null-terminated */
2452 buf += ClassName.Length / sizeof(WCHAR);
2453 *buf = L'\0';
2454 }
2455
2456 /* find the class object */
2457 if(ClassName.Buffer)
2458 {
2459 PWINSTATION_OBJECT WinStaObject;
2460
2461 if (PsGetWin32Thread()->Desktop == NULL)
2462 {
2463 SetLastWin32Error(ERROR_INVALID_HANDLE);
2464 goto Cleanup;
2465 }
2466
2467 WinStaObject = PsGetWin32Thread()->Desktop->WindowStation;
2468
2469 Status = RtlLookupAtomInAtomTable(
2470 WinStaObject->AtomTable,
2471 ClassName.Buffer,
2472 &ClassAtom);
2473
2474 if (!NT_SUCCESS(Status))
2475 {
2476 DPRINT1("Failed to lookup class atom!\n");
2477 SetLastWin32Error(ERROR_CLASS_DOES_NOT_EXIST);
2478 goto Cleanup;
2479 }
2480 }
2481
2482 if(Parent->hSelf == Desktop)
2483 {
2484 HWND *List, *phWnd;
2485 PWINDOW_OBJECT TopLevelWindow;
2486 BOOLEAN CheckWindowName;
2487 BOOLEAN CheckClassName;
2488 BOOLEAN WindowMatches;
2489 BOOLEAN ClassMatches;
2490
2491 /* windows searches through all top-level windows if the parent is the desktop
2492 window */
2493
2494 if((List = IntWinListChildren(Parent)))
2495 {
2496 phWnd = List;
2497
2498 if(ChildAfter)
2499 {
2500 /* skip handles before and including ChildAfter */
2501 while(*phWnd && (*(phWnd++) != ChildAfter->hSelf));
2502 }
2503
2504 CheckWindowName = WindowName.Length > 0;
2505 CheckClassName = ClassName.Buffer != NULL;
2506
2507 /* search children */
2508 while(*phWnd)
2509 {
2510 if(!(TopLevelWindow = IntGetWindowObject(*(phWnd++))))
2511 {
2512 continue;
2513 }
2514
2515 /* Do not send WM_GETTEXT messages in the kernel mode version!
2516 The user mode version however calls GetWindowText() which will
2517 send WM_GETTEXT messages to windows belonging to its processes */
2518 WindowMatches = !CheckWindowName || !RtlCompareUnicodeString(
2519 &WindowName, &TopLevelWindow->WindowName, FALSE);
2520 ClassMatches = !CheckClassName ||
2521 ClassAtom == TopLevelWindow->Class->Atom;
2522
2523 if (WindowMatches && ClassMatches)
2524 {
2525 Ret = TopLevelWindow->hSelf;
2526 IntReleaseWindowObject(TopLevelWindow);
2527 break;
2528 }
2529
2530 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
2531 {
2532 /* window returns the handle of the top-level window, in case it found
2533 the child window */
2534 Ret = TopLevelWindow->hSelf;
2535 IntReleaseWindowObject(TopLevelWindow);
2536 break;
2537 }
2538
2539 IntReleaseWindowObject(TopLevelWindow);
2540 }
2541 ExFreePool(List);
2542 }
2543 }
2544 else
2545 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
2546
2547 #if 0
2548 if(Ret == NULL && hwndParent == NULL && hwndChildAfter == NULL)
2549 {
2550 /* FIXME - if both hwndParent and hwndChildAfter are NULL, we also should
2551 search the message-only windows. Should this also be done if
2552 Parent is the desktop window??? */
2553 PWINDOW_OBJECT MsgWindows;
2554
2555 if((MsgWindows = IntGetWindowObject(IntGetMessageWindow())))
2556 {
2557 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
2558 IntReleaseWindowObject(MsgWindows);
2559 }
2560 }
2561 #endif
2562
2563 Cleanup:
2564 if(ClassName.Length > 0 && ClassName.Buffer)
2565 ExFreePool(ClassName.Buffer);
2566
2567 Cleanup2:
2568 RtlFreeUnicodeString(&WindowName);
2569
2570 Cleanup3:
2571 if(ChildAfter)
2572 IntReleaseWindowObject(ChildAfter);
2573 IntReleaseWindowObject(Parent);
2574
2575 RETURN( Ret);
2576
2577 CLEANUP:
2578 DPRINT("Leave NtUserFindWindowEx, ret %i\n",_ret_);
2579 UserLeave();
2580 END_CLEANUP;
2581 }
2582
2583
2584 /*
2585 * @unimplemented
2586 */
2587 DWORD STDCALL
2588 NtUserFlashWindowEx(DWORD Unknown0)
2589 {
2590 UNIMPLEMENTED
2591
2592 return 0;
2593 }
2594
2595
2596 /*
2597 * @implemented
2598 */
2599 HWND FASTCALL UserGetAncestor(HWND hWnd, UINT Type)
2600 {
2601 PWINDOW_OBJECT Wnd, WndAncestor, Parent;
2602 HWND hWndAncestor;
2603
2604 if (hWnd == IntGetDesktopWindow())
2605 {
2606 return NULL;
2607 }
2608
2609 if (!(Wnd = IntGetWindowObject(hWnd)))
2610 {
2611 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2612 return NULL;
2613 }
2614
2615 switch (Type)
2616 {
2617 case GA_PARENT:
2618 {
2619 WndAncestor = IntGetParentObject(Wnd);
2620 break;
2621 }
2622
2623 case GA_ROOT:
2624 {
2625 PWINDOW_OBJECT tmp;
2626 WndAncestor = Wnd;
2627 Parent = NULL;
2628
2629 for(;;)
2630 {
2631 tmp = Parent;
2632 if(!(Parent = IntGetParentObject(WndAncestor)))
2633 {
2634 break;
2635 }
2636 if(IntIsDesktopWindow(Parent))
2637 {
2638 IntReleaseWindowObject(Parent);
2639 break;
2640 }
2641 if(tmp)
2642 IntReleaseWindowObject(tmp);
2643 WndAncestor = Parent;
2644 }
2645 break;
2646 }
2647
2648 case GA_ROOTOWNER:
2649 {
2650 WndAncestor = Wnd;
2651 IntReferenceWindowObject(WndAncestor);
2652 for (;;)
2653 {
2654 PWINDOW_OBJECT Old;
2655 Old = WndAncestor;
2656 Parent = IntGetParent(WndAncestor);
2657 IntReleaseWindowObject(Old);
2658 if (!Parent)
2659 {
2660 break;
2661 }
2662 WndAncestor = Parent;
2663 }
2664 break;
2665 }
2666
2667 default:
2668 {
2669 IntReleaseWindowObject(Wnd);
2670 return NULL;
2671 }
2672 }
2673
2674 hWndAncestor = (WndAncestor ? WndAncestor->hSelf : NULL);
2675 IntReleaseWindowObject(Wnd);
2676
2677 if(WndAncestor && (WndAncestor != Wnd))
2678 IntReleaseWindowObject(WndAncestor);
2679
2680 return hWndAncestor;
2681 }
2682
2683
2684
2685 /*
2686 * @implemented
2687 */
2688 HWND STDCALL
2689 NtUserGetAncestor(HWND hWnd, UINT Type)
2690 {
2691 DECLARE_RETURN(HWND);
2692
2693 DPRINT("Enter NtUserGetAncestor\n");
2694 UserEnterExclusive();
2695
2696 RETURN(UserGetAncestor(hWnd, Type));
2697
2698 CLEANUP:
2699 DPRINT("Leave NtUserGetAncestor, ret=%i\n",_ret_);
2700 UserLeave();
2701 END_CLEANUP;
2702 }
2703
2704 /*!
2705 * Returns client window rectangle relative to the upper-left corner of client area.
2706 *
2707 * \param hWnd window handle.
2708 * \param Rect pointer to the buffer where the coordinates are returned.
2709 *
2710 */
2711 /*
2712 * @implemented
2713 */
2714 BOOL STDCALL
2715 NtUserGetClientRect(HWND hWnd, LPRECT Rect)
2716 {
2717 PWINDOW_OBJECT Window;
2718 RECT SafeRect;
2719 DECLARE_RETURN(BOOL);
2720
2721 DPRINT("Enter NtUserGetClientRect\n");
2722 UserEnterShared();
2723
2724 if(!(Window = IntGetWindowObject(hWnd)))
2725 {
2726 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2727 RETURN( FALSE);
2728 }
2729
2730 IntGetClientRect(Window, &SafeRect);
2731 IntReleaseWindowObject(Window);
2732
2733 if(!NT_SUCCESS(MmCopyToCaller(Rect, &SafeRect, sizeof(RECT))))
2734 {
2735 RETURN( FALSE);
2736 }
2737 RETURN( TRUE);
2738
2739 CLEANUP:
2740 DPRINT("Leave NtUserGetClientRect, ret=%i\n",_ret_);
2741 UserLeave();
2742 END_CLEANUP;
2743 }
2744
2745
2746 /*
2747 * @implemented
2748 */
2749 HWND STDCALL
2750 NtUserGetDesktopWindow()
2751 {
2752 DECLARE_RETURN(HWND);
2753
2754 DPRINT("Enter NtUserGetDesktopWindow\n");
2755 UserEnterShared();
2756
2757 RETURN( IntGetDesktopWindow());
2758
2759 CLEANUP:
2760 DPRINT("Leave NtUserGetDesktopWindow, ret=%i\n",_ret_);
2761 UserLeave();
2762 END_CLEANUP;
2763 }
2764
2765
2766 /*
2767 * @unimplemented
2768 */
2769 DWORD STDCALL
2770 NtUserGetInternalWindowPos(DWORD Unknown0,
2771 DWORD Unknown1,
2772 DWORD Unknown2)
2773 {
2774 UNIMPLEMENTED
2775
2776 return 0;
2777 }
2778
2779
2780 /*
2781 * @unimplemented
2782 */
2783 HWND STDCALL
2784 NtUserGetLastActivePopup(HWND hWnd)
2785 {
2786 /*
2787 * This code can't work, because hWndLastPopup member of WINDOW_OBJECT is
2788 * not changed anywhere.
2789 * -- Filip, 01/nov/2003
2790 */
2791 #if 0
2792 PWINDOW_OBJECT Wnd;
2793 HWND hWndLastPopup;
2794
2795 IntAcquireWinLockShared();
2796
2797 if (!(Wnd = IntGetWindowObject(hWnd)))
2798 {
2799 IntReleaseWinLock();
2800 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2801 return NULL;
2802 }
2803
2804 hWndLastPopup = Wnd->hWndLastPopup;
2805
2806 IntReleaseWinLock();
2807
2808 return hWndLastPopup;
2809 #else
2810 return NULL;
2811 #endif
2812 }
2813
2814 /*
2815 * NtUserGetParent
2816 *
2817 * The NtUserGetParent function retrieves a handle to the specified window's
2818 * parent or owner.
2819 *
2820 * Remarks
2821 * Note that, despite its name, this function can return an owner window
2822 * instead of a parent window.
2823 *
2824 * Status
2825 * @implemented
2826 */
2827
2828 HWND STDCALL
2829 NtUserGetParent(HWND hWnd)
2830 {
2831 PWINDOW_OBJECT Wnd, WndParent;
2832 HWND hWndParent = NULL;
2833 DECLARE_RETURN(HWND);
2834
2835 DPRINT("Enter NtUserGetParent\n");
2836 UserEnterExclusive();
2837
2838 if (!(Wnd = IntGetWindowObject(hWnd)))
2839 {
2840 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2841 RETURN( NULL);
2842 }
2843
2844 WndParent = IntGetParent(Wnd);
2845 if (WndParent)
2846 {
2847 hWndParent = WndParent->hSelf;
2848 IntReleaseWindowObject(WndParent);
2849 }
2850
2851 IntReleaseWindowObject(Wnd);
2852
2853 RETURN( hWndParent);
2854
2855 CLEANUP:
2856 DPRINT("Leave NtUserGetParent, ret=%i\n",_ret_);
2857 UserLeave();
2858 END_CLEANUP;
2859 }
2860
2861
2862
2863
2864 HWND FASTCALL
2865 UserSetParent(HWND hWndChild, HWND hWndNewParent)
2866 {
2867 PWINDOW_OBJECT Wnd = NULL, WndParent = NULL, WndOldParent;
2868 HWND hWndOldParent = NULL;
2869
2870 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
2871 {
2872 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2873 return( NULL);
2874 }
2875
2876 if (hWndChild == IntGetDesktopWindow())
2877 {
2878 SetLastWin32Error(ERROR_ACCESS_DENIED);
2879 return( NULL);
2880 }
2881
2882 if (hWndNewParent)
2883 {
2884 if (!(WndParent = IntGetWindowObject(hWndNewParent)))
2885 {
2886 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2887 return( NULL);
2888 }
2889 }
2890 else
2891 {
2892 if (!(WndParent = IntGetWindowObject(IntGetDesktopWindow())))
2893 {
2894 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2895 return( NULL);
2896 }
2897 }
2898
2899 if (!(Wnd = IntGetWindowObject(hWndChild)))
2900 {
2901 IntReleaseWindowObject(WndParent);
2902 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
2903 return( NULL);
2904 }
2905
2906 WndOldParent = IntSetParent(Wnd, WndParent);
2907
2908 if (WndOldParent)
2909 {
2910 hWndOldParent = WndOldParent->hSelf;
2911 IntReleaseWindowObject(WndOldParent);
2912 }
2913
2914 IntReleaseWindowObject(Wnd);
2915 IntReleaseWindowObject(WndParent);
2916
2917 return( hWndOldParent);
2918 }
2919
2920
2921
2922 /*
2923 * NtUserSetParent
2924 *
2925 * The NtUserSetParent function changes the parent window of the specified
2926 * child window.
2927 *
2928 * Remarks
2929 * The new parent window and the child window must belong to the same
2930 * application. If the window identified by the hWndChild parameter is
2931 * visible, the system performs the appropriate redrawing and repainting.
2932 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
2933 * or WS_POPUP window styles of the window whose parent is being changed.
2934 *
2935 * Status
2936 * @implemented
2937 */
2938
2939 HWND STDCALL
2940 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
2941 {
2942 DECLARE_RETURN(HWND);
2943
2944 DPRINT("Enter NtUserSetParent\n");
2945 UserEnterExclusive();
2946
2947 RETURN( UserSetParent(hWndChild, hWndNewParent));
2948
2949 CLEANUP:
2950 DPRINT("Leave NtUserSetParent, ret=%i\n",_ret_);
2951 UserLeave();
2952 END_CLEANUP;
2953 }
2954
2955
2956
2957
2958 HWND FASTCALL UserGetShellWindow()
2959 {
2960 PWINSTATION_OBJECT WinStaObject;
2961 HWND Ret;
2962
2963 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
2964 KernelMode,
2965 0,
2966 &WinStaObject);
2967
2968 if (!NT_SUCCESS(Status))
2969 {
2970 SetLastNtError(Status);
2971 return( (HWND)0);
2972 }
2973
2974 Ret = (HWND)WinStaObject->ShellWindow;
2975
2976 ObDereferenceObject(WinStaObject);
2977 return( Ret);
2978 }
2979
2980
2981 /*
2982 * NtUserGetShellWindow
2983 *
2984 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
2985 *
2986 * Status
2987 * @implemented
2988 */
2989
2990 HWND STDCALL
2991 NtUserGetShellWindow()
2992 {
2993 DECLARE_RETURN(HWND);
2994
2995 DPRINT("Enter NtUserGetShellWindow\n");
2996 UserEnterShared();
2997
2998 RETURN( UserGetShellWindow() );
2999
3000 CLEANUP:
3001 DPRINT("Leave NtUserGetShellWindow, ret=%i\n",_ret_);
3002 UserLeave();
3003 END_CLEANUP;
3004 }
3005
3006 /*
3007 * NtUserSetShellWindowEx
3008 *
3009 * This is undocumented function to set global shell window. The global
3010 * shell window has special handling of window position.
3011 *
3012 * Status
3013 * @implemented
3014 */
3015
3016 BOOL STDCALL
3017 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3018 {
3019 PWINSTATION_OBJECT WinStaObject;
3020 DECLARE_RETURN(BOOL);
3021
3022 DPRINT("Enter NtUserSetShellWindowEx\n");
3023 UserEnterExclusive();
3024
3025 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3026 KernelMode,
3027 0,
3028 &WinStaObject);
3029
3030 if (!NT_SUCCESS(Status))
3031 {
3032 SetLastNtError(Status);
3033 RETURN( FALSE);
3034 }
3035
3036 /*
3037 * Test if we are permitted to change the shell window.
3038 */
3039 if (WinStaObject->ShellWindow)
3040 {
3041 ObDereferenceObject(WinStaObject);
3042 RETURN( FALSE);
3043 }
3044
3045 /*
3046 * Move shell window into background.
3047 */
3048 if (hwndListView && hwndListView != hwndShell)
3049 {
3050 /*
3051 * Disabled for now to get Explorer working.
3052 * -- Filip, 01/nov/2003
3053 */
3054 #if 0
3055 co_WinPosSetWindowPos(hwndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3056 #endif
3057
3058 if (UserGetWindowLong(hwndListView, GWL_EXSTYLE, FALSE) & WS_EX_TOPMOST)
3059 {
3060 ObDereferenceObject(WinStaObject);
3061 RETURN( FALSE);
3062 }
3063 }
3064
3065 if (UserGetWindowLong(hwndShell, GWL_EXSTYLE, FALSE) & WS_EX_TOPMOST)
3066 {
3067 ObDereferenceObject(WinStaObject);
3068 RETURN( FALSE);
3069 }
3070
3071 co_WinPosSetWindowPos(hwndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3072
3073 WinStaObject->ShellWindow = hwndShell;
3074 WinStaObject->ShellListView = hwndListView;
3075
3076 ObDereferenceObject(WinStaObject);
3077 RETURN( TRUE);
3078
3079 CLEANUP:
3080 DPRINT("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3081 UserLeave();
3082 END_CLEANUP;
3083 }
3084
3085 /*
3086 * NtUserGetSystemMenu
3087 *
3088 * The NtUserGetSystemMenu function allows the application to access the
3089 * window menu (also known as the system menu or the control menu) for
3090 * copying and modifying.
3091 *
3092 * Parameters
3093 * hWnd
3094 * Handle to the window that will own a copy of the window menu.
3095 * bRevert
3096 * Specifies the action to be taken. If this parameter is FALSE,
3097 * NtUserGetSystemMenu returns a handle to the copy of the window menu
3098 * currently in use. The copy is initially identical to the window menu
3099 * but it can be modified.
3100 * If this parameter is TRUE, GetSystemMenu resets the window menu back
3101 * to the default state. The previous window menu, if any, is destroyed.
3102 *
3103 * Return Value
3104 * If the bRevert parameter is FALSE, the return value is a handle to a
3105 * copy of the window menu. If the bRevert parameter is TRUE, the return
3106 * value is NULL.
3107 *
3108 * Status
3109 * @implemented
3110 */
3111
3112 HMENU STDCALL
3113 NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
3114 {
3115 PWINDOW_OBJECT Window;
3116 PMENU_OBJECT Menu;
3117 DECLARE_RETURN(HMENU);
3118
3119 DPRINT("Enter NtUserGetSystemMenu\n");
3120 UserEnterShared();
3121
3122 if (!(Window = UserGetWindowObject(hWnd)))
3123 {
3124 RETURN(NULL);
3125 }
3126
3127 if (!(Menu = IntGetSystemMenu(Window, bRevert, FALSE)))
3128 {
3129 RETURN(NULL);
3130 }
3131
3132 RETURN(Menu->MenuInfo.Self);
3133
3134 CLEANUP:
3135 DPRINT("Leave NtUserGetSystemMenu, ret=%i\n",_ret_);
3136 UserLeave();
3137 END_CLEANUP;
3138 }
3139
3140 /*
3141 * NtUserSetSystemMenu
3142 *
3143 * Status
3144 * @implemented
3145 */
3146
3147 BOOL STDCALL
3148 NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
3149 {
3150 BOOL Result = FALSE;
3151 PWINDOW_OBJECT Window;
3152 PMENU_OBJECT Menu;
3153 DECLARE_RETURN(BOOL);
3154
3155 DPRINT("Enter NtUserSetSystemMenu\n");
3156 UserEnterExclusive();
3157
3158 if (!(Window = IntGetWindowObject(hWnd)))
3159 {
3160 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3161 RETURN( FALSE);
3162 }
3163
3164 if (hMenu)
3165 {
3166 /*
3167 * Assign new menu handle.
3168 */
3169 Menu = IntGetMenuObject(hMenu);
3170 if (!Menu)
3171 {
3172 IntReleaseWindowObject(Window);
3173 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
3174 RETURN( FALSE);
3175 }
3176
3177 Result = IntSetSystemMenu(Window, Menu);
3178
3179 IntReleaseMenuObject(Menu);
3180 }
3181
3182 IntReleaseWindowObject(Window);
3183
3184 RETURN( Result);
3185
3186 CLEANUP:
3187 DPRINT("Leave NtUserSetSystemMenu, ret=%i\n",_ret_);
3188 UserLeave();
3189 END_CLEANUP;
3190 }
3191
3192
3193
3194
3195 HWND FASTCALL
3196 UserGetWindow(HWND hWnd, UINT Relationship)
3197 {
3198 PWINDOW_OBJECT Parent, Window;
3199 HWND hWndResult = NULL;
3200
3201 if (!(Window = UserGetWindowObject(hWnd))) return NULL;
3202
3203 switch (Relationship)
3204 {
3205 case GW_HWNDFIRST:
3206 if((Parent = Window->Parent))
3207 {
3208 if (Parent->FirstChild)
3209 hWndResult = Parent->FirstChild->hSelf;
3210 }
3211 break;
3212
3213 case GW_HWNDLAST:
3214 if((Parent = Window->Parent))
3215 {
3216 if (Parent->LastChild)
3217 hWndResult = Parent->LastChild->hSelf;
3218 }
3219 break;
3220
3221 case GW_HWNDNEXT:
3222 if (Window->NextSibling)
3223 hWndResult = Window->NextSibling->hSelf;
3224 break;
3225
3226 case GW_HWNDPREV:
3227 if (Window->PrevSibling)
3228 hWndResult = Window->PrevSibling->hSelf;
3229 break;
3230
3231 case GW_OWNER:
3232 if((Parent = IntGetWindowObject(Window->hOwner)))
3233 {
3234 hWndResult = Parent->hSelf;
3235 IntReleaseWindowObject(Parent);
3236 }
3237 break;
3238 case GW_CHILD:
3239 if (Window->FirstChild)
3240 hWndResult = Window->FirstChild->hSelf;
3241 break;
3242 }
3243
3244 return hWndResult;
3245 }
3246
3247
3248
3249 /*
3250 * NtUserGetWindow
3251 *
3252 * The NtUserGetWindow function retrieves a handle to a window that has the
3253 * specified relationship (Z order or owner) to the specified window.
3254 *
3255 * Status
3256 * @implemented
3257 */
3258
3259 HWND STDCALL
3260 NtUserGetWindow(HWND hWnd, UINT Relationship)
3261 {
3262 DECLARE_RETURN(HWND);
3263
3264 DPRINT("Enter NtUserGetWindow\n");
3265 UserEnterShared();
3266
3267 RETURN(UserGetWindow(hWnd, Relationship));
3268
3269 CLEANUP:
3270 DPRINT("Leave NtUserGetWindow, ret=%i\n",_ret_);
3271 UserLeave();
3272 END_CLEANUP;
3273 }
3274
3275
3276
3277
3278 /*
3279 * NtUserGetWindowLong
3280 *
3281 * The NtUserGetWindowLong function retrieves information about the specified
3282 * window. The function also retrieves the 32-bit (long) value at the
3283 * specified offset into the extra window memory.
3284 *
3285 * Status
3286 * @implemented
3287 */
3288
3289 LONG FASTCALL
3290 UserGetWindowLong(HWND hWnd, DWORD Index, BOOL Ansi)
3291 {
3292 PWINDOW_OBJECT Window, Parent;
3293 LONG Result = 0;
3294
3295 DPRINT("NtUserGetWindowLong(%x,%d,%d)\n", hWnd, (INT)Index, Ansi);
3296
3297 if (!(Window = IntGetWindowObject(hWnd)))
3298 {
3299 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
3300 return 0;
3301 }
3302
3303 /*
3304 * WndProc is only available to the owner process
3305 */
3306 if (GWL_WNDPROC == Index
3307 && Window->OwnerThread->ThreadsProcess != PsGetCurrentProcess())
3308 {
3309 SetLastWin32Error(ERROR_ACCESS_DENIED);
3310 return 0;
3311 }
3312
3313 if ((INT)Index >= 0)
3314 {
3315 if ((Index + sizeof(LONG)) > Window->ExtraDataSize)
3316 {
3317 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3318 return 0;
3319 }
3320 Result = *((LONG *)(Window->ExtraData + Index));
3321 }
3322 else
3323 {
3324 switch (Index)
3325 {
3326 case GWL_EXSTYLE:
3327 Result = Window->ExStyle;
3328 break;
3329
3330 case GWL_STYLE:
3331 Result = Window->Style;
3332 break;
3333
3334 case GWL_WNDPROC:
3335 if (Ansi)
3336 Result = (LONG) Window->WndProcA;
3337 else
3338 Result = (LONG) Window->WndProcW;
3339 break;
3340
3341 case GWL_HINSTANCE:
3342 Result = (LONG) Window->Instance;
3343 break;
3344
3345 case GWL_HWNDPARENT:
3346 Parent = Window->Parent;
3347 if(Parent)
3348 {
3349 if (Parent && Parent->hSelf == IntGetDesktopWindow())
3350 Result = (LONG) UserGetWindow(Window->hSelf, GW_OWNER);
3351 else
3352 Result = (LONG) Parent->hSelf;
3353 }
3354 break;
3355
3356 case GWL_ID:
3357 Result = (LONG) Window->IDMenu;
3358 break;
3359
3360 case GWL_USERDATA:
3361 Result = Window->UserData;
3362 break;
3363
3364 default:
3365 DPRINT1("NtUserGetWindowLong(): Unsupported index %d\n", Index);
3366 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3367 Result = 0;
3368 break;
3369 }
3370 }
3371
3372 IntReleaseWindowObject(Window);
3373
3374 return Result;
3375 }
3376
3377
3378
3379
3380 /*