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