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