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