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