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