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