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