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