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