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