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