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