[WIN32K / USER32]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / window.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Windows
5 * FILE: subsystems/win32/win32k/ntuser/window.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISION HISTORY:
8 * 06-06-2001 CSH Created
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <win32k.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18
19 /* dialog resources appear to pass this in 16 bits, handle them properly */
20 #define CW_USEDEFAULT16 (0x8000)
21
22 #define POINT_IN_RECT(p, r) (((r.bottom >= p.y) && (r.top <= p.y))&&((r.left <= p.x )&&( r.right >= p.x )))
23
24 /* PRIVATE FUNCTIONS **********************************************************/
25
26 /*
27 * InitWindowImpl
28 *
29 * Initialize windowing implementation.
30 */
31
32 NTSTATUS FASTCALL
33 InitWindowImpl(VOID)
34 {
35 return STATUS_SUCCESS;
36 }
37
38 /*
39 * CleanupWindowImpl
40 *
41 * Cleanup windowing implementation.
42 */
43
44 NTSTATUS FASTCALL
45 CleanupWindowImpl(VOID)
46 {
47 return STATUS_SUCCESS;
48 }
49
50 /* HELPER FUNCTIONS ***********************************************************/
51
52 BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam)
53 {
54 WORD Action = LOWORD(wParam);
55 WORD Flags = HIWORD(wParam);
56
57 if (Flags & ~(UISF_HIDEFOCUS | UISF_HIDEACCEL | UISF_ACTIVE))
58 {
59 SetLastWin32Error(ERROR_INVALID_PARAMETER);
60 return FALSE;
61 }
62
63 switch (Action)
64 {
65 case UIS_INITIALIZE:
66 SetLastWin32Error(ERROR_INVALID_PARAMETER);
67 return FALSE;
68
69 case UIS_SET:
70 if (Flags & UISF_HIDEFOCUS)
71 Wnd->HideFocus = TRUE;
72 if (Flags & UISF_HIDEACCEL)
73 Wnd->HideAccel = TRUE;
74 break;
75
76 case UIS_CLEAR:
77 if (Flags & UISF_HIDEFOCUS)
78 Wnd->HideFocus = FALSE;
79 if (Flags & UISF_HIDEACCEL)
80 Wnd->HideAccel = FALSE;
81 break;
82 }
83
84 return TRUE;
85 }
86
87 PWINDOW_OBJECT FASTCALL IntGetWindowObject(HWND hWnd)
88 {
89 PWINDOW_OBJECT Window;
90
91 if (!hWnd) return NULL;
92
93 Window = UserGetWindowObject(hWnd);
94 if (Window)
95 {
96 ASSERT(Window->head.cLockObj >= 0);
97
98 Window->head.cLockObj++;
99 }
100 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 MsqRemoveTimersWindow(ThreadData->MessageQueue, Window->hSelf);
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 Wnd->style = dwStyle & ~WS_VISIBLE;
2002
2003 /* Correct the window style. */
2004 if ((Wnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
2005 {
2006 Wnd->style |= WS_CLIPSIBLINGS;
2007 DPRINT("3: Style is now %lx\n", dwStyle);
2008 if (!(Wnd->style & WS_POPUP))
2009 {
2010 Wnd->style |= WS_CAPTION;
2011 Window->state |= WINDOWOBJECT_NEED_SIZE;
2012 DPRINT("4: Style is now %lx\n", dwStyle);
2013 }
2014 }
2015
2016 /* create system menu */
2017 if((dwStyle & WS_SYSMENU) )//&& (dwStyle & WS_CAPTION) == WS_CAPTION)
2018 {
2019 SystemMenu = IntGetSystemMenu(Window, TRUE, TRUE);
2020 if(SystemMenu)
2021 {
2022 Window->SystemMenu = SystemMenu->MenuInfo.Self;
2023 IntReleaseMenuObject(SystemMenu);
2024 }
2025 }
2026
2027 /* Set the window menu */
2028 if ((dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
2029 {
2030 if (hMenu)
2031 IntSetMenu(Window, hMenu, &MenuChanged);
2032 else if (Wnd->pcls->lpszMenuName) // Take it from the parent.
2033 {
2034 UNICODE_STRING MenuName;
2035 if (IS_INTRESOURCE(Wnd->pcls->lpszMenuName))
2036 {
2037 MenuName.Length = 0;
2038 MenuName.MaximumLength = 0;
2039 MenuName.Buffer = Wnd->pcls->lpszMenuName;
2040 }
2041 else
2042 {
2043 RtlInitUnicodeString( &MenuName, Wnd->pcls->lpszMenuName);
2044 }
2045 hMenu = co_IntCallLoadMenu( Wnd->pcls->hModule, &MenuName);
2046 if (hMenu) IntSetMenu(Window, hMenu, &MenuChanged);
2047 }
2048 }
2049 else // Not a child
2050 Wnd->IDMenu = (UINT) hMenu;
2051
2052 /* Insert the window into the thread's window list. */
2053 InsertTailList (&pti->WindowListHead, &Window->ThreadListEntry);
2054
2055 /* Handle "CS_CLASSDC", it is tested first. */
2056 if ( (Wnd->pcls->style & CS_CLASSDC) && !(Wnd->pcls->pdce) )
2057 { /* One DCE per class to have CLASS. */
2058 Wnd->pcls->pdce = DceAllocDCE( Window, DCE_CLASS_DC );
2059 }
2060 else if ( Wnd->pcls->style & CS_OWNDC)
2061 { /* Allocate a DCE for this window. */
2062 DceAllocDCE(Window, DCE_WINDOW_DC);
2063 }
2064
2065 Pos.x = x;
2066 Pos.y = y;
2067 Size.cx = nWidth;
2068 Size.cy = nHeight;
2069
2070 Wnd->ExStyle = dwExStyle;
2071
2072 /* call hook */
2073 Cs.lpCreateParams = lpParam;
2074 Cs.hInstance = hInstance;
2075 Cs.hMenu = hMenu;
2076 Cs.hwndParent = hWndParent; //Pass the original Parent handle!
2077 Cs.cx = Size.cx;
2078 Cs.cy = Size.cy;
2079 Cs.x = Pos.x;
2080 Cs.y = Pos.y;
2081 Cs.style = Wnd->style;
2082 // Cs.lpszName = (LPCWSTR) WindowName->Buffer;
2083 // Cs.lpszClass = (LPCWSTR) ClassName->Buffer;
2084 Cs.lpszName = (LPCWSTR) WindowName;
2085 Cs.lpszClass = (LPCWSTR) ClassName;
2086 Cs.dwExStyle = dwExStyle;
2087 CbtCreate.lpcs = &Cs;
2088 CbtCreate.hwndInsertAfter = HWND_TOP;
2089 if (ISITHOOKED(WH_CBT))
2090 {
2091 if (co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) &CbtCreate))
2092 {
2093 /* FIXME - Delete window object and remove it from the thread windows list */
2094 /* FIXME - delete allocated DCE */
2095 DPRINT1("CBT-hook returned !0\n");
2096 RETURN( (PWND) NULL);
2097 }
2098 }
2099 x = Cs.x;
2100 y = Cs.y;
2101 nWidth = Cs.cx;
2102 nHeight = Cs.cy;
2103
2104 Cs.style = dwStyle;
2105 // FIXME: Need to set the Z order in the window link list if the hook callback changed it!
2106 // hwndInsertAfter = CbtCreate.hwndInsertAfter;
2107
2108 /* default positioning for overlapped windows */
2109 if(!(Wnd->style & (WS_POPUP | WS_CHILD)))
2110 {
2111 RECTL rc, WorkArea;
2112 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
2113 BOOL CalculatedDefPosSize = FALSE;
2114
2115 UserSystemParametersInfo(SPI_GETWORKAREA, 0, &WorkArea, 0);
2116
2117 rc = WorkArea;
2118 ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
2119
2120 if(x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
2121 {
2122 CalculatedDefPosSize = IntCalcDefPosSize(ParentWindow, &rc, TRUE);
2123
2124 if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
2125 {
2126 ProcessParams->WindowFlags &= ~STARTF_USEPOSITION;
2127 Pos.x = WorkArea.left + ProcessParams->StartingX;
2128 Pos.y = WorkArea.top + ProcessParams->StartingY;
2129 }
2130 else
2131 {
2132 Pos.x = rc.left;
2133 Pos.y = rc.top;
2134 }
2135
2136 /*
2137 According to wine, the ShowMode is set to y if x == CW_USEDEFAULT(16) and
2138 y is something else. and Quote!
2139 */
2140
2141 /* Never believe Microsoft's documentation... CreateWindowEx doc says
2142 * that if an overlapped window is created with WS_VISIBLE style bit
2143 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
2144 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
2145 * reveals that
2146 *
2147 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
2148 * 2) it does not ignore the y parameter as the docs claim; instead, it
2149 * uses it as second parameter to ShowWindow() unless y is either
2150 * CW_USEDEFAULT or CW_USEDEFAULT16.
2151 *
2152 * The fact that we didn't do 2) caused bogus windows pop up when wine
2153 * was running apps that were using this obscure feature. Example -
2154 * calc.exe that comes with Win98 (only Win98, it's different from
2155 * the one that comes with Win95 and NT)
2156 */
2157 if(y != CW_USEDEFAULT && y != CW_USEDEFAULT16)
2158 {
2159 dwShowMode = y;
2160 }
2161 }
2162 if(nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16)
2163 {
2164 if(!CalculatedDefPosSize)
2165 {
2166 IntCalcDefPosSize(ParentWindow, &rc, FALSE);
2167 }
2168 if(ProcessParams->WindowFlags & STARTF_USESIZE)
2169 {
2170 ProcessParams->WindowFlags &= ~STARTF_USESIZE;
2171 Size.cx = ProcessParams->CountX;
2172 Size.cy = ProcessParams->CountY;
2173 }
2174 else
2175 {
2176 Size.cx = rc.right - rc.left;
2177 Size.cy = rc.bottom - rc.top;
2178 }
2179
2180 /* move the window if necessary */
2181 if(Pos.x > rc.left)
2182 Pos.x = max(rc.left, 0);
2183 if(Pos.y > rc.top)
2184 Pos.y = max(rc.top, 0);
2185 }
2186 }
2187 else
2188 {
2189 /* if CW_USEDEFAULT(16) is set for non-overlapped windows, both values are set to zero) */
2190 if(x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
2191 {
2192 Pos.x = 0;
2193 Pos.y = 0;
2194 }
2195 if(nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16)
2196 {
2197 Size.cx = 0;
2198 Size.cy = 0;
2199 }
2200 }
2201
2202 /* Initialize the window dimensions. */
2203 Wnd->rcWindow.left = Pos.x;
2204 Wnd->rcWindow.top = Pos.y;
2205 Wnd->rcWindow.right = Pos.x + Size.cx;
2206 Wnd->rcWindow.bottom = Pos.y + Size.cy;
2207 if (0 != (Wnd->style & WS_CHILD) && ParentWindow)
2208 {
2209 RECTL_vOffsetRect(&(Wnd->rcWindow), ParentWindow->Wnd->rcClient.left,
2210 ParentWindow->Wnd->rcClient.top);
2211 }
2212 Wnd->rcClient = Wnd->rcWindow;
2213
2214 /*
2215 * Get the size and position of the window.
2216 */
2217 if ((dwStyle & WS_THICKFRAME) || !(dwStyle & (WS_POPUP | WS_CHILD)))
2218 {
2219 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
2220
2221 /* WinPosGetMinMaxInfo sends the WM_GETMINMAXINFO message */
2222 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
2223 if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
2224 if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
2225 if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
2226 if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
2227 }
2228
2229 if (Size.cx < 0) Size.cx = 0;
2230 if (Size.cy < 0) Size.cy = 0;
2231
2232 Wnd->rcWindow.left = Pos.x;
2233 Wnd->rcWindow.top = Pos.y;
2234 Wnd->rcWindow.right = Pos.x + Size.cx;
2235 Wnd->rcWindow.bottom = Pos.y + Size.cy;
2236 if (0 != (Wnd->style & WS_CHILD) && ParentWindow)
2237 {
2238 RECTL_vOffsetRect(&(Wnd->rcWindow), ParentWindow->Wnd->rcClient.left,
2239 ParentWindow->Wnd->rcClient.top);
2240 }
2241 Wnd->rcClient = Wnd->rcWindow;
2242
2243 /* FIXME: Initialize the window menu. */
2244
2245 /* Send a NCCREATE message. */
2246 DPRINT("[win32k.window] IntCreateWindowEx style %d, exstyle %d, parent %d\n", Cs.style, Cs.dwExStyle, Cs.hwndParent);
2247 DPRINT("IntCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, Size.cx, Size.cy);
2248 DPRINT("IntCreateWindowEx(): About to send NCCREATE message.\n");
2249 Result = co_IntSendMessage(Window->hSelf, WM_NCCREATE, 0, (LPARAM) &Cs);
2250 if (!Result)
2251 {
2252 /* FIXME: Cleanup. */
2253 DPRINT1("IntCreateWindowEx(): NCCREATE message failed. No cleanup performed!\n");
2254 RETURN((PWND)0);
2255 }
2256
2257 /* Calculate the non-client size. */
2258 MaxPos.x = Window->Wnd->rcWindow.left;
2259 MaxPos.y = Window->Wnd->rcWindow.top;
2260
2261
2262 DPRINT("IntCreateWindowEx(): About to get non-client size.\n");
2263 /* WinPosGetNonClientSize SENDS THE WM_NCCALCSIZE message */
2264 Result = co_WinPosGetNonClientSize(Window,
2265 &Window->Wnd->rcWindow,
2266 &Window->Wnd->rcClient);
2267
2268 RECTL_vOffsetRect(&Window->Wnd->rcWindow,
2269 MaxPos.x - Window->Wnd->rcWindow.left,
2270 MaxPos.y - Window->Wnd->rcWindow.top);
2271
2272
2273 if (NULL != ParentWindow)
2274 {
2275 /* link the window into the parent's child list */
2276 if ((dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2277 {
2278 PWINDOW_OBJECT PrevSibling;
2279
2280 PrevSibling = ParentWindow->spwndChild;
2281
2282 if(PrevSibling)
2283 {
2284 while (PrevSibling->spwndNext)
2285 PrevSibling = PrevSibling->spwndNext;
2286 }
2287
2288 /* link window as bottom sibling */
2289 IntLinkWindow(Window, ParentWindow, PrevSibling /*prev sibling*/);
2290 }
2291 else
2292 {
2293 /* link window as top sibling (but after topmost siblings) */
2294 PWINDOW_OBJECT InsertAfter, Sibling;
2295 if (!(dwExStyle & WS_EX_TOPMOST))
2296 {
2297 InsertAfter = NULL;
2298 Sibling = ParentWindow->spwndChild;
2299 while (Sibling && (Sibling->Wnd->ExStyle & WS_EX_TOPMOST))
2300 {
2301 InsertAfter = Sibling;
2302 Sibling = Sibling->spwndNext;
2303 }
2304 }
2305 else
2306 {
2307 InsertAfter = NULL;
2308 }
2309
2310 IntLinkWindow(Window, ParentWindow, InsertAfter /* prev sibling */);
2311 }
2312 }
2313
2314 /* Send the WM_CREATE message. */
2315 DPRINT("IntCreateWindowEx(): about to send CREATE message.\n");
2316 Result = co_IntSendMessage(Window->hSelf, WM_CREATE, 0, (LPARAM) &Cs);
2317
2318 if (Result == (LRESULT)-1)
2319 {
2320 /* FIXME: Cleanup. */
2321 DPRINT1("IntCreateWindowEx(): send CREATE message failed. No cleanup performed!\n");
2322 IntUnlinkWindow(Window);
2323 RETURN((PWND)0);
2324 }
2325
2326 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window->Wnd, OBJID_WINDOW, 0);
2327
2328 /* By setting the flag below it can be examined to determine if the window
2329 was created successfully and a valid pwnd was passed back to caller since
2330 from here the function has to succeed. */
2331 Window->Wnd->state2 |= WNDS2_WMCREATEMSGPROCESSED;
2332
2333 /* Send move and size messages. */
2334 if (!(Window->state & WINDOWOBJECT_NEED_SIZE))
2335 {
2336 LONG lParam;
2337
2338 DPRINT("IntCreateWindow(): About to send WM_SIZE\n");
2339
2340 if ((Window->Wnd->rcClient.right - Window->Wnd->rcClient.left) < 0 ||
2341 (Window->Wnd->rcClient.bottom - Window->Wnd->rcClient.top) < 0)
2342 {
2343 DPRINT("Sending bogus WM_SIZE\n");
2344 }
2345
2346 lParam = MAKE_LONG(Window->Wnd->rcClient.right -
2347 Window->Wnd->rcClient.left,
2348 Window->Wnd->rcClient.bottom -
2349 Window->Wnd->rcClient.top);
2350 co_IntSendMessage(Window->hSelf, WM_SIZE, SIZE_RESTORED,
2351 lParam);
2352
2353 DPRINT("IntCreateWindow(): About to send WM_MOVE\n");
2354
2355 if (0 != (Wnd->style & WS_CHILD) && ParentWindow)
2356 {
2357 lParam = MAKE_LONG(Wnd->rcClient.left - ParentWindow->Wnd->rcClient.left,
2358 Wnd->rcClient.top - ParentWindow->Wnd->rcClient.top);
2359 }
2360 else
2361 {
2362 lParam = MAKE_LONG(Wnd->rcClient.left,
2363 Wnd->rcClient.top);
2364 }
2365
2366 co_IntSendMessage(Window->hSelf, WM_MOVE, 0, lParam);
2367
2368 /* Call WNDOBJ change procs */
2369 IntEngWindowChanged(Window, WOC_RGN_CLIENT);
2370 }
2371
2372 /* Show or maybe minimize or maximize the window. */
2373 if (Wnd->style & (WS_MINIMIZE | WS_MAXIMIZE))
2374 {
2375 RECTL NewPos;
2376 UINT16 SwFlag;
2377
2378 SwFlag = (Wnd->style & WS_MINIMIZE) ? SW_MINIMIZE :
2379 SW_MAXIMIZE;
2380
2381 co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2382
2383 SwFlag = ((Wnd->style & WS_CHILD) || UserGetActiveWindow()) ?
2384 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED :
2385 SWP_NOZORDER | SWP_FRAMECHANGED;
2386
2387 DPRINT("IntCreateWindow(): About to minimize/maximize\n");
2388 DPRINT("%d,%d %dx%d\n", NewPos.left, NewPos.top, NewPos.right, NewPos.bottom);
2389 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2390 NewPos.right, NewPos.bottom, SwFlag);
2391 }
2392
2393 /* Notify the parent window of a new child. */
2394 if ((Wnd->style & WS_CHILD) &&
2395 (!(Wnd->ExStyle & WS_EX_NOPARENTNOTIFY)) && ParentWindow)
2396 {
2397 DPRINT("IntCreateWindow(): About to notify parent\n");
2398 co_IntSendMessage(ParentWindow->hSelf,
2399 WM_PARENTNOTIFY,
2400 MAKEWPARAM(WM_CREATE, Wnd->IDMenu),
2401 (LPARAM)Window->hSelf);
2402 }
2403
2404 if ((!hWndParent) && (!HasOwner))
2405 {
2406 DPRINT("Sending CREATED notify\n");
2407 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)hWnd);
2408 }
2409 else
2410 {
2411 DPRINT("Not sending CREATED notify, %x %d\n", ParentWindow, HasOwner);
2412 }
2413
2414 /* Initialize and show the window's scrollbars */
2415 if (Wnd->style & WS_VSCROLL)
2416 {
2417 co_UserShowScrollBar(Window, SB_VERT, TRUE);
2418 }
2419 if (Wnd->style & WS_HSCROLL)
2420 {
2421 co_UserShowScrollBar(Window, SB_HORZ, TRUE);
2422 }
2423
2424 if (dwStyle & WS_VISIBLE)
2425 {
2426 if (Wnd->style & WS_MAXIMIZE)
2427 dwShowMode = SW_SHOW;
2428 else if (Wnd->style & WS_MINIMIZE)
2429 dwShowMode = SW_SHOWMINIMIZED;
2430
2431 DPRINT("IntCreateWindow(): About to show window\n");
2432 co_WinPosShowWindow(Window, dwShowMode);
2433
2434 if (Wnd->ExStyle & WS_EX_MDICHILD)
2435 {
2436 co_IntSendMessage(ParentWindow->hSelf, WM_MDIREFRESHMENU, 0, 0);
2437 /* ShowWindow won't activate child windows */
2438 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2439 }
2440 }
2441
2442 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
2443 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
2444 Dont understand why it does this. */
2445 if (ClassAtom == gpsi->atomSysClass[ICLS_EDIT])
2446 {
2447 PCALLPROCDATA CallProc;
2448 //CallProc = CreateCallProc(NULL, Wnd->lpfnWndProc, bUnicodeWindow, Wnd->ti->ppi);
2449 CallProc = CreateCallProc(NULL, Wnd->lpfnWndProc, Wnd->Unicode , Wnd->head.pti->ppi);
2450
2451 if (!CallProc)
2452 {
2453 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2454 DPRINT1("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %x\n",hWnd);
2455 }
2456 else
2457 {
2458 UserAddCallProcToClass(Wnd->pcls, CallProc);
2459 }
2460 }
2461
2462 DPRINT("IntCreateWindow(): = %X\n", hWnd);
2463 DPRINT("WindowObject->SystemMenu = 0x%x\n", Window->SystemMenu);
2464 RETURN( Wnd);
2465
2466 CLEANUP:
2467 if (!_ret_ && Window && Window->Wnd && ti)
2468 co_UserDestroyWindow(Window);
2469 // UserFreeWindowInfo(ti, Window);
2470 if (Window)
2471 {
2472 UserDerefObjectCo(Window);
2473 UserDereferenceObject(Window);
2474 }
2475 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2476 if (!_ret_ && ti != NULL)
2477 {
2478 if (Class != NULL)
2479 {
2480 IntDereferenceClass(Class,
2481 ti->pDeskInfo,
2482 ti->ppi);
2483 }
2484 }
2485 END_CLEANUP;
2486 }
2487
2488 NTSTATUS
2489 NTAPI
2490 ProbeAndCaptureLargeString(
2491 OUT PLARGE_STRING plstrSafe,
2492 IN PLARGE_STRING plstrUnsafe)
2493 {
2494 LARGE_STRING lstrTemp;
2495 PVOID pvBuffer = NULL;
2496
2497 _SEH2_TRY
2498 {
2499 /* Probe and copy the string */
2500 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2501 lstrTemp = *plstrUnsafe;
2502 }
2503 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2504 {
2505 /* Fail */
2506 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2507 }
2508 _SEH2_END
2509
2510 if (lstrTemp.Length != 0)
2511 {
2512 /* Allocate a buffer from paged pool */
2513 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2514 if (!pvBuffer)
2515 {
2516 return STATUS_NO_MEMORY;
2517 }
2518
2519 _SEH2_TRY
2520 {
2521 /* Probe and copy the buffer */
2522 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2523 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2524 }
2525 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2526 {
2527 /* Cleanup and fail */
2528 ExFreePool(pvBuffer);
2529 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2530 }
2531 _SEH2_END
2532 }
2533
2534 /* Set the output string */
2535 plstrSafe->Buffer = pvBuffer;
2536 plstrSafe->Length = lstrTemp.Length;
2537 plstrSafe->MaximumLength = lstrTemp.Length;
2538
2539 return STATUS_SUCCESS;
2540 }
2541
2542 /**
2543 * \todo Allow passing plstrClassName as ANSI.
2544 */
2545 HWND
2546 NTAPI
2547 NtUserCreateWindowEx(
2548 DWORD dwExStyle,
2549 PLARGE_STRING plstrClassName,
2550 PLARGE_STRING plstrClsVersion,
2551 PLARGE_STRING plstrWindowName,
2552 DWORD dwStyle,
2553 int x,
2554 int y,
2555 int nWidth,
2556 int nHeight,
2557 HWND hWndParent,
2558 HMENU hMenu,
2559 HINSTANCE hInstance,
2560 LPVOID lpParam,
2561 DWORD dwFlags,
2562 PVOID acbiBuffer)
2563 {
2564 NTSTATUS Status;
2565 LARGE_STRING lstrWindowName;
2566 LARGE_STRING lstrClassName;
2567 UNICODE_STRING ustrClassName;
2568 HWND hwnd = NULL;
2569 PWND pwnd;
2570
2571 DPRINT("Enter NtUserCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, nWidth, nHeight);
2572 UserEnterExclusive();
2573
2574 lstrWindowName.Buffer = NULL;
2575 lstrClassName.Buffer = NULL;
2576
2577 /* Check if we got a Window name */
2578 if (plstrWindowName)
2579 {
2580 /* Copy the string to kernel mode */
2581 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2582 if (!NT_SUCCESS(Status))
2583 {
2584 SetLastNtError(Status);
2585 goto leave;
2586 }
2587 plstrWindowName = &lstrWindowName;
2588 }
2589
2590 /* Check if the class is an atom */
2591 if (IS_ATOM(plstrClassName))
2592 {
2593 /* It is, pass the atom in the UNICODE_STRING */
2594 ustrClassName.Buffer = (PVOID)plstrClassName;
2595 ustrClassName.Length = 0;
2596 ustrClassName.MaximumLength = 0;
2597 }
2598 else
2599 {
2600 /* It's not, capture the class name */
2601 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2602 if (!NT_SUCCESS(Status))
2603 {
2604 /* Set last error, cleanup and return */
2605 SetLastNtError(Status);
2606 goto cleanup;
2607 }
2608
2609 /* We pass it on as a UNICODE_STRING */
2610 ustrClassName.Buffer = lstrClassName.Buffer;
2611 ustrClassName.Length = lstrClassName.Length;
2612 ustrClassName.MaximumLength = lstrClassName.MaximumLength;
2613 }
2614
2615 /* Call the internal function */
2616 pwnd = co_IntCreateWindowEx(dwExStyle,
2617 &ustrClassName,
2618 plstrWindowName,
2619 dwStyle,
2620 x,
2621 y,
2622 nWidth,
2623 nHeight,
2624 hWndParent,
2625 hMenu,
2626 hInstance,
2627 lpParam,
2628 SW_SHOW,
2629 !(dwExStyle & WS_EX_SETANSICREATOR));
2630
2631 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2632
2633 cleanup:
2634 if (lstrWindowName.Buffer)
2635 {
2636 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2637 }
2638 if (lstrClassName.Buffer)
2639 {
2640 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2641 }
2642
2643 leave:
2644 DPRINT("Leave NtUserCreateWindowEx, hwnd=%i\n", hwnd);
2645 UserLeave();
2646
2647 return hwnd;
2648 }
2649
2650 /*
2651 * @unimplemented
2652 */
2653 HDWP APIENTRY
2654 NtUserDeferWindowPos(HDWP WinPosInfo,
2655 HWND Wnd,
2656 HWND WndInsertAfter,
2657 int x,
2658 int y,
2659 int cx,
2660 int cy,
2661 UINT Flags)
2662 {
2663 UNIMPLEMENTED
2664
2665 return 0;
2666 }
2667
2668
2669 BOOLEAN FASTCALL co_UserDestroyWindow(PWINDOW_OBJECT Window)
2670 {
2671 BOOLEAN isChild;
2672 PWND Wnd;
2673 HWND hWnd;
2674 PTHREADINFO ti;
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 if (!IntIsWindow(Window->hSelf))
2813 {
2814 return TRUE;
2815 }
2816
2817 /* Destroy the window storage */
2818 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2819
2820 return TRUE;
2821 }
2822
2823
2824 /*
2825 * @implemented
2826 */
2827 BOOLEAN APIENTRY
2828 NtUserDestroyWindow(HWND Wnd)
2829 {
2830 PWINDOW_OBJECT Window;
2831 DECLARE_RETURN(BOOLEAN);
2832 BOOLEAN ret;
2833 USER_REFERENCE_ENTRY Ref;
2834
2835 DPRINT("Enter NtUserDestroyWindow\n");
2836 UserEnterExclusive();
2837
2838 if (!(Window = UserGetWindowObject(Wnd)))
2839 {
2840 RETURN(FALSE);
2841 }
2842
2843 UserRefObjectCo(Window, &Ref);//faxme: dunno if win should be reffed during destroy..
2844 ret = co_UserDestroyWindow(Window);
2845 UserDerefObjectCo(Window);//faxme: dunno if win should be reffed during destroy..
2846
2847 RETURN(ret);
2848
2849 CLEANUP:
2850 DPRINT("Leave NtUserDestroyWindow, ret=%i\n",_ret_);
2851 UserLeave();
2852 END_CLEANUP;
2853 }
2854
2855
2856
2857 /*
2858 * @unimplemented
2859 */
2860 DWORD
2861 APIENTRY
2862 NtUserDrawMenuBarTemp(
2863 HWND hWnd,
2864 HDC hDC,
2865 PRECT hRect,
2866 HMENU hMenu,
2867 HFONT hFont)
2868 {
2869 /* we'll use this function just for caching the menu bar */
2870 UNIMPLEMENTED
2871 return 0;
2872 }
2873
2874
2875 /*
2876 * @unimplemented
2877 */
2878 DWORD APIENTRY
2879 NtUserEndDeferWindowPosEx(DWORD Unknown0,
2880 DWORD Unknown1)
2881 {
2882 UNIMPLEMENTED
2883
2884 return 0;
2885 }
2886
2887
2888 /*
2889 * FillWindow: Called from User; Dialog, Edit and ListBox procs during a WM_ERASEBKGND.
2890 */
2891 /*
2892 * @unimplemented
2893 */
2894 BOOL APIENTRY
2895 NtUserFillWindow(HWND hWndPaint,
2896 HWND hWndPaint1,
2897 HDC hDC,
2898 HBRUSH hBrush)
2899 {
2900 UNIMPLEMENTED
2901
2902 return 0;
2903 }
2904
2905
2906 static HWND FASTCALL
2907 IntFindWindow(PWINDOW_OBJECT Parent,
2908 PWINDOW_OBJECT ChildAfter,
2909 RTL_ATOM ClassAtom,
2910 PUNICODE_STRING WindowName)
2911 {
2912 BOOL CheckWindowName;
2913 HWND *List, *phWnd;
2914 HWND Ret = NULL;
2915 UNICODE_STRING CurrentWindowName;
2916
2917 ASSERT(Parent);
2918
2919 CheckWindowName = WindowName->Length != 0;
2920
2921 if((List = IntWinListChildren(Parent)))
2922 {
2923 phWnd = List;
2924 if(ChildAfter)
2925 {
2926 /* skip handles before and including ChildAfter */
2927 while(*phWnd && (*(phWnd++) != ChildAfter->hSelf))
2928 ;
2929 }
2930
2931 /* search children */
2932 while(*phWnd)
2933 {
2934 PWINDOW_OBJECT Child;
2935 if(!(Child = UserGetWindowObject(*(phWnd++))))
2936 {
2937 continue;
2938 }
2939
2940 /* Do not send WM_GETTEXT messages in the kernel mode version!
2941 The user mode version however calls GetWindowText() which will
2942 send WM_GETTEXT messages to windows belonging to its processes */
2943 if (!ClassAtom || Child->Wnd->pcls->atomClassName == ClassAtom)
2944 {
2945 // HACK: use UNICODE_STRING instead of LARGE_STRING
2946 CurrentWindowName.Buffer = Child->Wnd->strName.Buffer;
2947 CurrentWindowName.Length = Child->Wnd->strName.Length;
2948 CurrentWindowName.MaximumLength = Child->Wnd->strName.MaximumLength;
2949 if(!CheckWindowName ||
2950 (Child->Wnd->strName.Length < 0xFFFF &&
2951 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
2952 {
2953 Ret = Child->hSelf;
2954 break;
2955 }
2956 }
2957 }
2958 ExFreePool(List);
2959 }
2960
2961 return Ret;
2962 }
2963
2964 /*
2965 * FUNCTION:
2966 * Searches a window's children for a window with the specified
2967 * class and name
2968 * ARGUMENTS:
2969 * hwndParent = The window whose childs are to be searched.
2970 * NULL = desktop
2971 * HWND_MESSAGE = message-only windows
2972 *
2973 * hwndChildAfter = Search starts after this child window.
2974 * NULL = start from beginning
2975 *
2976 * ucClassName = Class name to search for
2977 * Reguired parameter.
2978 *
2979 * ucWindowName = Window name
2980 * ->Buffer == NULL = don't care
2981 *
2982 * RETURNS:
2983 * The HWND of the window if it was found, otherwise NULL
2984 */
2985 /*
2986 * @implemented
2987 */
2988 HWND APIENTRY
2989 NtUserFindWindowEx(HWND hwndParent,
2990 HWND hwndChildAfter,
2991 PUNICODE_STRING ucClassName,
2992 PUNICODE_STRING ucWindowName,
2993 DWORD dwUnknown)
2994 {
2995 PWINDOW_OBJECT Parent, ChildAfter;
2996 UNICODE_STRING ClassName = {0}, WindowName = {0};
2997 HWND Desktop, Ret = NULL;
2998 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2999 DECLARE_RETURN(HWND);
3000
3001 DPRINT("Enter NtUserFindWindowEx\n");
3002 UserEnterShared();
3003
3004 if (ucClassName != NULL || ucWindowName != NULL)
3005 {
3006 _SEH2_TRY
3007 {
3008 if (ucClassName != NULL)
3009 {
3010 ClassName = ProbeForReadUnicodeString(ucClassName);
3011 if (ClassName.Length != 0)
3012 {
3013 ProbeForRead(ClassName.Buffer,
3014 ClassName.Length,
3015 sizeof(WCHAR));
3016 }
3017 else if (!IS_ATOM(ClassName.Buffer))
3018 {
3019 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3020 _SEH2_LEAVE;
3021 }
3022
3023 if (!IntGetAtomFromStringOrAtom(&ClassName,
3024 &ClassAtom))
3025 {
3026 _SEH2_LEAVE;
3027 }
3028 }
3029
3030 if (ucWindowName != NULL)
3031 {
3032 WindowName = ProbeForReadUnicodeString(ucWindowName);
3033 if (WindowName.Length != 0)
3034 {
3035 ProbeForRead(WindowName.Buffer,
3036 WindowName.Length,
3037 sizeof(WCHAR));
3038 }
3039 }
3040 }
3041 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3042 {
3043 SetLastNtError(_SEH2_GetExceptionCode());
3044 _SEH2_YIELD(RETURN(NULL));
3045 }
3046 _SEH2_END;
3047
3048 if (ucClassName != NULL)
3049 {
3050 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
3051 !IS_ATOM(ClassName.Buffer))
3052 {
3053 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3054 RETURN(NULL);
3055 }
3056 else if (ClassAtom == (RTL_ATOM)0)
3057 {
3058 /* LastError code was set by IntGetAtomFromStringOrAtom */
3059 RETURN(NULL);
3060 }
3061 }
3062 }
3063
3064 Desktop = IntGetCurrentThreadDesktopWindow();
3065
3066 if(hwndParent == NULL)
3067 hwndParent = Desktop;
3068 else if(hwndParent == HWND_MESSAGE)
3069 {
3070 hwndParent = IntGetMessageWindow();
3071 }
3072
3073 if(!(Parent = UserGetWindowObject(hwndParent)))
3074 {
3075 RETURN( NULL);
3076 }
3077
3078 ChildAfter = NULL;
3079 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
3080 {
3081 RETURN( NULL);
3082 }
3083
3084 _SEH2_TRY
3085 {
3086 if(Parent->hSelf == Desktop)
3087 {
3088 HWND *List, *phWnd;
3089 PWINDOW_OBJECT TopLevelWindow;
3090 BOOLEAN CheckWindowName;
3091 BOOLEAN WindowMatches;
3092 BOOLEAN ClassMatches;
3093
3094 /* windows searches through all top-level windows if the parent is the desktop
3095 window */
3096
3097 if((List = IntWinListChildren(Parent)))
3098 {
3099 phWnd = List;
3100
3101 if(ChildAfter)
3102 {
3103 /* skip handles before and including ChildAfter */
3104 while(*phWnd && (*(phWnd++) != ChildAfter->hSelf))
3105 ;
3106 }
3107
3108 CheckWindowName = WindowName.Length != 0;
3109
3110 /* search children */
3111 while(*phWnd)
3112 {
3113 UNICODE_STRING ustr;
3114
3115 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
3116 {
3117 continue;
3118 }
3119
3120 /* Do not send WM_GETTEXT messages in the kernel mode version!
3121 The user mode version however calls GetWindowText() which will
3122 send WM_GETTEXT messages to windows belonging to its processes */
3123 ustr.Buffer = TopLevelWindow->Wnd->strName.Buffer;
3124 ustr.Length = TopLevelWindow->Wnd->strName.Length;
3125 ustr.MaximumLength = TopLevelWindow->Wnd->strName.MaximumLength;
3126 WindowMatches = !CheckWindowName ||
3127 (TopLevelWindow->Wnd->strName.Length < 0xFFFF &&
3128 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
3129 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
3130 ClassAtom == TopLevelWindow->Wnd->pcls->atomClassName;
3131
3132 if (WindowMatches && ClassMatches)
3133 {
3134 Ret = TopLevelWindow->hSelf;
3135 break;
3136 }
3137
3138 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
3139 {
3140 /* window returns the handle of the top-level window, in case it found
3141 the child window */
3142 Ret = TopLevelWindow->hSelf;
3143 break;
3144 }
3145
3146 }
3147 ExFreePool(List);
3148 }
3149 }
3150 else
3151 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
3152
3153 #if 0
3154
3155 if(Ret == NULL && hwndParent == NULL && hwndChildAfter == NULL)
3156 {
3157 /* FIXME - if both hwndParent and hwndChildAfter are NULL, we also should
3158 search the message-only windows. Should this also be done if
3159 Parent is the desktop window??? */
3160 PWINDOW_OBJECT MsgWindows;
3161
3162 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3163 {
3164 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3165 }
3166 }
3167 #endif
3168 }
3169 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3170 {
3171 SetLastNtError(_SEH2_GetExceptionCode());
3172 Ret = NULL;
3173 }
3174 _SEH2_END;
3175
3176 RETURN( Ret);
3177
3178 CLEANUP:
3179 DPRINT("Leave NtUserFindWindowEx, ret %i\n",_ret_);
3180 UserLeave();
3181 END_CLEANUP;
3182 }
3183
3184
3185 /*
3186 * @unimplemented
3187 */
3188 BOOL APIENTRY
3189 NtUserFlashWindowEx(IN PFLASHWINFO pfwi)
3190 {
3191 UNIMPLEMENTED
3192
3193 return 0;
3194 }
3195
3196
3197 /*
3198 * @implemented
3199 */
3200 PWINDOW_OBJECT FASTCALL UserGetAncestor(PWINDOW_OBJECT Wnd, UINT Type)
3201 {
3202 PWINDOW_OBJECT WndAncestor, Parent;
3203
3204 if (Wnd->hSelf == IntGetDesktopWindow())
3205 {
3206 return NULL;
3207 }
3208
3209 switch (Type)
3210 {
3211 case GA_PARENT:
3212 {
3213 WndAncestor = Wnd->spwndParent;
3214 break;
3215 }
3216
3217 case GA_ROOT:
3218 {
3219 WndAncestor = Wnd;
3220 Parent = NULL;
3221
3222 for(;;)
3223 {
3224 if(!(Parent = WndAncestor->spwndParent))
3225 {
3226 break;
3227 }
3228 if(IntIsDesktopWindow(Parent))
3229 {
3230 break;
3231 }
3232
3233 WndAncestor = Parent;
3234 }
3235 break;
3236 }
3237
3238 case GA_ROOTOWNER:
3239 {
3240 WndAncestor = Wnd;
3241
3242 for (;;)
3243 {
3244 PWINDOW_OBJECT Parent, Old;
3245
3246 Old = WndAncestor;
3247 Parent = IntGetParent(WndAncestor);
3248
3249 if (!Parent)
3250 {
3251 break;
3252 }
3253
3254 //temp hack
3255 // UserDereferenceObject(Parent);
3256
3257 WndAncestor = Parent;
3258 }
3259 break;
3260 }
3261
3262 default:
3263 {
3264 return NULL;
3265 }
3266 }
3267
3268 return WndAncestor;
3269 }
3270
3271 /*
3272 * @implemented
3273 */
3274 HWND APIENTRY
3275 NtUserGetAncestor(HWND hWnd, UINT Type)
3276 {
3277 PWINDOW_OBJECT Window, Ancestor;
3278 DECLARE_RETURN(HWND);
3279
3280 DPRINT("Enter NtUserGetAncestor\n");
3281 UserEnterExclusive();
3282
3283 if (!(Window = UserGetWindowObject(hWnd)))
3284 {
3285 RETURN(NULL);
3286 }
3287
3288 Ancestor = UserGetAncestor(Window, Type);
3289 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3290
3291 RETURN(Ancestor ? Ancestor->hSelf : NULL);
3292
3293 CLEANUP:
3294 DPRINT("Leave NtUserGetAncestor, ret=%i\n",_ret_);
3295 UserLeave();
3296 END_CLEANUP;
3297 }
3298
3299
3300 BOOL
3301 APIENTRY
3302 NtUserGetComboBoxInfo(
3303 HWND hWnd,
3304 PCOMBOBOXINFO pcbi)
3305 {
3306 PWINDOW_OBJECT Wnd;
3307 DECLARE_RETURN(BOOL);
3308
3309 DPRINT("Enter NtUserGetComboBoxInfo\n");
3310 UserEnterShared();
3311
3312 if (!(Wnd = UserGetWindowObject(hWnd)))
3313 {
3314 RETURN( FALSE );
3315 }
3316 _SEH2_TRY
3317 {
3318 if(pcbi)
3319 {
3320 ProbeForWrite(pcbi,
3321 sizeof(COMBOBOXINFO),
3322 1);
3323 }
3324 }
3325 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3326 {
3327 SetLastNtError(_SEH2_GetExceptionCode());
3328 _SEH2_YIELD(RETURN(FALSE));
3329 }
3330 _SEH2_END;
3331
3332 // Pass the user pointer, it was already probed.
3333 RETURN( (BOOL) co_IntSendMessage( Wnd->hSelf, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3334
3335 CLEANUP:
3336 DPRINT("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3337 UserLeave();
3338 END_CLEANUP;
3339 }
3340
3341
3342 /*
3343 * @implemented
3344 */
3345 DWORD APIENTRY
3346 NtUserGetInternalWindowPos( HWND hWnd,
3347 LPRECT rectWnd,
3348 LPPOINT ptIcon)
3349 {
3350 PWINDOW_OBJECT Window;
3351 PWND Wnd;
3352 DWORD Ret = 0;
3353 BOOL Hit = FALSE;
3354 WINDOWPLACEMENT wndpl;
3355
3356 UserEnterShared();
3357
3358 if (!(Window = UserGetWindowObject(hWnd)) || !Window->Wnd)
3359 {
3360 Hit = FALSE;
3361 goto Exit;
3362 }
3363 Wnd = Window->Wnd;
3364
3365 _SEH2_TRY
3366 {
3367 if(rectWnd)
3368 {
3369 ProbeForWrite(rectWnd,
3370 sizeof(RECT),
3371 1);
3372 }
3373 if(ptIcon)
3374 {
3375 ProbeForWrite(ptIcon,
3376 sizeof(POINT),
3377 1);
3378 }
3379
3380 }
3381 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3382 {
3383 SetLastNtError(_SEH2_GetExceptionCode());
3384 Hit = TRUE;
3385 }
3386 _SEH2_END;
3387
3388 wndpl.length = sizeof(WINDOWPLACEMENT);
3389
3390 if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
3391 {
3392 _SEH2_TRY
3393 {
3394 if (rectWnd)
3395 {
3396 RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));
3397 }
3398 if (ptIcon)
3399 {
3400 RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT));
3401 }
3402
3403 }
3404 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3405 {
3406 SetLastNtError(_SEH2_GetExceptionCode());
3407 Hit = TRUE;
3408 }
3409 _SEH2_END;
3410
3411 if (!Hit) Ret = wndpl.showCmd;
3412 }
3413 Exit:
3414 UserLeave();
3415 return Ret;
3416 }
3417
3418 DWORD
3419 APIENTRY
3420 NtUserGetListBoxInfo(
3421 HWND hWnd)
3422 {
3423 PWINDOW_OBJECT Wnd;
3424 DECLARE_RETURN(DWORD);
3425
3426 DPRINT("Enter NtUserGetListBoxInfo\n");
3427 UserEnterShared();
3428
3429 if (!(Wnd = UserGetWindowObject(hWnd)))
3430 {
3431 RETURN( 0 );
3432 }
3433
3434 RETURN( (DWORD) co_IntSendMessage( Wnd->hSelf, LB_GETLISTBOXINFO, 0, 0 ));
3435
3436 CLEANUP:
3437 DPRINT("Leave NtUserGetListBoxInfo, ret=%i\n",_ret_);
3438 UserLeave();
3439 END_CLEANUP;
3440 }
3441
3442
3443 HWND FASTCALL
3444 co_UserSetParent(HWND hWndChild, HWND hWndNewParent)
3445 {
3446 PWINDOW_OBJECT Wnd = NULL, WndParent = NULL, WndOldParent;
3447 HWND hWndOldParent = NULL;
3448 USER_REFERENCE_ENTRY Ref, ParentRef;
3449
3450 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
3451 {
3452 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3453 return( NULL);
3454 }
3455
3456 if (hWndChild == IntGetDesktopWindow())
3457 {
3458 SetLastWin32Error(ERROR_ACCESS_DENIED);
3459 return( NULL);
3460 }
3461
3462 if (hWndNewParent)
3463 {
3464 if (!(WndParent = UserGetWindowObject(hWndNewParent)))
3465 {
3466 return( NULL);
3467 }
3468 }
3469 else
3470 {
3471 if (!(WndParent = UserGetWindowObject(IntGetDesktopWindow())))
3472 {
3473 return( NULL);
3474 }
3475 }
3476
3477 if (!(Wnd = UserGetWindowObject(hWndChild)))
3478 {
3479 return( NULL);
3480 }
3481
3482 UserRefObjectCo(Wnd, &Ref);
3483 UserRefObjectCo(WndParent, &ParentRef);
3484
3485 WndOldParent = co_IntSetParent(Wnd, WndParent);
3486
3487 UserDerefObjectCo(WndParent);
3488 UserDerefObjectCo(Wnd);
3489
3490 if (WndOldParent)
3491 {
3492 hWndOldParent = WndOldParent->hSelf;
3493 UserDereferenceObject(WndOldParent);
3494 }
3495
3496 return( hWndOldParent);
3497 }
3498
3499 /*
3500 * NtUserSetParent
3501 *
3502 * The NtUserSetParent function changes the parent window of the specified
3503 * child window.
3504 *
3505 * Remarks
3506 * The new parent window and the child window must belong to the same
3507 * application. If the window identified by the hWndChild parameter is
3508 * visible, the system performs the appropriate redrawing and repainting.
3509 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3510 * or WS_POPUP window styles of the window whose parent is being changed.
3511 *
3512 * Status
3513 * @implemented
3514 */
3515
3516 HWND APIENTRY
3517 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3518 {
3519 DECLARE_RETURN(HWND);
3520
3521 DPRINT("Enter NtUserSetParent\n");
3522 UserEnterExclusive();
3523
3524 /*
3525 Check Parent first from user space, set it here.
3526 */
3527 if (!hWndNewParent)
3528 {
3529 hWndNewParent = IntGetDesktopWindow();
3530 }
3531 else if (hWndNewParent == HWND_MESSAGE)
3532 {
3533 hWndNewParent = IntGetMessageWindow();
3534 }
3535
3536 RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3537
3538 CLEANUP:
3539 DPRINT("Leave NtUserSetParent, ret=%i\n",_ret_);
3540 UserLeave();
3541 END_CLEANUP;
3542 }
3543
3544 /*
3545 * UserGetShellWindow
3546 *
3547 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3548 *
3549 * Status
3550 * @implemented
3551 */
3552 HWND FASTCALL UserGetShellWindow(VOID)
3553 {
3554 PWINSTATION_OBJECT WinStaObject;
3555 HWND Ret;
3556
3557 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3558 KernelMode,
3559 0,
3560 &WinStaObject);
3561
3562 if (!NT_SUCCESS(Status))
3563 {
3564 SetLastNtError(Status);
3565 return( (HWND)0);
3566 }
3567
3568 Ret = (HWND)WinStaObject->ShellWindow;
3569
3570 ObDereferenceObject(WinStaObject);
3571 return( Ret);
3572 }
3573
3574 /*
3575 * NtUserSetShellWindowEx
3576 *
3577 * This is undocumented function to set global shell window. The global
3578 * shell window has special handling of window position.
3579 *
3580 * Status
3581 * @implemented
3582 */
3583 BOOL APIENTRY
3584 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3585 {
3586 PWINSTATION_OBJECT WinStaObject;
3587 PWINDOW_OBJECT WndShell;
3588 DECLARE_RETURN(BOOL);
3589 USER_REFERENCE_ENTRY Ref;
3590 NTSTATUS Status;
3591 PTHREADINFO ti;
3592
3593 DPRINT("Enter NtUserSetShellWindowEx\n");
3594 UserEnterExclusive();
3595
3596 if (!(WndShell = UserGetWindowObject(hwndShell)))
3597 {
3598 RETURN(FALSE);
3599 }
3600
3601 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3602 KernelMode,
3603 0,
3604 &WinStaObject);
3605
3606 if (!NT_SUCCESS(Status))
3607 {
3608 SetLastNtError(Status);
3609 RETURN( FALSE);
3610 }
3611
3612 /*
3613 * Test if we are permitted to change the shell window.
3614 */
3615 if (WinStaObject->ShellWindow)
3616 {
3617 ObDereferenceObject(WinStaObject);
3618 RETURN( FALSE);
3619 }
3620
3621 /*
3622 * Move shell window into background.
3623 */
3624 if (hwndListView && hwndListView != hwndShell)
3625 {
3626 /*
3627 * Disabled for now to get Explorer working.
3628 * -- Filip, 01/nov/2003
3629 */
3630 #if 0
3631 co_WinPosSetWindowPos(hwndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3632 #endif
3633
3634 if (UserGetWindowLong(hwndListView, GWL_EXSTYLE, FALSE) & WS_EX_TOPMOST)
3635 {
3636 ObDereferenceObject(WinStaObject);
3637 RETURN( FALSE);
3638 }
3639 }
3640
3641 if (UserGetWindowLong(hwndShell, GWL_EXSTYLE, FALSE) & WS_EX_TOPMOST)
3642 {
3643 ObDereferenceObject(WinStaObject);
3644 RETURN( FALSE);
3645 }
3646
3647 UserRefObjectCo(WndShell, &Ref);
3648 co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3649
3650 WinStaObject->ShellWindow = hwndShell;
3651 WinStaObject->ShellListView = hwndListView;
3652
3653 ti = GetW32ThreadInfo();
3654 if (ti->pDeskInfo) ti->pDeskInfo->hShellWindow = hwndShell;
3655
3656 UserDerefObjectCo(WndShell);
3657
3658 ObDereferenceObject(WinStaObject);
3659 RETURN( TRUE);
3660
3661 CLEANUP:
3662 DPRINT("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3663 UserLeave();
3664 END_CLEANUP;
3665 }
3666
3667 /*
3668 * NtUserGetSystemMenu
3669 *
3670 * The NtUserGetSystemMenu function allows the application to access the
3671 * window menu (also known as the system menu or the control menu) for
3672 * copying and modifying.
3673 *
3674 * Parameters
3675 * hWnd
3676 * Handle to the window that will own a copy of the window menu.
3677 * bRevert
3678 * Specifies the action to be taken. If this parameter is FALSE,
3679 * NtUserGetSystemMenu returns a handle to the copy of the window menu
3680 * currently in use. The copy is initially identical to the window menu
3681 * but it can be modified.
3682 * If this parameter is TRUE, GetSystemMenu resets the window menu back
3683 * to the default state. The previous window menu, if any, is destroyed.
3684 *
3685 * Return Value
3686 * If the bRevert parameter is FALSE, the return value is a handle to a
3687 * copy of the window menu. If the bRevert parameter is TRUE, the return
3688 * value is NULL.
3689 *
3690 * Status
3691 * @implemented
3692 */
3693
3694 HMENU APIENTRY
3695 NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
3696 {
3697 PWINDOW_OBJECT Window;
3698 PMENU_OBJECT Menu;
3699 DECLARE_RETURN(HMENU);
3700
3701 DPRINT("Enter NtUserGetSystemMenu\n");
3702 UserEnterShared();
3703
3704 if (!(Window = UserGetWindowObject(hWnd)))
3705 {
3706 RETURN(NULL);
3707 }
3708
3709 if (!(Menu = IntGetSystemMenu(Window, bRevert, FALSE)))
3710 {
3711 RETURN(NULL);
3712 }
3713
3714 RETURN(Menu->MenuInfo.Self);
3715
3716 CLEANUP:
3717 DPRINT("Leave NtUserGetSystemMenu, ret=%i\n",_ret_);
3718 UserLeave();
3719 END_CLEANUP;
3720 }
3721
3722 /*
3723 * NtUserSetSystemMenu
3724 *
3725 * Status
3726 * @implemented
3727 */
3728
3729 BOOL APIENTRY
3730 NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
3731 {
3732 BOOL Result = FALSE;
3733 PWINDOW_OBJECT Window;
3734 PMENU_OBJECT Menu;
3735 DECLARE_RETURN(BOOL);
3736
3737 DPRINT("Enter NtUserSetSystemMenu\n");
3738 UserEnterExclusive();
3739
3740 if (!(Window = UserGetWindowObject(hWnd)))
3741 {
3742 RETURN( FALSE);
3743 }
3744
3745 if (hMenu)
3746 {
3747 /*
3748 * Assign new menu handle.
3749 */
3750 if (!(Menu = UserGetMenuObject(hMenu)))
3751 {
3752 RETURN( FALSE);
3753 }
3754
3755 Result = IntSetSystemMenu(Window, Menu);
3756 }
3757
3758 RETURN( Result);
3759
3760 CLEANUP:
3761 DPRINT("Leave NtUserSetSystemMenu, ret=%i\n",_ret_);
3762 UserLeave();
3763 END_CLEANUP;
3764 }
3765
3766 HWND FASTCALL
3767 UserGetWindow(HWND hWnd, UINT Relationship)
3768 {
3769 PWINDOW_OBJECT Parent, Window;
3770 HWND hWndResult = NULL;
3771
3772 if (!(Window = UserGetWindowObject(hWnd)))
3773 return NULL;
3774
3775 switch (Relationship)
3776 {
3777 case GW_HWNDFIRST:
3778 if((Parent = Window->spwndParent))
3779 {
3780 if (Parent->spwndChild)
3781 hWndResult = Parent->spwndChild->hSelf;
3782 }
3783 break;
3784
3785 case GW_HWNDLAST:
3786 if((Parent = Window->spwndParent))
3787 {
3788 if (Parent->spwndChild)
3789 {
3790 Window = Parent->spwndChild;
3791 if(Window)
3792 {
3793 while(Window->spwndNext)
3794 Window = Window->spwndNext;
3795 }
3796 hWndResult = Window->hSelf;
3797 }
3798 }
3799 break;
3800
3801 case GW_HWNDNEXT:
3802 if (Window->spwndNext)
3803 hWndResult = Window->spwndNext->hSelf;
3804 break;
3805
3806 case GW_HWNDPREV:
3807 if (Window->spwndPrev)
3808 hWndResult = Window->spwndPrev->hSelf;
3809 break;
3810
3811 case GW_OWNER:
3812 if((Parent = UserGetWindowObject(Window->hOwner)))
3813 {
3814 hWndResult = Parent->hSelf;
3815 }
3816 break;
3817 case GW_CHILD:
3818 if (Window->spwndChild)
3819 hWndResult = Window->spwndChild->hSelf;
3820 break;
3821 }
3822
3823 return hWndResult;
3824 }
3825
3826 /*
3827 * NtUserGetWindowLong
3828 *
3829 * The NtUserGetWindowLong function retrieves information about the specified
3830 * window. The function also retrieves the 32-bit (long) value at the
3831 * specified offset into the extra window memory.
3832 *
3833 * Status
3834 * @implemented
3835 */
3836
3837 LONG FASTCALL
3838 UserGetWindowLong(HWND hWnd, DWORD Index, BOOL Ansi)
3839 {
3840 PWINDOW_OBJECT Window, Parent;
3841 PWND Wnd;
3842 LONG Result = 0;
3843
3844 DPRINT("NtUserGetWindowLong(%x,%d,%d)\n", hWnd, (INT)Index, Ansi);
3845
3846 if (!(Window = UserGetWindowObject(hWnd)) || !Window->Wnd)
3847 {
3848 return 0;
3849 }
3850
3851 Wnd = Window->Wnd;
3852
3853 /*
3854 * WndProc is only available to the owner process
3855 */
3856 if (GWL_WNDPROC == Index
3857 && Window->pti->pEThread->ThreadsProcess != PsGetCurrentProcess())
3858 {
3859 SetLastWin32Error(ERROR_ACCESS_DENIED);
3860 return 0;
3861 }
3862
3863 if ((INT)Index >= 0)
3864 {
3865 if ((Index + sizeof(LONG)) > Window->Wnd->cbwndExtra)
3866 {
3867 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3868 return 0;
3869 }
3870 Result = *((LONG *)((PCHAR)(Window->Wnd + 1) + Index));
3871 }
3872 else
3873 {
3874 switch (Index)
3875 {
3876 case GWL_EXSTYLE:
3877 Result = Wnd->ExStyle;
3878 break;
3879
3880 case GWL_STYLE:
3881 Result = Wnd->style;
3882 break;
3883
3884 case GWL_WNDPROC:
3885 Result = (LONG)IntGetWindowProc(Wnd, Ansi);
3886 break;
3887
3888 case GWL_HINSTANCE:
3889 Result = (LONG) Wnd->hModule;
3890 break;
3891
3892 case GWL_HWNDPARENT:
3893 Parent = Window->spwndParent;
3894 if(Parent)
3895 {
3896 if (Parent && Parent->hSelf == IntGetDesktopWindow())
3897 Result = (LONG) UserGetWindow(Window->hSelf, GW_OWNER);
3898 else
3899 Result = (LONG) Parent->hSelf;
3900 }
3901 break;
3902
3903 case GWL_ID:
3904 Result = (LONG) Wnd->IDMenu;
3905 break;
3906
3907 case GWL_USERDATA:
3908 Result = Wnd->dwUserData;
3909 break;
3910
3911 default:
3912 DPRINT1("NtUserGetWindowLong(): Unsupported index %d\n", Index);
3913 SetLastWin32Error(ERROR_INVALID_PARAMETER);
3914 Result = 0;
3915 break;
3916 }
3917 }
3918
3919 return Result;
3920 }
3921
3922 LONG FASTCALL
3923 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3924 {
3925 PWINDOW_OBJECT Window, Parent;
3926 PWND Wnd;
3927 PWINSTATION_OBJECT WindowStation;
3928 LONG OldValue;
3929 STYLESTRUCT Style;
3930
3931 if (hWnd == IntGetDesktopWindow())
3932 {
3933 SetLastWin32Error(STATUS_ACCESS_DENIED);
3934 return( 0);
3935 }
3936
3937 if (!(Window = UserGetWindowObject(hWnd)))
3938 {
3939 return( 0);
3940 }
3941
3942 Wnd = Window->Wnd;
3943
3944 if (!Wnd) return 0; // No go on zero.
3945
3946 if ((INT)Index >= 0)
3947 {
3948 if ((Index + sizeof(LONG)) > Wnd->cbwndExtra)
3949 {
3950 SetLastWin32Error(ERROR_INVALID_INDEX);
3951 return( 0);
3952 }
3953
3954 OldValue = *((LONG *)((PCHAR)(Wnd + 1) + Index));
3955 /*
3956 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3957 {
3958 OldValue = (LONG)IntSetWindowProc( Wnd,
3959 (WNDPROC)NewValue,
3960 Ansi);
3961 if (!OldValue) return 0;
3962 }
3963 */
3964 *((LONG *)((PCHAR)(Wnd + 1) + Index)) = NewValue;
3965 }
3966 else
3967 {
3968 switch (Index)
3969 {
3970 case GWL_EXSTYLE:
3971 OldValue = (LONG) Wnd->ExStyle;
3972 Style.styleOld = OldValue;
3973 Style.styleNew = NewValue;
3974
3975 /*
3976 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3977 */
3978 WindowStation = Window->pti->rpdesk->rpwinstaParent;
3979 if(WindowStation)
3980 {
3981 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3982 Style.styleNew &= ~WS_EX_TOPMOST;
3983 }
3984
3985 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3986 Wnd->ExStyle = (DWORD)Style.styleNew;
3987 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3988 break;
3989
3990 case GWL_STYLE:
3991 OldValue = (LONG) Wnd->style;
3992 Style.styleOld = OldValue;
3993 Style.styleNew = NewValue;
3994 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3995 Wnd->style = (DWORD)Style.styleNew;
3996 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3997 break;
3998
3999 case GWL_WNDPROC:
4000 {
4001 if ( Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
4002 Wnd->fnid & FNID_FREED)
4003 {
4004 SetLastWin32Error(ERROR_ACCESS_DENIED);
4005 return( 0);
4006 }
4007 OldValue = (LONG)IntSetWindowProc(Wnd,
4008 (WNDPROC)NewValue,
4009 Ansi);
4010 break;
4011 }
4012
4013 case GWL_HINSTANCE:
4014 OldValue = (LONG) Wnd->hModule;
4015 Wnd->hModule = (HINSTANCE) NewValue;
4016 break;
4017
4018 case GWL_HWNDPARENT:
4019 Parent = Window->spwndParent;
4020 if (Parent && (Parent->hSelf == IntGetDesktopWindow()))
4021 OldValue = (LONG) IntSetOwner(Window->hSelf, (HWND) NewValue);
4022 else
4023 OldValue = (LONG) co_UserSetParent(Window->hSelf, (HWND) NewValue);
4024 break;
4025
4026 case GWL_ID:
4027 OldValue = (LONG) Wnd->IDMenu;
4028 Wnd->IDMenu = (UINT) NewValue;
4029 break;
4030
4031 case GWL_USERDATA:
4032 OldValue = Wnd->dwUserData;
4033 Wnd->dwUserData = NewValue;
4034 break;
4035
4036 default:
4037 DPRINT1("NtUserSetWindowLong(): Unsupported index %d\n", Index);
4038 SetLastWin32Error(ERROR_INVALID_INDEX);
4039 OldValue = 0;
4040 break;
4041 }
4042 }
4043
4044 return( OldValue);
4045 }
4046
4047 /*
4048 * NtUserSetWindowLong
4049 *
4050 * The NtUserSetWindowLong function changes an attribute of the specified
4051 * window. The function also sets the 32-bit (long) value at the specified
4052 * offset into the extra window memory.
4053 *
4054 * Status
4055 * @implemented
4056 */
4057
4058 LONG APIENTRY
4059 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
4060 {
4061 DECLARE_RETURN(LONG);
4062
4063 DPRINT("Enter NtUserSetWindowLong\n");
4064 UserEnterExclusive();
4065
4066 RETURN( co_UserSetWindowLong(hWnd, Index, NewValue, Ansi));
4067
4068 CLEANUP:
4069 DPRINT("Leave NtUserSetWindowLong, ret=%i\n",_ret_);
4070 UserLeave();
4071 END_CLEANUP;
4072 }
4073
4074 /*
4075 * NtUserSetWindowWord
4076 *
4077 * Legacy function similar to NtUserSetWindowLong.
4078 *
4079 * Status
4080 * @implemented
4081 */
4082
4083 WORD APIENTRY
4084 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
4085 {
4086 PWINDOW_OBJECT Window;
4087 WORD OldValue;
4088 DECLARE_RETURN(WORD);
4089
4090 DPRINT("Enter NtUserSetWindowWord\n");
4091 UserEnterExclusive();
4092
4093 if (!(Window = UserGetWindowObject(hWnd)))
4094 {
4095 RETURN( 0);
4096 }
4097
4098 switch (Index)
4099 {
4100 case GWL_ID:
4101 case GWL_HINSTANCE:
4102 case GWL_HWNDPARENT:
4103 RETURN( co_UserSetWindowLong(Window->hSelf, Index, (UINT)NewValue, TRUE));
4104 default:
4105 if (Index < 0)
4106 {
4107 SetLastWin32Error(ERROR_INVALID_INDEX);
4108 RETURN( 0);
4109 }
4110 }
4111
4112 if (Index > Window->Wnd->cbwndExtra - sizeof(WORD))
4113 {
4114 SetLastWin32Error(ERROR_INVALID_PARAMETER);
4115 RETURN( 0);
4116 }
4117
4118 OldValue = *((WORD *)((PCHAR)(Window->Wnd + 1) + Index));
4119 *((WORD *)((PCHAR)(Window->Wnd + 1) + Index)) = NewValue;
4120
4121 RETURN( OldValue);
4122
4123 CLEANUP:
4124 DPRINT("Leave NtUserSetWindowWord, ret=%i\n",_ret_);
4125 UserLeave();
4126 END_CLEANUP;
4127 }
4128
4129 /*
4130 * @implemented
4131 */
4132 BOOL APIENTRY
4133 NtUserGetWindowPlacement(HWND hWnd,
4134 WINDOWPLACEMENT *lpwndpl)
4135 {
4136 PWINDOW_OBJECT Window;
4137 PWND Wnd;
4138 POINT Size;
4139 WINDOWPLACEMENT Safepl;
4140 NTSTATUS Status;
4141 DECLARE_RETURN(BOOL);
4142
4143 DPRINT("Enter NtUserGetWindowPlacement\n");
4144 UserEnterShared();
4145
4146 if (!(Window = UserGetWindowObject(hWnd)))
4147 {
4148 RETURN( FALSE);
4149 }
4150 Wnd = Window->Wnd;
4151
4152 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
4153 if(!NT_SUCCESS(Status))
4154 {
4155 SetLastNtError(Status);
4156 RETURN( FALSE);
4157 }
4158 if(Safepl.length != sizeof(WINDOWPLACEMENT))
4159 {
4160 RETURN( FALSE);
4161 }
4162
4163 Safepl.flags = 0;
4164 if (0 == (Wnd->style & WS_VISIBLE))
4165 {
4166 Safepl.showCmd = SW_HIDE;
4167 }
4168 else if ((0 != (Window->state & WINDOWOBJECT_RESTOREMAX) ||
4169 0 != (Wnd->style & WS_MAXIMIZE)) &&
4170 0 == (Wnd->style & WS_MINIMIZE))
4171 {
4172 Safepl.showCmd = SW_SHOWMAXIMIZED;
4173 }
4174 else if (0 != (Wnd->style & WS_MINIMIZE))
4175 {
4176 Safepl.showCmd = SW_SHOWMINIMIZED;
4177 }
4178 else if (0 != (Wnd->style & WS_VISIBLE))
4179 {
4180 Safepl.showCmd = SW_SHOWNORMAL;
4181 }
4182
4183 Size.x = Wnd->rcWindow.left;
4184 Size.y = Wnd->rcWindow.top;
4185 WinPosInitInternalPos(Window, &Size,
4186 &Wnd->rcWindow);
4187
4188 Safepl.rcNormalPosition = Wnd->InternalPos.NormalRect;
4189 Safepl.ptMinPosition = Wnd->InternalPos.IconPos;
4190 Safepl.ptMaxPosition = Wnd->InternalPos.MaxPos;
4191
4192 Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
4193 if(!NT_SUCCESS(Status))
4194 {
4195 SetLastNtError(Status);
4196 RETURN( FALSE);
4197 }
4198
4199 RETURN( TRUE);
4200
4201 CLEANUP:
4202 DPRINT("Leave NtUserGetWindowPlacement, ret=%i\n",_ret_);
4203 UserLeave();
4204 END_CLEANUP;
4205 }
4206
4207
4208 /*
4209 * @unimplemented
4210 */
4211 BOOL APIENTRY
4212 NtUserLockWindowUpdate(HWND hWnd)
4213 {
4214 UNIMPLEMENTED
4215
4216 return 0;
4217 }
4218
4219
4220 /*
4221 * @implemented
4222 */
4223 BOOL APIENTRY
4224 NtUserMoveWindow(
4225 HWND hWnd,
4226 int X,
4227 int Y,
4228 int nWidth,
4229 int nHeight,
4230 BOOL bRepaint)
4231 {
4232 return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight,
4233 (bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE :
4234 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW));
4235 }
4236
4237 /*
4238 QueryWindow based on KJK::Hyperion and James Tabor.
4239
4240 0 = QWUniqueProcessId
4241 1 = QWUniqueThreadId
4242 2 = QWActiveWindow
4243 3 = QWFocusWindow
4244 4 = QWIsHung Implements IsHungAppWindow found
4245 by KJK::Hyperion.
4246
4247 9 = QWKillWindow When I called this with hWnd ==
4248 DesktopWindow, it shutdown the system
4249 and rebooted.
4250 */
4251 /*
4252 * @implemented
4253 */
4254 DWORD APIENTRY
4255 NtUserQueryWindow(HWND hWnd, DWORD Index)
4256 {
4257 PWINDOW_OBJECT Window;
4258 PWND pWnd;
4259 DWORD Result;
4260 DECLARE_RETURN(UINT);
4261
4262 DPRINT("Enter NtUserQueryWindow\n");
4263 UserEnterShared();
4264
4265 if (!(Window = UserGetWindowObject(hWnd)) || !Window->Wnd)
4266 {
4267 RETURN( 0);
4268 }
4269
4270 pWnd = Window->Wnd;
4271
4272 switch(Index)
4273 {
4274 case QUERY_WINDOW_UNIQUE_PROCESS_ID:
4275 Result = (DWORD)IntGetWndProcessId(Window);
4276 break;
4277
4278 case QUERY_WINDOW_UNIQUE_THREAD_ID:
4279 Result = (DWORD)IntGetWndThreadId(Window);
4280 break;
4281
4282 case QUERY_WINDOW_ACTIVE:
4283 Result = (DWORD)UserGetActiveWindow();
4284 break;
4285
4286 case QUERY_WINDOW_FOCUS:
4287 Result = (DWORD)IntGetFocusWindow();
4288 break;
4289
4290 case QUERY_WINDOW_ISHUNG:
4291 Result = (DWORD)MsqIsHung(Window->pti->MessageQueue);
4292 break;
4293
4294 case QUERY_WINDOW_REAL_ID:
4295 Result = (DWORD)pWnd->head.pti->pEThread->Cid.UniqueProcess;
4296
4297 default:
4298 Result = (DWORD)NULL;
4299 break;
4300 }
4301
4302 RETURN( Result);
4303
4304 CLEANUP:
4305 DPRINT("Leave NtUserQueryWindow, ret=%i\n",_ret_);
4306 UserLeave();
4307 END_CLEANUP;
4308 }
4309
4310
4311 /*
4312 * @unimplemented
4313 */
4314 DWORD APIENTRY
4315 NtUserRealChildWindowFromPoint(DWORD Unknown0,
4316 DWORD Unknown1,
4317 DWORD Unknown2)
4318 {
4319 UNIMPLEMENTED
4320
4321 return 0;
4322 }
4323
4324
4325 /*
4326 * @implemented
4327 */
4328 UINT APIENTRY
4329 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
4330 {
4331 UNICODE_STRING SafeMessageName;
4332 NTSTATUS Status;
4333 UINT Ret;
4334 DECLARE_RETURN(UINT);
4335
4336 DPRINT("Enter NtUserRegisterWindowMessage\n");
4337 UserEnterExclusive();
4338
4339 if(MessageNameUnsafe == NULL)
4340 {
4341 SetLastWin32Error(ERROR_INVALID_PARAMETER);
4342 RETURN( 0);
4343 }
4344
4345 Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
4346 if(!NT_SUCCESS(Status))
4347 {
4348 SetLastNtError(Status);
4349 RETURN( 0);
4350 }
4351
4352 Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
4353 if (SafeMessageName.Buffer)
4354 ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING);
4355 RETURN( Ret);
4356
4357 CLEANUP:
4358 DPRINT("Leave NtUserRegisterWindowMessage, ret=%i\n",_ret_);
4359 UserLeave();
4360 END_CLEANUP;
4361 }
4362
4363
4364 /*
4365 * @unimplemented
4366 */
4367 DWORD APIENTRY
4368 NtUserSetImeOwnerWindow(DWORD Unknown0,
4369 DWORD Unknown1)
4370 {
4371 UNIMPLEMENTED
4372
4373 return 0;
4374 }
4375
4376
4377 /*
4378 * @unimplemented
4379 */
4380 DWORD APIENTRY
4381 NtUserSetInternalWindowPos(
4382 HWND hwnd,
4383 UINT showCmd,
4384 LPRECT rect,
4385 LPPOINT pt)
4386 {
4387 UNIMPLEMENTED
4388
4389 return 0;
4390
4391 }
4392
4393
4394 /*
4395 * @unimplemented
4396 */
4397 BOOL APIENTRY
4398 NtUserSetLayeredWindowAttributes(HWND hwnd,
4399 COLORREF crKey,
4400 BYTE bAlpha,
4401 DWORD dwFlags)
4402 {
4403 UNIMPLEMENTED;
4404 return FALSE;
4405 }
4406
4407
4408 /*
4409 * @unimplemented
4410 */
4411 BOOL APIENTRY
4412 NtUserSetLogonNotifyWindow(HWND hWnd)
4413 {
4414 UNIMPLEMENTED
4415
4416 return 0;
4417 }
4418
4419
4420 /*
4421 * @implemented
4422 */
4423 BOOL APIENTRY
4424 NtUserSetMenu(
4425 HWND hWnd,
4426 HMENU Menu,
4427 BOOL Repaint)
4428 {
4429 PWINDOW_OBJECT Window;
4430 BOOL Changed;
4431 DECLARE_RETURN(BOOL);
4432
4433 DPRINT("Enter NtUserSetMenu\n");
4434 UserEnterExclusive();
4435
4436 if (!(Window = UserGetWindowObject(hWnd)))
4437 {
4438 RETURN( FALSE);
4439 }
4440
4441 if (! IntSetMenu(Window, Menu, &Changed))
4442 {
4443 RETURN( FALSE);
4444 }
4445
4446 if (Changed && Repaint)
4447 {
4448 USER_REFERENCE_ENTRY Ref;
4449
4450 UserRefObjectCo(Window, &Ref);
4451 co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4452 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
4453
4454 UserDerefObjectCo(Window);
4455 }
4456
4457 RETURN( TRUE);
4458
4459 CLEANUP:
4460 DPRINT("Leave NtUserSetMenu, ret=%i\n",_ret_);
4461 UserLeave();
4462 END_CLEANUP;
4463 }
4464
4465
4466 /*
4467 * @implemented
4468 */
4469 BOOL APIENTRY
4470 NtUserSetWindowFNID(HWND hWnd,
4471 WORD fnID)
4472 {
4473 PWINDOW_OBJECT Window;
4474 PWND Wnd;
4475 DECLARE_RETURN(BOOL);
4476
4477 DPRINT("Enter NtUserSetWindowFNID\n");
4478 UserEnterExclusive();
4479
4480 if (!(Window = UserGetWindowObject(hWnd)))
4481 {
4482 RETURN( FALSE);
4483 }
4484 Wnd = Window->Wnd;
4485
4486 if (Wnd->pcls)
4487 { // From user land we only set these.
4488 if ((fnID != FNID_DESTROY) || ((fnID < FNID_BUTTON) && (fnID > FNID_IME)) )
4489 {
4490 RETURN( FALSE);
4491 }
4492 else
4493 Wnd->pcls->fnid |= fnID;
4494 }
4495 RETURN( TRUE);
4496
4497 CLEANUP:
4498 DPRINT("Leave NtUserSetWindowFNID\n");
4499 UserLeave();
4500 END_CLEANUP;
4501 }
4502
4503
4504 /*
4505 * @implemented
4506 */
4507 BOOL APIENTRY
4508 NtUserSetWindowPlacement(HWND hWnd,
4509 WINDOWPLACEMENT *lpwndpl)
4510 {
4511 PWINDOW_OBJECT Window;
4512 PWND Wnd;
4513 WINDOWPLACEMENT Safepl;
4514 NTSTATUS Status;
4515 DECLARE_RETURN(BOOL);
4516 USER_REFERENCE_ENTRY Ref;
4517
4518 DPRINT("Enter NtUserSetWindowPlacement\n");
4519 UserEnterExclusive();
4520
4521 if (!(Window = UserGetWindowObject(hWnd)))
4522 {
4523 RETURN( FALSE);
4524 }
4525 Wnd = Window->Wnd;
4526
4527 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
4528 if(!NT_SUCCESS(Status))
4529 {
4530 SetLastNtError(Status);
4531 RETURN( FALSE);
4532 }
4533 if(Safepl.length != sizeof(WINDOWPLACEMENT))
4534 {
4535 RETURN( FALSE);
4536 }
4537
4538 UserRefObjectCo(Window, &Ref);
4539
4540 if ((Wnd->style & (WS_MAXIMIZE | WS_MINIMIZE)) == 0)
4541 {
4542 co_WinPosSetWindowPos(Window, NULL,
4543 Safepl.rcNormalPosition.left, Safepl.rcNormalPosition.top,
4544 Safepl.rcNormalPosition.right - Safepl.rcNormalPosition.left,
4545 Safepl.rcNormalPosition.bottom - Safepl.rcNormalPosition.top,
4546 SWP_NOZORDER | SWP_NOACTIVATE);
4547 }
4548
4549 /* FIXME - change window status */
4550 co_WinPosShowWindow(Window, Safepl.showCmd);
4551
4552 Wnd->InternalPosInitialized = TRUE;
4553 Wnd->InternalPos.NormalRect = Safepl.rcNormalPosition;
4554 Wnd->InternalPos.IconPos = Safepl.ptMinPosition;
4555 Wnd->InternalPos.MaxPos = Safepl.ptMaxPosition;
4556
4557 UserDerefObjectCo(Window);
4558 RETURN(TRUE);
4559
4560 CLEANUP:
4561 DPRINT("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
4562 UserLeave();
4563 END_CLEANUP;
4564 }
4565
4566
4567 /*
4568 * @implemented
4569 */
4570 BOOL APIENTRY
4571 NtUserSetWindowPos(
4572 HWND hWnd,
4573 HWND hWndInsertAfter,
4574 int X,
4575 int Y,
4576 int cx,
4577 int cy,
4578 UINT uFlags)
4579 {
4580 DECLARE_RETURN(BOOL);
4581 PWINDOW_OBJECT Window;
4582 BOOL ret;
4583 USER_REFERENCE_ENTRY Ref;
4584
4585 DPRINT("Enter NtUserSetWindowPos\n");
4586 UserEnterExclusive();
4587
4588 if (!(Window = UserGetWindowObject(hWnd)))
4589 {
4590 RETURN(FALSE);
4591 }
4592
4593 /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
4594 if (!(uFlags & SWP_NOMOVE))
4595 {
4596 if (X < -32768) X = -32768;
4597 else if (X > 32767) X = 32767;
4598 if (Y < -32768) Y = -32768;
4599 else if (Y > 32767) Y = 32767;
4600 }
4601 if (!(uFlags & SWP_NOSIZE))
4602 {
4603 if (cx < 0) cx = 0;
4604 else if (cx > 32767) cx = 32767;
4605 if (cy < 0) cy = 0;
4606 else if (cy > 32767) cy = 32767;
4607 }
4608
4609 UserRefObjectCo(Window, &Ref);
4610 ret = co_WinPosSetWindowPos(Window, hWndInsertAfter, X, Y, cx, cy, uFlags);
4611 UserDerefObjectCo(Window);
4612
4613 RETURN(ret);
4614
4615 CLEANUP:
4616 DPRINT("Leave NtUserSetWindowPos, ret=%i\n",_ret_);
4617 UserLeave();
4618 END_CLEANUP;
4619 }
4620
4621
4622 INT FASTCALL
4623 IntGetWindowRgn(PWINDOW_OBJECT Window, HRGN hRgn)
4624 {
4625 INT Ret;
4626 HRGN VisRgn;
4627 ROSRGNDATA *pRgn;
4628 PWND Wnd;
4629
4630 if(!Window)
4631 {
4632 return ERROR;
4633 }
4634 if(!hRgn)
4635 {
4636 return ERROR;
4637 }
4638
4639 Wnd = Window->Wnd;
4640
4641 /* Create a new window region using the window rectangle */
4642 VisRgn = IntSysCreateRectRgnIndirect(&Window->Wnd->rcWindow);
4643 NtGdiOffsetRgn(VisRgn, -Window->Wnd->rcWindow.left, -Window->Wnd->rcWindow.top);
4644 /* if there's a region assigned to the window, combine them both */
4645 if(Window->hrgnClip && !(Wnd->style & WS_MINIMIZE))
4646 NtGdiCombineRgn(VisRgn, VisRgn, Window->hrgnClip, RGN_AND);
4647 /* Copy the region into hRgn */
4648 NtGdiCombineRgn(hRgn, VisRgn, NULL, RGN_COPY);
4649
4650 if((pRgn = RGNOBJAPI_Lock(hRgn, NULL)))
4651 {
4652 Ret = pRgn->rdh.iType;
4653 RGNOBJAPI_Unlock(pRgn);
4654 }
4655 else
4656 Ret = ERROR;
4657
4658 REGION_FreeRgnByHandle(VisRgn);
4659
4660 return Ret;
4661 }
4662
4663 INT FASTCALL
4664 IntGetWindowRgnBox(PWINDOW_OBJECT Window, RECTL *Rect)
4665 {
4666 INT Ret;
4667 HRGN VisRgn;
4668 ROSRGNDATA *pRgn;
4669 PWND Wnd;
4670
4671 if(!Window)
4672 {
4673 return ERROR;
4674 }
4675 if(!Rect)
4676 {
4677 return ERROR;
4678 }
4679
4680 Wnd = Window->Wnd;
4681
4682 /* Create a new window region using the window rectangle */
4683 VisRgn = IntSysCreateRectRgnIndirect(&Window->Wnd->rcWindow);
4684 NtGdiOffsetRgn(VisRgn, -Window->Wnd->rcWindow.left, -Window->Wnd->rcWindow.top);
4685 /* if there's a region assigned to the window, combine them both */
4686 if(Window->hrgnClip && !(Wnd->style & WS_MINIMIZE))
4687 NtGdiCombineRgn(VisRgn, VisRgn, Window->hrgnClip, RGN_AND);
4688
4689 if((pRgn = RGNOBJAPI_Lock(VisRgn, NULL)))
4690 {
4691 Ret = pRgn->rdh.iType;
4692 *Rect = pRgn->rdh.rcBound;
4693 RGNOBJAPI_Unlock(pRgn);
4694 }
4695 else
4696 Ret = ERROR;
4697
4698 REGION_FreeRgnByHandle(VisRgn);
4699
4700 return Ret;
4701 }
4702
4703
4704 /*
4705 * @implemented
4706 */
4707 INT APIENTRY
4708 NtUserSetWindowRgn(
4709 HWND hWnd,
4710 HRGN hRgn,
4711 BOOL bRedraw)
4712 {
4713 HRGN hrgnCopy;
4714 PWINDOW_OBJECT Window;
4715 DECLARE_RETURN(INT);
4716
4717 DPRINT("Enter NtUserSetWindowRgn\n");
4718 UserEnterExclusive();
4719
4720 if (!(Window = UserGetWindowObject(hWnd)))
4721 {
4722 RETURN( 0);
4723 }
4724
4725 if (hRgn) // The region will be deleted in user32.
4726 {
4727 if (GDIOBJ_ValidateHandle(hRgn, GDI_OBJECT_TYPE_REGION))
4728 {
4729 hrgnCopy = IntSysCreateRectRgn(0, 0, 0, 0);
4730 NtGdiCombineRgn(hrgnCopy, hRgn, 0, RGN_COPY);
4731 }
4732 else
4733 RETURN( 0);
4734 }
4735 else
4736 hrgnCopy = (HRGN) 1;
4737
4738 if (Window->hrgnClip)
4739 {
4740 /* Delete no longer needed region handle */
4741 GreDeleteObject(Window->hrgnClip);
4742 }
4743 Window->hrgnClip = hrgnCopy;
4744
4745 /* FIXME - send WM_WINDOWPOSCHANGING and WM_WINDOWPOSCHANGED messages to the window */
4746
4747 if(bRedraw)
4748 {
4749 USER_REFERENCE_ENTRY Ref;
4750 UserRefObjectCo(Window, &Ref);
4751 co_UserRedrawWindow(Window, NULL, NULL, RDW_INVALIDATE);
4752 UserDerefObjectCo(Window);
4753 }
4754
4755 RETURN( (INT)hRgn);
4756
4757 CLEANUP:
4758 DPRINT("Leave NtUserSetWindowRgn, ret=%i\n",_ret_);
4759 UserLeave();
4760 END_CLEANUP;
4761 }
4762
4763
4764 /*
4765 * @implemented
4766 */
4767 BOOL APIENTRY
4768 NtUserShowWindow(HWND hWnd, LONG nCmdShow)
4769 {
4770 PWINDOW_OBJECT Window;
4771 BOOL ret;
4772 DECLARE_RETURN(BOOL);
4773 USER_REFERENCE_ENTRY Ref;
4774
4775 DPRINT("Enter NtUserShowWindow\n");
4776 UserEnterExclusive();
4777
4778 if (!(Window = UserGetWindowObject(hWnd)))
4779 {
4780 RETURN(FALSE);
4781 }
4782
4783 UserRefObjectCo(Window, &Ref);
4784 ret = co_WinPosShowWindow(Window, nCmdShow);
4785 UserDerefObjectCo(Window);
4786
4787 RETURN(ret);
4788
4789 CLEANUP:
4790 DPRINT("Leave NtUserShowWindow, ret=%i\n",_ret_);
4791 UserLeave();
4792 END_CLEANUP;
4793 }
4794
4795
4796 /*
4797 * @unimplemented
4798 */
4799 BOOL APIENTRY
4800 NtUserShowWindowAsync(HWND hWnd, LONG nCmdShow)
4801 {
4802 #if 0
4803 UNIMPLEMENTED
4804 return 0;
4805 #else
4806 return NtUserShowWindow(hWnd, nCmdShow);
4807 #endif
4808 }
4809
4810
4811 /*
4812 * @unimplemented
4813 */
4814 BOOL
4815 APIENTRY
4816 NtUserUpdateLayeredWindow(
4817 HWND hwnd,
4818 HDC hdcDst,
4819 POINT *pptDst,
4820 SIZE *psize,
4821 HDC hdcSrc,
4822 POINT *pptSrc,
4823 COLORREF crKey,
4824 BLENDFUNCTION *pblend,
4825 DWORD dwFlags,
4826 RECT *prcDirty)
4827 {
4828 UNIMPLEMENTED
4829
4830 return 0;
4831 }
4832
4833 /*
4834 * @unimplemented
4835 */
4836 HWND APIENTRY
4837 NtUserWindowFromPhysicalPoint(POINT Point)
4838 {
4839 UNIMPLEMENTED
4840
4841 return NULL;
4842 }
4843
4844 /*
4845 * @implemented
4846 */
4847 HWND APIENTRY
4848 NtUserWindowFromPoint(LONG X, LONG Y)
4849 {
4850 POINT pt;
4851 HWND Ret;
4852 PWINDOW_OBJECT DesktopWindow = NULL, Window = NULL;
4853 DECLARE_RETURN(HWND);
4854 USER_REFERENCE_ENTRY Ref;
4855
4856 DPRINT("Enter NtUserWindowFromPoint\n");
4857 UserEnterExclusive();
4858
4859 if ((DesktopWindow = UserGetWindowObject(IntGetDesktopWindow())))
4860 {
4861 PTHREADINFO pti;
4862 USHORT Hit;
4863
4864 pt.x = X;
4865 pt.y = Y;
4866
4867 //hmm... threads live on desktops thus we have a reference on the desktop and indirectly the desktop window
4868 //its possible this referencing is useless, thou it shouldnt hurt...
4869 UserRefObjectCo(DesktopWindow, &Ref);
4870
4871 pti = PsGetCurrentThreadWin32Thread();
4872 Hit = co_WinPosWindowFromPoint(DesktopWindow, pti->MessageQueue, &pt, &Window);
4873
4874 if(Window)
4875 {
4876 Ret = Window->hSelf;
4877
4878 RETURN( Ret);
4879 }
4880 }
4881
4882 RETURN( NULL);
4883
4884 CLEANUP:
4885 if (Window) UserDereferenceObject(Window);
4886 if (DesktopWindow) UserDerefObjectCo(DesktopWindow);
4887
4888 DPRINT("Leave NtUserWindowFromPoint, ret=%i\n",_ret_);
4889 UserLeave();
4890 END_CLEANUP;
4891
4892 }
4893
4894
4895 /*
4896 * NtUserDefSetText
4897 *
4898 * Undocumented function that is called from DefWindowProc to set
4899 * window text.
4900 *
4901 * Status
4902 * @implemented
4903 */
4904 BOOL APIENTRY
4905 NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText)
4906 {
4907 PWINDOW_OBJECT Window;
4908 PWND Wnd;
4909 LARGE_STRING SafeText;
4910 UNICODE_STRING UnicodeString;
4911 BOOL Ret = TRUE;
4912
4913 DPRINT("Enter NtUserDefSetText\n");
4914
4915 if (WindowText != NULL)
4916 {
4917 _SEH2_TRY
4918 {
4919 SafeText = ProbeForReadLargeString(WindowText);
4920 }
4921 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4922 {
4923 Ret = FALSE;
4924 SetLastNtError(_SEH2_GetExceptionCode());
4925 }
4926 _SEH2_END;
4927
4928 if (!Ret)
4929 return FALSE;
4930 }
4931 else
4932 return TRUE;
4933
4934 UserEnterExclusive();
4935
4936 if(!(Window = UserGetWindowObject(hWnd)) || !Window->Wnd)
4937 {
4938 UserLeave();
4939 return FALSE;
4940 }
4941 Wnd = Window->Wnd;
4942
4943 // ReactOS uses Unicode and not mixed. Up/Down converting will take time.
4944 // Brought to you by: The Wine Project! Dysfunctional Thought Processes!
4945 // Now we know what the bAnsi is for.
4946 RtlInitUnicodeString(&UnicodeString, NULL);
4947 if (SafeText.Buffer)
4948 {
4949 _SEH2_TRY
4950 {
4951 if (SafeText.bAnsi)
4952 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR));
4953 else
4954 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR));
4955 Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText);
4956 }
4957 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4958 {
4959 Ret = FALSE;
4960 SetLastNtError(_SEH2_GetExceptionCode());
4961 }
4962 _SEH2_END;
4963 if (!Ret) goto Exit;
4964 }
4965
4966 if (UnicodeString.Length != 0)
4967 {
4968 if (Wnd->strName.MaximumLength > 0 &&
4969 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4970 {
4971 ASSERT(Wnd->strName.Buffer != NULL);
4972
4973 Wnd->strName.Length = UnicodeString.Length;
4974 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4975 RtlCopyMemory(Wnd->strName.Buffer,
4976 UnicodeString.Buffer,
4977 UnicodeString.Length);
4978 }
4979 else
4980 {
4981 PWCHAR buf;
4982 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4983 buf = Wnd->strName.Buffer;
4984 Wnd->strName.Buffer = NULL;
4985 if (buf != NULL)
4986 {
4987 DesktopHeapFree(Wnd->head.rpdesk, buf);
4988 }
4989
4990 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4991 UnicodeString.Length + sizeof(UNICODE_NULL));
4992 if (Wnd->strName.Buffer != NULL)
4993 {
4994 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4995 RtlCopyMemory(Wnd->strName.Buffer,
4996 UnicodeString.Buffer,
4997 UnicodeString.Length);
4998 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4999 Wnd->strName.Length = UnicodeString.Length;
5000 }
5001 else
5002 {
5003 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
5004 Ret = FALSE;
5005 goto Exit;
5006 }
5007 }
5008 }
5009 else
5010 {
5011 Wnd->strName.Length = 0;
5012 if (Wnd->strName.Buffer != NULL)
5013 Wnd->strName.Buffer[0] = L'\0';
5014 }
5015
5016 // HAX! FIXME! Windows does not do this in here!
5017 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
5018 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
5019 /* Send shell notifications */
5020 if (!IntGetOwner(Window) && !IntGetParent(Window))
5021 {
5022 co_IntShellHookNotify(HSHELL_REDRAW, (LPARAM) hWnd);
5023 }
5024
5025 Ret = TRUE;
5026 Exit:
5027 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
5028 DPRINT("Leave NtUserDefSetText, ret=%i\n", Ret);
5029 UserLeave();
5030 return Ret;
5031 }
5032
5033 /*
5034 * NtUserInternalGetWindowText
5035 *
5036 * Status
5037 * @implemented
5038 */
5039
5040 INT APIENTRY
5041 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount)
5042 {
5043 PWINDOW_OBJECT Window;
5044 PWND Wnd;
5045 NTSTATUS Status;
5046 INT Result;
5047 DECLARE_RETURN(INT);
5048
5049 DPRINT("Enter NtUserInternalGetWindowText\n");
5050 UserEnterShared();
5051
5052 if(lpString && (nMaxCount <= 1))
5053 {
5054 SetLastWin32Error(ERROR_INVALID_PARAMETER);
5055 RETURN( 0);
5056 }
5057
5058 if(!(Window = UserGetWindowObject(hWnd)))
5059 {
5060 RETURN( 0);
5061 }
5062 Wnd = Window->Wnd;
5063
5064 Result = Wnd->strName.Length / sizeof(WCHAR);
5065 if(lpString)
5066 {
5067 const WCHAR Terminator = L'\0';
5068 INT Copy;
5069 WCHAR *Buffer = (WCHAR*)lpString;
5070
5071 Copy = min(nMaxCount - 1, Result);
5072 if(Copy > 0)
5073 {
5074 Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR));
5075 if(!NT_SUCCESS(Status))
5076 {
5077 SetLastNtError(Status);
5078 RETURN( 0);
5079 }
5080 Buffer += Copy;
5081 }
5082
5083 Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
5084 if(!NT_SUCCESS(Status))
5085 {
5086 SetLastNtError(Status);
5087 RETURN( 0);
5088 }
5089
5090 Result = Copy;
5091 }
5092
5093 RETURN( Result);
5094
5095 CLEANUP:
5096 DPRINT("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_);
5097 UserLeave();
5098 END_CLEANUP;
5099 }
5100
5101
5102 BOOL
5103 FASTCALL
5104 IntShowOwnedPopups(PWINDOW_OBJECT OwnerWnd, BOOL fShow )
5105 {
5106 int count = 0;
5107 PWINDOW_OBJECT pWnd;
5108 HWND *win_array;
5109
5110 // ASSERT(OwnerWnd);
5111
5112 win_array = IntWinListChildren(UserGetWindowObject(IntGetDesktopWindow()));
5113
5114 if (!win_array)
5115 return TRUE;
5116
5117 while (win_array[count])
5118 count++;
5119 while (--count >= 0)
5120 {
5121 if (UserGetWindow( win_array[count], GW_OWNER ) != OwnerWnd->hSelf)
5122 continue;
5123 if (!(pWnd = UserGetWindowObject( win_array[count] )))
5124 continue;
5125 // if (pWnd == WND_OTHER_PROCESS) continue;
5126
5127 if (fShow)
5128 {
5129 if (pWnd->Wnd->state & WNDS_HIDDENPOPUP)
5130 {
5131 /* In Windows, ShowOwnedPopups(TRUE) generates
5132 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
5133 * regardless of the state of the owner
5134 */
5135 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
5136 continue;
5137 }
5138 }
5139 else
5140 {
5141 if (pWnd->Wnd->style & WS_VISIBLE)
5142 {
5143 /* In Windows, ShowOwnedPopups(FALSE) generates
5144 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
5145 * regardless of the state of the owner
5146 */
5147 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
5148 continue;
5149 }
5150 }
5151
5152 }
5153 ExFreePool( win_array );
5154 return TRUE;
5155 }
5156
5157 /*
5158 * NtUserValidateHandleSecure
5159 *
5160 * Status
5161 * @implemented
5162 */
5163
5164 BOOL
5165 APIENTRY
5166 NtUserValidateHandleSecure(
5167 HANDLE handle,
5168 BOOL Restricted)
5169 {
5170 if(!Restricted)
5171 {
5172 UINT uType;
5173 {
5174 PUSER_HANDLE_ENTRY entry;
5175 if (!(entry = handle_to_entry(gHandleTable, handle )))
5176 {
5177 SetLastWin32Error(ERROR_INVALID_HANDLE);
5178 return FALSE;
5179 }
5180 uType = entry->type;
5181 }
5182 switch (uType)
5183 {
5184 case otWindow:
5185 {
5186 PWINDOW_OBJECT Window;
5187 if ((Window = UserGetWindowObject((HWND) handle))) return TRUE;
5188 return FALSE;
5189 }
5190 case otMenu:
5191 {
5192 PMENU_OBJECT Menu;
5193 if ((Menu = UserGetMenuObject((HMENU) handle))) return TRUE;
5194 return FALSE;
5195 }
5196 case otAccel:
5197 {
5198 PACCELERATOR_TABLE Accel;
5199 if ((Accel = UserGetAccelObject((HACCEL) handle))) return TRUE;
5200 return FALSE;
5201 }
5202 case otCursorIcon:
5203 {
5204 PCURICON_OBJECT Cursor;
5205 if ((Cursor = UserGetCurIconObject((HCURSOR) handle))) return TRUE;
5206 return FALSE;
5207 }
5208 case otHook:
5209 {
5210 PHOOK Hook;
5211 if ((Hook = IntGetHookObject((HHOOK) handle))) return TRUE;
5212 return FALSE;
5213 }
5214 case otMonitor:
5215 {
5216 PMONITOR Monitor;
5217 if ((Monitor = UserGetMonitorObject((HMONITOR) handle))) return TRUE;
5218 return FALSE;
5219 }
5220 case otCallProc:
5221 {
5222 WNDPROC_INFO Proc;
5223 return UserGetCallProcInfo( handle, &Proc );
5224 }
5225 default:
5226 SetLastWin32Error(ERROR_INVALID_HANDLE);
5227 }
5228 }
5229 else
5230 { /* Is handle entry restricted? */
5231 UNIMPLEMENTED
5232 }
5233 return FALSE;
5234 }
5235
5236
5237 /* EOF */