526b15ac5157236c00742a3a0d6f54c19a3d30aa
[reactos.git] / subsystems / win32 / win32k / ntuser / window.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Windows
5 * FILE: subsystems/win32/win32k/ntuser/window.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISION HISTORY:
8 * 06-06-2001 CSH Created
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <win32k.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18
19 /* dialog resources appear to pass this in 16 bits, handle them properly */
20 #define CW_USEDEFAULT16 (0x8000)
21
22 #define POINT_IN_RECT(p, r) (((r.bottom >= p.y) && (r.top <= p.y))&&((r.left <= p.x )&&( r.right >= p.x )))
23
24 /* PRIVATE FUNCTIONS **********************************************************/
25
26 /*
27 * InitWindowImpl
28 *
29 * Initialize windowing implementation.
30 */
31
32 NTSTATUS FASTCALL
33 InitWindowImpl(VOID)
34 {
35 return STATUS_SUCCESS;
36 }
37
38 /*
39 * CleanupWindowImpl
40 *
41 * Cleanup windowing implementation.
42 */
43
44 NTSTATUS FASTCALL
45 CleanupWindowImpl(VOID)
46 {
47 return STATUS_SUCCESS;
48 }
49
50 /* HELPER FUNCTIONS ***********************************************************/
51
52 BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam)
53 {
54 WORD Action = LOWORD(wParam);
55 WORD Flags = HIWORD(wParam);
56
57 if (Flags & ~(UISF_HIDEFOCUS | UISF_HIDEACCEL | UISF_ACTIVE))
58 {
59 SetLastWin32Error(ERROR_INVALID_PARAMETER);
60 return FALSE;
61 }
62
63 switch (Action)
64 {
65 case UIS_INITIALIZE:
66 SetLastWin32Error(ERROR_INVALID_PARAMETER);
67 return FALSE;
68
69 case UIS_SET:
70 if (Flags & UISF_HIDEFOCUS)
71 Wnd->HideFocus = TRUE;
72 if (Flags & UISF_HIDEACCEL)
73 Wnd->HideAccel = TRUE;
74 break;
75
76 case UIS_CLEAR:
77 if (Flags & UISF_HIDEFOCUS)
78 Wnd->HideFocus = FALSE;
79 if (Flags & UISF_HIDEACCEL)
80 Wnd->HideAccel = FALSE;
81 break;
82 }
83
84 return TRUE;
85 }
86
87 PWINDOW_OBJECT FASTCALL IntGetWindowObject(HWND hWnd)
88 {
89 PWINDOW_OBJECT Window;
90
91 if (!hWnd) return NULL;
92
93 Window = UserGetWindowObject(hWnd);
94 if (Window)
95 {
96 ASSERT(Window->head.cLockObj >= 0);
97
98 Window->head.cLockObj++;
99 }
100 return Window;
101 }
102
103 /* temp hack */
104 PWINDOW_OBJECT FASTCALL UserGetWindowObject(HWND hWnd)
105 {
106 PTHREADINFO ti;
107 PWINDOW_OBJECT Window;
108
109 if (PsGetCurrentProcess() != PsInitialSystemProcess)
110 {
111 ti = GetW32ThreadInfo();
112 if (ti == NULL)
113 {
114 SetLastWin32Error(ERROR_ACCESS_DENIED);
115 return NULL;
116 }
117 }
118
119 if (!hWnd)
120 {
121 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
122 return NULL;
123 }
124
125 Window = (PWINDOW_OBJECT)UserGetObject(gHandleTable, hWnd, otWindow);
126 if (!Window || 0 != (Window->state & WINDOWSTATUS_DESTROYED))
127 {
128 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
129 return NULL;
130 }
131
132 ASSERT(Window->head.cLockObj >= 0);
133 return Window;
134 }
135
136
137 /*
138 * IntIsWindow
139 *
140 * The function determines whether the specified window handle identifies
141 * an existing window.
142 *
143 * Parameters
144 * hWnd
145 * Handle to the window to test.
146 *
147 * Return Value
148 * If the window handle identifies an existing window, the return value
149 * is TRUE. If the window handle does not identify an existing window,
150 * the return value is FALSE.
151 */
152
153 BOOL FASTCALL
154 IntIsWindow(HWND hWnd)
155 {
156 PWINDOW_OBJECT Window;
157
158 if (!(Window = UserGetWindowObject(hWnd)))
159 return FALSE;
160
161 return TRUE;
162 }
163
164
165
166 /*
167 Caller must NOT dereference retval!
168 But if caller want the returned value to persist spanning a co_ call,
169 it must reference the value (because the owner is not garanteed to
170 exist just because the owned window exist)!
171 */
172 PWINDOW_OBJECT FASTCALL
173 IntGetParent(PWINDOW_OBJECT Wnd)
174 {
175 if (!Wnd->Wnd) return NULL;
176
177 if (Wnd->Wnd->style & WS_POPUP)
178 {
179 return UserGetWindowObject(Wnd->hOwner);
180 }
181 else if (Wnd->Wnd->style & WS_CHILD)
182 {
183 return Wnd->spwndParent;
184 }
185
186 return NULL;
187 }
188
189
190 /*
191 Caller must NOT dereference retval!
192 But if caller want the returned value to persist spanning a co_ call,
193 it must reference the value (because the owner is not garanteed to
194 exist just because the owned window exist)!
195 */
196 PWINDOW_OBJECT FASTCALL
197 IntGetOwner(PWINDOW_OBJECT Wnd)
198 {
199 return UserGetWindowObject(Wnd->hOwner);
200 }
201
202
203
204 /*
205 * IntWinListChildren
206 *
207 * Compile a list of all child window handles from given window.
208 *
209 * Remarks
210 * This function is similar to Wine WIN_ListChildren. The caller
211 * must free the returned list with ExFreePool.
212 */
213
214 HWND* FASTCALL
215 IntWinListChildren(PWINDOW_OBJECT Window)
216 {
217 PWINDOW_OBJECT Child;
218 HWND *List;
219 UINT Index, NumChildren = 0;
220
221 if (!Window) return NULL;
222
223 for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
224 ++NumChildren;
225
226 List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), TAG_WINLIST);
227 if(!List)
228 {
229 DPRINT1("Failed to allocate memory for children array\n");
230 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
231 return NULL;
232 }
233 for (Child = Window->spwndChild, Index = 0;
234 Child != NULL;
235 Child = Child->spwndNext, ++Index)
236 List[Index] = Child->hSelf;
237 List[Index] = NULL;
238
239 return List;
240 }
241
242 /***********************************************************************
243 * IntSendDestroyMsg
244 */
245 static void IntSendDestroyMsg(HWND hWnd)
246 {
247
248 PWINDOW_OBJECT Window;
249 #if 0 /* FIXME */
250
251 GUITHREADINFO info;
252
253 if (GetGUIThreadInfo(GetCurrentThreadId(), &info))
254 {
255 if (hWnd == info.hwndCaret)
256 {
257 DestroyCaret();
258 }
259 }
260 #endif
261
262 Window = UserGetWindowObject(hWnd);
263 if (Window)
264 {
265 // USER_REFERENCE_ENTRY Ref;
266 // UserRefObjectCo(Window, &Ref);
267
268 if (!IntGetOwner(Window) && !IntGetParent(Window))
269 {
270 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (LPARAM) hWnd);
271 }
272
273 // UserDerefObjectCo(Window);
274 }
275
276 /* The window could already be destroyed here */
277
278 /*
279 * Send the WM_DESTROY to the window.
280 */
281
282 co_IntSendMessage(hWnd, WM_DESTROY, 0, 0);
283
284 /*
285 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
286 * make sure that the window still exists when we come back.
287 */
288 #if 0 /* FIXME */
289
290 if (IsWindow(Wnd))
291 {
292 HWND* pWndArray;
293 int i;
294
295 if (!(pWndArray = WIN_ListChildren( hwnd )))
296 return;
297
298 /* start from the end (FIXME: is this needed?) */
299 for (i = 0; pWndArray[i]; i++)
300 ;
301
302 while (--i >= 0)
303 {
304 if (IsWindow( pWndArray[i] ))
305 WIN_SendDestroyMsg( pWndArray[i] );
306 }
307 HeapFree(GetProcessHeap(), 0, pWndArray);
308 }
309 else
310 {
311 DPRINT("destroyed itself while in WM_DESTROY!\n");
312 }
313 #endif
314 }
315
316 static VOID
317 UserFreeWindowInfo(PTHREADINFO ti, PWINDOW_OBJECT WindowObject)
318 {
319 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
320 PWND Wnd = WindowObject->Wnd;
321
322 if (!Wnd) return;
323
324 if (ClientInfo->CallbackWnd.pvWnd == DesktopHeapAddressToUser(WindowObject->Wnd))
325 {
326 ClientInfo->CallbackWnd.hWnd = NULL;
327 ClientInfo->CallbackWnd.pvWnd = NULL;
328 }
329
330 if (Wnd->strName.Buffer != NULL)
331 {
332 Wnd->strName.Length = 0;
333 Wnd->strName.MaximumLength = 0;
334 DesktopHeapFree(Wnd->head.rpdesk,
335 Wnd->strName.Buffer);
336 Wnd->strName.Buffer = NULL;
337 }
338
339 DesktopHeapFree(Wnd->head.rpdesk, Wnd);
340 WindowObject->Wnd = NULL;
341 }
342
343 /***********************************************************************
344 * IntDestroyWindow
345 *
346 * Destroy storage associated to a window. "Internals" p.358
347 *
348 * This is the "functional" DestroyWindows function ei. all stuff
349 * done in CreateWindow is undone here and not in DestroyWindow:-P
350
351 */
352 static LRESULT co_UserFreeWindow(PWINDOW_OBJECT Window,
353 PPROCESSINFO ProcessData,
354 PTHREADINFO ThreadData,
355 BOOLEAN SendMessages)
356 {
357 HWND *Children;
358 HWND *ChildHandle;
359 PWINDOW_OBJECT Child;
360 PMENU_OBJECT Menu;
361 BOOLEAN BelongsToThreadData;
362 PWND Wnd;
363
364 ASSERT(Window);
365
366 Wnd = Window->Wnd;
367
368 if(Window->state & WINDOWSTATUS_DESTROYING)
369 {
370 DPRINT("Tried to call IntDestroyWindow() twice\n");
371 return 0;
372 }
373 Window->state |= WINDOWSTATUS_DESTROYING;
374 Wnd->style &= ~WS_VISIBLE;
375
376 IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Wnd, OBJID_WINDOW, 0);
377
378 /* remove the window already at this point from the thread window list so we
379 don't get into trouble when destroying the thread windows while we're still
380 in IntDestroyWindow() */
381 RemoveEntryList(&Window->ThreadListEntry);
382
383 BelongsToThreadData = IntWndBelongsToThread(Window, ThreadData);
384
385 IntDeRegisterShellHookWindow(Window->hSelf);
386
387 if(SendMessages)
388 {
389 /* Send destroy messages */
390 IntSendDestroyMsg(Window->hSelf);
391 }
392
393 /* free child windows */
394 Children = IntWinListChildren(Window);
395 if (Children)
396 {
397 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
398 {
399 if ((Child = IntGetWindowObject(*ChildHandle)))
400 {
401 if(!IntWndBelongsToThread(Child, ThreadData))
402 {
403 /* send WM_DESTROY messages to windows not belonging to the same thread */
404 IntSendDestroyMsg(Child->hSelf);
405 }
406 else
407 co_UserFreeWindow(Child, ProcessData, ThreadData, SendMessages);
408
409 UserDereferenceObject(Child);
410 }
411 }
412 ExFreePool(Children);
413 }
414
415 if(SendMessages)
416 {
417 /*
418 * Clear the update region to make sure no WM_PAINT messages will be
419 * generated for this window while processing the WM_NCDESTROY.
420 */
421 co_UserRedrawWindow(Window, NULL, 0,
422 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
423 RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
424 if(BelongsToThreadData)
425 co_IntSendMessage(Window->hSelf, WM_NCDESTROY, 0, 0);
426 }
427 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 Wnd->style = dwStyle & ~WS_VISIBLE;
2002
2003 /* Correct the window style. */
2004 if ((Wnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
2005 {
2006 Wnd->style |= WS_CLIPSIBLINGS;
2007 DPRINT("3: Style is now %lx\n", dwStyle);
2008 if (!(Wnd->style & WS_POPUP))
2009 {
2010 Wnd->style |= WS_CAPTION;
2011 Window->state |= WINDOWOBJECT_NEED_SIZE;
2012 DPRINT("4: Style is now %lx\n", dwStyle);
2013 }
2014 }
2015
2016 /* create system menu */
2017 if((dwStyle & WS_SYSMENU) )//&& (dwStyle & WS_CAPTION) == WS_CAPTION)
2018 {
2019 SystemMenu = IntGetSystemMenu(Window, TRUE, TRUE);
2020 if(SystemMenu)
2021 {
2022 Window->SystemMenu = SystemMenu->MenuInfo.Self;
2023 IntReleaseMenuObject(SystemMenu);
2024 }
2025 }
2026
2027 /* Set the window menu */
2028 if ((dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
2029 {
2030 if (hMenu)
2031 IntSetMenu(Window, hMenu, &MenuChanged);
2032 else if (Wnd->pcls->lpszMenuName) // Take it from the parent.
2033 {
2034 UNICODE_STRING MenuName;
2035 if (IS_INTRESOURCE(Wnd->pcls->lpszMenuName))
2036 {
2037 MenuName.Length = 0;
2038 MenuName.MaximumLength = 0;
2039 MenuName.Buffer = Wnd->pcls->lpszMenuName;
2040 }
2041 else
2042 {
2043 RtlInitUnicodeString( &MenuName, Wnd->pcls->lpszMenuName);
2044 }
2045 hMenu = co_IntCallLoadMenu( Wnd->pcls->hModule, &MenuName);
2046 if (hMenu) IntSetMenu(Window, hMenu, &MenuChanged);
2047 }
2048 }
2049 else // Not a child
2050 Wnd->IDMenu = (UINT) hMenu;
2051
2052 /* Insert the window into the thread's window list. */
2053 InsertTailList (&pti->WindowListHead, &Window->ThreadListEntry);
2054
2055 /* Handle "CS_CLASSDC", it is tested first. */
2056 if ( (Wnd->pcls->style & CS_CLASSDC) && !(Wnd->pcls->pdce) )
2057 { /* One DCE per class to have CLASS. */
2058 Wnd->pcls->pdce = DceAllocDCE( Window, DCE_CLASS_DC );
2059 }
2060 else if ( Wnd->pcls->style & CS_OWNDC)
2061 { /* Allocate a DCE for this window. */
2062 DceAllocDCE(Window, DCE_WINDOW_DC);
2063 }
2064
2065 Pos.x = x;
2066 Pos.y = y;
2067 Size.cx = nWidth;
2068 Size.cy = nHeight;
2069
2070 Wnd->ExStyle = dwExStyle;
2071
2072 /* call hook */
2073 Cs.lpCreateParams = lpParam;
2074 Cs.hInstance = hInstance;
2075 Cs.hMenu = hMenu;
2076 Cs.hwndParent = hWndParent; //Pass the original Parent handle!
2077 Cs.cx = Size.cx;
2078 Cs.cy = Size.cy;
2079 Cs.x = Pos.x;
2080 Cs.y = Pos.y;
2081 Cs.style = Wnd->style;
2082 // Cs.lpszName = (LPCWSTR) WindowName->Buffer;
2083 // Cs.lpszClass = (LPCWSTR) ClassName->Buffer;
2084 Cs.lpszName = (LPCWSTR) WindowName;
2085 Cs.lpszClass = (LPCWSTR) ClassName;
2086 Cs.dwExStyle = dwExStyle;
2087 CbtCreate.lpcs = &Cs;
2088 CbtCreate.hwndInsertAfter = HWND_TOP;
2089 if (ISITHOOKED(WH_CBT))
2090 {
2091 if (co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) &CbtCreate))
2092 {
2093 /* FIXME - Delete window object and remove it from the thread windows list */
2094 /* FIXME - delete allocated DCE */
2095 DPRINT1("CBT-hook returned !0\n");
2096 RETURN( (PWND) NULL);
2097 }
2098 }
2099 x = Cs.x;
2100 y = Cs.y;
2101 nWidth = Cs.cx;
2102 nHeight = Cs.cy;
2103
2104 Cs.style = dwStyle;
2105 // FIXME: Need to set the Z order in the window link list if the hook callback changed it!
2106 // hwndInsertAfter = CbtCreate.hwndInsertAfter;
2107
2108 /* default positioning for overlapped windows */
2109 if(!(Wnd->style & (WS_POPUP | WS_CHILD)))
2110 {
2111 RECTL rc, WorkArea;
2112 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
2113 BOOL CalculatedDefPosSize = FALSE;
2114
2115 IntGetDesktopWorkArea(Window->pti->rpdesk, &WorkArea);
2116
2117 rc = WorkArea;
2118 ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
2119
2120 if(x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
2121 {
2122 CalculatedDefPosSize = IntCalcDefPosSize(ParentWindow, &rc, TRUE);
2123
2124 if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
2125 {
2126 ProcessParams->WindowFlags &= ~STARTF_USEPOSITION;
2127 Pos.x = WorkArea.left + ProcessParams->StartingX;
2128 Pos.y = WorkArea.top + ProcessParams->StartingY;
2129 }
2130 else
2131 {
2132 Pos.x = rc.left;
2133 Pos.y = rc.top;
2134 }
2135
2136 /*
2137 According to wine, the ShowMode is set to y if x == CW_USEDEFAULT(16) and
2138 y is something else. and Quote!
2139 */
2140
2141 /* Never believe Microsoft's documentation... CreateWindowEx doc says
2142 * that if an overlapped window is created with WS_VISIBLE style bit
2143 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
2144 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
2145 * reveals that
2146 *
2147 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
2148 * 2) it does not ignore the y parameter as the docs claim; instead, it
2149 * uses it as second parameter to ShowWindow() unless y is either
2150 * CW_USEDEFAULT or CW_USEDEFAULT16.
2151 *
2152 * The fact that we didn't do 2) caused bogus windows pop up when wine
2153 * was running apps that were using this obscure feature. Example -
2154 * calc.exe that comes with Win98 (only Win98, it's different from
2155 * the one that comes with Win95 and NT)
2156 */
2157 if(y != CW_USEDEFAULT && y != CW_USEDEFAULT16)
2158 {
2159 dwShowMode = y;
2160 }
2161 }
2162 if(nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16)
2163 {
2164 if(!CalculatedDefPosSize)
2165 {
2166 IntCalcDefPosSize(ParentWindow, &rc, FALSE);
2167 }
2168 if(ProcessParams->WindowFlags & STARTF_USESIZE)
2169 {
2170 ProcessParams->WindowFlags &= ~STARTF_USESIZE;
2171 Size.cx = ProcessParams->CountX;
2172 Size.cy = ProcessParams->CountY;
2173 }
2174 else
2175 {
2176 Size.cx = rc.right - rc.left;
2177 Size.cy = rc.bottom - rc.top;
2178 }
2179
2180 /* move the window if necessary */
2181 if(Pos.x > rc.left)
2182 Pos.x = max(rc.left, 0);
2183 if(Pos.y > rc.top)
2184 Pos.y = max(rc.top, 0);
2185 }
2186 }
2187 else
2188 {
2189 /* if CW_USEDEFAULT(16) is set for non-overlapped windows, both values are set to zero) */
2190 if(x == CW_USEDEFAULT || x == CW_USEDEFAULT16)
2191 {
2192 Pos.x = 0;
2193 Pos.y = 0;
2194 }
2195 if(nWidth == CW_USEDEFAULT || nWidth == CW_USEDEFAULT16)
2196 {
2197 Size.cx = 0;
2198 Size.cy = 0;
2199 }
2200 }
2201
2202 /* Initialize the window dimensions. */
2203 Wnd->rcWindow.left = Pos.x;
2204 Wnd->rcWindow.top = Pos.y;
2205 Wnd->rcWindow.right = Pos.x + Size.cx;
2206 Wnd->rcWindow.bottom = Pos.y + Size.cy;
2207 if (0 != (Wnd->style & WS_CHILD) && ParentWindow)
2208 {
2209 RECTL_vOffsetRect(&(Wnd->rcWindow), ParentWindow->Wnd->rcClient.left,
2210 ParentWindow->Wnd->rcClient.top);
2211 }
2212 Wnd->rcClient = Wnd->rcWindow;
2213
2214 /*
2215 * Get the size and position of the window.
2216 */
2217 if ((dwStyle & WS_THICKFRAME) || !(dwStyle & (WS_POPUP | WS_CHILD)))
2218 {
2219 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
2220
2221 /* WinPosGetMinMaxInfo sends the WM_GETMINMAXINFO message */
2222 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack,
2223 &MaxTrack);
2224 if (MaxSize.x < Size.cx)
2225 Size.cx = MaxSize.x;
2226 if (MaxSize.y < Size.cy)
2227 Size.cy = MaxSize.y;
2228 if (Size.cx < MinTrack.x )
2229 Size.cx = MinTrack.x;
2230 if (Size.cy < MinTrack.y )
2231 Size.cy = MinTrack.y;
2232 if (Size.cx < 0)
2233 Size.cx = 0;
2234 if (Size.cy < 0)
2235 Size.cy = 0;
2236 }
2237
2238 Wnd->rcWindow.left = Pos.x;
2239 Wnd->rcWindow.top = Pos.y;
2240 Wnd->rcWindow.right = Pos.x + Size.cx;
2241 Wnd->rcWindow.bottom = Pos.y + Size.cy;
2242 if (0 != (Wnd->style & WS_CHILD) && ParentWindow)
2243 {
2244 RECTL_vOffsetRect(&(Wnd->rcWindow), ParentWindow->Wnd->rcClient.left,
2245 ParentWindow->Wnd->rcClient.top);
2246 }
2247 Wnd->rcClient = Wnd->rcWindow;
2248
2249 /* FIXME: Initialize the window menu. */
2250
2251 /* Send a NCCREATE message. */
2252 DPRINT("[win32k.window] IntCreateWindowEx style %d, exstyle %d, parent %d\n", Cs.style, Cs.dwExStyle, Cs.hwndParent);
2253 DPRINT("IntCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, Size.cx, Size.cy);
2254 DPRINT("IntCreateWindowEx(): About to send NCCREATE message.\n");
2255 Result = co_IntSendMessage(Window->hSelf, WM_NCCREATE, 0, (LPARAM) &Cs);
2256 if (!Result)
2257 {
2258 /* FIXME: Cleanup. */
2259 DPRINT1("IntCreateWindowEx(): NCCREATE message failed. No cleanup performed!\n");
2260 RETURN((PWND)0);
2261 }
2262
2263 /* Calculate the non-client size. */
2264 MaxPos.x = Window->Wnd->rcWindow.left;
2265 MaxPos.y = Window->Wnd->rcWindow.top;
2266
2267
2268 DPRINT("IntCreateWindowEx(): About to get non-client size.\n");
2269 /* WinPosGetNonClientSize SENDS THE WM_NCCALCSIZE message */
2270 Result = co_WinPosGetNonClientSize(Window,
2271 &Window->Wnd->rcWindow,
2272 &Window->Wnd->rcClient);
2273
2274 RECTL_vOffsetRect(&Window->Wnd->rcWindow,
2275 MaxPos.x - Window->Wnd->rcWindow.left,
2276 MaxPos.y - Window->Wnd->rcWindow.top);
2277
2278
2279 if (NULL != ParentWindow)
2280 {
2281 /* link the window into the parent's child list */
2282 if ((dwStyle & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2283 {
2284 PWINDOW_OBJECT PrevSibling;
2285
2286 PrevSibling = ParentWindow->spwndChild;
2287
2288 if(PrevSibling)
2289 {
2290 while (PrevSibling->spwndNext)
2291 PrevSibling = PrevSibling->spwndNext;
2292 }
2293
2294 /* link window as bottom sibling */
2295 IntLinkWindow(Window, ParentWindow, PrevSibling /*prev sibling*/);
2296 }
2297 else
2298 {
2299 /* link window as top sibling (but after topmost siblings) */
2300 PWINDOW_OBJECT InsertAfter, Sibling;
2301 if (!(dwExStyle & WS_EX_TOPMOST))
2302 {
2303 InsertAfter = NULL;
2304 Sibling = ParentWindow->spwndChild;
2305 while (Sibling && (Sibling->Wnd->ExStyle & WS_EX_TOPMOST))
2306 {
2307 InsertAfter = Sibling;
2308 Sibling = Sibling->spwndNext;
2309 }
2310 }
2311 else
2312 {
2313 InsertAfter = NULL;
2314 }
2315
2316 IntLinkWindow(Window, ParentWindow, InsertAfter /* prev sibling */);
2317 }
2318 }
2319
2320 /* Send the WM_CREATE message. */
2321 DPRINT("IntCreateWindowEx(): about to send CREATE message.\n");
2322 Result = co_IntSendMessage(Window->hSelf, WM_CREATE, 0, (LPARAM) &Cs);
2323
2324 if (Result == (LRESULT)-1)
2325 {
2326 /* FIXME: Cleanup. */
2327 DPRINT1("IntCreateWindowEx(): send CREATE message failed. No cleanup performed!\n");
2328 IntUnlinkWindow(Window);
2329 RETURN((PWND)0);
2330 }
2331
2332 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window->Wnd, OBJID_WINDOW, 0);
2333
2334 /* By setting the flag below it can be examined to determine if the window
2335 was created successfully and a valid pwnd was passed back to caller since
2336 from here the function has to succeed. */
2337 Window->Wnd->state2 |= WNDS2_WMCREATEMSGPROCESSED;
2338
2339 /* Send move and size messages. */
2340 if (!(Window->state & WINDOWOBJECT_NEED_SIZE))
2341 {
2342 LONG lParam;
2343
2344 DPRINT("IntCreateWindow(): About to send WM_SIZE\n");
2345
2346 if ((Window->Wnd->rcClient.right - Window->Wnd->rcClient.left) < 0 ||
2347 (Window->Wnd->rcClient.bottom - Window->Wnd->rcClient.top) < 0)
2348 {
2349 DPRINT("Sending bogus WM_SIZE\n");
2350 }
2351
2352 lParam = MAKE_LONG(Window->Wnd->rcClient.right -
2353 Window->Wnd->rcClient.left,
2354 Window->Wnd->rcClient.bottom -
2355 Window->Wnd->rcClient.top);
2356 co_IntSendMessage(Window->hSelf, WM_SIZE, SIZE_RESTORED,
2357 lParam);
2358
2359 DPRINT("IntCreateWindow(): About to send WM_MOVE\n");
2360
2361 if (0 != (Wnd->style & WS_CHILD) && ParentWindow)
2362 {
2363 lParam = MAKE_LONG(Wnd->rcClient.left - ParentWindow->Wnd->rcClient.left,
2364 Wnd->rcClient.top - ParentWindow->Wnd->rcClient.top);
2365 }
2366 else
2367 {
2368 lParam = MAKE_LONG(Wnd->rcClient.left,
2369 Wnd->rcClient.top);
2370 }
2371
2372 co_IntSendMessage(Window->hSelf, WM_MOVE, 0, lParam);
2373
2374 /* Call WNDOBJ change procs */
2375 IntEngWindowChanged(Window, WOC_RGN_CLIENT);
2376 }
2377
2378 /* Show or maybe minimize or maximize the window. */
2379 if (Wnd->style & (WS_MINIMIZE | WS_MAXIMIZE))
2380 {
2381 RECTL NewPos;
2382 UINT16 SwFlag;
2383
2384 SwFlag = (Wnd->style & WS_MINIMIZE) ? SW_MINIMIZE :
2385 SW_MAXIMIZE;
2386
2387 co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2388
2389 SwFlag = ((Wnd->style & WS_CHILD) || UserGetActiveWindow()) ?
2390 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED :
2391 SWP_NOZORDER | SWP_FRAMECHANGED;
2392
2393 DPRINT("IntCreateWindow(): About to minimize/maximize\n");
2394 DPRINT("%d,%d %dx%d\n", NewPos.left, NewPos.top, NewPos.right, NewPos.bottom);
2395 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2396 NewPos.right, NewPos.bottom, SwFlag);
2397 }
2398
2399 /* Notify the parent window of a new child. */
2400 if ((Wnd->style & WS_CHILD) &&
2401 (!(Wnd->ExStyle & WS_EX_NOPARENTNOTIFY)) && ParentWindow)
2402 {
2403 DPRINT("IntCreateWindow(): About to notify parent\n");
2404 co_IntSendMessage(ParentWindow->hSelf,
2405 WM_PARENTNOTIFY,
2406 MAKEWPARAM(WM_CREATE, Wnd->IDMenu),
2407 (LPARAM)Window->hSelf);
2408 }
2409
2410 if ((!hWndParent) && (!HasOwner))
2411 {
2412 DPRINT("Sending CREATED notify\n");
2413 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)hWnd);
2414 }
2415 else
2416 {
2417 DPRINT("Not sending CREATED notify, %x %d\n", ParentWindow, HasOwner);
2418 }
2419
2420 /* Initialize and show the window's scrollbars */
2421 if (Wnd->style & WS_VSCROLL)
2422 {
2423 co_UserShowScrollBar(Window, SB_VERT, TRUE);
2424 }
2425 if (Wnd->style & WS_HSCROLL)
2426 {
2427 co_UserShowScrollBar(Window, SB_HORZ, TRUE);
2428 }
2429
2430 if (dwStyle & WS_VISIBLE)
2431 {
2432 if (Wnd->style & WS_MAXIMIZE)
2433 dwShowMode = SW_SHOW;
2434 else if (Wnd->style & WS_MINIMIZE)
2435 dwShowMode = SW_SHOWMINIMIZED;
2436
2437 DPRINT("IntCreateWindow(): About to show window\n");
2438 co_WinPosShowWindow(Window, dwShowMode);
2439
2440 if (Wnd->ExStyle & WS_EX_MDICHILD)
2441 {
2442 co_IntSendMessage(ParentWindow->hSelf, WM_MDIREFRESHMENU, 0, 0);
2443 /* ShowWindow won't activate child windows */
2444 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2445 }
2446 }
2447
2448 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
2449 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
2450 Dont understand why it does this. */
2451 if (ClassAtom == gpsi->atomSysClass[ICLS_EDIT])
2452 {
2453 PCALLPROCDATA CallProc;
2454 //CallProc = CreateCallProc(NULL, Wnd->lpfnWndProc, bUnicodeWindow, Wnd->ti->ppi);
2455 CallProc = CreateCallProc(NULL, Wnd->lpfnWndProc, Wnd->Unicode , Wnd->head.pti->ppi);
2456
2457 if (!CallProc)
2458 {
2459 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
2460 DPRINT1("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %x\n",hWnd);
2461 }
2462 else
2463 {
2464 UserAddCallProcToClass(Wnd->pcls, CallProc);
2465 }
2466 }
2467
2468 DPRINT("IntCreateWindow(): = %X\n", hWnd);
2469 DPRINT("WindowObject->SystemMenu = 0x%x\n", Window->SystemMenu);
2470 RETURN( Wnd);
2471
2472 CLEANUP:
2473 if (!_ret_ && Window && Window->Wnd && ti)
2474 co_UserDestroyWindow(Window);
2475 // UserFreeWindowInfo(ti, Window);
2476 if (Window)
2477 {
2478 UserDerefObjectCo(Window);
2479 UserDereferenceObject(Window);
2480 }
2481 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2482 if (!_ret_ && ti != NULL)
2483 {
2484 if (Class != NULL)
2485 {
2486 IntDereferenceClass(Class,
2487 ti->pDeskInfo,
2488 ti->ppi);
2489 }
2490 }
2491 END_CLEANUP;
2492 }
2493
2494 HWND APIENTRY
2495 NtUserCreateWindowEx(DWORD dwExStyle,
2496 PUNICODE_STRING UnsafeClassName,
2497 PUNICODE_STRING UnsafeWindowName,
2498 DWORD dwStyle,
2499 LONG x,
2500 LONG y,
2501 LONG nWidth,
2502 LONG nHeight,
2503 HWND hWndParent,
2504 HMENU hMenu,
2505 HINSTANCE hInstance,
2506 LPVOID lpParam,
2507 DWORD dwShowMode,
2508 BOOL bUnicodeWindow,
2509 DWORD dwUnknown)
2510 {
2511 NTSTATUS Status;
2512 UNICODE_STRING WindowName;
2513 UNICODE_STRING ClassName;
2514 HWND NewWindow = NULL;
2515 PWND pNewWindow;
2516 DECLARE_RETURN(HWND);
2517
2518 DPRINT("Enter NtUserCreateWindowEx(): (%d,%d-%d,%d)\n", x, y, nWidth, nHeight);
2519 UserEnterExclusive();
2520
2521 /* Get the class name (string or atom) */
2522 Status = MmCopyFromCaller(&ClassName, UnsafeClassName, sizeof(UNICODE_STRING));
2523 if (! NT_SUCCESS(Status))
2524 {
2525 SetLastNtError(Status);
2526 RETURN( NULL);
2527 }
2528 if (ClassName.Length != 0)
2529 {
2530 Status = IntSafeCopyUnicodeStringTerminateNULL(&ClassName, UnsafeClassName);
2531 if (! NT_SUCCESS(Status))
2532 {
2533 SetLastNtError(Status);
2534 RETURN( NULL);
2535 }
2536 }
2537 else if (! IS_ATOM(ClassName.Buffer))
2538 {
2539 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2540 RETURN(NULL);
2541 }
2542
2543 /* safely copy the window name */
2544 if (NULL != UnsafeWindowName)
2545 {
2546 Status = IntSafeCopyUnicodeString(&WindowName, UnsafeWindowName);
2547 if (! NT_SUCCESS(Status))
2548 {
2549 if (! IS_ATOM(ClassName.Buffer))
2550 {
2551 ExFreePoolWithTag(ClassName.Buffer, TAG_STRING);
2552 }
2553 SetLastNtError(Status);
2554 RETURN( NULL);
2555 }
2556 }
2557 else
2558 {
2559 RtlInitUnicodeString(&WindowName, NULL);
2560 }
2561
2562 pNewWindow = co_IntCreateWindowEx( dwExStyle,
2563 &ClassName,
2564 &WindowName,
2565 dwStyle,
2566 x,
2567 y,
2568 nWidth,
2569 nHeight,
2570 hWndParent,
2571 hMenu,
2572 hInstance,
2573 lpParam,
2574 dwShowMode,
2575 bUnicodeWindow);
2576
2577 if (pNewWindow) NewWindow = UserHMGetHandle(pNewWindow);
2578
2579 if (WindowName.Buffer)
2580 {
2581 ExFreePoolWithTag(WindowName.Buffer, TAG_STRING);
2582 }
2583 if (! IS_ATOM(ClassName.Buffer))
2584 {
2585 ExFreePoolWithTag(ClassName.Buffer, TAG_STRING);
2586 }
2587
2588 RETURN( NewWindow);
2589
2590 CLEANUP:
2591 DPRINT("Leave NtUserCreateWindowEx, ret=%i\n",_ret_);
2592 UserLeave();
2593 END_CLEANUP;
2594 }
2595
2596 /*
2597 * @unimplemented
2598 */
2599 HDWP APIENTRY
2600 NtUserDeferWindowPos(HDWP WinPosInfo,
2601 HWND Wnd,
2602 HWND WndInsertAfter,
2603 int x,
2604 int y,
2605 int cx,
2606 int cy,
2607 UINT Flags)
2608 {
2609 UNIMPLEMENTED
2610
2611 return 0;
2612 }
2613
2614
2615 BOOLEAN FASTCALL co_UserDestroyWindow(PWINDOW_OBJECT Window)
2616 {
2617 BOOLEAN isChild;
2618 PWND Wnd;
2619 HWND hWnd;
2620 PTHREADINFO ti;
2621
2622 ASSERT_REFS_CO(Window); // FIXME: temp hack?
2623
2624 hWnd = Window->hSelf;
2625
2626 Wnd = Window->Wnd;
2627
2628 if (!Wnd) return TRUE; // FIXME: Need to finish object rewrite or lock the thread when killing the window!
2629
2630 DPRINT("co_UserDestroyWindow \n");
2631
2632 /* Check for owner thread */
2633 if ( (Window->pti->pEThread != PsGetCurrentThread()) ||
2634 Wnd->head.pti != PsGetCurrentThreadWin32Thread() )
2635 {
2636 SetLastWin32Error(ERROR_ACCESS_DENIED);
2637 return FALSE;
2638 }
2639
2640 /* If window was created successfully and it is hooked */
2641 if ((Wnd->state2 & WNDS2_WMCREATEMSGPROCESSED) && (ISITHOOKED(WH_CBT)))
2642 {
2643 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0)) return FALSE;
2644 }
2645
2646 /* Look whether the focus is within the tree of windows we will
2647 * be destroying.
2648 */
2649 if (!co_WinPosShowWindow(Window, SW_HIDE))
2650 {
2651 if (UserGetActiveWindow() == Window->hSelf)
2652 {
2653 co_WinPosActivateOtherWindow(Window);
2654 }
2655 }
2656
2657 if (Window->pti->MessageQueue->ActiveWindow == Window->hSelf)
2658 Window->pti->MessageQueue->ActiveWindow = NULL;
2659 if (Window->pti->MessageQueue->FocusWindow == Window->hSelf)
2660 Window->pti->MessageQueue->FocusWindow = NULL;
2661 if (Window->pti->MessageQueue->CaptureWindow == Window->hSelf)
2662 Window->pti->MessageQueue->CaptureWindow = NULL;
2663
2664 /*
2665 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2666 */
2667
2668 ti = PsGetCurrentThreadWin32Thread();
2669
2670 if ((ti != NULL) & (ti->pDeskInfo != NULL))
2671 {
2672 if (ti->pDeskInfo->hShellWindow == hWnd)
2673 {
2674 DPRINT1("Destroying the ShellWindow!\n");
2675 ti->pDeskInfo->hShellWindow = NULL;
2676 }
2677 }
2678
2679 IntDereferenceMessageQueue(Window->pti->MessageQueue);
2680
2681 IntEngWindowChanged(Window, WOC_DELETE);
2682 isChild = (0 != (Wnd->style & WS_CHILD));
2683
2684 #if 0 /* FIXME */
2685
2686 if (isChild)
2687 {
2688 if (! USER_IsExitingThread(GetCurrentThreadId()))
2689 {
2690 send_parent_notify(hwnd, WM_DESTROY);
2691 }
2692 }
2693 else if (NULL != GetWindow(Wnd, GW_OWNER))
2694 {
2695 co_HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
2696 /* FIXME: clean up palette - see "Internals" p.352 */
2697 }
2698 #endif
2699
2700 if (!IntIsWindow(Window->hSelf))
2701 {
2702 return TRUE;
2703 }
2704
2705 /* Recursively destroy owned windows */
2706 if (! isChild)
2707 {
2708 for (;;)
2709 {
2710 BOOL GotOne = FALSE;
2711 HWND *Children;
2712 HWND *ChildHandle;
2713 PWINDOW_OBJECT Child, Desktop;
2714
2715 Desktop = IntIsDesktopWindow(Window) ? Window :
2716 UserGetWindowObject(IntGetDesktopWindow());
2717 Children = IntWinListChildren(Desktop);
2718
2719 if (Children)
2720 {
2721 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2722 {
2723 Child = UserGetWindowObject(*ChildHandle);
2724 if (Child == NULL)
2725 continue;
2726 if (Child->hOwner != Window->hSelf)
2727 {
2728 continue;
2729 }
2730
2731 if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
2732 {
2733 USER_REFERENCE_ENTRY ChildRef;
2734 UserRefObjectCo(Child, &ChildRef);//temp hack?
2735 co_UserDestroyWindow(Child);
2736 UserDerefObjectCo(Child);//temp hack?
2737
2738 GotOne = TRUE;
2739 continue;
2740 }
2741
2742 if (Child->hOwner != NULL)
2743 {
2744 Child->hOwner = NULL;
2745 Child->Wnd->spwndOwner = NULL;
2746 }
2747
2748 }
2749 ExFreePool(Children);
2750 }
2751 if (! GotOne)
2752 {
2753 break;
2754 }
2755 }
2756 }
2757
2758 if (!IntIsWindow(Window->hSelf))
2759 {
2760 return TRUE;
2761 }
2762
2763 /* Destroy the window storage */
2764 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2765
2766 return TRUE;
2767 }
2768
2769
2770 /*
2771 * @implemented
2772 */
2773 BOOLEAN APIENTRY
2774 NtUserDestroyWindow(HWND Wnd)
2775 {
2776 PWINDOW_OBJECT Window;
2777 DECLARE_RETURN(BOOLEAN);
2778 BOOLEAN ret;
2779 USER_REFERENCE_ENTRY Ref;
2780
2781 DPRINT("Enter NtUserDestroyWindow\n");
2782 UserEnterExclusive();
2783
2784 if (!(Window = UserGetWindowObject(Wnd)))
2785 {
2786 RETURN(FALSE);
2787 }
2788
2789 UserRefObjectCo(Window, &Ref);//faxme: dunno if win should be reffed during destroy..
2790 ret = co_UserDestroyWindow(Window);
2791 UserDerefObjectCo(Window);//faxme: dunno if win should be reffed during destroy..
2792
2793 RETURN(ret);
2794
2795 CLEANUP:
2796 DPRINT("Leave NtUserDestroyWindow, ret=%i\n",_ret_);
2797 UserLeave();
2798 END_CLEANUP;
2799 }
2800
2801
2802
2803 /*
2804 * @unimplemented
2805 */
2806 DWORD
2807 APIENTRY
2808 NtUserDrawMenuBarTemp(
2809 HWND hWnd,
2810 HDC hDC,
2811 PRECT hRect,
2812 HMENU hMenu,
2813 HFONT hFont)
2814 {
2815 /* we'll use this function just for caching the menu bar */
2816 UNIMPLEMENTED
2817 return 0;
2818 }
2819
2820
2821 /*
2822 * @unimplemented
2823 */
2824 DWORD APIENTRY
2825 NtUserEndDeferWindowPosEx(DWORD Unknown0,
2826 DWORD Unknown1)
2827 {
2828 UNIMPLEMENTED
2829
2830 return 0;
2831 }
2832
2833
2834 /*
2835 * FillWindow: Called from User; Dialog, Edit and ListBox procs during a WM_ERASEBKGND.
2836 */
2837 /*
2838 * @unimplemented
2839 */
2840 BOOL APIENTRY
2841 NtUserFillWindow(HWND hWndPaint,
2842 HWND hWndPaint1,
2843 HDC hDC,
2844 HBRUSH hBrush)
2845 {
2846 UNIMPLEMENTED
2847
2848 return 0;
2849 }
2850
2851
2852 static HWND FASTCALL
2853 IntFindWindow(PWINDOW_OBJECT Parent,
2854 PWINDOW_OBJECT ChildAfter,
2855 RTL_ATOM ClassAtom,
2856 PUNICODE_STRING WindowName)
2857 {
2858 BOOL CheckWindowName;
2859 HWND *List, *phWnd;
2860 HWND Ret = NULL;
2861
2862 ASSERT(Parent);
2863
2864 CheckWindowName = WindowName->Length != 0;
2865
2866 if((List = IntWinListChildren(Parent)))
2867 {
2868 phWnd = List;
2869 if(ChildAfter)
2870 {
2871 /* skip handles before and including ChildAfter */
2872 while(*phWnd && (*(phWnd++) != ChildAfter->hSelf))
2873 ;
2874 }
2875
2876 /* search children */
2877 while(*phWnd)
2878 {
2879 PWINDOW_OBJECT Child;
2880 if(!(Child = UserGetWindowObject(*(phWnd++))))
2881 {
2882 continue;
2883 }
2884
2885 /* Do not send WM_GETTEXT messages in the kernel mode version!
2886 The user mode version however calls GetWindowText() which will
2887 send WM_GETTEXT messages to windows belonging to its processes */
2888 if((!CheckWindowName || !RtlCompareUnicodeString(WindowName, &(Child->Wnd->strName), TRUE)) &&
2889 (!ClassAtom || Child->Wnd->pcls->atomClassName == ClassAtom))
2890 {
2891 Ret = Child->hSelf;
2892 break;
2893 }
2894
2895 }
2896 ExFreePool(List);
2897 }
2898
2899 return Ret;
2900 }
2901
2902 /*
2903 * FUNCTION:
2904 * Searches a window's children for a window with the specified
2905 * class and name
2906 * ARGUMENTS:
2907 * hwndParent = The window whose childs are to be searched.
2908 * NULL = desktop
2909 * HWND_MESSAGE = message-only windows
2910 *
2911 * hwndChildAfter = Search starts after this child window.
2912 * NULL = start from beginning
2913 *
2914 * ucClassName = Class name to search for
2915 * Reguired parameter.
2916 *
2917 * ucWindowName = Window name
2918 * ->Buffer == NULL = don't care
2919 *
2920 * RETURNS:
2921 * The HWND of the window if it was found, otherwise NULL
2922 */
2923 /*
2924 * @implemented
2925 */
2926 HWND APIENTRY
2927 NtUserFindWindowEx(HWND hwndParent,
2928 HWND hwndChildAfter,
2929 PUNICODE_STRING ucClassName,
2930 PUNICODE_STRING ucWindowName,
2931 DWORD dwUnknown)
2932 {
2933 PWINDOW_OBJECT Parent, ChildAfter;
2934 UNICODE_STRING ClassName = {0}, WindowName = {0};
2935 HWND Desktop, Ret = NULL;
2936 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2937 DECLARE_RETURN(HWND);
2938
2939 DPRINT("Enter NtUserFindWindowEx\n");
2940 UserEnterShared();
2941
2942 if (ucClassName != NULL || ucWindowName != NULL)
2943 {
2944 _SEH2_TRY
2945 {
2946 if (ucClassName != NULL)
2947 {
2948 ClassName = ProbeForReadUnicodeString(ucClassName);
2949 if (ClassName.Length != 0)
2950 {
2951 ProbeForRead(ClassName.Buffer,
2952 ClassName.Length,
2953 sizeof(WCHAR));
2954 }
2955 else if (!IS_ATOM(ClassName.Buffer))
2956 {
2957 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2958 _SEH2_LEAVE;
2959 }
2960
2961 if (!IntGetAtomFromStringOrAtom(&ClassName,
2962 &ClassAtom))
2963 {
2964 _SEH2_LEAVE;
2965 }
2966 }
2967
2968 if (ucWindowName != NULL)
2969 {
2970 WindowName = ProbeForReadUnicodeString(ucWindowName);
2971 if (WindowName.Length != 0)
2972 {
2973 ProbeForRead(WindowName.Buffer,
2974 WindowName.Length,
2975 sizeof(WCHAR));
2976 }
2977 }
2978 }
2979 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2980 {
2981 SetLastNtError(_SEH2_GetExceptionCode());
2982 _SEH2_YIELD(RETURN(NULL));
2983 }
2984 _SEH2_END;
2985
2986 if (ucClassName != NULL)
2987 {
2988 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
2989 !IS_ATOM(ClassName.Buffer))
2990 {
2991 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2992 RETURN(NULL);
2993 }
2994 else if (ClassAtom == (RTL_ATOM)0)
2995 {
2996 /* LastError code was set by IntGetAtomFromStringOrAtom */
2997 RETURN(NULL);
2998 }
2999 }
3000 }
3001
3002 Desktop = IntGetCurrentThreadDesktopWindow();
3003
3004 if(hwndParent == NULL)
3005 hwndParent = Desktop;
3006 else if(hwndParent == HWND_MESSAGE)
3007 {
3008 hwndParent = IntGetMessageWindow();
3009 }
3010
3011 if(!(Parent = UserGetWindowObject(hwndParent)))
3012 {
3013 RETURN( NULL);
3014 }
3015
3016 ChildAfter = NULL;
3017 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
3018 {
3019 RETURN( NULL);
3020 }
3021
3022 _SEH2_TRY
3023 {
3024 if(Parent->hSelf == Desktop)
3025 {
3026 HWND *List, *phWnd;
3027 PWINDOW_OBJECT TopLevelWindow;
3028 BOOLEAN CheckWindowName;
3029 BOOLEAN WindowMatches;
3030 BOOLEAN ClassMatches;
3031
3032 /* windows searches through all top-level windows if the parent is the desktop
3033 window */
3034
3035 if((List = IntWinListChildren(Parent)))
3036 {
3037 phWnd = List;
3038
3039 if(ChildAfter)
3040 {
3041 /* skip handles before and including ChildAfter */
3042 while(*phWnd && (*(phWnd++) != ChildAfter->hSelf))
3043 ;
3044 }
3045
3046 CheckWindowName = WindowName.Length != 0;
3047
3048 /* search children */
3049 while(*phWnd)
3050 {
3051 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
3052 {
3053 continue;
3054 }
3055
3056 /* Do not send WM_GETTEXT messages in the kernel mode version!
3057 The user mode version however calls GetWindowText() which will
3058 send WM_GETTEXT messages to windows belonging to its processes */
3059 WindowMatches = !CheckWindowName || !RtlCompareUnicodeString(
3060 &WindowName, &TopLevelWindow->Wnd->strName, TRUE);
3061 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
3062 ClassAtom == TopLevelWindow->Wnd->pcls->atomClassName;
3063
3064 if (WindowMatches && ClassMatches)
3065 {
3066 Ret = TopLevelWindow->hSelf;
3067 break;
3068 }
3069
3070 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
3071 {
3072 /* window returns the handle of the top-level window, in case it found
3073 the child window */
3074 Ret = TopLevelWindow->hSelf;
3075 break;
3076 }
3077
3078 }
3079 ExFreePool(List);
3080 }
3081 }
3082 else
3083 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
3084
3085 #if 0
3086
3087 if(Ret == NULL && hwndParent == NULL && hwndChildAfter == NULL)
3088 {
3089 /* FIXME - if both hwndParent and hwndChildAfter are NULL, we also should
3090 search the message-only windows. Should this also be done if
3091 Parent is the desktop window??? */
3092 PWINDOW_OBJECT MsgWindows;
3093
3094 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3095 {
3096 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3097 }
3098 }
3099 #endif
3100 }
3101 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3102 {
3103 SetLastNtError(_SEH2_GetExceptionCode());
3104 Ret = NULL;
3105 }
3106 _SEH2_END;
3107
3108 RETURN( Ret);
3109
3110 CLEANUP:
3111 DPRINT("Leave NtUserFindWindowEx, ret %i\n",_ret_);
3112 UserLeave();
3113 END_CLEANUP;
3114 }
3115
3116
3117 /*
3118 * @unimplemented
3119 */
3120 BOOL APIENTRY
3121 NtUserFlashWindowEx(IN PFLASHWINFO pfwi)
3122 {
3123 UNIMPLEMENTED
3124
3125 return 0;
3126 }
3127
3128
3129 /*
3130 * @implemented
3131 */
3132 PWINDOW_OBJECT FASTCALL UserGetAncestor(PWINDOW_OBJECT Wnd, UINT Type)
3133 {
3134 PWINDOW_OBJECT WndAncestor, Parent;
3135
3136 if (Wnd->hSelf == IntGetDesktopWindow())
3137 {
3138 return NULL;
3139 }
3140
3141 switch (Type)
3142 {
3143 case GA_PARENT:
3144 {
3145 WndAncestor = Wnd->spwndParent;
3146 break;
3147 }
3148
3149 case GA_ROOT:
3150 {
3151 WndAncestor = Wnd;
3152 Parent = NULL;
3153
3154 for(;;)
3155 {
3156 if(!(Parent = WndAncestor->spwndParent))
3157 {
3158 break;
3159 }
3160 if(IntIsDesktopWindow(Parent))
3161 {
3162 break;
3163 }
3164
3165 WndAncestor = Parent;
3166 }
3167 break;
3168 }
3169
3170 case GA_ROOTOWNER:
3171 {
3172 WndAncestor = Wnd;
3173
3174 for (;;)
3175 {
3176 PWINDOW_OBJECT Parent, Old;
3177
3178 Old = WndAncestor;
3179 Parent = IntGetParent(WndAncestor);
3180
3181 if (!Parent)
3182 {
3183 break;
3184 }
3185
3186 //temp hack
3187 // UserDereferenceObject(Parent);
3188
3189 WndAncestor = Parent;
3190 }
3191 break;
3192 }
3193
3194 default:
3195 {
3196 return NULL;
3197 }
3198 }
3199
3200 return WndAncestor;
3201 }
3202
3203 /*
3204 * @implemented
3205 */
3206 HWND APIENTRY
3207 NtUserGetAncestor(HWND hWnd, UINT Type)
3208 {
3209 PWINDOW_OBJECT Window, Ancestor;
3210 DECLARE_RETURN(HWND);
3211
3212 DPRINT("Enter NtUserGetAncestor\n");
3213 UserEnterExclusive();
3214
3215 if (!(Window = UserGetWindowObject(hWnd)))
3216 {
3217 RETURN(NULL);
3218 }
3219
3220 Ancestor = UserGetAncestor(Window, Type);
3221 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3222
3223 RETURN(Ancestor ? Ancestor->hSelf : NULL);
3224
3225 CLEANUP:
3226 DPRINT("Leave NtUserGetAncestor, ret=%i\n",_ret_);
3227 UserLeave();
3228 END_CLEANUP;
3229 }
3230
3231
3232 BOOL
3233 APIENTRY
3234 NtUserGetComboBoxInfo(
3235 HWND hWnd,
3236 PCOMBOBOXINFO pcbi)
3237 {
3238 PWINDOW_OBJECT Wnd;
3239 DECLARE_RETURN(BOOL);
3240
3241 DPRINT("Enter NtUserGetComboBoxInfo\n");
3242 UserEnterShared();
3243
3244 if (!(Wnd = UserGetWindowObject(hWnd)))
3245 {
3246 RETURN( FALSE );
3247 }
3248 _SEH2_TRY
3249 {
3250 if(pcbi)
3251 {
3252 ProbeForWrite(pcbi,
3253 sizeof(COMBOBOXINFO),
3254 1);
3255 }
3256 }
3257 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3258 {
3259 SetLastNtError(_SEH2_GetExceptionCode());
3260 _SEH2_YIELD(RETURN(FALSE));
3261 }
3262 _SEH2_END;
3263
3264 // Pass the user pointer, it was already probed.
3265 RETURN( (BOOL) co_IntSendMessage( Wnd->hSelf, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3266
3267 CLEANUP:
3268 DPRINT("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3269 UserLeave();
3270 END_CLEANUP;
3271 }
3272
3273
3274 /*
3275 * @implemented
3276 */
3277 DWORD APIENTRY
3278 NtUserGetInternalWindowPos( HWND hWnd,
3279 LPRECT rectWnd,
3280 LPPOINT ptIcon)
3281 {
3282 PWINDOW_OBJECT Window;
3283 PWND Wnd;
3284 DWORD Ret = 0;
3285 BOOL Hit = FALSE;
3286 WINDOWPLACEMENT wndpl;
3287
3288 UserEnterShared();
3289
3290 if (!(Window = UserGetWindowObject(hWnd)) || !Window->Wnd)
3291 {
3292 Hit = FALSE;
3293 goto Exit;
3294 }
3295 Wnd = Window->Wnd;
3296
3297 _SEH2_TRY
3298 {
3299 if(rectWnd)
3300 {
3301 ProbeForWrite(rectWnd,
3302 sizeof(RECT),
3303 1);
3304 }
3305 if(ptIcon)
3306 {
3307 ProbeForWrite(ptIcon,
3308 sizeof(POINT),
3309 1);
3310 }
3311
3312 }
3313 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3314 {
3315 SetLastNtError(_SEH2_GetExceptionCode());
3316 Hit = TRUE;
3317 }
3318 _SEH2_END;
3319
3320 wndpl.length = sizeof(WINDOWPLACEMENT);
3321
3322 if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
3323 {
3324 _SEH2_TRY
3325 {
3326 if (rectWnd)
3327 {
3328 RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));