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