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