Patch by johnyadams@hotmail.com: Some applications try to set a child as a parent...
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / window.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Windows
5 * FILE: subsystems/win32/win32k/ntuser/window.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISION HISTORY:
8 * 06-06-2001 CSH Created
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <w32k.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18
19 /* dialog resources appear to pass this in 16 bits, handle them properly */
20 #define CW_USEDEFAULT16 (0x8000)
21
22 #define POINT_IN_RECT(p, r) (((r.bottom >= p.y) && (r.top <= p.y))&&((r.left <= p.x )&&( r.right >= p.x )))
23
24 /* PRIVATE FUNCTIONS **********************************************************/
25
26 /*
27 * InitWindowImpl
28 *
29 * Initialize windowing implementation.
30 */
31
32 NTSTATUS FASTCALL
33 InitWindowImpl(VOID)
34 {
35 return STATUS_SUCCESS;
36 }
37
38 /*
39 * CleanupWindowImpl
40 *
41 * Cleanup windowing implementation.
42 */
43
44 NTSTATUS FASTCALL
45 CleanupWindowImpl(VOID)
46 {
47 return STATUS_SUCCESS;
48 }
49
50 /* HELPER FUNCTIONS ***********************************************************/
51
52 BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam)
53 {
54 WORD Action = LOWORD(wParam);
55 WORD Flags = HIWORD(wParam);
56
57 if (Flags & ~(UISF_HIDEFOCUS | UISF_HIDEACCEL | UISF_ACTIVE))
58 {
59 SetLastWin32Error(ERROR_INVALID_PARAMETER);
60 return FALSE;
61 }
62
63 switch (Action)
64 {
65 case UIS_INITIALIZE:
66 SetLastWin32Error(ERROR_INVALID_PARAMETER);
67 return FALSE;
68
69 case UIS_SET:
70 if (Flags & UISF_HIDEFOCUS)
71 Wnd->HideFocus = TRUE;
72 if (Flags & UISF_HIDEACCEL)
73 Wnd->HideAccel = TRUE;
74 break;
75
76 case UIS_CLEAR:
77 if (Flags & UISF_HIDEFOCUS)
78 Wnd->HideFocus = FALSE;
79 if (Flags & UISF_HIDEACCEL)
80 Wnd->HideAccel = FALSE;
81 break;
82 }
83
84 return TRUE;
85 }
86
87 PWINDOW_OBJECT FASTCALL IntGetWindowObject(HWND hWnd)
88 {
89 PWINDOW_OBJECT Window;
90
91 if (!hWnd) return NULL;
92
93 Window = UserGetWindowObject(hWnd);
94 if (Window)
95 {
96 ASSERT(USER_BODY_TO_HEADER(Window)->RefCount >= 0);
97
98 USER_BODY_TO_HEADER(Window)->RefCount++;
99 }
100 return Window;
101 }
102
103 /* temp hack */
104 PWINDOW_OBJECT FASTCALL UserGetWindowObject(HWND hWnd)
105 {
106 PTHREADINFO ti;
107 PWINDOW_OBJECT Window;
108
109 if (PsGetCurrentProcess() != PsInitialSystemProcess)
110 {
111 ti = GetW32ThreadInfo();
112 if (ti == NULL)
113 {
114 SetLastWin32Error(ERROR_ACCESS_DENIED);
115 return NULL;
116 }
117 }
118
119 if (!hWnd)
120 {
121 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
122 return NULL;
123 }
124
125 Window = (PWINDOW_OBJECT)UserGetObject(gHandleTable, hWnd, otWindow);
126 if (!Window || 0 != (Window->Status & WINDOWSTATUS_DESTROYED))
127 {
128 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
129 return NULL;
130 }
131
132 ASSERT(USER_BODY_TO_HEADER(Window)->RefCount >= 0);
133 return Window;
134 }
135
136
137 /*
138 * IntIsWindow
139 *
140 * The function determines whether the specified window handle identifies
141 * an existing window.
142 *
143 * Parameters
144 * hWnd
145 * Handle to the window to test.
146 *
147 * Return Value
148 * If the window handle identifies an existing window, the return value
149 * is TRUE. If the window handle does not identify an existing window,
150 * the return value is FALSE.
151 */
152
153 BOOL FASTCALL
154 IntIsWindow(HWND hWnd)
155 {
156 PWINDOW_OBJECT Window;
157
158 if (!(Window = UserGetWindowObject(hWnd)))
159 return FALSE;
160
161 return TRUE;
162 }
163
164
165
166 /*
167 Caller must NOT dereference retval!
168 But if caller want the returned value to persist spanning a co_ call,
169 it must reference the value (because the owner is not garanteed to
170 exist just because the owned window exist)!
171 */
172 PWINDOW_OBJECT FASTCALL
173 IntGetParent(PWINDOW_OBJECT Wnd)
174 {
175 if (!Wnd->Wnd) return NULL;
176
177 if (Wnd->Wnd->style & WS_POPUP)
178 {
179 return UserGetWindowObject(Wnd->hOwner);
180 }
181 else if (Wnd->Wnd->style & WS_CHILD)
182 {
183 return Wnd->Parent;
184 }
185
186 return NULL;
187 }
188
189
190 /*
191 Caller must NOT dereference retval!
192 But if caller want the returned value to persist spanning a co_ call,
193 it must reference the value (because the owner is not garanteed to
194 exist just because the owned window exist)!
195 */
196 PWINDOW_OBJECT FASTCALL
197 IntGetOwner(PWINDOW_OBJECT Wnd)
198 {
199 return UserGetWindowObject(Wnd->hOwner);
200 }
201
202
203
204 /*
205 * IntWinListChildren
206 *
207 * Compile a list of all child window handles from given window.
208 *
209 * Remarks
210 * This function is similar to Wine WIN_ListChildren. The caller
211 * must free the returned list with ExFreePool.
212 */
213
214 HWND* FASTCALL
215 IntWinListChildren(PWINDOW_OBJECT Window)
216 {
217 PWINDOW_OBJECT Child;
218 HWND *List;
219 UINT Index, NumChildren = 0;
220
221 if (!Window) return NULL;
222
223 for (Child = Window->FirstChild; Child; Child = Child->NextSibling)
224 ++NumChildren;
225
226 List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), TAG_WINLIST);
227 if(!List)
228 {
229 DPRINT1("Failed to allocate memory for children array\n");
230 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
231 return NULL;
232 }
233 for (Child = Window->FirstChild, Index = 0;
234 Child != NULL;
235 Child = Child->NextSibling, ++Index)
236 List[Index] = Child->hSelf;
237 List[Index] = NULL;
238
239 return List;
240 }
241
242 /***********************************************************************
243 * IntSendDestroyMsg
244 */
245 static void IntSendDestroyMsg(HWND hWnd)
246 {
247
248 PWINDOW_OBJECT Window;
249 #if 0 /* FIXME */
250
251 GUITHREADINFO info;
252
253 if (GetGUIThreadInfo(GetCurrentThreadId(), &info))
254 {
255 if (hWnd == info.hwndCaret)
256 {
257 DestroyCaret();
258 }
259 }
260 #endif
261
262 Window = UserGetWindowObject(hWnd);
263 if (Window)
264 {
265 // USER_REFERENCE_ENTRY Ref;
266 // UserRefObjectCo(Window, &Ref);
267
268 if (!IntGetOwner(Window) && !IntGetParent(Window))
269 {
270 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (LPARAM) hWnd);
271 }
272
273 // UserDerefObjectCo(Window);
274 }
275
276 /* The window could already be destroyed here */
277
278 /*
279 * Send the WM_DESTROY to the window.
280 */
281
282 co_IntSendMessage(hWnd, WM_DESTROY, 0, 0);
283
284 /*
285 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
286 * make sure that the window still exists when we come back.
287 */
288 #if 0 /* FIXME */
289
290 if (IsWindow(Wnd))
291 {
292 HWND* pWndArray;
293 int i;
294
295 if (!(pWndArray = WIN_ListChildren( hwnd )))
296 return;
297
298 /* start from the end (FIXME: is this needed?) */
299 for (i = 0; pWndArray[i]; i++)
300 ;
301
302 while (--i >= 0)
303 {
304 if (IsWindow( pWndArray[i] ))
305 WIN_SendDestroyMsg( pWndArray[i] );
306 }
307 HeapFree(GetProcessHeap(), 0, pWndArray);
308 }
309 else
310 {
311 DPRINT("destroyed itself while in WM_DESTROY!\n");
312 }
313 #endif
314 }
315
316 static VOID
317 UserFreeWindowInfo(PTHREADINFO ti, PWINDOW_OBJECT WindowObject)
318 {
319 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
320 PWND Wnd = WindowObject->Wnd;
321
322 if (!Wnd) return;
323
324 if (ClientInfo->CallbackWnd.pvWnd == DesktopHeapAddressToUser(WindowObject->Wnd))
325 {
326 ClientInfo->CallbackWnd.hWnd = NULL;
327 ClientInfo->CallbackWnd.pvWnd = NULL;
328 }
329
330 if (Wnd->strName.Buffer != NULL)
331 {
332 Wnd->strName.Length = 0;
333 Wnd->strName.MaximumLength = 0;
334 DesktopHeapFree(Wnd->head.rpdesk,
335 Wnd->strName.Buffer);
336 Wnd->strName.Buffer = NULL;
337 }
338
339 DesktopHeapFree(Wnd->head.rpdesk, Wnd);
340 WindowObject->Wnd = NULL;
341 }
342
343 /***********************************************************************
344 * IntDestroyWindow
345 *
346 * Destroy storage associated to a window. "Internals" p.358
347 *
348 * This is the "functional" DestroyWindows function ei. all stuff
349 * done in CreateWindow is undone here and not in DestroyWindow:-P
350
351 */
352 static LRESULT co_UserFreeWindow(PWINDOW_OBJECT Window,
353 PPROCESSINFO ProcessData,
354 PTHREADINFO ThreadData,
355 BOOLEAN SendMessages)
356 {
357 HWND *Children;
358 HWND *ChildHandle;
359 PWINDOW_OBJECT Child;
360 PMENU_OBJECT Menu;
361 BOOLEAN BelongsToThreadData;
362 PWND Wnd;
363
364 ASSERT(Window);
365
366 Wnd = Window->Wnd;
367
368 if(Window->Status & WINDOWSTATUS_DESTROYING)
369 {
370 DPRINT("Tried to call IntDestroyWindow() twice\n");
371 return 0;
372 }
373 Window->Status |= WINDOWSTATUS_DESTROYING;
374 Wnd->style &= ~WS_VISIBLE;
375
376 IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Wnd, OBJID_WINDOW, 0);
377
378 /* remove the window already at this point from the thread window list so we
379 don't get into trouble when destroying the thread windows while we're still
380 in IntDestroyWindow() */
381 RemoveEntryList(&Window->ThreadListEntry);
382
383 BelongsToThreadData = IntWndBelongsToThread(Window, ThreadData);
384
385 IntDeRegisterShellHookWindow(Window->hSelf);
386
387 if(SendMessages)
388 {
389 /* Send destroy messages */
390 IntSendDestroyMsg(Window->hSelf);
391 }
392
393 /* free child windows */
394 Children = IntWinListChildren(Window);
395 if (Children)
396 {
397 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
398 {
399 if ((Child = IntGetWindowObject(*ChildHandle)))
400 {
401 if(!IntWndBelongsToThread(Child, ThreadData))
402 {
403 /* send WM_DESTROY messages to windows not belonging to the same thread */
404 IntSendDestroyMsg(Child->hSelf);
405 }
406 else
407 co_UserFreeWindow(Child, ProcessData, ThreadData, SendMessages);
408
409 UserDereferenceObject(Child);
410 }
411 }
412 ExFreePool(Children);
413 }
414
415 if(SendMessages)
416 {
417 /*
418 * Clear the update region to make sure no WM_PAINT messages will be
419 * generated for this window while processing the WM_NCDESTROY.
420 */
421 co_UserRedrawWindow(Window, NULL, 0,
422 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
423 RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
424 if(BelongsToThreadData)
425 co_IntSendMessage(Window->hSelf, WM_NCDESTROY, 0, 0);
426 }
427 MsqRemoveTimersWindow(ThreadData->MessageQueue, Window->hSelf);
428
429 /* flush the message queue */
430 MsqRemoveWindowMessagesFromQueue(Window);
431
432 /* from now on no messages can be sent to this window anymore */
433 Window->Status |= WINDOWSTATUS_DESTROYED;
434 Wnd->state |= WNDS_DESTROYED;
435
436 /* don't remove the WINDOWSTATUS_DESTROYING bit */
437
438 /* reset shell window handles */
439 if(ThreadData->Desktop)
440 {
441 if (Window->hSelf == ThreadData->Desktop->WindowStation->ShellWindow)
442 ThreadData->Desktop->WindowStation->ShellWindow = NULL;
443
444 if (Window->hSelf == ThreadData->Desktop->WindowStation->ShellListView)
445 ThreadData->Desktop->WindowStation->ShellListView = NULL;
446 }
447
448 /* Unregister hot keys */
449 UnregisterWindowHotKeys (Window);
450
451 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
452
453 #if 0 /* FIXME */
454
455 WinPosCheckInternalPos(Window->hSelf);
456 if (Window->hSelf == GetCapture())
457 {
458 ReleaseCapture();
459 }
460
461 /* free resources associated with the window */
462 TIMER_RemoveWindowTimers(Window->hSelf);
463 #endif
464
465 if (!(Wnd->style & WS_CHILD) && Wnd->IDMenu
466 && (Menu = UserGetMenuObject((HMENU)Wnd->IDMenu)))
467 {
468 IntDestroyMenuObject(Menu, TRUE, TRUE);
469 Wnd->IDMenu = 0;
470 }
471
472 if(Window->SystemMenu
473 && (Menu = UserGetMenuObject(Window->SystemMenu)))
474 {
475 IntDestroyMenuObject(Menu, TRUE, TRUE);
476 Window->SystemMenu = (HMENU)0;
477 }
478
479 DceFreeWindowDCE(Window); /* Always do this to catch orphaned DCs */
480 #if 0 /* FIXME */
481
482 WINPROC_FreeProc(Window->winproc, WIN_PROC_WINDOW);
483 CLASS_RemoveWindow(Window->Class);
484 #endif
485
486 IntUnlinkWindow(Window);
487
488 UserReferenceObject(Window);
489 UserDeleteObject(Window->hSelf, otWindow);
490
491 IntDestroyScrollBars(Window);
492
493 /* dereference the class */
494 IntDereferenceClass(Wnd->pcls,
495 Window->ti->pDeskInfo,
496 Window->ti->ppi);
497 Wnd->pcls = NULL;
498
499 if(Window->WindowRegion)
500 {
501 GreDeleteObject(Window->WindowRegion);
502 }
503
504 ASSERT(Window->Wnd != NULL);
505 UserFreeWindowInfo(Window->ti, Window);
506
507 UserDereferenceObject(Window);
508
509 IntClipboardFreeWindow(Window);
510
511 return 0;
512 }
513
514 VOID FASTCALL
515 IntGetWindowBorderMeasures(PWINDOW_OBJECT Window, UINT *cx, UINT *cy)
516 {
517 PWND Wnd = Window->Wnd;
518 if(HAS_DLGFRAME(Wnd->style, Wnd->ExStyle) && !(Wnd->style & WS_MINIMIZE))
519 {
520 *cx = UserGetSystemMetrics(SM_CXDLGFRAME);
521 *cy = UserGetSystemMetrics(SM_CYDLGFRAME);
522 }
523 else
524 {
525 if(HAS_THICKFRAME(Wnd->style, Wnd->ExStyle)&& !(Wnd->style & WS_MINIMIZE))
526 {
527 *cx = UserGetSystemMetrics(SM_CXFRAME);
528 *cy = UserGetSystemMetrics(SM_CYFRAME);
529 }
530 else if(HAS_THINFRAME(Wnd->style, Wnd->ExStyle))
531 {
532 *cx = UserGetSystemMetrics(SM_CXBORDER);
533 *cy = UserGetSystemMetrics(SM_CYBORDER);
534 }
535 else
536 {
537 *cx = *cy = 0;
538 }
539 }
540 }
541
542 static WNDPROC
543 IntGetWindowProc(IN PWINDOW_OBJECT Window,
544 IN BOOL Ansi)
545 {
546 PWND Wnd = Window->Wnd;
547
548 ASSERT(UserIsEnteredExclusive() == TRUE);
549
550 if (Wnd->IsSystem)
551 {
552 return (Ansi ? Wnd->WndProcExtra : Wnd->lpfnWndProc);
553 }
554 else
555 {
556 if (!Ansi == Wnd->Unicode)
557 {
558 return Wnd->lpfnWndProc;
559 }
560 else
561 {
562 if (Wnd->CallProc != NULL)
563 {
564 return GetCallProcHandle(Wnd->CallProc);
565 }
566 /* BUGBOY Comments: Maybe theres something Im not undestanding here, but why would a CallProc be created
567 on a function that I thought is only suppose to return the current Windows Proc? */
568 else
569 {
570 PCALLPROCDATA NewCallProc, CallProc;
571
572 NewCallProc = UserFindCallProc(Wnd->pcls,
573 Wnd->lpfnWndProc,
574 Wnd->Unicode);
575 if (NewCallProc == NULL)
576 {
577 NewCallProc = CreateCallProc(Wnd->head.pti->pDeskInfo,
578 Wnd->lpfnWndProc,
579 Wnd->Unicode,
580 Wnd->head.pti->ppi);
581 if (NewCallProc == NULL)
582 {
583 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
584 return NULL;
585 }
586
587 UserAddCallProcToClass(Wnd->pcls,
588 NewCallProc);
589 }
590
591 CallProc = Wnd->CallProc;
592 Wnd->CallProc = NewCallProc;
593
594 return GetCallProcHandle((CallProc == NULL ? NewCallProc : CallProc));
595 }
596 }
597 }
598 }
599
600 BOOL FASTCALL
601 IntGetWindowInfo(PWINDOW_OBJECT Window, PWINDOWINFO pwi)
602 {
603 PWND Wnd = Window->Wnd;
604
605 pwi->cbSize = sizeof(WINDOWINFO);
606 pwi->rcWindow = Window->Wnd->rcWindow;
607 pwi->rcClient = Window->Wnd->rcClient;
608 pwi->dwStyle = Wnd->style;
609 pwi->dwExStyle = Wnd->ExStyle;
610 pwi->dwWindowStatus = (UserGetForegroundWindow() == Window->hSelf); /* WS_ACTIVECAPTION */
611 IntGetWindowBorderMeasures(Window, &pwi->cxWindowBorders, &pwi->cyWindowBorders);
612 pwi->atomWindowType = (Wnd->pcls ? Wnd->pcls->atomClassName : 0);
613 pwi->wCreatorVersion = 0x400; /* FIXME - return a real version number */
614 return TRUE;
615 }
616
617 static BOOL FASTCALL
618 IntSetMenu(
619 PWINDOW_OBJECT Window,
620 HMENU Menu,
621 BOOL *Changed)
622 {
623 PMENU_OBJECT OldMenu, NewMenu = NULL;
624 PWND Wnd = Window->Wnd;
625
626 if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
627 {
628 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
629 return FALSE;
630 }
631
632 *Changed = (Wnd->IDMenu != (UINT) Menu);
633 if (! *Changed)
634 {
635 return TRUE;
636 }
637
638 if (Wnd->IDMenu)
639 {
640 OldMenu = IntGetMenuObject((HMENU) Wnd->IDMenu);
641 ASSERT(NULL == OldMenu || OldMenu->MenuInfo.Wnd == Window->hSelf);
642 }
643 else
644 {
645 OldMenu = NULL;
646 }
647
648 if (NULL != Menu)
649 {
650 NewMenu = IntGetMenuObject(Menu);
651 if (NULL == NewMenu)
652 {
653 if (NULL != OldMenu)
654 {
655 IntReleaseMenuObject(OldMenu);
656 }
657 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
658 return FALSE;
659 }
660 if (NULL != NewMenu->MenuInfo.Wnd)
661 {
662 /* Can't use the same menu for two windows */
663 if (NULL != OldMenu)
664 {
665 IntReleaseMenuObject(OldMenu);
666 }
667 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
668 return FALSE;
669 }
670
671 }
672
673 Wnd->IDMenu = (UINT) Menu;
674 if (NULL != NewMenu)
675 {
676 NewMenu->MenuInfo.Wnd = Window->hSelf;
677 IntReleaseMenuObject(NewMenu);
678 }
679 if (NULL != OldMenu)
680 {
681 OldMenu->MenuInfo.Wnd = NULL;
682 IntReleaseMenuObject(OldMenu);
683 }
684
685 return TRUE;
686 }
687
688
689 /* INTERNAL ******************************************************************/
690
691
692 VOID FASTCALL
693 co_DestroyThreadWindows(struct _ETHREAD *Thread)
694 {
695 PTHREADINFO WThread;
696 PLIST_ENTRY Current;
697 PWINDOW_OBJECT Wnd;
698 USER_REFERENCE_ENTRY Ref;
699 WThread = (PTHREADINFO)Thread->Tcb.Win32Thread;
700
701 while (!IsListEmpty(&WThread->WindowListHead))
702 {
703 Current = WThread->WindowListHead.Flink;
704 Wnd = CONTAINING_RECORD(Current, WINDOW_OBJECT, ThreadListEntry);
705
706 DPRINT("thread cleanup: while destroy wnds, wnd=0x%x\n",Wnd);
707
708 /* window removes itself from the list */
709
710 /*
711 fixme: it is critical that the window removes itself! if now, we will loop
712 here forever...
713 */
714
715 //ASSERT(co_UserDestroyWindow(Wnd));
716
717 UserRefObjectCo(Wnd, &Ref);//faxme: temp hack??
718 if (!co_UserDestroyWindow(Wnd))
719 {
720 DPRINT1("Unable to destroy window 0x%x at thread cleanup... This is _VERY_ bad!\n", Wnd);
721 }
722 UserDerefObjectCo(Wnd);//faxme: temp hack??
723 }
724 }
725
726
727
728 /*!
729 * Internal function.
730 * Returns client window rectangle relative to the upper-left corner of client area.
731 *
732 * \note Does not check the validity of the parameters
733 */
734 VOID FASTCALL
735 IntGetClientRect(PWINDOW_OBJECT Window, RECTL *Rect)
736 {
737 ASSERT( Window );
738 ASSERT( Rect );
739
740 Rect->left = Rect->top = 0;
741 Rect->right = Window->Wnd->rcClient.right - Window->Wnd->rcClient.left;
742 Rect->bottom = Window->Wnd->rcClient.bottom - Window->Wnd->rcClient.top;
743 }
744
745
746 #if 0
747 HWND FASTCALL
748 IntGetFocusWindow(VOID)
749 {
750 PUSER_MESSAGE_QUEUE Queue;
751 PDESKTOP pdo = IntGetActiveDesktop();
752
753 if( !pdo )
754 return NULL;
755
756 Queue = (PUSER_MESSAGE_QUEUE)pdo->ActiveMessageQueue;
757
758 if (Queue == NULL)
759 return(NULL);
760 else
761 return(Queue->FocusWindow);
762 }
763 #endif
764
765 PMENU_OBJECT FASTCALL
766 IntGetSystemMenu(PWINDOW_OBJECT Window, BOOL bRevert, BOOL RetMenu)
767 {
768 PMENU_OBJECT Menu, NewMenu = NULL, SysMenu = NULL, ret = NULL;
769 PTHREADINFO W32Thread;
770 HMENU hNewMenu, hSysMenu;
771 ROSMENUITEMINFO ItemInfo;
772
773 if(bRevert)
774 {
775 W32Thread = PsGetCurrentThreadWin32Thread();
776
777 if(!W32Thread->Desktop)
778 return NULL;
779
780 if(Window->SystemMenu)
781 {
782 Menu = UserGetMenuObject(Window->SystemMenu);
783 if(Menu)
784 {
785 IntDestroyMenuObject(Menu, TRUE, TRUE);
786 Window->SystemMenu = (HMENU)0;
787 }
788 }
789
790 if(W32Thread->Desktop->WindowStation->SystemMenuTemplate)
791 {
792 /* clone system menu */
793 Menu = UserGetMenuObject(W32Thread->Desktop->WindowStation->SystemMenuTemplate);
794 if(!Menu)
795 return NULL;
796
797 NewMenu = IntCloneMenu(Menu);
798 if(NewMenu)
799 {
800 Window->SystemMenu = NewMenu->MenuInfo.Self;
801 NewMenu->MenuInfo.Flags |= MF_SYSMENU;
802 NewMenu->MenuInfo.Wnd = Window->hSelf;
803 ret = NewMenu;
804 //IntReleaseMenuObject(NewMenu);
805 }
806 }
807 else
808 {
809 hSysMenu = UserCreateMenu(FALSE);
810 if (NULL == hSysMenu)
811 {
812 return NULL;
813 }
814 SysMenu = IntGetMenuObject(hSysMenu);
815 if (NULL == SysMenu)
816 {
817 UserDestroyMenu(hSysMenu);
818 return NULL;
819 }
820 SysMenu->MenuInfo.Flags |= MF_SYSMENU;
821 SysMenu->MenuInfo.Wnd = Window->hSelf;
822 hNewMenu = co_IntLoadSysMenuTemplate();
823 if(!hNewMenu)
824 {
825 IntReleaseMenuObject(SysMenu);
826 UserDestroyMenu(hSysMenu);
827 return NULL;
828 }
829 Menu = IntGetMenuObject(hNewMenu);
830 if(!Menu)
831 {
832 IntReleaseMenuObject(SysMenu);
833 UserDestroyMenu(hSysMenu);
834 return NULL;
835 }
836
837 NewMenu = IntCloneMenu(Menu);
838 if(NewMenu)
839 {
840 NewMenu->MenuInfo.Flags |= MF_SYSMENU | MF_POPUP;
841 IntReleaseMenuObject(NewMenu);
842 UserSetMenuDefaultItem(NewMenu, SC_CLOSE, FALSE);
843
844 ItemInfo.cbSize = sizeof(MENUITEMINFOW);
845 ItemInfo.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_SUBMENU;
846 ItemInfo.fType = MF_POPUP;
847 ItemInfo.fState = MFS_ENABLED;
848 ItemInfo.dwTypeData = NULL;
849 ItemInfo.cch = 0;
850 ItemInfo.hSubMenu = NewMenu->MenuInfo.Self;
851 IntInsertMenuItem(SysMenu, (UINT) -1, TRUE, &ItemInfo);
852
853 Window->SystemMenu = SysMenu->MenuInfo.Self;
854
855 ret = SysMenu;
856 }
857 IntDestroyMenuObject(Menu, FALSE, TRUE);
858 }
859 if(RetMenu)
860 return ret;
861 else
862 return NULL;
863 }
864 else
865 {
866 if(Window->SystemMenu)
867 return IntGetMenuObject((HMENU)Window->SystemMenu);
868 else
869 return NULL;
870 }
871 }
872
873
874 BOOL FASTCALL
875 IntIsChildWindow(PWINDOW_OBJECT Parent, PWINDOW_OBJECT BaseWindow)
876 {
877 PWINDOW_OBJECT Window;
878 PWND Wnd;
879
880 Window = BaseWindow;
881 while (Window)
882 {
883 Wnd = Window->Wnd;
884 if (Window == Parent)
885 {
886 return(TRUE);
887 }
888 if(!(Wnd->style & WS_CHILD))
889 {
890 break;
891 }
892
893 Window = Window->Parent;
894 }
895
896 return(FALSE);
897 }
898
899 BOOL FASTCALL
900 IntIsWindowVisible(PWINDOW_OBJECT BaseWindow)
901 {
902 PWINDOW_OBJECT Window;
903 PWND Wnd;
904
905 Window = BaseWindow;
906 while(Window)
907 {
908 Wnd = Window->Wnd;
909 if(!(Wnd->style & WS_CHILD))
910 {
911 break;
912 }
913 if(!(Wnd->style & WS_VISIBLE))
914 {
915 return FALSE;
916 }
917
918 Window = Window->Parent;
919 }
920
921 if(Window && Wnd->style & WS_VISIBLE)
922 {
923 return TRUE;
924 }
925
926 return FALSE;
927 }
928
929
930 /* link the window into siblings and parent. children are kept in place. */
931 VOID FASTCALL
932 IntLinkWindow(
933 PWINDOW_OBJECT Wnd,
934 PWINDOW_OBJECT WndParent,
935 PWINDOW_OBJECT WndPrevSibling /* set to NULL if top sibling */
936 )
937 {
938 PWINDOW_OBJECT Parent;
939
940 Wnd->Parent = WndParent;
941 Wnd->Wnd->spwndParent = WndParent ? WndParent->Wnd : NULL;
942 if ((Wnd->PrevSibling = WndPrevSibling))
943 {
944 /* link after WndPrevSibling */
945 if ((Wnd->NextSibling = WndPrevSibling->NextSibling))
946 Wnd->NextSibling->PrevSibling = Wnd;
947 else if ((Parent = Wnd->Parent))
948 {
949 if(Parent->LastChild == WndPrevSibling)
950 Parent->LastChild = Wnd;
951 }
952 Wnd->PrevSibling->NextSibling = Wnd;
953 }
954 else
955 {
956 /* link at top */
957 Parent = Wnd->Parent;
958 if ((Wnd->NextSibling = WndParent->FirstChild))
959 Wnd->NextSibling->PrevSibling = Wnd;
960 else if (Parent)
961 {
962 Parent->LastChild = Wnd;
963 Parent->FirstChild = Wnd;
964 return;
965 }
966 if(Parent)
967 {
968 Parent->FirstChild = Wnd;
969 }
970 }
971
972 }
973
974 HWND FASTCALL
975 IntSetOwner(HWND hWnd, HWND hWndNewOwner)
976 {
977 PWINDOW_OBJECT Wnd, WndOldOwner, WndNewOwner;
978 HWND ret;
979
980 Wnd = IntGetWindowObject(hWnd);
981 if(!Wnd)
982 return NULL;
983
984 WndOldOwner = IntGetWindowObject(Wnd->hOwner);
985 if (WndOldOwner)
986 {
987 ret = WndOldOwner->hSelf;
988 UserDereferenceObject(WndOldOwner);
989 }
990 else
991 {
992 ret = 0;
993 }
994
995 if((WndNewOwner = UserGetWindowObject(hWndNewOwner)))
996 {
997 Wnd->hOwner = hWndNewOwner;
998 Wnd->Wnd->spwndOwner = WndNewOwner->Wnd;
999 }
1000 else
1001 {
1002 Wnd->hOwner = NULL;
1003 Wnd->Wnd->spwndOwner = NULL;
1004 }
1005
1006 UserDereferenceObject(Wnd);
1007 return ret;
1008 }
1009
1010 PWINDOW_OBJECT FASTCALL
1011 co_IntSetParent(PWINDOW_OBJECT Wnd, PWINDOW_OBJECT WndNewParent)
1012 {
1013 PWINDOW_OBJECT WndOldParent, Sibling, InsertAfter;
1014 // HWND hWnd, hWndNewParent;
1015 BOOL WasVisible;
1016
1017 ASSERT(Wnd);
1018 ASSERT(WndNewParent);
1019 ASSERT_REFS_CO(Wnd);
1020 ASSERT_REFS_CO(WndNewParent);
1021
1022 // hWnd = Wnd->hSelf;
1023 // hWndNewParent = WndNewParent->hSelf;
1024
1025 /* Some applications try to set a child as a parent */
1026 if (IntIsChildWindow(Wnd, WndNewParent))
1027 {
1028 SetLastWin32Error( ERROR_INVALID_PARAMETER );
1029 return 0;
1030 }
1031
1032 /*
1033 * Windows hides the window first, then shows it again
1034 * including the WM_SHOWWINDOW messages and all
1035 */
1036 WasVisible = co_WinPosShowWindow(Wnd, SW_HIDE);
1037
1038 // /* Validate that window and parent still exist */
1039 // if (!IntIsWindow(hWnd) || !IntIsWindow(hWndNewParent))
1040 // return NULL;
1041
1042 /* Window must belong to current process */
1043 if (Wnd->OwnerThread->ThreadsProcess != PsGetCurrentProcess())
1044 return NULL;
1045
1046 WndOldParent = Wnd->Parent;
1047
1048 if (WndOldParent) UserReferenceObject(WndOldParent); /* caller must deref */
1049
1050 if (WndNewParent != WndOldParent)
1051 {
1052 IntUnlinkWindow(Wnd);
1053 InsertAfter = NULL;
1054 if (0 == (Wnd->Wnd->ExStyle & WS_EX_TOPMOST))
1055 {
1056 /* Not a TOPMOST window, put after TOPMOSTs of new parent */
1057 Sibling = WndNewParent->FirstChild;
1058 while (NULL != Sibling && 0 != (Sibling->Wnd->ExStyle & WS_EX_TOPMOST))
1059 {
1060 InsertAfter = Sibling;
1061 Sibling = Sibling->NextSibling;
1062 }
1063 }
1064 if (NULL == InsertAfter)
1065 {
1066 IntLinkWindow(Wnd, WndNewParent, InsertAfter /*prev sibling*/);
1067 }
1068 else
1069 {
1070 // UserReferenceObject(InsertAfter);
1071 IntLinkWindow(Wnd, WndNewParent, InsertAfter /*prev sibling*/);
1072 // UserDereferenceObject(InsertAfter);
1073 }
1074 }
1075
1076 /*
1077 * SetParent additionally needs to make hwnd the top window
1078 * in the z-order and send the expected WM_WINDOWPOSCHANGING and
1079 * WM_WINDOWPOSCHANGED notification messages.
1080 */
1081 co_WinPosSetWindowPos(Wnd, (0 == (Wnd->Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
1082 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE
1083 | (WasVisible ? SWP_SHOWWINDOW : 0));
1084
1085 /*
1086 * FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
1087 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE
1088 */
1089
1090 /*
1091 * Validate that the old parent still exist, since it migth have been
1092 * destroyed during the last callbacks to user-mode
1093 */
1094 // if(WndOldParent)
1095 // {
1096 // if(!IntIsWindow(WndOldParent->hSelf))
1097 // {
1098 // UserDereferenceObject(WndOldParent);
1099 // return NULL;
1100 // }
1101
1102 /* don't dereference the window object here, it must be done by the caller
1103 of IntSetParent() */
1104 // return WndOldParent;
1105 // }
1106
1107 return WndOldParent;//NULL;
1108 }
1109
1110 BOOL FASTCALL
1111 IntSetSystemMenu(PWINDOW_OBJECT Window, PMENU_OBJECT Menu)
1112 {
1113 PMENU_OBJECT OldMenu;
1114 if(Window->SystemMenu)
1115 {
1116 OldMenu = IntGetMenuObject(Window->SystemMenu);
1117 if(OldMenu)
1118 {
1119 OldMenu->MenuInfo.Flags &= ~ MF_SYSMENU;
1120 IntReleaseMenuObject(OldMenu);
1121 }
1122 }
1123
1124 if(Menu)
1125 {
1126 /* FIXME check window style, propably return FALSE ? */
1127 Window->SystemMenu = Menu->MenuInfo.Self;
1128 Menu->MenuInfo.Flags |= MF_SYSMENU;
1129 }
1130 else
1131 Window->SystemMenu = (HMENU)0;
1132
1133 return TRUE;
1134 }
1135
1136
1137 /* unlink the window from siblings and parent. children are kept in place. */
1138 VOID FASTCALL
1139 IntUnlinkWindow(PWINDOW_OBJECT Wnd)
1140 {
1141 PWINDOW_OBJECT WndParent = Wnd->Parent;
1142
1143 if (Wnd->NextSibling)
1144 Wnd->NextSibling->PrevSibling = Wnd->PrevSibling;
1145 else if (WndParent && WndParent->LastChild == Wnd)
1146 WndParent->LastChild = Wnd->PrevSibling;
1147
1148 if (Wnd->PrevSibling)
1149 Wnd->PrevSibling->NextSibling = Wnd->NextSibling;
1150 else if (WndParent && WndParent->FirstChild == Wnd)
1151 WndParent->FirstChild = Wnd->NextSibling;
1152
1153 Wnd->PrevSibling = Wnd->NextSibling = Wnd->Parent = NULL;
1154 if (Wnd->Wnd)
1155 Wnd->Wnd->spwndParent = NULL;
1156 }
1157
1158 BOOL FASTCALL
1159 IntAnyPopup(VOID)
1160 {
1161 PWINDOW_OBJECT Window, Child;
1162
1163 if(!(Window = UserGetWindowObject(IntGetDesktopWindow())))
1164 {
1165 return FALSE;
1166 }
1167
1168 for(Child = Window->FirstChild; Child; Child = Child->NextSibling)
1169 {
1170 if(Child->hOwner && Child->Wnd->style & WS_VISIBLE)
1171 {
1172 /*
1173 * The desktop has a popup window if one of them has
1174 * an owner window and is visible
1175 */
1176 return TRUE;
1177 }
1178 }
1179
1180 return FALSE;
1181 }
1182
1183 BOOL FASTCALL
1184 IntIsWindowInDestroy(PWINDOW_OBJECT Window)
1185 {
1186 return ((Window->Status & WINDOWSTATUS_DESTROYING) == WINDOWSTATUS_DESTROYING);
1187 }
1188
1189
1190 BOOL
1191 FASTCALL
1192 IntGetWindowPlacement(PWINDOW_OBJECT Window, WINDOWPLACEMENT *lpwndpl)
1193 {
1194 PWND Wnd;
1195 POINT Size;
1196
1197 Wnd = Window->Wnd;
1198 if (!Wnd) return FALSE;
1199
1200 if(lpwndpl->length != sizeof(WINDOWPLACEMENT))
1201 {
1202 return FALSE;
1203 }
1204
1205 lpwndpl->flags = 0;
1206 if (0 == (Wnd->style & WS_VISIBLE))
1207 {
1208 lpwndpl->showCmd = SW_HIDE;
1209 }
1210 else if (0 != (Window->Flags & WINDOWOBJECT_RESTOREMAX) ||
1211 0 != (Wnd->style & WS_MAXIMIZE))
1212 {
1213 lpwndpl->showCmd = SW_MAXIMIZE;
1214 }
1215 else if (0 != (Wnd->style & WS_MINIMIZE))
1216 {
1217 lpwndpl->showCmd = SW_MINIMIZE;
1218 }
1219 else if (0 != (Wnd->style & WS_VISIBLE))
1220 {
1221 lpwndpl->showCmd = SW_SHOWNORMAL;
1222 }
1223
1224 Size.x = Wnd->rcWindow.left;
1225 Size.y = Wnd->rcWindow.top;
1226 WinPosInitInternalPos(Window, &Size,
1227 &Wnd->rcWindow);
1228
1229 lpwndpl->rcNormalPosition = Wnd->InternalPos.NormalRect;
1230 lpwndpl->ptMinPosition = Wnd->InternalPos.IconPos;
1231 lpwndpl->ptMaxPosition = Wnd->InternalPos.MaxPos;
1232
1233 return TRUE;
1234 }
1235
1236
1237 /* FUNCTIONS *****************************************************************/
1238
1239 /*
1240 * @unimplemented
1241 */
1242 DWORD APIENTRY
1243 NtUserAlterWindowStyle(DWORD Unknown0,
1244 DWORD Unknown1,
1245 DWORD Unknown2)
1246 {
1247 UNIMPLEMENTED
1248
1249 return(0);
1250 }
1251
1252 /*
1253 * As best as I can figure, this function is used by EnumWindows,
1254 * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
1255 *
1256 * It's supposed to build a list of HWNDs to return to the caller.
1257 * We can figure out what kind of list by what parameters are
1258 * passed to us.
1259 */
1260 /*
1261 * @implemented
1262 */
1263 NTSTATUS
1264 APIENTRY
1265 NtUserBuildHwndList(
1266 HDESK hDesktop,
1267 HWND hwndParent,
1268 BOOLEAN bChildren,
1269 ULONG dwThreadId,
1270 ULONG lParam,
1271 HWND* pWnd,
1272 ULONG* pBufSize)
1273 {
1274 NTSTATUS Status;
1275 ULONG dwCount = 0;
1276
1277 if (pBufSize == 0)
1278 return ERROR_INVALID_PARAMETER;
1279
1280 if (hwndParent || !dwThreadId)
1281 {
1282 PDESKTOP Desktop;
1283 PWINDOW_OBJECT Parent, Window;
1284
1285 if(!hwndParent)
1286 {
1287 if(hDesktop == NULL && !(Desktop = IntGetActiveDesktop()))
1288 {
1289 return ERROR_INVALID_HANDLE;
1290 }
1291
1292 if(hDesktop)
1293 {
1294 Status = IntValidateDesktopHandle(hDesktop,
1295 UserMode,
1296 0,
1297 &Desktop);
1298 if(!NT_SUCCESS(Status))
1299 {
1300 return ERROR_INVALID_HANDLE;
1301 }
1302 }
1303 hwndParent = Desktop->DesktopWindow;
1304 }
1305 else
1306 {
1307 hDesktop = 0;
1308 }
1309
1310 if((Parent = UserGetWindowObject(hwndParent)) &&
1311 (Window = Parent->FirstChild))
1312 {
1313 BOOL bGoDown = TRUE;
1314
1315 Status = STATUS_SUCCESS;
1316 while(TRUE)
1317 {
1318 if (bGoDown)
1319 {
1320 if(dwCount++ < *pBufSize && pWnd)
1321 {
1322 _SEH2_TRY
1323 {
1324 ProbeForWrite(pWnd, sizeof(HWND), 1);
1325 *pWnd = Window->hSelf;
1326 pWnd++;
1327 }
1328 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1329 {
1330 Status = _SEH2_GetExceptionCode();
1331 }
1332 _SEH2_END
1333 if(!NT_SUCCESS(Status))
1334 {
1335 SetLastNtError(Status);
1336 break;
1337 }
1338 }
1339 if (Window->FirstChild && bChildren)
1340 {
1341 Window = Window->FirstChild;
1342 continue;
1343 }
1344 bGoDown = FALSE;
1345 }
1346 if (Window->NextSibling)
1347 {
1348 Window = Window->NextSibling;
1349 bGoDown = TRUE;
1350 continue;
1351 }
1352 Window = Window->Parent;
1353 if (Window == Parent)
1354 {
1355 break;
1356 }
1357 }
1358 }
1359
1360 if(hDesktop)
1361 {
1362 ObDereferenceObject(Desktop);
1363 }
1364 }
1365 else
1366 {
1367 PETHREAD Thread;
1368 PTHREADINFO W32Thread;
1369 PLIST_ENTRY Current;
1370 PWINDOW_OBJECT Window;
1371
1372 Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
1373 if(!NT_SUCCESS(Status))
1374 {
1375 return ERROR_INVALID_PARAMETER;
1376 }
1377 if(!(W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread))
1378 {
1379 ObDereferenceObject(Thread);
1380 DPRINT("Thread is not a GUI Thread!\n");
1381 return ERROR_INVALID_PARAMETER;
1382 }
1383
1384 Current = W32Thread->WindowListHead.Flink;
1385 while(Current != &(W32Thread->WindowListHead))
1386 {
1387 Window = CONTAINING_RECORD(Current, WINDOW_OBJECT, ThreadListEntry);
1388 ASSERT(Window);
1389
1390 if(bChildren || Window->hOwner != NULL)
1391 {
1392 if(dwCount < *pBufSize && pWnd)
1393 {
1394 Status = MmCopyToCaller(pWnd++, &Window->hSelf, sizeof(HWND));
1395 if(!NT_SUCCESS(Status))
1396 {
1397 SetLastNtError(Status);
1398 break;
1399 }
1400 }
1401 dwCount++;
1402 }
1403 Current = Current->Flink;
1404 }
1405
1406 ObDereferenceObject(Thread);
1407 }
1408
1409 *pBufSize = dwCount;
1410 return STATUS_SUCCESS;
1411 }
1412
1413
1414 /*
1415 * @implemented
1416 */
1417 HWND APIENTRY
1418 NtUserChildWindowFromPointEx(HWND hwndParent,
1419 LONG x,
1420 LONG y,
1421 UINT uiFlags)
1422 {
1423 PWINDOW_OBJECT Parent;
1424 POINTL Pt;
1425 HWND Ret;
1426 HWND *List, *phWnd;
1427
1428 if(!(Parent = UserGetWindowObject(hwndParent)))
1429 {
1430 return NULL;
1431 }
1432
1433 Pt.x = x;
1434 Pt.y = y;
1435
1436 if(Parent->hSelf != IntGetDesktopWindow())
1437 {
1438 Pt.x += Parent->Wnd->rcClient.left;
1439 Pt.y += Parent->Wnd->rcClient.top;
1440 }
1441
1442 if(!IntPtInWindow(Parent, Pt.x, Pt.y))
1443 {
1444 return NULL;
1445 }
1446
1447 Ret = Parent->hSelf;
1448 if((List = IntWinListChildren(Parent)))
1449 {
1450 for(phWnd = List; *phWnd; phWnd++)
1451 {
1452 PWINDOW_OBJECT Child;
1453 PWND ChildWnd;
1454 if((Child = UserGetWindowObject(*phWnd)))
1455 {
1456 ChildWnd = Child->Wnd;
1457 if(!(ChildWnd->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE))
1458 {
1459 continue;
1460 }
1461 if((ChildWnd->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED))
1462 {
1463 continue;
1464 }
1465 if((ChildWnd->ExStyle & WS_EX_TRANSPARENT) && (uiFlags & CWP_SKIPTRANSPARENT))
1466 {
1467 continue;
1468 }
1469 if(IntPtInWindow(Child, Pt.x, Pt.y))
1470 {
1471 Ret = Child->hSelf;
1472 break;
1473 }
1474 }
1475 }
1476 ExFreePool(List);
1477 }
1478
1479 return Ret;
1480 }
1481
1482
1483 /*
1484 * calculates the default position of a window
1485 */
1486 BOOL FASTCALL
1487 IntCalcDefPosSize(PWINDOW_OBJECT Parent, PWINDOW_OBJECT Window, RECTL *rc, BOOL IncPos)
1488 {
1489 SIZE Sz;
1490 POINT Pos = {0, 0};
1491
1492 if(Parent != NULL)
1493 {
1494 RECTL_bIntersectRect(rc, rc, &Parent->Wnd->rcClient);
1495
1496 if(IncPos)
1497 {
1498 Pos.x = Parent->TiledCounter * (UserGetSystemMetrics(SM_CXSIZE) + UserGetSystemMetrics(SM_CXFRAME));
1499 Pos.y = Parent->TiledCounter * (UserGetSystemMetrics(SM_CYSIZE) + UserGetSystemMetrics(SM_CYFRAME));
1500 if(Pos.x > ((rc->right - rc->left) / 4) ||
1501 Pos.y > ((rc->bottom - rc->top) / 4))
1502 {
1503 /* reset counter and position */
1504 Pos.x = 0;
1505 Pos.y = 0;
1506 Parent->TiledCounter = 0;
1507 }
1508 Parent->TiledCounter++;
1509 }
1510 Pos.x += rc->left;
1511 Pos.y += rc->top;
1512 }
1513 else
1514 {
1515 Pos.x = rc->left;
1516 Pos.y = rc->top;
1517 }
1518
1519 Sz.cx = EngMulDiv(rc->right - rc->left, 3, 4);
1520 Sz.cy = EngMulDiv(rc->bottom - rc->top, 3, 4);
1521
1522 rc->left = Pos.x;
1523 rc->top = Pos.y;
1524 rc->right = rc->left + Sz.cx;
1525 rc->bottom = rc->top + Sz.cy;
1526 return TRUE;
1527 }
1528
1529
1530 /*
1531 * @implemented
1532 */
1533 PWND APIENTRY
1534 co_IntCreateWindowEx(DWORD dwExStyle,
1535 PUNICODE_STRING ClassName,
1536 PUNICODE_STRING WindowName,
1537 DWORD dwStyle,
1538 LONG x,
1539 LONG y,
1540 LONG nWidth,
1541 LONG nHeight,
1542 HWND hWndParent,
1543 HMENU hMenu,
1544 HINSTANCE hInstance,
1545 LPVOID lpParam,
1546 DWORD dwShowMode,
1547 BOOL bUnicodeWindow)
1548 {
1549 PWINSTATION_OBJECT WinSta;
1550 PWND Wnd = NULL;
1551 PCLS *ClassLink, Class = NULL;
1552 RTL_ATOM ClassAtom;
1553 PWINDOW_OBJECT Window = NULL;
1554 PWINDOW_OBJECT ParentWindow = NULL, OwnerWindow;
1555 HWND ParentWindowHandle = NULL;
1556 HWND OwnerWindowHandle;
1557 PMENU_OBJECT SystemMenu;
1558 HWND hWnd;
1559 POINT Pos;
1560 SIZE Size;
1561 PTHREADINFO ti = NULL;
1562 #if 0
1563
1564 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
1565 #else
1566
1567 POINT MaxPos;
1568 #endif
1569 CREATESTRUCTW Cs;
1570 CBT_CREATEWNDW CbtCreate;
1571 LRESULT Result;
1572 BOOL MenuChanged;
1573 DECLARE_RETURN(PWND);
1574 BOOL HasOwner;
1575 USER_REFERENCE_ENTRY ParentRef, Ref;
1576 PTHREADINFO pti;
1577
1578 pti = PsGetCurrentThreadWin32Thread();
1579
1580 if (pti->Desktop)
1581 {
1582 ParentWindowHandle = pti->Desktop->DesktopWindow;
1583 }
1584
1585 OwnerWindowHandle = NULL;
1586
1587 if (hWndParent == HWND_MESSAGE)
1588 {
1589 /*
1590 * native ole32.OleInitialize uses HWND_MESSAGE to create the
1591 * message window (style: WS_POPUP|WS_DISABLED)
1592 */
1593 ParentWindowHandle = IntGetMessageWindow();
1594 DPRINT("Parent is HWND_MESSAGE 0x%x\n", ParentWindowHandle);
1595 }
1596 else if (hWndParent)
1597 {
1598 if ((dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1599 { //temp hack
1600 PWINDOW_OBJECT Par = UserGetWindowObject(hWndParent), Root;
1601 if (Par && (Root = UserGetAncestor(Par, GA_ROOT)))
1602 OwnerWindowHandle = Root->hSelf;
1603 }
1604 else
1605 ParentWindowHandle = hWndParent;
1606 }
1607 else if ((dwStyle & (WS_CHILD | WS_POPUP)) == WS_CHILD)
1608 {
1609 SetLastWin32Error(ERROR_TLW_WITH_WSCHILD);
1610 RETURN( (PWND)0); /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1611 }
1612
1613 if (ParentWindowHandle)
1614 {
1615 ParentWindow = UserGetWindowObject(ParentWindowHandle);
1616
1617 if (ParentWindow) UserRefObjectCo(ParentWindow, &ParentRef);
1618 }
1619 else
1620 {
1621 ParentWindow = NULL;
1622 }
1623
1624 /* FIXME: parent must belong to the current process */
1625
1626 /* Check the window station. */
1627 ti = GetW32ThreadInfo();
1628 if (ti == NULL || pti->Desktop == NULL)
1629 {
1630 DPRINT1("Thread is not attached to a desktop! Cannot create window!\n");
1631 RETURN( (PWND)0);
1632 }
1633
1634 /* Check the class. */
1635
1636 ClassAtom = IntGetClassAtom(ClassName,
1637 hInstance,
1638 ti->ppi,
1639 &Class,
1640 &ClassLink);
1641
1642 if (ClassAtom == (RTL_ATOM)0)
1643 {
1644 if (IS_ATOM(ClassName->Buffer))
1645 {
1646 DPRINT1("Class 0x%p not found\n", (DWORD_PTR) ClassName->Buffer);
1647 }
1648 else
1649 {
1650 DPRINT1("Class \"%wZ\" not found\n", ClassName);
1651 }
1652
1653 SetLastWin32Error(ERROR_CANNOT_FIND_WND_CLASS);
1654 RETURN((PWND)0);
1655 }
1656
1657 Class = IntReferenceClass(Class,
1658 ClassLink,
1659 pti->Desktop);
1660 if (Class == NULL)
1661 {
1662 DPRINT1("Failed to reference window class!\n");
1663 RETURN(NULL);
1664 }
1665
1666 WinSta = pti->Desktop->WindowStation;
1667
1668 //FIXME: Reference thread/desktop instead
1669 ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
1670
1671 /* Create the window object. */
1672 Window = (PWINDOW_OBJECT) UserCreateObject( gHandleTable,
1673 (PHANDLE)&hWnd,
1674 otWindow,
1675 sizeof(WINDOW_OBJECT));
1676 if (Window)
1677 {
1678 Window->Wnd = DesktopHeapAlloc(pti->Desktop,
1679 sizeof(WND) + Class->cbwndExtra);
1680 if (!Window->Wnd)
1681 goto AllocErr;
1682 RtlZeroMemory(Window->Wnd,
1683 sizeof(WND) + Class->cbwndExtra);
1684 Window->Wnd->head.h = hWnd;
1685 Wnd = Window->Wnd;
1686
1687 Wnd->head.pti = ti;
1688 Wnd->head.rpdesk = pti->Desktop;
1689 Wnd->hWndLastActive = hWnd;
1690 Wnd->state2 |= WNDS2_WIN40COMPAT;
1691 }
1692
1693 DPRINT("Created object with handle %X\n", hWnd);
1694 if (!Window)
1695 {
1696 AllocErr:
1697 ObDereferenceObject(WinSta);
1698 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1699 RETURN( (PWND)0);
1700 }
1701
1702 UserRefObjectCo(Window, &Ref);
1703
1704 ObDereferenceObject(WinSta);
1705
1706 if (NULL == pti->Desktop->DesktopWindow)
1707 {
1708 /* If there is no desktop window yet, we must be creating it */
1709 pti->Desktop->DesktopWindow = hWnd;
1710 pti->Desktop->DesktopInfo->Wnd = Wnd;
1711 }
1712
1713 /*
1714 * Fill out the structure describing it.
1715 */
1716 Window->ti = ti;
1717 Wnd->pcls = Class;
1718 Class = NULL;
1719
1720 Window->SystemMenu = (HMENU)0;
1721 Wnd->IDMenu = 0;
1722 Wnd->hModule = hInstance;
1723 Window->hSelf = hWnd;
1724
1725 Window->MessageQueue = pti->MessageQueue;
1726 IntReferenceMessageQueue(Window->MessageQueue);
1727 Window->Parent = ParentWindow;
1728 Wnd->spwndParent = ParentWindow ? ParentWindow->Wnd : NULL;
1729 if (Wnd->spwndParent != NULL && hWndParent != 0)
1730 {
1731 Wnd->HideFocus = Wnd->spwndParent->HideFocus;
1732 Wnd->HideAccel = Wnd->spwndParent->HideAccel;
1733 }
1734
1735 if((OwnerWindow = UserGetWindowObject(OwnerWindowHandle)))
1736 {
1737 Window->hOwner = OwnerWindowHandle;
1738 Wnd->spwndOwner = OwnerWindow->Wnd;
1739 HasOwner = TRUE;
1740 }
1741 else
1742 {
1743 Window->hOwner = NULL;
1744 Wnd->spwndOwner = NULL;
1745 HasOwner = FALSE;
1746 }
1747
1748 Wnd->dwUserData = 0;
1749
1750 Wnd->IsSystem = Wnd->pcls->System;
1751
1752 /* BugBoy Comments: Comment below say that System classes are always created as UNICODE.
1753 In windows, creating a window with the ANSI version of CreateWindow sets the window
1754 to ansi as verified by testing with IsUnicodeWindow API.
1755
1756 No where can I see in code or through testing does the window change back to ANSI
1757 after being created as UNICODE in ROS. I didnt do more testing to see what problems this would cause.*/
1758 // See NtUserDefSetText! We convert to Unicode all the time and never use Mix. (jt)
1759 if (Wnd->pcls->System)
1760 {
1761 /* NOTE: Always create a unicode window for system classes! */
1762 Wnd->Unicode = TRUE;
1763 Wnd->lpfnWndProc = Wnd->pcls->lpfnWndProc;
1764 Wnd->WndProcExtra = Wnd->pcls->WndProcExtra;
1765 }
1766 else
1767 {
1768 Wnd->Unicode = Wnd->pcls->Unicode;
1769 Wnd->lpfnWndProc = Wnd->pcls->lpfnWndProc;
1770 Wnd->CallProc = NULL;
1771 }
1772
1773 Window->OwnerThread = PsGetCurrentThread();
1774 Window->FirstChild = NULL;
1775 Window->LastChild = NULL;
1776 Window->PrevSibling = NULL;
1777 Window->NextSibling = NULL;
1778 Wnd->cbwndExtra = Wnd->pcls->cbwndExtra;
1779
1780 InitializeListHead(&Wnd->PropListHead);
1781 InitializeListHead(&Window->WndObjListHead);
1782
1783 if ( NULL != WindowName->Buffer && WindowName->Length > 0 )
1784 {
1785 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
1786 WindowName->Length + sizeof(UNICODE_NULL));
1787 if (Wnd->strName.Buffer == NULL)
1788 {
1789 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1790 RETURN( (PWND)0);
1791 }
1792
1793 Wnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
1794 _SEH2_TRY
1795 {
1796 RtlCopyMemory(Wnd->strName.Buffer,
1797 WindowName->Buffer,
1798 WindowName->Length);
1799 Wnd->strName.Length = WindowName->Length;
1800 }
1801 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1802 {
1803 WindowName->Length = 0;
1804 Wnd->strName.Buffer[0] = L'\0';
1805 }
1806 _SEH2_END;
1807 }
1808
1809 /*
1810 * This has been tested for WS_CHILD | WS_VISIBLE. It has not been
1811 * tested for WS_POPUP
1812 */
1813 if ((dwExStyle & WS_EX_DLGMODALFRAME) ||
1814 ((!(dwExStyle & WS_EX_STATICEDGE)) &&
1815 (dwStyle & (WS_DLGFRAME | WS_THICKFRAME))))
1816 dwExStyle |= WS_EX_WINDOWEDGE;
1817 else
1818 dwExStyle &= ~WS_EX_WINDOWEDGE;
1819
1820 /* Correct the window style. */
1821 if (!(dwStyle & WS_CHILD))
1822 {
1823 dwStyle |= WS_CLIPSIBLINGS;
1824 DPRINT("3: Style is now %lx\n", dwStyle);
1825 if (!(dwStyle & WS_POPUP))
1826 {
1827 dwStyle |= WS_CAPTION;
1828 Window->Flags |= WINDOWOBJECT_NEED_SIZE;
1829 DPRINT("4: Style is now %lx\n", dwStyle);
1830 }
1831 }
1832
1833 /* create system menu */
1834 if((dwStyle & WS_SYSMENU) )//&& (dwStyle & WS_CAPTION) == WS_CAPTION)
1835 {
1836 SystemMenu = IntGetSystemMenu(Window, TRUE, TRUE);
1837 if(SystemMenu)
1838 {
1839 Window->SystemMenu = SystemMenu->MenuInfo.Self;
1840 IntReleaseMenuObject(SystemMenu);
1841 }
1842 }
1843
1844 /* Set the window menu */
1845 if ((dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1846 {
1847 if (hMenu)
1848 IntSetMenu(Window, hMenu, &MenuChanged);
1849 else if (Wnd->pcls->lpszMenuName) // Take it from the parent.
1850 {
1851 UNICODE_STRING MenuName;
1852 if (IS_INTRESOURCE(Wnd->pcls->lpszMenuName))
1853 {
1854 MenuName.Length = 0;
1855 MenuName.MaximumLength = 0;
1856 MenuName.Buffer = Wnd->pcls->lpszMenuName;
1857 }
1858 else
1859 {
1860 RtlInitUnicodeString( &MenuName, Wnd->pcls->lpszMenuName);
1861 }
1862 hMenu = co_IntCallLoadMenu( Wnd->pcls->hModule, &MenuName);
1863 if (hMenu) IntSetMenu(Window, hMenu, &MenuChanged);
1864 }
1865 }
1866 else // Not a child
1867 Wnd->IDMenu = (UINT) hMenu;
1868
1869 /* Insert the window into the thread's window list. */
1870 InsertTailList (&pti->WindowListHead, &Window->ThreadListEntry);
1871
1872 /* Handle "CS_CLASSDC", it is tested first. */
1873 if ((Wnd->pcls->style & CS_CLASSDC) && !(Wnd->pcls->pdce)) // One DCE per class to have CLASS.
1874 Wnd->pcls->pdce = DceAllocDCE(Window, DCE_CLASS_DC);
1875 /* Allocate a DCE for this window. */
1876 else if ( Wnd->pcls->style & CS_OWNDC)
1877 Window->Dce = DceAllocDCE(Window, DCE_WINDOW_DC);
1878
1879 Pos.x = x;
1880 Pos.y = y;
1881 Size.cx = nWidth;
1882 Size.cy = nHeight;
1883
1884 Wnd->ExStyle = dwExStyle;
1885 Wnd->style = dwStyle & ~WS_VISIBLE;
1886
1887 /* call hook */
1888 Cs.lpCreateParams = lpParam;
1889 Cs.hInstance = hInstance;
1890 Cs.hMenu = hMenu;
1891 Cs.hwndParent = hWndParent; //Pass the original Parent handle!
1892 Cs.cx = Size.cx;
1893 Cs.cy = Size.cy;
1894 Cs.x = Pos.x;
1895 Cs.y = Pos.y;
1896 Cs.style = Wnd->style;
1897 // Cs.lpszName = (LPCWSTR) WindowName->Buffer;
1898 // Cs.lpszClass = (LPCWSTR) ClassName->Buffer;
1899 Cs.lpszName = (LPCWSTR) WindowName;
1900 Cs.lpszClass = (LPCWSTR) ClassName;
1901 Cs.dwExStyle = dwExStyle;
1902 CbtCreate.lpcs = &Cs;
1903 CbtCreate.hwndInsertAfter = HWND_TOP;
1904 if (ISITHOOKED(WH_CBT))
1905 {
1906 if (co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) &CbtCreate))
1907 {
1908 /* FIXME - Delete window object and remove it from the thread windows list */
1909 /* FIXME - delete allocated DCE */
1910 DPRINT1("CBT-hook returned !0\n");
1911 RETURN( (PWND) NULL);
1912 }
1913 }
1914 x = Cs.x;
1915 y = Cs.y;
1916 nWidth = Cs.cx;
1917 nHeight = Cs.cy;
1918 // FIXME: Need to set the Z order in the window link list if the hook callback changed it!
1919 // hwndInsertAfter = CbtCreate.hwndInsertAfter;
1920
1921 /* default positioning for overlapped windows */
1922 if(!(Wnd->style & (WS_POPUP | WS_CHILD)))
1923 {
1924 RECTL rc, WorkArea;
1925 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
1926 BOOL CalculatedDefPosSize = FALSE;
1927
1928 IntGetDesktopWorkArea(((PTHREADINFO)Window->OwnerThread->Tcb.Win32Thread)->Desktop, &WorkArea);
1929
1930 rc = WorkArea;
1931 ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
1932
1933 if(x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
1934 {
1935 CalculatedDefPosSize = IntCalcDefPosSize(ParentWindow, Window, &rc, TRUE);
1936
1937 if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
1938 {
1939 ProcessParams->WindowFlags &= ~STARTF_USEPOSITION;
1940 Pos.x = WorkArea.left + ProcessParams->StartingX;
1941 Pos.y = WorkArea.top + ProcessParams->StartingY;
1942 }
1943 else
1944 {
1945 Pos.x = rc.left;
1946 Pos.y = rc.top;
1947 }
1948
1949 /*
1950 According to wine, the ShowMode is set to y if x == CW_USEDEFAULT(16) and
1951 y is something else. and Quote!
1952 */
1953
1954 /* Never believe Microsoft's documentation... CreateWindowEx doc says
1955 * that if an overlapped window is created with WS_VISIBLE style bit
1956 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
1957 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
1958 * reveals that
1959 *
1960 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
1961 * 2) it does not ignore the y parameter as the docs claim; instead, it
1962 * uses it as second parameter to ShowWindow() unless y is either
1963 * CW_USEDEFAULT or CW_USEDEFAULT16.
1964 *
1965 * The fact that we didn't do 2) caused bogus windows pop up when wine
1966 * was running apps that were using this obscure feature. Example -
1967 * calc.exe that comes with Win98 (only Win98, it's different from
1968 * the one that comes with Win95 and NT)
1969 */
1970 if(y != CW_USEDEFAULT && y != CW_USEDEFAULT16)
1971 {
1972 dwShowMode = y;
1973 }
1974 }
1975 if(nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16)
1976 {
1977 if(!CalculatedDefPosSize)
1978 {
1979 IntCalcDefPosSize(ParentWindow, Window, &rc, FALSE);
1980 }
1981 if(ProcessParams->WindowFlags & STARTF_USESIZE)
1982 {
1983 ProcessParams->WindowFlags &= ~STARTF_USESIZE;
1984 Size.cx = ProcessParams->CountX;
1985 Size.cy = ProcessParams->CountY;
1986 }
1987 else
1988 {
1989 Size.cx = rc.right - rc.left;
1990 Size.cy = rc.bottom - rc.top;
1991 }
1992
1993 /* move the window if necessary */
1994 if(Pos.x > rc.left)
1995 Pos.x = max(rc.left, 0);
1996 if(Pos.y > rc.top)
1997 Pos.y = max(rc.top, 0);
1998 }
1999 }
2000 else
2001 {
2002 /* if CW_USEDEFAULT(16) is set for non-overlapped windows, both values are set to zero) */
2003 if(x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
2004 {
2005 Pos.x = 0;
2006 Pos.y = 0;
2007 }
2008 if(nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16)
2009 {
2010 Size.cx = 0;
2011 Size.cy = 0;
2012 }
2013 }
2014
2015 /* Initialize the window dimensions. */
2016 Wnd->rcWindow.left = Pos.x;
2017 Wnd->rcWindow.top = Pos.y;
2018 Wnd->rcWindow.right = Pos.x + Size.cx;
2019 Wnd->rcWindow.bottom = Pos.y + Size.cy;
2020 if (0 != (Wnd->style & WS_CHILD) && ParentWindow)
2021 {
2022 RECTL_vOffsetRect(&(Wnd->rcWindow), ParentWindow->Wnd->rcClient.left,
2023 ParentWindow->Wnd->rcClient.top);
2024 }
2025 Wnd->rcClient = Wnd->rcWindow;
2026
2027 /*
2028 * Get the size and position of the window.
2029 */
2030 if ((dwStyle & WS_THICKFRAME) || !(dwStyle & (WS_POPUP | WS_CHILD)))
2031 {
2032 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
2033
2034 /* WinPosGetMinMaxInfo sends the WM_GETMINMAXINFO message */
2035 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack,
2036 &MaxTrack);
2037 if (MaxSize.x < Size.cx)
2038 Size.cx = MaxSize.x;
2039 if (MaxSize.y < Size.cy)
2040 Size.cy = MaxSize.y;
2041 if (Size.cx < MinTrack.x )
2042 Size.cx = MinTrack.x;
2043 if (Size.cy < MinTrack.y )
2044 Size.cy = MinTrack.y;
2045 if (Size.cx < 0)
2046 Size.cx = 0;
2047 if (Size.cy < 0)
2048 Size.cy = 0;
2049 }
2050
2051 Wnd->rcWindow.left = Pos.x;
2052 Wnd->rcWindow.top = Pos.y;
2053 Wnd->rcWindow.right = Pos.x + Size.cx;
2054 Wnd->rcWindow.bottom = Pos.y + Size.cy;
2055 if (0 != (Wnd->style & WS_CHILD) && ParentWindow)
2056 {
2057 RECTL_vOffsetRect(&(Wnd->rcWindow), ParentWindow->Wnd->rcClient.left,
2058 ParentWindow->Wnd->rcClient.top);
2059 }
2060 Wnd->rcClient = Wnd->rcWindow;
2061
2062 /* FIXME: Initialize the window menu. */
2063
2064 /* Send a NCCREATE message. */
2065 Cs.cx = Size.cx;
2066 Cs.cy = Size.cy;
2067 Cs.x = Pos.x;
2068 Cs.y = Pos.y;
2069
2070 DPRINT("[win32k.window] IntCreateWindowEx style %d, exstyle %d, parent %d\n", Cs.style, Cs.dwExStyle, Cs.hwndParent);
2071 DPRINT("IntCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, Size.cx, Size.cy);
2072 DPRINT("IntCreateWindowEx(): About to send NCCREATE message.\n");
2073 Result = co_IntSendMessage(Window->hSelf, WM_NCCREATE, 0, (LPARAM) &Cs);
2074 if (!Result)
2075 {
2076 /* FIXME: Cleanup. */
2077 DPRINT1("IntCreateWindowEx(): NCCREATE message failed. No cleanup performed!\n");
2078 RETURN((PWND)0);
2079 }
2080
2081 /* Calculate the non-client size. */
2082 MaxPos.x = Window->Wnd->rcWindow.left;
2083 MaxPos.y = Window->Wnd->rcWindow.top;
2084
2085
2086 DPRINT("IntCreateWindowEx(): About to get non-client size.\n");
2087 /* WinPosGetNonClientSize SENDS THE WM_NCCALCSIZE message */
2088 Result = co_WinPosGetNonClientSize(Window,
2089 &Window->Wnd->rcWindow,
2090 &Window->Wnd->rcClient);
2091
2092 RECTL_vOffsetRect(&Window->Wnd->rcWindow,
2093 MaxPos.x - Window->Wnd->rcWindow.left,
2094 MaxPos.y - Window->Wnd->rcWindow.top);
2095
2096
2097 if (NULL != ParentWindow)
2098 {
2099 /* link the window into the parent's child list */
2100 if ((dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2101 {
2102 PWINDOW_OBJECT PrevSibling;
2103
2104 PrevSibling = ParentWindow->LastChild;
2105
2106 /* link window as bottom sibling */
2107 IntLinkWindow(Window, ParentWindow, PrevSibling /*prev sibling*/);
2108 }
2109 else
2110 {
2111 /* link window as top sibling (but after topmost siblings) */
2112 PWINDOW_OBJECT InsertAfter, Sibling;
2113 if (!(dwExStyle & WS_EX_TOPMOST))
2114 {
2115 InsertAfter = NULL;
2116 Sibling = ParentWindow->FirstChild;
2117 while (Sibling && (Sibling->Wnd->ExStyle & WS_EX_TOPMOST))
2118 {
2119 InsertAfter = Sibling;
2120 Sibling = Sibling->NextSibling;
2121 }
2122 }
2123 else
2124 {
2125 InsertAfter = NULL;
2126 }
2127
2128 IntLinkWindow(Window, ParentWindow, InsertAfter /* prev sibling */);
2129
2130 }
2131 }
2132
2133 /* Send the WM_CREATE message. */
2134 DPRINT("IntCreateWindowEx(): about to send CREATE message.\n");
2135 Result = co_IntSendMessage(Window->hSelf, WM_CREATE, 0, (LPARAM) &Cs);
2136
2137 if (Result == (LRESULT)-1)
2138 {
2139 /* FIXME: Cleanup. */
2140 DPRINT1("IntCreateWindowEx(): send CREATE message failed. No cleanup performed!\n");
2141 IntUnlinkWindow(Window);
2142 RETURN((PWND)0);
2143 }
2144
2145 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window->Wnd, OBJID_WINDOW, 0);
2146
2147 /* Send move and size messages. */
2148 if (!(Window->Flags & WINDOWOBJECT_NEED_SIZE))
2149 {
2150 LONG lParam;
2151
2152 DPRINT("IntCreateWindow(): About to send WM_SIZE\n");
2153
2154 if ((Window->Wnd->rcClient.right - Window->Wnd->rcClient.left) < 0 ||
2155 (Window->Wnd->rcClient.bottom - Window->Wnd->rcClient.top) < 0)
2156 {
2157 DPRINT("Sending bogus WM_SIZE\n");
2158 }
2159
2160 lParam = MAKE_LONG(Window->Wnd->rcClient.right -
2161 Window->Wnd->rcClient.left,
2162 Window->Wnd->rcClient.bottom -
2163 Window->Wnd->rcClient.top);
2164 co_IntSendMessage(Window->hSelf, WM_SIZE, SIZE_RESTORED,
2165 lParam);
2166
2167 DPRINT("IntCreateWindow(): About to send WM_MOVE\n");
2168
2169 if (0 != (Wnd->style & WS_CHILD) && ParentWindow)
2170 {
2171 lParam = MAKE_LONG(Wnd->rcClient.left - ParentWindow->Wnd->rcClient.left,
2172 Wnd->rcClient.top - ParentWindow->Wnd->rcClient.top);
2173 }
2174 else
2175 {
2176 lParam = MAKE_LONG(Wnd->rcClient.left,
2177 Wnd->rcClient.top);
2178 }
2179
2180 co_IntSendMessage(Window->hSelf, WM_MOVE, 0, lParam);
2181
2182 /* Call WNDOBJ change procs */
2183 IntEngWindowChanged(Window, WOC_RGN_CLIENT);
2184 }
2185
2186 /* Show or maybe minimize or maximize the window. */
2187 if (Wnd->style & (WS_MINIMIZE | WS_MAXIMIZE))
2188 {
2189 RECTL NewPos;
2190 UINT16 SwFlag;
2191
2192 SwFlag = (Wnd->style & WS_MINIMIZE) ? SW_MINIMIZE :
2193 SW_MAXIMIZE;
2194
2195 co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2196
2197 SwFlag = ((Wnd->style & WS_CHILD) || UserGetActiveWindow()) ?
2198 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED :
2199 SWP_NOZORDER | SWP_FRAMECHANGED;
2200
2201 DPRINT("IntCreateWindow(): About to minimize/maximize\n");
2202 DPRINT("%d,%d %dx%d\n", NewPos.left, NewPos.top, NewPos.right, NewPos.bottom);
2203 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2204 NewPos.right, NewPos.bottom, SwFlag);
2205 }
2206
2207 /* Notify the parent window of a new child. */
2208 if ((Wnd->style & WS_CHILD) &&
2209 (!(Wnd->ExStyle & WS_EX_NOPARENTNOTIFY)) && ParentWindow)
2210 {
2211 DPRINT("IntCreateWindow(): About to notify parent\n");
2212 co_IntSendMessage(ParentWindow->hSelf,
2213 WM_PARENTNOTIFY,
2214 MAKEWPARAM(WM_CREATE, Wnd->IDMenu),
2215 (LPARAM)Window->hSelf);
2216 }
2217
2218 if ((!hWndParent) && (!HasOwner))
2219 {
2220 DPRINT("Sending CREATED notify\n");
2221 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)hWnd);
2222 }
2223 else
2224 {
2225 DPRINT("Not sending CREATED notify, %x %d\n", ParentWindow, HasOwner);
2226 }
2227
2228 /* Initialize and show the window's scrollbars */
2229 if (Wnd->style & WS_VSCROLL)
2230 {
2231 co_UserShowScrollBar(Window, SB_VERT, TRUE);
2232 }
2233 if (Wnd->style & WS_HSCROLL)
2234 {
2235 co_UserShowScrollBar(Window, SB_HORZ, TRUE);
2236 }
2237
2238 if (dwStyle & WS_VISIBLE)
2239 {
2240 if (Wnd->style & WS_MAXIMIZE)
2241 dwShowMode = SW_SHOW;
2242 else if (Wnd->style & WS_MINIMIZE)
2243 dwShowMode = SW_SHOWMINIMIZED;
2244
2245 DPRINT("IntCreateWindow(): About to show window\n");
2246 co_WinPosShowWindow(Window, dwShowMode);
2247
2248 if (Wnd->ExStyle & WS_EX_MDICHILD)
2249 {
2250 co_IntSendMessage(ParentWindow->hSelf, WM_MDIREFRESHMENU, 0, 0);
2251 /* ShowWindow won't activate child windows */
2252 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2253 }
2254 }
2255
2256 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
2257 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
2258 Dont understand why it does this. */
2259 if (ClassAtom == gpsi->atomSysClass[ICLS_EDIT])
2260 {
2261 PCALLPROCDATA CallProc;
2262 //CallProc = CreateCallProc(NULL, Wnd->lpfnWndProc, bUnicodeWindow, Wnd->ti->ppi);
2263 CallProc = CreateCallProc(NULL, Wnd->lpfnWndProc, Wnd->Unicode , Wnd->head.pti->ppi);
2264
2265 if (!CallProc)
2266 {
2267 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2268 DPRINT1("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %x\n",hWnd);
2269 }
2270 else
2271 {
2272 UserAddCallProcToClass(Wnd->pcls, CallProc);
2273 Wnd->CallProc = CallProc;
2274 Wnd->IsSystem = FALSE;
2275 }
2276 }
2277
2278 DPRINT("IntCreateWindow(): = %X\n", hWnd);
2279 DPRINT("WindowObject->SystemMenu = 0x%x\n", Window->SystemMenu);
2280 RETURN( Wnd);
2281
2282 CLEANUP:
2283 if (!_ret_ && Window && Window->Wnd && ti)
2284 UserFreeWindowInfo(ti, Window);
2285 if (Window)
2286 {
2287 UserDerefObjectCo(Window);
2288 UserDereferenceObject(Window);
2289 }
2290 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2291 if (!_ret_ && ti != NULL)
2292 {
2293 if (Class != NULL)
2294 {
2295 IntDereferenceClass(Class,
2296 ti->pDeskInfo,
2297 ti->ppi);
2298 }
2299 }
2300 END_CLEANUP;
2301 }
2302
2303 HWND APIENTRY
2304 NtUserCreateWindowEx(DWORD dwExStyle,
2305 PUNICODE_STRING UnsafeClassName,
2306 PUNICODE_STRING UnsafeWindowName,
2307 DWORD dwStyle,
2308 LONG x,
2309 LONG y,
2310 LONG nWidth,
2311 LONG nHeight,
2312 HWND hWndParent,
2313 HMENU hMenu,
2314 HINSTANCE hInstance,
2315 LPVOID lpParam,
2316 DWORD dwShowMode,
2317 BOOL bUnicodeWindow,
2318 DWORD dwUnknown)
2319 {
2320 NTSTATUS Status;
2321 UNICODE_STRING WindowName;
2322 UNICODE_STRING ClassName;
2323 HWND NewWindow = NULL;
2324 PWND pNewWindow;
2325 DECLARE_RETURN(HWND);
2326
2327 DPRINT("Enter NtUserCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, nWidth, nHeight);
2328 UserEnterExclusive();
2329
2330 /* Get the class name (string or atom) */
2331 Status = MmCopyFromCaller(&ClassName, UnsafeClassName, sizeof(UNICODE_STRING));
2332 if (! NT_SUCCESS(Status))
2333 {
2334 SetLastNtError(Status);
2335 RETURN( NULL);
2336 }
2337 if (ClassName.Length != 0)
2338 {
2339 Status = IntSafeCopyUnicodeStringTerminateNULL(&ClassName, UnsafeClassName);
2340 if (! NT_SUCCESS(Status))
2341 {
2342 SetLastNtError(Status);
2343 RETURN( NULL);
2344 }
2345 }
2346 else if (! IS_ATOM(ClassName.Buffer))
2347 {
2348 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2349 RETURN(NULL);
2350 }
2351
2352 /* safely copy the window name */
2353 if (NULL != UnsafeWindowName)
2354 {
2355 Status = IntSafeCopyUnicodeString(&WindowName, UnsafeWindowName);
2356 if (! NT_SUCCESS(Status))
2357 {
2358 if (! IS_ATOM(ClassName.Buffer))
2359 {
2360 ExFreePoolWithTag(ClassName.Buffer, TAG_STRING);
2361 }
2362 SetLastNtError(Status);
2363 RETURN( NULL);
2364 }
2365 }
2366 else
2367 {
2368 RtlInitUnicodeString(&WindowName, NULL);
2369 }
2370
2371 pNewWindow = co_IntCreateWindowEx( dwExStyle,
2372 &ClassName,
2373 &WindowName,
2374 dwStyle,
2375 x,
2376 y,
2377 nWidth,
2378 nHeight,
2379 hWndParent,
2380 hMenu,
2381 hInstance,
2382 lpParam,
2383 dwShowMode,
2384 bUnicodeWindow);
2385
2386 if (pNewWindow) NewWindow = UserHMGetHandle(pNewWindow);
2387
2388 if (WindowName.Buffer)
2389 {
2390 ExFreePoolWithTag(WindowName.Buffer, TAG_STRING);
2391 }
2392 if (! IS_ATOM(ClassName.Buffer))
2393 {
2394 ExFreePoolWithTag(ClassName.Buffer, TAG_STRING);
2395 }
2396
2397 RETURN( NewWindow);
2398
2399 CLEANUP:
2400 DPRINT("Leave NtUserCreateWindowEx, ret=%i\n",_ret_);
2401 UserLeave();
2402 END_CLEANUP;
2403 }
2404
2405 /*
2406 * @unimplemented
2407 */
2408 HDWP APIENTRY
2409 NtUserDeferWindowPos(HDWP WinPosInfo,
2410 HWND Wnd,
2411 HWND WndInsertAfter,
2412 int x,
2413 int y,
2414 int cx,
2415 int cy,
2416 UINT Flags)
2417 {
2418 UNIMPLEMENTED
2419
2420 return 0;
2421 }
2422
2423
2424 BOOLEAN FASTCALL co_UserDestroyWindow(PWINDOW_OBJECT Window)
2425 {
2426 BOOLEAN isChild;
2427 PWND Wnd;
2428 HWND hWnd;
2429
2430 ASSERT_REFS_CO(Window); // FIXME: temp hack?
2431
2432 hWnd = Window->hSelf;
2433
2434 Wnd = Window->Wnd;
2435
2436 if (!Wnd) return TRUE; // FIXME: Need to finish object rewrite or lock the thread when killing the window!
2437
2438 /* Check for owner thread */
2439 if ((Window->OwnerThread != PsGetCurrentThread()))
2440 {
2441 SetLastWin32Error(ERROR_ACCESS_DENIED);
2442 return FALSE;
2443 }
2444
2445 /* Call hooks */
2446 if (ISITHOOKED(WH_CBT))
2447 {
2448 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0)) return FALSE;
2449 }
2450
2451 /* Look whether the focus is within the tree of windows we will
2452 * be destroying.
2453 */
2454 if (!co_WinPosShowWindow(Window, SW_HIDE))
2455 {
2456 if (UserGetActiveWindow() == Window->hSelf)
2457 {
2458 co_WinPosActivateOtherWindow(Window);
2459 }
2460 }
2461
2462 if (Window->MessageQueue->ActiveWindow == Window->hSelf)
2463 Window->MessageQueue->ActiveWindow = NULL;
2464 if (Window->MessageQueue->FocusWindow == Window->hSelf)
2465 Window->MessageQueue->FocusWindow = NULL;
2466 if (Window->MessageQueue->CaptureWindow == Window->hSelf)
2467 Window->MessageQueue->CaptureWindow = NULL;
2468
2469 IntDereferenceMessageQueue(Window->MessageQueue);
2470
2471 IntEngWindowChanged(Window, WOC_DELETE);
2472 isChild = (0 != (Wnd->style & WS_CHILD));
2473
2474 #if 0 /* FIXME */
2475
2476 if (isChild)
2477 {
2478 if (! USER_IsExitingThread(GetCurrentThreadId()))
2479 {
2480 send_parent_notify(hwnd, WM_DESTROY);
2481 }
2482 }
2483 else if (NULL != GetWindow(Wnd, GW_OWNER))
2484 {
2485 co_HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
2486 /* FIXME: clean up palette - see "Internals" p.352 */
2487 }
2488 #endif
2489
2490 if (!IntIsWindow(Window->hSelf))
2491 {
2492 return TRUE;
2493 }
2494
2495 /* Recursively destroy owned windows */
2496 if (! isChild)
2497 {
2498 for (;;)
2499 {
2500 BOOL GotOne = FALSE;
2501 HWND *Children;
2502 HWND *ChildHandle;
2503 PWINDOW_OBJECT Child, Desktop;
2504
2505 Desktop = IntIsDesktopWindow(Window) ? Window :
2506 UserGetWindowObject(IntGetDesktopWindow());
2507 Children = IntWinListChildren(Desktop);
2508
2509 if (Children)
2510 {
2511 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2512 {
2513 Child = UserGetWindowObject(*ChildHandle);
2514 if (Child == NULL)
2515 continue;
2516 if (Child->hOwner != Window->hSelf)
2517 {
2518 continue;
2519 }
2520
2521 if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
2522 {
2523 USER_REFERENCE_ENTRY ChildRef;
2524 UserRefObjectCo(Child, &ChildRef);//temp hack?
2525 co_UserDestroyWindow(Child);
2526 UserDerefObjectCo(Child);//temp hack?
2527
2528 GotOne = TRUE;
2529 continue;
2530 }
2531
2532 if (Child->hOwner != NULL)
2533 {
2534 Child->hOwner = NULL;
2535 Child->Wnd->spwndOwner = NULL;
2536 }
2537
2538 }
2539 ExFreePool(Children);
2540 }
2541 if (! GotOne)
2542 {
2543 break;
2544 }
2545 }
2546 }
2547
2548 if (!IntIsWindow(Window->hSelf))
2549 {
2550 return TRUE;
2551 }
2552
2553 /* Destroy the window storage */
2554 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2555
2556 return TRUE;
2557 }
2558
2559
2560
2561
2562 /*
2563 * @implemented
2564 */
2565 BOOLEAN APIENTRY
2566 NtUserDestroyWindow(HWND Wnd)
2567 {
2568 PWINDOW_OBJECT Window;
2569 DECLARE_RETURN(BOOLEAN);
2570 BOOLEAN ret;
2571 USER_REFERENCE_ENTRY Ref;
2572
2573 DPRINT("Enter NtUserDestroyWindow\n");
2574 UserEnterExclusive();
2575
2576 if (!(Window = UserGetWindowObject(Wnd)))
2577 {
2578 RETURN(FALSE);
2579 }
2580
2581 UserRefObjectCo(Window, &Ref);//faxme: dunno if win should be reffed during destroy..
2582 ret = co_UserDestroyWindow(Window);
2583 UserDerefObjectCo(Window);//faxme: dunno if win should be reffed during destroy..
2584
2585 RETURN(ret);
2586
2587 CLEANUP:
2588 DPRINT("Leave NtUserDestroyWindow, ret=%i\n",_ret_);
2589 UserLeave();
2590 END_CLEANUP;
2591 }
2592
2593
2594
2595 /*
2596 * @unimplemented
2597 */
2598 DWORD
2599 APIENTRY
2600 NtUserDrawMenuBarTemp(
2601 HWND hWnd,
2602 HDC hDC,
2603 PRECT hRect,
2604 HMENU hMenu,
2605 HFONT hFont)
2606 {
2607 /* we'll use this function just for caching the menu bar */
2608 UNIMPLEMENTED
2609 return 0;
2610 }
2611
2612
2613 /*
2614 * @unimplemented
2615 */
2616 DWORD APIENTRY
2617 NtUserEndDeferWindowPosEx(DWORD Unknown0,
2618 DWORD Unknown1)
2619 {
2620 UNIMPLEMENTED
2621
2622 return 0;
2623 }
2624
2625
2626 /*
2627 * FillWindow: Called from User; Dialog, Edit and ListBox procs during a WM_ERASEBKGND.
2628 */
2629 /*
2630 * @unimplemented
2631 */
2632 BOOL APIENTRY
2633 NtUserFillWindow(HWND hWndPaint,
2634 HWND hWndPaint1,
2635 HDC hDC,
2636 HBRUSH hBrush)
2637 {
2638 UNIMPLEMENTED
2639
2640 return 0;
2641 }
2642
2643
2644 static HWND FASTCALL
2645 IntFindWindow(PWINDOW_OBJECT Parent,
2646 PWINDOW_OBJECT ChildAfter,
2647 RTL_ATOM ClassAtom,
2648 PUNICODE_STRING WindowName)
2649 {
2650 BOOL CheckWindowName;
2651 HWND *List, *phWnd;
2652 HWND Ret = NULL;
2653
2654 ASSERT(Parent);
2655
2656 CheckWindowName = WindowName->Length != 0;
2657
2658 if((List = IntWinListChildren(Parent)))
2659 {
2660 phWnd = List;
2661 if(ChildAfter)
2662 {
2663 /* skip handles before and including ChildAfter */
2664 while(*phWnd && (*(phWnd++) != ChildAfter->hSelf))
2665 ;
2666 }
2667
2668 /* search children */
2669 while(*phWnd)
2670 {
2671 PWINDOW_OBJECT Child;
2672 if(!(Child = UserGetWindowObject(*(phWnd++))))
2673 {
2674 continue;
2675 }
2676
2677 /* Do not send WM_GETTEXT messages in the kernel mode version!
2678 The user mode version however calls GetWindowText() which will
2679 send WM_GETTEXT messages to windows belonging to its processes */
2680 if((!CheckWindowName || !RtlCompareUnicodeString(WindowName, &(Child->Wnd->strName), TRUE)) &&
2681 (!ClassAtom || Child->Wnd->pcls->atomClassName == ClassAtom))
2682 {
2683 Ret = Child->hSelf;
2684 break;
2685 }
2686
2687 }
2688 ExFreePool(List);
2689 }
2690
2691 return Ret;
2692 }
2693
2694 /*
2695 * FUNCTION:
2696 * Searches a window's children for a window with the specified
2697 * class and name
2698 * ARGUMENTS:
2699 * hwndParent = The window whose childs are to be searched.
2700 * NULL = desktop
2701 * HWND_MESSAGE = message-only windows
2702 *
2703 * hwndChildAfter = Search starts after this child window.
2704 * NULL = start from beginning
2705 *
2706 * ucClassName = Class name to search for
2707 * Reguired parameter.
2708 *
2709 * ucWindowName = Window name
2710 * ->Buffer == NULL = don't care
2711 *
2712 * RETURNS:
2713 * The HWND of the window if it was found, otherwise NULL
2714 */
2715 /*
2716 * @implemented
2717 */
2718 HWND APIENTRY
2719 NtUserFindWindowEx(HWND hwndParent,
2720 HWND hwndChildAfter,
2721 PUNICODE_STRING ucClassName,
2722 PUNICODE_STRING ucWindowName,
2723 DWORD dwUnknown)
2724 {
2725 PWINDOW_OBJECT Parent, ChildAfter;
2726 UNICODE_STRING ClassName = {0}, WindowName = {0};
2727 HWND Desktop, Ret = NULL;
2728 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2729 DECLARE_RETURN(HWND);
2730
2731 DPRINT("Enter NtUserFindWindowEx\n");
2732 UserEnterShared();
2733
2734 if (ucClassName != NULL || ucWindowName != NULL)
2735 {
2736 _SEH2_TRY
2737 {
2738 if (ucClassName != NULL)
2739 {
2740 ClassName = ProbeForReadUnicodeString(ucClassName);
2741 if (ClassName.Length != 0)
2742 {
2743 ProbeForRead(ClassName.Buffer,
2744 ClassName.Length,
2745 sizeof(WCHAR));
2746 }
2747 else if (!IS_ATOM(ClassName.Buffer))
2748 {
2749 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2750 _SEH2_LEAVE;
2751 }
2752
2753 if (!IntGetAtomFromStringOrAtom(&ClassName,
2754 &ClassAtom))
2755 {
2756 _SEH2_LEAVE;
2757 }
2758 }
2759
2760 if (ucWindowName != NULL)
2761 {
2762 WindowName = ProbeForReadUnicodeString(ucWindowName);
2763 if (WindowName.Length != 0)
2764 {
2765 ProbeForRead(WindowName.Buffer,
2766 WindowName.Length,
2767 sizeof(WCHAR));
2768 }
2769 }
2770 }
2771 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2772 {
2773 SetLastNtError(_SEH2_GetExceptionCode());
2774 _SEH2_YIELD(RETURN(NULL));
2775 }
2776 _SEH2_END;
2777
2778 if (ucClassName != NULL)
2779 {
2780 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
2781 !IS_ATOM(ClassName.Buffer))
2782 {
2783 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2784 RETURN(NULL);
2785 }
2786 else if (ClassAtom == (RTL_ATOM)0)
2787 {
2788 /* LastError code was set by IntGetAtomFromStringOrAtom */
2789 RETURN(NULL);
2790 }
2791 }
2792 }
2793
2794 Desktop = IntGetCurrentThreadDesktopWindow();
2795
2796 if(hwndParent == NULL)
2797 hwndParent = Desktop;
2798 else if(hwndParent == HWND_MESSAGE)
2799 {
2800 hwndParent = IntGetMessageWindow();
2801 }
2802
2803 if(!(Parent = UserGetWindowObject(hwndParent)))
2804 {
2805 RETURN( NULL);
2806 }
2807
2808 ChildAfter = NULL;
2809 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
2810 {
2811 RETURN( NULL);
2812 }
2813
2814 _SEH2_TRY
2815 {
2816 if(Parent->hSelf == Desktop)
2817 {
2818 HWND *List, *phWnd;
2819 PWINDOW_OBJECT TopLevelWindow;
2820 BOOLEAN CheckWindowName;
2821 BOOLEAN WindowMatches;
2822 BOOLEAN ClassMatches;
2823
2824 /* windows searches through all top-level windows if the parent is the desktop
2825 window */
2826
2827 if((List = IntWinListChildren(Parent)))
2828 {
2829 phWnd = List;
2830
2831 if(ChildAfter)
2832 {
2833 /* skip handles before and including ChildAfter */
2834 while(*phWnd && (*(phWnd++) != ChildAfter->hSelf))
2835 ;
2836 }
2837
2838 CheckWindowName = WindowName.Length != 0;
2839
2840 /* search children */
2841 while(*phWnd)
2842 {
2843 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
2844 {
2845 continue;
2846 }
2847
2848 /* Do not send WM_GETTEXT messages in the kernel mode version!
2849 The user mode version however calls GetWindowText() which will
2850 send WM_GETTEXT messages to windows belonging to its processes */
2851 WindowMatches = !CheckWindowName || !RtlCompareUnicodeString(
2852 &WindowName, &TopLevelWindow->Wnd->strName, TRUE);
2853 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
2854 ClassAtom == TopLevelWindow->Wnd->pcls->atomClassName;
2855
2856 if (WindowMatches && ClassMatches)
2857 {
2858 Ret = TopLevelWindow->hSelf;
2859 break;
2860 }
2861
2862 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
2863 {
2864 /* window returns the handle of the top-level window, in case it found
2865 the child window */
2866 Ret = TopLevelWindow->hSelf;
2867 break;
2868 }
2869
2870 }
2871 ExFreePool(List);
2872 }
2873 }
2874 else
2875 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
2876
2877 #if 0
2878
2879 if(Ret == NULL && hwndParent == NULL && hwndChildAfter == NULL)
2880 {
2881 /* FIXME - if both hwndParent and hwndChildAfter are NULL, we also should
2882 search the message-only windows. Should this also be done if
2883 Parent is the desktop window??? */
2884 PWINDOW_OBJECT MsgWindows;
2885
2886 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
2887 {
2888 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
2889 }
2890 }
2891 #endif
2892 }
2893 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2894 {
2895 SetLastNtError(_SEH2_GetExceptionCode());
2896 Ret = NULL;
2897 }
2898 _SEH2_END;
2899
2900 RETURN( Ret);
2901
2902 CLEANUP:
2903 DPRINT("Leave NtUserFindWindowEx, ret %i\n",_ret_);
2904 UserLeave();
2905 END_CLEANUP;
2906 }
2907
2908
2909 /*
2910 * @unimplemented
2911 */
2912 BOOL APIENTRY
2913 NtUserFlashWindowEx(IN PFLASHWINFO pfwi)
2914 {
2915 UNIMPLEMENTED
2916
2917 return 0;
2918 }
2919
2920
2921 /*
2922 * @implemented
2923 */
2924 PWINDOW_OBJECT FASTCALL UserGetAncestor(PWINDOW_OBJECT Wnd, UINT Type)
2925 {
2926 PWINDOW_OBJECT WndAncestor, Parent;
2927
2928 if (Wnd->hSelf == IntGetDesktopWindow())
2929 {
2930 return NULL;
2931 }
2932
2933 switch (Type)
2934 {
2935 case GA_PARENT:
2936 {
2937 WndAncestor = Wnd->Parent;
2938 break;
2939 }
2940
2941 case GA_ROOT:
2942 {
2943 WndAncestor = Wnd;
2944 Parent = NULL;
2945
2946 for(;;)
2947 {
2948 if(!(Parent = WndAncestor->Parent))
2949 {
2950 break;
2951 }
2952 if(IntIsDesktopWindow(Parent))
2953 {
2954 break;
2955 }
2956
2957 WndAncestor = Parent;
2958 }
2959 break;
2960 }
2961
2962 case GA_ROOTOWNER:
2963 {
2964 WndAncestor = Wnd;
2965
2966 for (;;)
2967 {
2968 PWINDOW_OBJECT Parent, Old;
2969
2970 Old = WndAncestor;
2971 Parent = IntGetParent(WndAncestor);
2972
2973 if (!Parent)
2974 {
2975 break;
2976 }
2977
2978 //temp hack
2979 // UserDereferenceObject(Parent);
2980
2981 WndAncestor = Parent;
2982 }
2983 break;
2984 }
2985
2986 default:
2987 {
2988 return NULL;
2989 }
2990 }
2991
2992 return WndAncestor;
2993 }
2994
2995
2996
2997 /*
2998 * @implemented
2999 */
3000 HWND APIENTRY
3001 NtUserGetAncestor(HWND hWnd, UINT Type)
3002 {
3003 PWINDOW_OBJECT Window, Ancestor;
3004 DECLARE_RETURN(HWND);
3005
3006 DPRINT("Enter NtUserGetAncestor\n");
3007 UserEnterExclusive();
3008
3009 if (!(Window = UserGetWindowObject(hWnd)))
3010 {
3011 RETURN(NULL);
3012 }
3013
3014 Ancestor = UserGetAncestor(Window, Type);
3015 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3016
3017 RETURN(Ancestor ? Ancestor->hSelf : NULL);
3018
3019 CLEANUP:
3020 DPRINT("Leave NtUserGetAncestor, ret=%i\n",_ret_);
3021 UserLeave();
3022 END_CLEANUP;
3023 }
3024
3025
3026 BOOL
3027 APIENTRY
3028 NtUserGetComboBoxInfo(
3029 HWND hWnd,
3030 PCOMBOBOXINFO pcbi)
3031 {
3032 PWINDOW_OBJECT Wnd;
3033 DECLARE_RETURN(BOOL);
3034
3035 DPRINT("Enter NtUserGetComboBoxInfo\n");
3036 UserEnterShared();
3037
3038 if (!(Wnd = UserGetWindowObject(hWnd)))
3039 {
3040 RETURN( FALSE );
3041 }
3042 _SEH2_TRY
3043 {
3044 if(pcbi)
3045 {
3046 ProbeForWrite(pcbi,
3047 sizeof(COMBOBOXINFO),
3048 1);
3049 }
3050 }
3051 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3052 {
3053 SetLastNtError(_SEH2_GetExceptionCode());
3054 _SEH2_YIELD(RETURN(FALSE));
3055 }
3056 _SEH2_END;
3057
3058 // Pass the user pointer, it was already probed.
3059 RETURN( (BOOL) co_IntSendMessage( Wnd->hSelf, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3060
3061 CLEANUP:
3062 DPRINT("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3063 UserLeave();
3064 END_CLEANUP;
3065 }
3066
3067
3068 /*
3069 * @implemented
3070 */
3071 DWORD APIENTRY
3072 NtUserGetInternalWindowPos( HWND hWnd,
3073 LPRECT rectWnd,
3074 LPPOINT ptIcon)
3075 {
3076 PWINDOW_OBJECT Window;
3077 PWND Wnd;
3078 DWORD Ret = 0;
3079 BOOL Hit = FALSE;
3080 WINDOWPLACEMENT wndpl;
3081
3082 UserEnterShared();
3083
3084 if (!(Window = UserGetWindowObject(hWnd)) || !Window->Wnd)
3085 {
3086 Hit = FALSE;
3087 goto Exit;
3088 }
3089 Wnd = Window->Wnd;
3090
3091 _SEH2_TRY
3092 {
3093 if(rectWnd)
3094 {
3095 ProbeForWrite(rectWnd,
3096 sizeof(RECT),
3097 1);
3098 }
3099 if(ptIcon)
3100 {
3101 ProbeForWrite(ptIcon,
3102 sizeof(POINT),
3103 1);
3104 }
3105
3106 }
3107 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3108 {
3109 SetLastNtError(_SEH2_GetExceptionCode());
3110 Hit = TRUE;
3111 }
3112 _SEH2_END;
3113
3114 wndpl.length = sizeof(WINDOWPLACEMENT);
3115
3116 if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
3117 {
3118 _SEH2_TRY
3119 {
3120 if (rectWnd)
3121 {
3122 RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));
3123 }
3124 if (ptIcon)
3125 {
3126 RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT));
3127 }
3128
3129 }
3130 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3131 {
3132 SetLastNtError(_SEH2_GetExceptionCode());
3133 Hit = TRUE;
3134 }
3135 _SEH2_END;
3136
3137 if (!Hit) Ret = wndpl.showCmd;
3138 }
3139 Exit:
3140 UserLeave();
3141 return Ret;
3142 }
3143
3144 DWORD
3145 APIENTRY
3146 NtUserGetListBoxInfo(
3147 HWND hWnd)
3148 {
3149 PWINDOW_OBJECT Wnd;
3150 DECLARE_RETURN(DWORD);
3151
3152 DPRINT("Enter NtUserGetListBoxInfo\n");
3153 UserEnterShared();
3154
3155 if (!(Wnd = UserGetWindowObject(hWnd)))
3156 {
3157 RETURN( 0 );
3158 }
3159
3160 RETURN( (DWORD) co_IntSendMessage( Wnd->hSelf, LB_GETLISTBOXINFO, 0, 0 ));
3161
3162 CLEANUP:
3163 DPRINT("Leave NtUserGetListBoxInfo, ret=%i\n",_ret_);
3164 UserLeave();
3165 END_CLEANUP;
3166 }
3167
3168
3169 HWND FASTCALL
3170 co_UserSetParent(HWND hWndChild, HWND hWndNewParent)
3171 {
3172 PWINDOW_OBJECT Wnd = NULL, WndParent = NULL, WndOldParent;
3173 HWND hWndOldParent = NULL;
3174 USER_REFERENCE_ENTRY Ref, ParentRef;
3175
3176 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
3177 {
3178 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3179 return( NULL);
3180 }
3181
3182 if (hWndChild == IntGetDesktopWindow())
3183 {
3184 SetLastWin32Error(ERROR_ACCESS_DENIED);
3185 return( NULL);
3186 }
3187
3188 if (hWndNewParent)
3189 {
3190 if (!(WndParent = UserGetWindowObject(hWndNewParent)))
3191 {
3192 return( NULL);
3193 }
3194 }
3195 else
3196 {
3197 if (!(WndParent = UserGetWindowObject(IntGetDesktopWindow())))
3198 {
3199 return( NULL);
3200 }
3201 }
3202
3203 if (!(Wnd = UserGetWindowObject(hWndChild)))
3204 {
3205 return( NULL);
3206 }
3207
3208 UserRefObjectCo(Wnd, &Ref);
3209 UserRefObjectCo(WndParent, &ParentRef);
3210
3211 WndOldParent = co_IntSetParent(Wnd, WndParent);
3212
3213 UserDerefObjectCo(WndParent);
3214 UserDerefObjectCo(Wnd);
3215
3216 if (WndOldParent)
3217 {
3218 hWndOldParent = WndOldParent->hSelf;
3219 UserDereferenceObject(WndOldParent);
3220 }
3221
3222 return( hWndOldParent);
3223 }
3224
3225
3226
3227 /*
3228 * NtUserSetParent
3229 *
3230 * The NtUserSetParent function changes the parent window of the specified
3231 * child window.
3232 *
3233 * Remarks
3234 * The new parent window and the child window must belong to the same
3235 * application. If the window identified by the hWndChild parameter is
3236 * visible, the system performs the appropriate redrawing and repainting.
3237 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3238 * or WS_POPUP window styles of the window whose parent is being changed.
3239 *
3240 * Status
3241 * @implemented
3242 */
3243
3244 HWND APIENTRY
3245 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3246 {
3247 DECLARE_RETURN(HWND);
3248
3249 DPRINT("Enter NtUserSetParent\n");
3250 UserEnterExclusive();
3251
3252 /*
3253 Check Parent first from user space, set it here.
3254 */
3255 if (!hWndNewParent)
3256 {
3257 hWndNewParent = IntGetDesktopWindow();
3258 }
3259 else if (hWndNewParent == HWND_MESSAGE)
3260 {
3261 hWndNewParent = IntGetMessageWindow();
3262 }
3263
3264 RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3265
3266 CLEANUP:
3267 DPRINT("Leave NtUserSetParent, ret=%i\n",_ret_);
3268 UserLeave();
3269 END_CLEANUP;
3270 }
3271
3272
3273
3274 /*
3275 * UserGetShellWindow
3276 *
3277 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3278 *
3279 * Status
3280 * @implemented
3281 */
3282 HWND FASTCALL UserGetShellWindow(VOID)
3283 {
3284 PWINSTATION_OBJECT WinStaObject;
3285 HWND Ret;
3286
3287 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3288 KernelMode,
3289 0,
3290 &WinStaObject);
3291
3292 if (!NT_SUCCESS(Status))
3293 {
3294 SetLastNtError(Status);
3295 return( (HWND)0);
3296 }
3297
3298 Ret = (HWND)WinStaObject->ShellWindow;
3299
3300 ObDereferenceObject(WinStaObject);
3301 return( Ret);
3302 }
3303
3304 /*
3305 * NtUserSetShellWindowEx
3306 *
3307 * This is undocumented function to set global shell window. The global
3308 * shell window has special handling of window position.
3309 *
3310 * Status
3311 * @implemented
3312 */
3313 BOOL APIENTRY
3314 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3315 {
3316 PWINSTATION_OBJECT WinStaObject;
3317 PWINDOW_OBJECT WndShell;
3318 DECLARE_RETURN(BOOL);
3319 USER_REFERENCE_ENTRY Ref;
3320 NTSTATUS Status;
3321 PTHREADINFO ti;
3322
3323 DPRINT("Enter NtUserSetShellWindowEx\n");
3324 UserEnterExclusive();
3325
3326 if (!(WndShell = UserGetWindowObject(hwndShell)))
3327 {
3328 RETURN(FALSE);
3329 }
3330
3331 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3332 KernelMode,
3333 0,
3334 &WinStaObject);
3335
3336 if (!NT_SUCCESS(Status))
3337 {
3338 SetLastNtError(Status);
3339 RETURN( FALSE);
3340 }
3341
3342 /*
3343 * Test if we are permitted to change the shell window.
3344 */
3345 if (WinStaObject->ShellWindow)
3346 {
3347 ObDereferenceObject(WinStaObject);
3348 RETURN( FALSE);
3349 }
3350
3351 /*
3352 * Move shell window into background.
3353 */
3354 if (hwndListView && hwndListView != hwndShell)
3355 {
3356 /*
3357 * Disabled for now to get Explorer working.
3358 * -- Filip, 01/nov/2003
3359 */
3360 #if 0
3361 co_WinPosSetWindowPos(hwndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3362 #endif
3363
3364 if (UserGetWindowLong(hwndListView, GWL_EXSTYLE, FALSE) & WS_EX_TOPMOST)
3365 {
3366 ObDereferenceObject(WinStaObject);
3367 RETURN( FALSE);
3368 }
3369 }
3370
3371 if (UserGetWindowLong(hwndShell, GWL_EXSTYLE, FALSE) & WS_EX_TOPMOST)
3372 {
3373 ObDereferenceObject(WinStaObject);
3374 RETURN( FALSE);
3375 }
3376
3377 UserRefObjectCo(WndShell, &Ref);
3378 co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3379
3380 WinStaObject->ShellWindow = hwndShell;
3381 WinStaObject->ShellListView = hwndListView;
3382
3383 ti = GetW32ThreadInfo();
3384 if (ti->pDeskInfo) ti->pDeskInfo->hShellWindow = hwndShell;
3385
3386 UserDerefObjectCo(WndShell);
3387
3388 ObDereferenceObject(WinStaObject);
3389 RETURN( TRUE);
3390
3391 CLEANUP:
3392 DPRINT("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3393 UserLeave();
3394 END_CLEANUP;
3395 }
3396
3397 /*
3398 * NtUserGetSystemMenu
3399 *
3400 * The NtUserGetSystemMenu function allows the application to access the
3401 * window menu (also known as the system menu or the control menu) for
3402 * copying and modifying.
3403 *
3404 * Parameters
3405 * hWnd
3406 * Handle to the window that will own a copy of the window menu.
3407 * bRevert
3408 * Specifies the action to be taken. If this parameter is FALSE,
3409 * NtUserGetSystemMenu returns a handle to the copy of the window menu
3410 * currently in use. The copy is initially identical to the window menu
3411 * but it can be modified.
3412 * If this parameter is TRUE, GetSystemMenu resets the window menu back
3413 * to the default state. The previous window menu, if any, is destroyed.
3414 *
3415 * Return Value
3416 * If the bRevert parameter is FALSE, the return value is a handle to a
3417 * copy of the window menu. If the bRevert parameter is TRUE, the return
3418 * value is NULL.
3419 *
3420 * Status
3421 * @implemented
3422 */
3423
3424 HMENU APIENTRY
3425 NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
3426 {
3427 PWINDOW_OBJECT Window;
3428 PMENU_OBJECT Menu;
3429 DECLARE_RETURN(HMENU);
3430
3431 DPRINT("Enter NtUserGetSystemMenu\n");
3432 UserEnterShared();
3433
3434 if (!(Window = UserGetWindowObject(hWnd)))
3435 {
3436 RETURN(NULL);
3437 }
3438
3439 if (!(Menu = IntGetSystemMenu(Window, bRevert, FALSE)))
3440 {
3441 RETURN(NULL);
3442 }
3443
3444 RETURN(Menu->MenuInfo.Self);
3445
3446 CLEANUP:
3447 DPRINT("Leave NtUserGetSystemMenu, ret=%i\n",_ret_);
3448 UserLeave();
3449 END_CLEANUP;
3450 }
3451
3452 /*
3453 * NtUserSetSystemMenu
3454 *
3455 * Status
3456 * @implemented
3457 */
3458
3459 BOOL APIENTRY
3460 NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
3461 {
3462 BOOL Result = FALSE;
3463 PWINDOW_OBJECT Window;
3464 PMENU_OBJECT Menu;
3465 DECLARE_RETURN(BOOL);
3466
3467 DPRINT("Enter NtUserSetSystemMenu\n");
3468 UserEnterExclusive();
3469
3470 if (!(Window = UserGetWindowObject(hWnd)))
3471 {
3472 RETURN( FALSE);
3473 }
3474
3475 if (hMenu)
3476 {
3477 /*
3478 * Assign new menu handle.
3479 */
3480 if (!(Menu = UserGetMenuObject(hMenu)))
3481 {
3482 RETURN( FALSE);
3483 }
3484
3485 Result = IntSetSystemMenu(Window, Menu);
3486 }
3487
3488 RETURN( Result);
3489
3490 CLEANUP:
3491 DPRINT("Leave NtUserSetSystemMenu, ret=%i\n",_ret_);
3492 UserLeave();
3493 END_CLEANUP;
3494 }
3495
3496
3497
3498
3499 HWND FASTCALL
3500 UserGetWindow(HWND hWnd, UINT Relationship)
3501 {
3502 PWINDOW_OBJECT Parent, Window;
3503 HWND hWndResult = NULL;
3504
3505 if (!(Window = UserGetWindowObject(hWnd)))
3506 return NULL;
3507
3508 switch (Relationship)
3509 {
3510 case GW_HWNDFIRST:
3511 if((Parent = Window->Parent))
3512 {
3513 if (Parent->FirstChild)
3514 hWndResult = Parent->FirstChild->hSelf;
3515 }
3516 break;
3517
3518 case GW_HWNDLAST:
3519 if((Parent = Window->Parent))
3520 {
3521 if (Parent->LastChild)
3522 hWndResult = Parent->LastChild->hSelf;
3523 }
3524 break;
3525
3526 case GW_HWNDNEXT:
3527 if (Window->NextSibling)
3528 hWndResult = Window->NextSibling->hSelf;
3529 break;
3530
3531 case GW_HWNDPREV:
3532 if (Window->PrevSibling)
3533 hWndResult = Window->PrevSibling->hSelf;
3534 break;
3535
3536 case GW_OWNER:
3537 if((Parent = UserGetWindowObject(Window->hOwner)))
3538 {
3539 hWndResult = Parent->hSelf;
3540 }
3541 break;
3542 case GW_CHILD:
3543 if (Window->FirstChild)
3544 hWndResult = Window->FirstChild->hSelf;
3545 break;
3546 }
3547
3548 return hWndResult;
3549 }
3550
3551
3552
3553 /*
3554 * NtUserGetWindow
3555 *
3556 * The NtUserGetWindow function retrieves a handle to a window that has the
3557 * specified relationship (Z order or owner) to the specified window.
3558 *
3559 * Status
3560 * @implemented
3561 */
3562
3563 HWND APIENTRY
3564 NtUserGetWindow(HWND hWnd, UINT Relationship)
3565 {
3566 DECLARE_RETURN(HWND);
3567
3568 DPRINT("Enter NtUserGetWindow\n");
3569 UserEnterShared();
3570
3571 RETURN(UserGetWindow(hWnd, Relationship));
3572
3573 CLEANUP:
3574 DPRINT("Leave NtUserGetWindow, ret=%i\n",_ret_);
3575 UserLeave();
3576 END_CLEANUP;
3577 }
3578
3579
3580
3581
3582 /*
3583 * NtUserGetWindowLong
3584 *
3585 * The NtUserGetWindowLong function retrieves information about the specified
3586 * window. The function also retrieves the 32-bit (long) value at the
3587 * specified offset into the extra window memory.
3588 *
3589 * Status
3590 * @implemented
3591 */
3592
3593 LONG FASTCALL
3594 UserGetWindowLong(HWND hWnd, DWORD Index, BOOL Ansi)
3595 {
3596 PWINDOW_OBJECT Window, Parent;
3597 PWND Wnd;
3598 LONG Result = 0;
3599
3600 DPRINT("NtUserGetWindowLong(%x,%d,%d)\n", hWnd, (INT)Index, Ansi);
3601
3602 if (!(Window = UserGetWindowObject(hWnd)) || !Window->Wnd)
3603 {
3604 return 0;
3605 }
3606
3607 Wnd = Window->Wnd;
3608
3609 /*
3610 * WndProc is only available to the owner process
3611 */
3612 if (GWL_WNDPROC == Index
3613 && Window->OwnerThread->ThreadsProcess != PsGetCurrentProcess())
3614 {
3615 SetLastWin32Error(ERROR_ACCESS_DENIED);
3616 return 0;
3617 }
3618
3619 if ((INT)Index >= 0)
3620 {
3621 if ((Index + sizeof(LONG)) > Window->Wnd->cbwndExtra)
3622 {
3623 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3624 return 0;
3625 }
3626 Result = *((LONG *)((PCHAR)(Window->Wnd + 1) + Index));
3627 }
3628 else
3629 {
3630 switch (Index)
3631 {
3632 case GWL_EXSTYLE:
3633 Result = Wnd->ExStyle;
3634 break;
3635
3636 case GWL_STYLE:
3637 Result = Wnd->style;
3638 break;
3639
3640 case GWL_WNDPROC:
3641 Result = (LONG)IntGetWindowProc(Window,
3642 Ansi);
3643 break;
3644
3645 case GWL_HINSTANCE:
3646 Result = (LONG) Wnd->hModule;
3647 break;
3648
3649 case GWL_HWNDPARENT:
3650 Parent = Window->Parent;
3651 if(Parent)
3652 {
3653 if (Parent && Parent->hSelf == IntGetDesktopWindow())
3654 Result = (LONG) UserGetWindow(Window->hSelf, GW_OWNER);
3655 else
3656 Result = (LONG) Parent->hSelf;
3657 }
3658 break;
3659
3660 case GWL_ID:
3661 Result = (LONG) Wnd->IDMenu;
3662 break;
3663
3664 case GWL_USERDATA:
3665 Result = Wnd->dwUserData;
3666 break;
3667
3668 default:
3669 DPRINT1("NtUserGetWindowLong(): Unsupported index %d\n", Index);
3670 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3671 Result = 0;
3672 break;
3673 }
3674 }
3675
3676 return Result;
3677 }
3678
3679
3680
3681
3682 /*
3683 * NtUserGetWindowLong
3684 *
3685 * The NtUserGetWindowLong function retrieves information about the specified
3686 * window. The function also retrieves the 32-bit (long) value at the
3687 * specified offset into the extra window memory.
3688 *
3689 * Status
3690 * @implemented
3691 */
3692
3693 LONG APIENTRY
3694 NtUserGetWindowLong(HWND hWnd, DWORD Index, BOOL Ansi)
3695 {
3696 DECLARE_RETURN(LONG);
3697
3698 DPRINT("Enter NtUserGetWindowLong(%x,%d,%d)\n", hWnd, (INT)Index, Ansi);
3699 UserEnterExclusive();
3700
3701 RETURN(UserGetWindowLong(hWnd, Index, Ansi));
3702
3703 CLEANUP:
3704 DPRINT("Leave NtUserGetWindowLong, ret=%i\n",_ret_);
3705 UserLeave();
3706 END_CLEANUP;
3707 }
3708
3709 static WNDPROC
3710 IntSetWindowProc(PWINDOW_OBJECT Window,
3711 WNDPROC NewWndProc,
3712 BOOL Ansi)
3713 {
3714 WNDPROC Ret;
3715 PCALLPROCDATA CallProc;
3716 PWND Wnd = Window->Wnd;
3717
3718 /* resolve any callproc handle if possible */
3719 if (IsCallProcHandle(NewWndProc))
3720 {
3721 WNDPROC_INFO wpInfo;
3722
3723 if (UserGetCallProcInfo((HANDLE)NewWndProc,
3724 &wpInfo))
3725 {
3726 NewWndProc = wpInfo.WindowProc;
3727 /* FIXME - what if wpInfo.IsUnicode doesn't match Ansi? */
3728 }
3729 }
3730
3731 /* attempt to get the previous window proc */
3732 if (Wnd->IsSystem)
3733 {
3734 Ret = (Ansi ? Wnd->WndProcExtra : Wnd->lpfnWndProc);
3735 }
3736 else
3737 {
3738 if (!Ansi == Wnd->Unicode)
3739 {
3740 Ret = Wnd->lpfnWndProc;
3741 }
3742 else
3743 {
3744 CallProc = UserFindCallProc(Wnd->pcls,
3745 Wnd->lpfnWndProc,
3746 Wnd->Unicode);
3747 if (CallProc == NULL)
3748 {
3749 CallProc = CreateCallProc(NULL,
3750 Wnd->lpfnWndProc,
3751 Wnd->Unicode,
3752 Wnd->head.pti->ppi);
3753 if (CallProc == NULL)
3754 {
3755 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
3756 return NULL;
3757 }
3758
3759 UserAddCallProcToClass(Wnd->pcls,
3760 CallProc);
3761 }
3762 /* BugBoy Comments: Added this if else, see below comments */
3763 if (!Wnd->CallProc)
3764 {
3765 Ret = Wnd->lpfnWndProc;
3766 }
3767 else
3768 {
3769 Ret = GetCallProcHandle(Wnd->CallProc);
3770 }
3771
3772 Wnd->CallProc = CallProc;
3773
3774 /* BugBoy Comments: Above sets the current CallProc for the
3775 window and below we set the Ret value to it.
3776 SetWindowLong for WNDPROC should return the previous proc
3777 Ret = GetCallProcHandle(Wnd->CallProc); */
3778 }
3779 }
3780
3781 if (Wnd->pcls->System)
3782 {
3783 /* check if the new procedure matches with the one in the
3784 window class. If so, we need to restore both procedures! */
3785 Wnd->IsSystem = (NewWndProc == Wnd->pcls->lpfnWndProc ||
3786 NewWndProc == Wnd->pcls->WndProcExtra);
3787
3788 if (Wnd->IsSystem)
3789 {
3790 Wnd->lpfnWndProc = Wnd->pcls->lpfnWndProc;
3791 Wnd->WndProcExtra = Wnd->pcls->WndProcExtra;
3792 Wnd->Unicode = !Ansi;
3793 return Ret;
3794 }
3795 }
3796
3797 ASSERT(!Wnd->IsSystem);
3798
3799 /* update the window procedure */
3800 Wnd->lpfnWndProc = NewWndProc;
3801 Wnd->Unicode = !Ansi;
3802
3803 return Ret;
3804 }
3805
3806
3807 LONG FASTCALL
3808 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3809 {
3810 PWINDOW_OBJECT Window, Parent;
3811 PWND Wnd;
3812 PWINSTATION_OBJECT WindowStation;
3813 LONG OldValue;
3814 STYLESTRUCT Style;
3815
3816 if (hWnd == IntGetDesktopWindow())
3817 {
3818 SetLastWin32Error(STATUS_ACCESS_DENIED);
3819 return( 0);
3820 }
3821
3822 if (!(Window = UserGetWindowObject(hWnd)))
3823 {
3824 return( 0);
3825 }
3826
3827 Wnd = Window->Wnd;
3828
3829 if (!Wnd) return 0; // No go on zero.
3830
3831 if ((INT)Index >= 0)
3832 {
3833 if ((Index + sizeof(LONG)) > Wnd->cbwndExtra)
3834 {
3835 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3836 return( 0);
3837 }
3838 OldValue = *((LONG *)((PCHAR)(Wnd + 1) + Index));
3839 *((LONG *)((PCHAR)(Wnd + 1) + Index)) = NewValue;
3840 }
3841 else
3842 {
3843 switch (Index)
3844 {
3845 case GWL_EXSTYLE:
3846 OldValue = (LONG) Wnd->ExStyle;
3847 Style.styleOld = OldValue;
3848 Style.styleNew = NewValue;
3849
3850 /*
3851 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3852 */
3853 WindowStation = ((PTHREADINFO)Window->OwnerThread->Tcb.Win32Thread)->Desktop->WindowStation;
3854 if(WindowStation)
3855 {
3856 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3857 Style.styleNew &= ~WS_EX_TOPMOST;
3858 }
3859
3860 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3861 Wnd->ExStyle = (DWORD)Style.styleNew;
3862 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3863 break;
3864
3865 case GWL_STYLE:
3866 OldValue = (LONG) Wnd->style;
3867 Style.styleOld = OldValue;
3868 Style.styleNew = NewValue;
3869 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3870 Wnd->style = (DWORD)Style.styleNew;
3871 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3872 break;
3873
3874 case GWL_WNDPROC:
3875 {
3876 /* FIXME: should check if window belongs to current process */
3877 OldValue = (LONG)IntSetWindowProc(Window,
3878 (WNDPROC)NewValue,
3879 Ansi);
3880 break;
3881 }
3882
3883 case GWL_HINSTANCE:
3884 OldValue = (LONG) Wnd->hModule;
3885 Wnd->hModule = (HINSTANCE) NewValue;
3886 break;
3887
3888 case GWL_HWNDPARENT:
3889 Parent = Window->Parent;
3890 if (Parent && (Parent->hSelf == IntGetDesktopWindow()))
3891 OldValue = (LONG) IntSetOwner(Window->hSelf, (HWND) NewValue);
3892 else
3893 OldValue = (LONG) co_UserSetParent(Window->hSelf, (HWND) NewValue);
3894 break;
3895
3896 case GWL_ID:
3897 OldValue = (LONG) Wnd->IDMenu;
3898 Wnd->IDMenu = (UINT) NewValue;
3899 break;
3900
3901 case GWL_USERDATA:
3902 OldValue = Wnd->dwUserData;
3903 Wnd->dwUserData = NewValue;
3904 break;
3905
3906 default:
3907 DPRINT1("NtUserSetWindowLong(): Unsupported index %d\n", Index);
3908 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3909 OldValue = 0;
3910 break;
3911 }
3912 }
3913
3914 return( OldValue);
3915 }
3916
3917
3918
3919 /*
3920 * NtUserSetWindowLong
3921 *
3922 * The NtUserSetWindowLong function changes an attribute of the specified
3923 * window. The function also sets the 32-bit (long) value at the specified
3924 * offset into the extra window memory.
3925 *
3926 * Status
3927 * @implemented
3928 */
3929
3930 LONG APIENTRY
3931 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3932 {
3933 DECLARE_RETURN(LONG);
3934
3935 DPRINT("Enter NtUserSetWindowLong\n");
3936 UserEnterExclusive();
3937
3938 RETURN( co_UserSetWindowLong(hWnd, Index, NewValue, Ansi));
3939
3940 CLEANUP:
3941 DPRINT("Leave NtUserSetWindowLong, ret=%i\n",_ret_);
3942 UserLeave();
3943 END_CLEANUP;
3944 }
3945
3946 /*
3947 * NtUserSetWindowWord
3948 *
3949 * Legacy function similar to NtUserSetWindowLong.
3950 *
3951 * Status
3952 * @implemented
3953 */
3954
3955 WORD APIENTRY
3956 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
3957 {
3958 PWINDOW_OBJECT Window;
3959 WORD OldValue;
3960 DECLARE_RETURN(WORD);
3961
3962 DPRINT("Enter NtUserSetWindowWord\n");
3963 UserEnterExclusive();
3964
3965 if (!(Window = UserGetWindowObject(hWnd)))
3966 {
3967 RETURN( 0);
3968 }
3969
3970 switch (Index)
3971 {
3972 case GWL_ID:
3973 case GWL_HINSTANCE:
3974 case GWL_HWNDPARENT:
3975 RETURN( co_UserSetWindowLong(Window->hSelf, Index, (UINT)NewValue, TRUE));
3976 default:
3977 if (Index < 0)
3978 {
3979 SetLastWin32Error(ERROR_INVALID_INDEX);
3980 RETURN( 0);
3981 }
3982 }
3983
3984 if (Index > Window->Wnd->cbwndExtra - sizeof(WORD))
3985 {
3986 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3987 RETURN( 0);
3988 }
3989
3990 OldValue = *((WORD *)((PCHAR)(Window->Wnd + 1) + Index));
3991 *((WORD *)((PCHAR)(Window->Wnd + 1) + Index)) = NewValue;
3992
3993 RETURN( OldValue);
3994
3995 CLEANUP:
3996 DPRINT("Leave NtUserSetWindowWord, ret=%i\n",_ret_);
3997 UserLeave();
3998 END_CLEANUP;
3999 }
4000
4001 /*
4002 * @implemented
4003 */
4004 BOOL APIENTRY
4005 NtUserGetWindowPlacement(HWND hWnd,
4006 WINDOWPLACEMENT *lpwndpl)
4007 {
4008 PWINDOW_OBJECT Window;
4009 PWND Wnd;
4010 POINT Size;
4011 WINDOWPLACEMENT Safepl;
4012 NTSTATUS Status;
4013 DECLARE_RETURN(BOOL);
4014
4015 DPRINT("Enter NtUserGetWindowPlacement\n");
4016 UserEnterShared();
4017
4018 if (!(Window = UserGetWindowObject(hWnd)))
4019 {
4020 RETURN( FALSE);
4021 }
4022 Wnd = Window->Wnd;
4023
4024 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
4025 if(!NT_SUCCESS(Status))
4026 {
4027 SetLastNtError(Status);
4028 RETURN( FALSE);
4029 }
4030 if(Safepl.length != sizeof(WINDOWPLACEMENT))
4031 {
4032 RETURN( FALSE);
4033 }
4034
4035 Safepl.flags = 0;
4036 if (0 == (Wnd->style & WS_VISIBLE))
4037 {
4038 Safepl.showCmd = SW_HIDE;
4039 }
4040 else if ((0 != (Window->Flags & WINDOWOBJECT_RESTOREMAX) ||
4041 0 != (Wnd->style & WS_MAXIMIZE)) &&
4042 0 == (Wnd->style & WS_MINIMIZE))
4043 {
4044 Safepl.showCmd = SW_SHOWMAXIMIZED;
4045 }
4046 else if (0 != (Wnd->style & WS_MINIMIZE))
4047 {
4048 Safepl.showCmd = SW_SHOWMINIMIZED;
4049 }
4050 else if (0 != (Wnd->style & WS_VISIBLE))
4051 {
4052 Safepl.showCmd = SW_SHOWNORMAL;
4053 }
4054
4055 Size.x = Wnd->rcWindow.left;
4056 Size.y = Wnd->rcWindow.top;
4057 WinPosInitInternalPos(Window, &Size,
4058 &Wnd->rcWindow);
4059
4060 Safepl.rcNormalPosition = Wnd->InternalPos.NormalRect;
4061 Safepl.ptMinPosition = Wnd->InternalPos.IconPos;
4062 Safepl.ptMaxPosition = Wnd->InternalPos.MaxPos;
4063
4064 Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
4065 if(!NT_SUCCESS(Status))
4066 {
4067 SetLastNtError(Status);
4068 RETURN( FALSE);
4069 }
4070
4071 RETURN( TRUE);
4072
4073 CLEANUP:
4074 DPRINT("Leave NtUserGetWindowPlacement, ret=%i\n",_ret_);
4075 UserLeave();
4076 END_CLEANUP;
4077 }
4078
4079
4080 /*
4081 * @unimplemented
4082 */
4083 BOOL APIENTRY
4084 NtUserLockWindowUpdate(HWND hWnd)
4085 {
4086 UNIMPLEMENTED
4087
4088 return 0;
4089 }
4090
4091
4092 /*
4093 * @implemented
4094 */
4095 BOOL APIENTRY
4096 NtUserMoveWindow(
4097 HWND hWnd,
4098 int X,
4099 int Y,
4100 int nWidth,
4101 int nHeight,
4102 BOOL bRepaint)
4103 {
4104 return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight,
4105 (bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE :
4106 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW));
4107 }
4108
4109 /*
4110 QueryWindow based on KJK::Hyperion and James Tabor.
4111
4112 0 = QWUniqueProcessId
4113 1 = QWUniqueThreadId
4114 2 = QWActiveWindow
4115 3 = QWFocusWindow
4116 4 = QWIsHung Implements IsHungAppWindow found
4117 by KJK::Hyperion.
4118
4119 9 = QWKillWindow When I called this with hWnd ==
4120 DesktopWindow, it shutdown the system
4121 and rebooted.
4122 */
4123 /*
4124 * @implemented
4125 */
4126 DWORD APIENTRY
4127 NtUserQueryWindow(HWND hWnd, DWORD Index)
4128 {
4129 PWINDOW_OBJECT Window;
4130 DWORD Result;
4131 DECLARE_RETURN(UINT);
4132
4133 DPRINT("Enter NtUserQueryWindow\n");
4134 UserEnterShared();
4135
4136 if (!(Window = UserGetWindowObject(hWnd)))
4137 {
4138 RETURN( 0);
4139 }
4140
4141 switch(Index)
4142 {
4143 case QUERY_WINDOW_UNIQUE_PROCESS_ID:
4144 Result = (DWORD)IntGetWndProcessId(Window);
4145 break;
4146
4147 case QUERY_WINDOW_UNIQUE_THREAD_ID:
4148 Result = (DWORD)IntGetWndThreadId(Window);
4149 break;
4150
4151 case QUERY_WINDOW_ACTIVE:
4152 Result = (DWORD)UserGetActiveWindow();
4153 break;
4154
4155 case QUERY_WINDOW_FOCUS:
4156 Result = (DWORD)IntGetFocusWindow();
4157 break;
4158
4159 case QUERY_WINDOW_ISHUNG:
4160 Result = (DWORD)MsqIsHung(Window->MessageQueue);
4161 break;
4162
4163 default:
4164 Result = (DWORD)NULL;
4165 break;
4166 }
4167
4168 RETURN( Result);
4169
4170 CLEANUP:
4171 DPRINT("Leave NtUserQueryWindow, ret=%i\n",_ret_);
4172 UserLeave();
4173 END_CLEANUP;
4174 }
4175
4176
4177 /*
4178 * @unimplemented
4179 */
4180 DWORD APIENTRY
4181 NtUserRealChildWindowFromPoint(DWORD Unknown0,
4182 DWORD Unknown1,
4183 DWORD Unknown2)
4184 {
4185 UNIMPLEMENTED
4186
4187 return 0;
4188 }
4189
4190
4191 /*
4192 * @implemented
4193 */
4194 UINT APIENTRY
4195 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
4196 {
4197 UNICODE_STRING SafeMessageName;
4198 NTSTATUS Status;
4199 UINT Ret;
4200 DECLARE_RETURN(UINT);
4201
4202 DPRINT("Enter NtUserRegisterWindowMessage\n");
4203 UserEnterExclusive();
4204
4205 if(MessageNameUnsafe == NULL)
4206 {
4207 SetLastWin32Error(ERROR_INVALID_PARAMETER);
4208 RETURN( 0);
4209 }
4210
4211 Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
4212 if(!NT_SUCCESS(Status))
4213 {
4214 SetLastNtError(Status);
4215 RETURN( 0);
4216 }
4217
4218 Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
4219
4220 ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING);
4221 RETURN( Ret);
4222
4223 CLEANUP:
4224 DPRINT("Leave NtUserRegisterWindowMessage, ret=%i\n",_ret_);
4225 UserLeave();
4226 END_CLEANUP;
4227 }
4228
4229
4230 /*
4231 * @unimplemented
4232 */
4233 DWORD APIENTRY
4234 NtUserSetImeOwnerWindow(DWORD Unknown0,
4235 DWORD Unknown1)
4236 {
4237 UNIMPLEMENTED
4238
4239 return 0;
4240 }
4241
4242
4243 /*
4244 * @unimplemented
4245 */
4246 DWORD APIENTRY
4247 NtUserSetInternalWindowPos(
4248 HWND hwnd,
4249 UINT showCmd,
4250 LPRECT rect,
4251 LPPOINT pt)
4252 {
4253 UNIMPLEMENTED
4254
4255 return 0;
4256
4257 }
4258
4259
4260 /*
4261 * @unimplemented
4262 */
4263 BOOL APIENTRY
4264 NtUserSetLayeredWindowAttributes(HWND hwnd,
4265 COLORREF crKey,
4266 BYTE bAlpha,
4267 DWORD dwFlags)
4268 {
4269 UNIMPLEMENTED;
4270 return FALSE;
4271 }
4272
4273
4274 /*
4275 * @unimplemented
4276 */
4277 BOOL APIENTRY
4278 NtUserSetLogonNotifyWindow(HWND hWnd)
4279 {
4280 UNIMPLEMENTED
4281
4282 return 0;
4283 }
4284
4285
4286 /*
4287 * @implemented
4288 */
4289 BOOL APIENTRY
4290 NtUserSetMenu(
4291 HWND hWnd,
4292 HMENU Menu,
4293 BOOL Repaint)
4294 {
4295 PWINDOW_OBJECT Window;
4296 BOOL Changed;
4297 DECLARE_RETURN(BOOL);
4298
4299 DPRINT("Enter NtUserSetMenu\n");
4300 UserEnterExclusive();
4301
4302 if (!(Window = UserGetWindowObject(hWnd)))
4303 {
4304 RETURN( FALSE);
4305 }
4306
4307 if (! IntSetMenu(Window, Menu, &Changed))
4308 {
4309 RETURN( FALSE);
4310 }
4311
4312 if (Changed && Repaint)
4313 {
4314 USER_REFERENCE_ENTRY Ref;
4315
4316 UserRefObjectCo(Window, &Ref);
4317 co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4318 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
4319
4320 UserDerefObjectCo(Window);
4321 }
4322
4323 RETURN( TRUE);
4324
4325 CLEANUP:
4326 DPRINT("Leave NtUserSetMenu, ret=%i\n",_ret_);
4327 UserLeave();
4328 END_CLEANUP;
4329 }
4330
4331
4332 /*
4333 * @implemented
4334 */
4335 BOOL APIENTRY
4336 NtUserSetWindowFNID(HWND hWnd,
4337 WORD fnID)
4338 {
4339 PWINDOW_OBJECT Window;
4340 PWND Wnd;
4341 DECLARE_RETURN(BOOL);
4342
4343 DPRINT("Enter NtUserSetWindowFNID\n");
4344 UserEnterExclusive();
4345
4346 if (!(Window = UserGetWindowObject(hWnd)))
4347 {
4348 RETURN( FALSE);
4349 }
4350 Wnd = Window->Wnd;
4351
4352 if (Wnd->pcls)
4353 { // From user land we only set these.
4354 if ((fnID != FNID_DESTROY) || ((fnID < FNID_BUTTON) && (fnID > FNID_IME)) )
4355 {
4356 RETURN( FALSE);
4357 }
4358 else
4359 Wnd->pcls->fnid |= fnID;
4360 }
4361 RETURN( TRUE);
4362
4363 CLEANUP:
4364 DPRINT("Leave NtUserSetWindowFNID\n");
4365 UserLeave();
4366 END_CLEANUP;
4367 }
4368
4369
4370 /*
4371 * @implemented
4372 */
4373 BOOL APIENTRY
4374 NtUserSetWindowPlacement(HWND hWnd,
4375 WINDOWPLACEMENT *lpwndpl)
4376 {
4377 PWINDOW_OBJECT Window;
4378 PWND Wnd;
4379 WINDOWPLACEMENT Safepl;
4380 NTSTATUS Status;
4381 DECLARE_RETURN(BOOL);
4382 USER_REFERENCE_ENTRY Ref;
4383
4384 DPRINT("Enter NtUserSetWindowPlacement\n");
4385 UserEnterExclusive();
4386
4387 if (!(Window = UserGetWindowObject(hWnd)))
4388 {
4389 RETURN( FALSE);
4390 }
4391 Wnd = Window->Wnd;
4392
4393 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
4394 if(!NT_SUCCESS(Status))
4395 {
4396 SetLastNtError(Status);
4397 RETURN( FALSE);
4398 }
4399 if(Safepl.length != sizeof(WINDOWPLACEMENT))
4400 {
4401 RETURN( FALSE);
4402 }
4403
4404 UserRefObjectCo(Window, &Ref);
4405
4406 if ((Wnd->style & (WS_MAXIMIZE | WS_MINIMIZE)) == 0)
4407 {
4408 co_WinPosSetWindowPos(Window, NULL,
4409 Safepl.rcNormalPosition.left, Safepl.rcNormalPosition.top,
4410 Safepl.rcNormalPosition.right - Safepl.rcNormalPosition.left,
4411 Safepl.rcNormalPosition.bottom - Safepl.rcNormalPosition.top,
4412 SWP_NOZORDER | SWP_NOACTIVATE);
4413 }
4414
4415 /* FIXME - change window status */
4416 co_WinPosShowWindow(Window, Safepl.showCmd);
4417
4418 Wnd->InternalPosInitialized = TRUE;
4419 Wnd->InternalPos.NormalRect = Safepl.rcNormalPosition;
4420 Wnd->InternalPos.IconPos = Safepl.ptMinPosition;
4421 Wnd->InternalPos.MaxPos = Safepl.ptMaxPosition;
4422
4423 UserDerefObjectCo(Window);
4424 RETURN(TRUE);
4425
4426 CLEANUP:
4427 DPRINT("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
4428 UserLeave();
4429 END_CLEANUP;
4430 }
4431
4432
4433 /*
4434 * @implemented
4435 */
4436 BOOL APIENTRY
4437 NtUserSetWindowPos(
4438 HWND hWnd,
4439 HWND hWndInsertAfter,
4440 int X,
4441 int Y,
4442 int cx,
4443 int cy,
4444 UINT uFlags)
4445 {
4446 DECLARE_RETURN(BOOL);
4447 PWINDOW_OBJECT Window;
4448 BOOL ret;
4449 USER_REFERENCE_ENTRY Ref;
4450
4451 DPRINT("Enter NtUserSetWindowPos\n");
4452 UserEnterExclusive();
4453
4454 if (!(Window = UserGetWindowObject(hWnd)))
4455 {
4456 RETURN(FALSE);
4457 }
4458
4459 /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
4460 if (!(uFlags & SWP_NOMOVE))
4461 {
4462 if (X < -32768) X = -32768;
4463 else if (X > 32767) X = 32767;
4464 if (Y < -32768) Y = -32768;
4465 else if (Y > 32767) Y = 32767;
4466 }
4467 if (!(uFlags & SWP_NOSIZE))
4468 {
4469 if (cx < 0) cx = 0;
4470 else if (cx > 32767) cx = 32767;
4471 if (cy < 0) cy = 0;
4472 else if (cy > 32767) cy = 32767;
4473 }
4474
4475 UserRefObjectCo(Window, &Ref);
4476 ret = co_WinPosSetWindowPos(Window, hWndInsertAfter, X, Y, cx, cy, uFlags);
4477 UserDerefObjectCo(Window);
4478
4479 RETURN(ret);
4480
4481 CLEANUP:
4482 DPRINT("Leave NtUserSetWindowPos, ret=%i\n",_ret_);
4483 UserLeave();
4484 END_CLEANUP;
4485 }
4486
4487
4488 INT FASTCALL
4489 IntGetWindowRgn(PWINDOW_OBJECT Window, HRGN hRgn)
4490 {
4491 INT Ret;
4492 HRGN VisRgn;
4493 ROSRGNDATA *pRgn;
4494 PWND Wnd;
4495
4496 if(!Window)
4497 {
4498 return ERROR;
4499 }
4500 if(!hRgn)
4501 {
4502 return ERROR;
4503 }
4504
4505 Wnd = Window->Wnd;
4506
4507 /* Create a new window region using the window rectangle */
4508 VisRgn = UnsafeIntCreateRectRgnIndirect(&Window->Wnd->rcWindow);
4509 NtGdiOffsetRgn(VisRgn, -Window->Wnd->rcWindow.left, -Window->Wnd->rcWindow.top);
4510 /* if there's a region assigned to the window, combine them both */
4511 if(Window->WindowRegion && !(Wnd->style & WS_MINIMIZE))
4512 NtGdiCombineRgn(VisRgn, VisRgn, Window->WindowRegion, RGN_AND);
4513 /* Copy the region into hRgn */
4514 NtGdiCombineRgn(hRgn, VisRgn, NULL, RGN_COPY);
4515
4516 if((pRgn = REGION_LockRgn(hRgn)))
4517 {
4518 Ret = pRgn->rdh.iType;
4519 REGION_UnlockRgn(pRgn);
4520 }
4521 else
4522 Ret = ERROR;
4523
4524 GreDeleteObject(VisRgn);
4525
4526 return Ret;
4527 }
4528
4529 INT FASTCALL
4530 IntGetWindowRgnBox(PWINDOW_OBJECT Window, RECTL *Rect)
4531 {
4532 INT Ret;
4533 HRGN VisRgn;
4534 ROSRGNDATA *pRgn;
4535 PWND Wnd;
4536
4537 if(!Window)
4538 {
4539 return ERROR;
4540 }
4541 if(!Rect)
4542 {
4543 return ERROR;
4544 }
4545
4546 Wnd = Window->Wnd;
4547
4548 /* Create a new window region using the window rectangle */
4549 VisRgn = UnsafeIntCreateRectRgnIndirect(&Window->Wnd->rcWindow);
4550 NtGdiOffsetRgn(VisRgn, -Window->Wnd->rcWindow.left, -Window->Wnd->rcWindow.top);
4551 /* if there's a region assigned to the window, combine them both */
4552 if(Window->WindowRegion && !(Wnd->style & WS_MINIMIZE))
4553 NtGdiCombineRgn(VisRgn, VisRgn, Window->WindowRegion, RGN_AND);
4554
4555 if((pRgn = REGION_LockRgn(VisRgn)))
4556 {
4557 Ret = pRgn->rdh.iType;
4558 *Rect = pRgn->rdh.rcBound;
4559 REGION_UnlockRgn(pRgn);
4560 }
4561 else
4562 Ret = ERROR;
4563
4564 GreDeleteObject(VisRgn);
4565
4566 return Ret;
4567 }
4568
4569
4570 /*
4571 * @implemented
4572 */
4573 INT APIENTRY
4574 NtUserSetWindowRgn(
4575 HWND hWnd,
4576 HRGN hRgn,
4577 BOOL bRedraw)
4578 {
4579 PWINDOW_OBJECT Window;
4580 DECLARE_RETURN(INT);
4581
4582 DPRINT("Enter NtUserSetWindowRgn\n");
4583 UserEnterExclusive();
4584
4585 if (!(Window = UserGetWindowObject(hWnd)))
4586 {
4587 RETURN( 0);
4588 }
4589
4590 /* FIXME - Verify if hRgn is a valid handle!!!!
4591 Propably make this operation thread-safe, but maybe it's not necessary */
4592
4593 if(Window->WindowRegion)
4594 {
4595 /* Delete no longer needed region handle */
4596 GreDeleteObject(Window->WindowRegion);
4597 }
4598 Window->WindowRegion = hRgn;
4599
4600 /* FIXME - send WM_WINDOWPOSCHANGING and WM_WINDOWPOSCHANGED messages to the window */
4601
4602 if(bRedraw)
4603 {
4604 USER_REFERENCE_ENTRY Ref;
4605 UserRefObjectCo(Window, &Ref);
4606 co_UserRedrawWindow(Window, NULL, NULL, RDW_INVALIDATE);
4607 UserDerefObjectCo(Window);
4608 }
4609
4610 RETURN( (INT)hRgn);
4611
4612 CLEANUP:
4613 DPRINT("Leave NtUserSetWindowRgn, ret=%i\n",_ret_);
4614 UserLeave();
4615 END_CLEANUP;
4616 }
4617
4618
4619 /*
4620 * @implemented
4621 */
4622 BOOL APIENTRY
4623 NtUserShowWindow(HWND hWnd, LONG nCmdShow)
4624 {
4625 PWINDOW_OBJECT Window;
4626 BOOL ret;
4627 DECLARE_RETURN(BOOL);
4628 USER_REFERENCE_ENTRY Ref;
4629
4630 DPRINT("Enter NtUserShowWindow\n");
4631 UserEnterExclusive();
4632
4633 if (!(Window = UserGetWindowObject(hWnd)))
4634 {
4635 RETURN(FALSE);
4636 }
4637
4638 UserRefObjectCo(Window, &Ref);
4639 ret = co_WinPosShowWindow(Window, nCmdShow);
4640 UserDerefObjectCo(Window);
4641
4642 RETURN(ret);
4643
4644 CLEANUP:
4645 DPRINT("Leave NtUserShowWindow, ret=%i\n",_ret_);
4646 UserLeave();
4647 END_CLEANUP;
4648 }
4649
4650
4651 /*
4652 * @unimplemented
4653 */
4654 BOOL APIENTRY
4655 NtUserShowWindowAsync(HWND hWnd, LONG nCmdShow)
4656 {
4657 #if 0
4658 UNIMPLEMENTED
4659 return 0;
4660 #else
4661 return NtUserShowWindow(hWnd, nCmdShow);
4662 #endif
4663 }
4664
4665
4666 /*
4667 * @unimplemented
4668 */
4669 BOOL
4670 APIENTRY
4671 NtUserUpdateLayeredWindow(
4672 HWND hwnd,
4673 HDC hdcDst,
4674 POINT *pptDst,
4675 SIZE *psize,
4676 HDC hdcSrc,
4677 POINT *pptSrc,
4678 COLORREF crKey,
4679 BLENDFUNCTION *pblend,
4680 DWORD dwFlags,
4681 RECT *prcDirty)
4682 {
4683 UNIMPLEMENTED
4684
4685 return 0;
4686 }
4687
4688 /*
4689 * @unimplemented
4690 */
4691 HWND APIENTRY
4692 NtUserWindowFromPhysicalPoint(POINT Point)
4693 {
4694 UNIMPLEMENTED
4695
4696 return NULL;
4697 }
4698
4699 /*
4700 * @implemented
4701 */
4702 HWND APIENTRY
4703 NtUserWindowFromPoint(LONG X, LONG Y)
4704 {
4705 POINT pt;
4706 HWND Ret;
4707 PWINDOW_OBJECT DesktopWindow = NULL, Window = NULL;
4708 DECLARE_RETURN(HWND);
4709 USER_REFERENCE_ENTRY Ref;
4710
4711 DPRINT("Enter NtUserWindowFromPoint\n");
4712 UserEnterExclusive();
4713
4714 if ((DesktopWindow = UserGetWindowObject(IntGetDesktopWindow())))
4715 {
4716 PTHREADINFO pti;
4717 USHORT Hit;
4718
4719 pt.x = X;
4720 pt.y = Y;
4721
4722 //hmm... threads live on desktops thus we have a reference on the desktop and indirectly the desktop window
4723 //its possible this referencing is useless, thou it shouldnt hurt...
4724 UserRefObjectCo(DesktopWindow, &Ref);
4725
4726 pti = PsGetCurrentThreadWin32Thread();
4727 Hit = co_WinPosWindowFromPoint(DesktopWindow, pti->MessageQueue, &pt, &Window);
4728
4729 if(Window)
4730 {
4731 Ret = Window->hSelf;
4732
4733 RETURN( Ret);
4734 }
4735 }
4736
4737 RETURN( NULL);
4738
4739 CLEANUP:
4740 if (Window) UserDereferenceObject(Window);
4741 if (DesktopWindow) UserDerefObjectCo(DesktopWindow);
4742
4743 DPRINT("Leave NtUserWindowFromPoint, ret=%i\n",_ret_);
4744 UserLeave();
4745 END_CLEANUP;
4746
4747 }
4748
4749
4750 /*
4751 * NtUserDefSetText
4752 *
4753 * Undocumented function that is called from DefWindowProc to set
4754 * window text.
4755 *
4756 * Status
4757 * @implemented
4758 */
4759 BOOL APIENTRY
4760 NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText)
4761 {
4762 PWINDOW_OBJECT Window;
4763 PWND Wnd;
4764 LARGE_STRING SafeText;
4765 UNICODE_STRING UnicodeString;
4766 BOOL Ret = TRUE;
4767
4768 DPRINT("Enter NtUserDefSetText\n");
4769
4770 if (WindowText != NULL)
4771 {
4772 _SEH2_TRY
4773 {
4774 SafeText = ProbeForReadLargeString(WindowText);
4775 }
4776 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4777 {
4778 Ret = FALSE;
4779 SetLastNtError(_SEH2_GetExceptionCode());
4780 }
4781 _SEH2_END;
4782
4783 if (!Ret)
4784 return FALSE;
4785 }
4786 else
4787 return TRUE;
4788
4789 UserEnterExclusive();
4790
4791 if(!(Window = UserGetWindowObject(hWnd)) || !Window->Wnd)
4792 {
4793 UserLeave();
4794 return FALSE;
4795 }
4796 Wnd = Window->Wnd;
4797
4798 // ReactOS uses Unicode and not mixed. Up/Down converting will take time.
4799 // Brought to you by: The Wine Project! Dysfunctional Thought Processes!
4800 // Now we know what the bAnsi is for.
4801 RtlInitUnicodeString(&UnicodeString, NULL);
4802 if (SafeText.Buffer)
4803 {
4804 _SEH2_TRY
4805 {
4806 if (SafeText.bAnsi)
4807 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR));
4808 else
4809 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR));
4810 Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText);
4811 }
4812 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4813 {
4814 Ret = FALSE;
4815 SetLastNtError(_SEH2_GetExceptionCode());
4816 }
4817 _SEH2_END;
4818 if (!Ret) goto Exit;
4819 }
4820
4821 if (UnicodeString.Length != 0)
4822 {
4823 if (Wnd->strName.MaximumLength > 0 &&
4824 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4825 {
4826 ASSERT(Wnd->strName.Buffer != NULL);
4827
4828 Wnd->strName.Length = UnicodeString.Length;
4829 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4830 RtlCopyMemory(Wnd->strName.Buffer,
4831 UnicodeString.Buffer,
4832 UnicodeString.Length);
4833 }
4834 else
4835 {
4836 PWCHAR buf;
4837 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4838 buf = Wnd->strName.Buffer;
4839 Wnd->strName.Buffer = NULL;
4840 if (buf != NULL)
4841 {
4842 DesktopHeapFree(Wnd->head.rpdesk, buf);
4843 }
4844
4845 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4846 UnicodeString.Length + sizeof(UNICODE_NULL));
4847 if (Wnd->strName.Buffer != NULL)
4848 {
4849 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4850 RtlCopyMemory(Wnd->strName.Buffer,
4851 UnicodeString.Buffer,
4852 UnicodeString.Length);
4853 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4854 Wnd->strName.Length = UnicodeString.Length;
4855 }
4856 else
4857 {
4858 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
4859 Ret = FALSE;
4860 goto Exit;
4861 }
4862 }
4863 }
4864 else
4865 {
4866 Wnd->strName.Length = 0;
4867 if (Wnd->strName.Buffer != NULL)
4868 Wnd->strName.Buffer[0] = L'\0';
4869 }
4870
4871 // HAX! FIXME! Windows does not do this in here!
4872 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4873 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4874 /* Send shell notifications */
4875 if (!IntGetOwner(Window) && !IntGetParent(Window))
4876 {
4877 co_IntShellHookNotify(HSHELL_REDRAW, (LPARAM) hWnd);
4878 }
4879
4880 Ret = TRUE;
4881 Exit:
4882 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4883 DPRINT("Leave NtUserDefSetText, ret=%i\n", Ret);
4884 UserLeave();
4885 return Ret;
4886 }
4887
4888 /*
4889 * NtUserInternalGetWindowText
4890 *
4891 * Status
4892 * @implemented
4893 */
4894
4895 INT APIENTRY
4896 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount)
4897 {
4898 PWINDOW_OBJECT Window;
4899 PWND Wnd;
4900 NTSTATUS Status;
4901 INT Result;
4902 DECLARE_RETURN(INT);
4903
4904 DPRINT("Enter NtUserInternalGetWindowText\n");
4905 UserEnterShared();
4906
4907 if(lpString && (nMaxCount <= 1))
4908 {
4909 SetLastWin32Error(ERROR_INVALID_PARAMETER);
4910 RETURN( 0);
4911 }
4912
4913 if(!(Window = UserGetWindowObject(hWnd)))
4914 {
4915 RETURN( 0);
4916 }
4917 Wnd = Window->Wnd;
4918
4919 Result = Wnd->strName.Length / sizeof(WCHAR);
4920 if(lpString)
4921 {
4922 const WCHAR Terminator = L'\0';
4923 INT Copy;
4924 WCHAR *Buffer = (WCHAR*)lpString;
4925
4926 Copy = min(nMaxCount - 1, Result);
4927 if(Copy > 0)
4928 {
4929 Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR));
4930 if(!NT_SUCCESS(Status))
4931 {
4932 SetLastNtError(Status);
4933 RETURN( 0);
4934 }
4935 Buffer += Copy;
4936 }
4937
4938 Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
4939 if(!NT_SUCCESS(Status))
4940 {
4941 SetLastNtError(Status);
4942 RETURN( 0);
4943 }
4944
4945 Result = Copy;
4946 }
4947
4948 RETURN( Result);
4949
4950 CLEANUP:
4951 DPRINT("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_);
4952 UserLeave();
4953 END_CLEANUP;
4954 }
4955
4956
4957 BOOL
4958 FASTCALL
4959 IntShowOwnedPopups(PWINDOW_OBJECT OwnerWnd, BOOL fShow )
4960 {
4961 int count = 0;
4962 PWINDOW_OBJECT pWnd;
4963 HWND *win_array;
4964
4965 // ASSERT(OwnerWnd);
4966
4967 win_array = IntWinListChildren(UserGetWindowObject(IntGetDesktopWindow()));
4968
4969 if (!win_array)
4970 return TRUE;
4971
4972 while (win_array[count])
4973 count++;
4974 while (--count >= 0)
4975 {
4976 if (UserGetWindow( win_array[count], GW_OWNER ) != OwnerWnd->hSelf)
4977 continue;
4978 if (!(pWnd = UserGetWindowObject( win_array[count] )))
4979 continue;
4980 // if (pWnd == WND_OTHER_PROCESS) continue;
4981
4982 if (fShow)
4983 {
4984 if (pWnd->Wnd->state & WNDS_HIDDENPOPUP)
4985 {
4986 /* In Windows, ShowOwnedPopups(TRUE) generates
4987 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
4988 * regardless of the state of the owner
4989 */
4990 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
4991 continue;
4992 }
4993 }
4994 else
4995 {
4996 if (pWnd->Wnd->style & WS_VISIBLE)
4997 {
4998 /* In Windows, ShowOwnedPopups(FALSE) generates
4999 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
5000 * regardless of the state of the owner
5001 */
5002 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
5003 continue;
5004 }
5005 }
5006
5007 }
5008 ExFreePool( win_array );
5009 return TRUE;
5010 }
5011
5012 /*
5013 * NtUserValidateHandleSecure
5014 *
5015 * Status
5016 * @implemented
5017 */
5018
5019 BOOL
5020 APIENTRY
5021 NtUserValidateHandleSecure(
5022 HANDLE handle,
5023 BOOL Restricted)
5024 {
5025 if(!Restricted)
5026 {
5027 UINT uType;
5028 {
5029 PUSER_HANDLE_ENTRY entry;
5030 if (!(entry = handle_to_entry(gHandleTable, handle )))
5031 {
5032 SetLastWin32Error(ERROR_INVALID_HANDLE);
5033 return FALSE;
5034 }
5035 uType = entry->type;
5036 }
5037 switch (uType)
5038 {
5039 case otWindow:
5040 {
5041 PWINDOW_OBJECT Window;
5042 if ((Window = UserGetWindowObject((HWND) handle))) return TRUE;
5043 return FALSE;
5044 }
5045 case otMenu:
5046 {
5047 PMENU_OBJECT Menu;
5048 if ((Menu = UserGetMenuObject((HMENU) handle))) return TRUE;
5049 return FALSE;
5050 }
5051 case otAccel:
5052 {
5053 PACCELERATOR_TABLE Accel;
5054 if ((Accel = UserGetAccelObject((HACCEL) handle))) return TRUE;
5055 return FALSE;
5056 }
5057 case otCursorIcon:
5058 {
5059 PCURICON_OBJECT Cursor;
5060 if ((Cursor = UserGetCurIconObject((HCURSOR) handle))) return TRUE;
5061 return FALSE;
5062 }
5063 case otHook:
5064 {
5065 PHOOK Hook;
5066 if ((Hook = IntGetHookObject((HHOOK) handle))) return TRUE;
5067 return FALSE;
5068 }
5069 case otMonitor:
5070 {
5071 PMONITOR_OBJECT Monitor;
5072 if ((Monitor = UserGetMonitorObject((HMONITOR) handle))) return TRUE;
5073 return FALSE;
5074 }
5075 case otCallProc:
5076 {
5077 WNDPROC_INFO Proc;
5078 return UserGetCallProcInfo( handle, &Proc );
5079 }
5080 default:
5081 SetLastWin32Error(ERROR_INVALID_HANDLE);
5082 }
5083 }
5084 else
5085 { /* Is handle entry restricted? */
5086 UNIMPLEMENTED
5087 }
5088 return FALSE;
5089 }
5090
5091
5092 /* EOF */