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