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