[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->hWnd = 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 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 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->hWnd == 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->hWnd)
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->hWnd = Wnd->head.h;
849 IntReleaseMenuObject(NewMenu);
850 }
851 if (NULL != OldMenu)
852 {
853 OldMenu->hWnd = 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 FASTCALL
899 IntGetSystemMenu(PWND Window, BOOL bRevert, BOOL RetMenu)
900 {
901 PMENU Menu, NewMenu = NULL, SysMenu = NULL, ret = NULL;
902 PTHREADINFO W32Thread;
903 HMENU hNewMenu, hSysMenu;
904 ROSMENUITEMINFO ItemInfo = {0};
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 { // Use spmenuSys
933 Window->SystemMenu = NewMenu->head.h;
934 NewMenu->fFlags |= MNF_SYSDESKMN;
935 NewMenu->hWnd = 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->fFlags |= MNF_SYSDESKMN;
954 SysMenu->hWnd = Window->head.h;
955 hNewMenu = co_IntLoadSysMenuTemplate();
956 //if ( Window->ExStyle & WS_EX_MDICHILD )
957 //hNewMenu = co_IntCallLoadMenu( NULL, L"SYSMENUMDI");
958 // else
959 //hNewMenu = co_IntCallLoadMenu( NULL, L"SYSMENU");
960 // Do the rest in here.
961 if(!hNewMenu)
962 {
963 IntReleaseMenuObject(SysMenu);
964 UserDestroyMenu(hSysMenu);
965 return NULL;
966 }
967 Menu = IntGetMenuObject(hNewMenu);
968 if(!Menu)
969 {
970 IntReleaseMenuObject(SysMenu);
971 UserDestroyMenu(hSysMenu);
972 return NULL;
973 }
974
975 NewMenu = IntCloneMenu(Menu);
976 if(NewMenu)
977 {
978 NewMenu->fFlags |= MNF_SYSDESKMN | MNF_POPUP;
979 // Do not set MNS_CHECKORBMP it breaks menus, also original code destroyed the style anyway.
980 IntReleaseMenuObject(NewMenu);
981 UserSetMenuDefaultItem(NewMenu, SC_CLOSE, FALSE);
982
983 if (Window->pcls->style & CS_NOCLOSE)
984 IntRemoveMenuItem(NewMenu, SC_CLOSE, MF_BYCOMMAND, TRUE);
985
986 ItemInfo.cbSize = sizeof(MENUITEMINFOW);
987 ItemInfo.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_SUBMENU;
988 ItemInfo.fType = 0;
989 ItemInfo.fState = MFS_ENABLED;
990 ItemInfo.dwTypeData = NULL;
991 ItemInfo.cch = 0;
992 ItemInfo.hSubMenu = NewMenu->head.h;
993 IntInsertMenuItem(SysMenu, (UINT) -1, TRUE, &ItemInfo, NULL);
994
995 Window->SystemMenu = SysMenu->head.h;
996
997 ret = SysMenu;
998 }
999 IntDestroyMenuObject(Menu, FALSE, TRUE);
1000 }
1001 if(RetMenu)
1002 return ret;
1003 else
1004 return NULL;
1005 }
1006 else
1007 {
1008 if(Window->SystemMenu)
1009 return IntGetMenuObject((HMENU)Window->SystemMenu);
1010 else
1011 return NULL;
1012 }
1013 }
1014
1015
1016 BOOL FASTCALL
1017 IntIsChildWindow(PWND Parent, PWND BaseWindow)
1018 {
1019 PWND Window;
1020
1021 Window = BaseWindow;
1022 while (Window && ((Window->style & (WS_POPUP|WS_CHILD)) == WS_CHILD))
1023 {
1024 if (Window == Parent)
1025 {
1026 return(TRUE);
1027 }
1028
1029 Window = Window->spwndParent;
1030 }
1031
1032 return(FALSE);
1033 }
1034
1035 /*
1036 Link the window into siblings list
1037 children and parent are kept in place.
1038 */
1039 VOID FASTCALL
1040 IntLinkWindow(
1041 PWND Wnd,
1042 PWND WndInsertAfter /* set to NULL if top sibling */
1043 )
1044 {
1045 if ((Wnd->spwndPrev = WndInsertAfter))
1046 {
1047 /* link after WndInsertAfter */
1048 if ((Wnd->spwndNext = WndInsertAfter->spwndNext))
1049 Wnd->spwndNext->spwndPrev = Wnd;
1050
1051 Wnd->spwndPrev->spwndNext = Wnd;
1052 }
1053 else
1054 {
1055 /* link at top */
1056 if ((Wnd->spwndNext = Wnd->spwndParent->spwndChild))
1057 Wnd->spwndNext->spwndPrev = Wnd;
1058
1059 Wnd->spwndParent->spwndChild = Wnd;
1060 }
1061 }
1062
1063 /*
1064 Note: Wnd->spwndParent can be null if it is the desktop.
1065 */
1066 VOID FASTCALL IntLinkHwnd(PWND Wnd, HWND hWndPrev)
1067 {
1068 if (hWndPrev == HWND_NOTOPMOST)
1069 {
1070 if (!(Wnd->ExStyle & WS_EX_TOPMOST) &&
1071 (Wnd->ExStyle2 & WS_EX2_LINKED)) return; /* nothing to do */
1072 Wnd->ExStyle &= ~WS_EX_TOPMOST;
1073 hWndPrev = HWND_TOP; /* fallback to the HWND_TOP case */
1074 }
1075
1076 IntUnlinkWindow(Wnd); /* unlink it from the previous location */
1077
1078 if (hWndPrev == HWND_BOTTOM)
1079 {
1080 /* Link in the bottom of the list */
1081 PWND WndInsertAfter;
1082
1083 WndInsertAfter = Wnd->spwndParent->spwndChild;
1084 while( WndInsertAfter && WndInsertAfter->spwndNext)
1085 WndInsertAfter = WndInsertAfter->spwndNext;
1086
1087 IntLinkWindow(Wnd, WndInsertAfter);
1088 Wnd->ExStyle &= ~WS_EX_TOPMOST;
1089 }
1090 else if (hWndPrev == HWND_TOPMOST)
1091 {
1092 /* Link in the top of the list */
1093 IntLinkWindow(Wnd, NULL);
1094
1095 Wnd->ExStyle |= WS_EX_TOPMOST;
1096 }
1097 else if (hWndPrev == HWND_TOP)
1098 {
1099 /* Link it after the last topmost window */
1100 PWND WndInsertBefore;
1101
1102 WndInsertBefore = Wnd->spwndParent->spwndChild;
1103
1104 if (!(Wnd->ExStyle & WS_EX_TOPMOST)) /* put it above the first non-topmost window */
1105 {
1106 while (WndInsertBefore != NULL && WndInsertBefore->spwndNext != NULL)
1107 {
1108 if (!(WndInsertBefore->ExStyle & WS_EX_TOPMOST)) break;
1109 if (WndInsertBefore == Wnd->spwndOwner) /* keep it above owner */
1110 {
1111 Wnd->ExStyle |= WS_EX_TOPMOST;
1112 break;
1113 }
1114 WndInsertBefore = WndInsertBefore->spwndNext;
1115 }
1116 }
1117
1118 IntLinkWindow(Wnd, WndInsertBefore ? WndInsertBefore->spwndPrev : NULL);
1119 }
1120 else
1121 {
1122 /* Link it after hWndPrev */
1123 PWND WndInsertAfter;
1124
1125 WndInsertAfter = UserGetWindowObject(hWndPrev);
1126 /* Are we called with an erroneous handle */
1127 if(WndInsertAfter == NULL)
1128 {
1129 /* Link in a default position */
1130 IntLinkHwnd(Wnd, HWND_TOP);
1131 return;
1132 }
1133
1134 IntLinkWindow(Wnd, WndInsertAfter);
1135
1136 /* Fix the WS_EX_TOPMOST flag */
1137 if (!(WndInsertAfter->ExStyle & WS_EX_TOPMOST))
1138 {
1139 Wnd->ExStyle &= ~WS_EX_TOPMOST;
1140 }
1141 else
1142 {
1143 if(WndInsertAfter->spwndNext &&
1144 WndInsertAfter->spwndNext->ExStyle & WS_EX_TOPMOST)
1145 {
1146 Wnd->ExStyle |= WS_EX_TOPMOST;
1147 }
1148 }
1149 }
1150 Wnd->ExStyle2 |= WS_EX2_LINKED;
1151 }
1152
1153 VOID FASTCALL
1154 IntProcessOwnerSwap(PWND Wnd, PWND WndNewOwner, PWND WndOldOwner)
1155 {
1156 if (WndOldOwner)
1157 {
1158 if (Wnd->head.pti != WndOldOwner->head.pti)
1159 {
1160 if (!WndNewOwner ||
1161 Wnd->head.pti == WndNewOwner->head.pti ||
1162 WndOldOwner->head.pti != WndNewOwner->head.pti )
1163 {
1164 //ERR("ProcessOwnerSwap Old out.\n");
1165 UserAttachThreadInput(Wnd->head.pti, WndOldOwner->head.pti, FALSE);
1166 }
1167 }
1168 }
1169 if (WndNewOwner)
1170 {
1171 if (Wnd->head.pti != WndNewOwner->head.pti)
1172 {
1173 if (!WndOldOwner ||
1174 WndOldOwner->head.pti != WndNewOwner->head.pti )
1175 {
1176 //ERR("ProcessOwnerSwap New in.\n");
1177 UserAttachThreadInput(Wnd->head.pti, WndNewOwner->head.pti, TRUE);
1178 }
1179 }
1180 }
1181 // FIXME: System Tray checks.
1182 }
1183
1184 HWND FASTCALL
1185 IntSetOwner(HWND hWnd, HWND hWndNewOwner)
1186 {
1187 PWND Wnd, WndOldOwner, WndNewOwner;
1188 HWND ret;
1189
1190 Wnd = IntGetWindowObject(hWnd);
1191 if(!Wnd)
1192 return NULL;
1193
1194 WndOldOwner = Wnd->spwndOwner;
1195
1196 ret = WndOldOwner ? UserHMGetHandle(WndOldOwner) : 0;
1197 WndNewOwner = UserGetWindowObject(hWndNewOwner);
1198
1199 if (!WndNewOwner && hWndNewOwner)
1200 {
1201 EngSetLastError(ERROR_INVALID_PARAMETER);
1202 ret = NULL;
1203 goto Error;
1204 }
1205
1206 /* if parent belongs to a different thread and the window isn't */
1207 /* top-level, attach the two threads */
1208 IntProcessOwnerSwap(Wnd, WndNewOwner, WndOldOwner);
1209
1210 if (IntValidateOwnerDepth(Wnd, WndNewOwner))
1211 {
1212 if (WndNewOwner)
1213 {
1214 Wnd->spwndOwner= WndNewOwner;
1215 }
1216 else
1217 {
1218 Wnd->spwndOwner = NULL;
1219 }
1220 }
1221 else
1222 {
1223 IntProcessOwnerSwap(Wnd, WndOldOwner, WndNewOwner);
1224 EngSetLastError(ERROR_INVALID_PARAMETER);
1225 ret = NULL;
1226 }
1227 Error:
1228 UserDereferenceObject(Wnd);
1229 return ret;
1230 }
1231
1232 PWND FASTCALL
1233 co_IntSetParent(PWND Wnd, PWND WndNewParent)
1234 {
1235 PWND WndOldParent, pWndExam;
1236 BOOL WasVisible;
1237 POINT pt;
1238 int swFlags = SWP_NOSIZE|SWP_NOZORDER;
1239
1240 ASSERT(Wnd);
1241 ASSERT(WndNewParent);
1242 ASSERT_REFS_CO(Wnd);
1243 ASSERT_REFS_CO(WndNewParent);
1244
1245 if (Wnd == Wnd->head.rpdesk->spwndMessage)
1246 {
1247 EngSetLastError(ERROR_ACCESS_DENIED);
1248 return( NULL);
1249 }
1250
1251 /* Some applications try to set a child as a parent */
1252 if (IntIsChildWindow(Wnd, WndNewParent))
1253 {
1254 TRACE("IntSetParent try to set a child as a parent.\n");
1255 EngSetLastError( ERROR_INVALID_PARAMETER );
1256 return NULL;
1257 }
1258
1259 pWndExam = WndNewParent; // Load parent Window to examine.
1260 // Now test for set parent to parent hit.
1261 while (pWndExam)
1262 {
1263 if (Wnd == pWndExam)
1264 {
1265 TRACE("IntSetParent Failed Test for set parent to parent!\n");
1266 EngSetLastError(ERROR_INVALID_PARAMETER);
1267 return NULL;
1268 }
1269 pWndExam = pWndExam->spwndParent;
1270 }
1271
1272 /*
1273 * Windows hides the window first, then shows it again
1274 * including the WM_SHOWWINDOW messages and all
1275 */
1276 WasVisible = co_WinPosShowWindow(Wnd, SW_HIDE);
1277
1278 /* Window must belong to current process */
1279 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
1280 {
1281 ERR("IntSetParent Window must belong to current process!\n");
1282 return NULL;
1283 }
1284
1285 WndOldParent = Wnd->spwndParent;
1286
1287 if ( WndOldParent &&
1288 WndOldParent->ExStyle & WS_EX_LAYOUTRTL)
1289 pt.x = Wnd->rcWindow.right;
1290 else
1291 pt.x = Wnd->rcWindow.left;
1292 pt.y = Wnd->rcWindow.top;
1293
1294 IntScreenToClient(WndOldParent, &pt);
1295
1296 if (WndOldParent) UserReferenceObject(WndOldParent); /* Caller must deref */
1297
1298 if (WndNewParent != WndOldParent)
1299 {
1300 /* Unlink the window from the siblings list */
1301 IntUnlinkWindow(Wnd);
1302 Wnd->ExStyle2 &= ~WS_EX2_LINKED;
1303
1304 /* Set the new parent */
1305 Wnd->spwndParent = WndNewParent;
1306
1307 if ( Wnd->style & WS_CHILD &&
1308 Wnd->spwndOwner &&
1309 Wnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1310 {
1311 ERR("SetParent Top Most from Pop up!\n");
1312 Wnd->ExStyle |= WS_EX_TOPMOST;
1313 }
1314
1315 /* Link the window with its new siblings */
1316 IntLinkHwnd( Wnd,
1317 ((0 == (Wnd->ExStyle & WS_EX_TOPMOST) &&
1318 WndNewParent == UserGetDesktopWindow() ) ? HWND_TOP : HWND_TOPMOST ) );
1319
1320 }
1321
1322 if ( WndNewParent == co_GetDesktopWindow(Wnd) &&
1323 !(Wnd->style & WS_CLIPSIBLINGS) )
1324 {
1325 Wnd->style |= WS_CLIPSIBLINGS;
1326 DceResetActiveDCEs(Wnd);
1327 }
1328
1329 /* if parent belongs to a different thread and the window isn't */
1330 /* top-level, attach the two threads */
1331 if ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1332 {
1333 if ( Wnd->spwndParent != co_GetDesktopWindow(Wnd))
1334 {
1335 if (Wnd->head.pti != WndOldParent->head.pti)
1336 {
1337 //ERR("SetParent Old out.\n");
1338 UserAttachThreadInput(Wnd->head.pti, WndOldParent->head.pti, FALSE);
1339 }
1340 }
1341 if ( WndNewParent != co_GetDesktopWindow(Wnd))
1342 {
1343 if (Wnd->head.pti != WndNewParent->head.pti)
1344 {
1345 //ERR("SetParent New in.\n");
1346 UserAttachThreadInput(Wnd->head.pti, WndNewParent->head.pti, TRUE);
1347 }
1348 }
1349 }
1350
1351 if (WndOldParent == UserGetMessageWindow() || WndNewParent == UserGetMessageWindow())
1352 swFlags |= SWP_NOACTIVATE;
1353
1354 IntNotifyWinEvent(EVENT_OBJECT_PARENTCHANGE, Wnd ,OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1355 /*
1356 * SetParent additionally needs to make hwnd the top window
1357 * in the z-order and send the expected WM_WINDOWPOSCHANGING and
1358 * WM_WINDOWPOSCHANGED notification messages.
1359 */
1360 //ERR("IntSetParent SetWindowPos 1\n");
1361 co_WinPosSetWindowPos( Wnd,
1362 (0 == (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
1363 pt.x, pt.y, 0, 0, swFlags);
1364 //ERR("IntSetParent SetWindowPos 2 X %d Y %d\n",pt.x, pt.y);
1365 if (WasVisible) co_WinPosShowWindow(Wnd, SW_SHOWNORMAL);
1366
1367 return WndOldParent;
1368 }
1369
1370 HWND FASTCALL
1371 co_UserSetParent(HWND hWndChild, HWND hWndNewParent)
1372 {
1373 PWND Wnd = NULL, WndParent = NULL, WndOldParent;
1374 HWND hWndOldParent = NULL;
1375 USER_REFERENCE_ENTRY Ref, ParentRef;
1376
1377 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
1378 {
1379 EngSetLastError(ERROR_INVALID_PARAMETER);
1380 return( NULL);
1381 }
1382
1383 if (hWndChild == IntGetDesktopWindow())
1384 {
1385 ERR("UserSetParent Access Denied!\n");
1386 EngSetLastError(ERROR_ACCESS_DENIED);
1387 return( NULL);
1388 }
1389
1390 if (hWndNewParent)
1391 {
1392 if (!(WndParent = UserGetWindowObject(hWndNewParent)))
1393 {
1394 ERR("UserSetParent Bad New Parent!\n");
1395 return( NULL);
1396 }
1397 }
1398 else
1399 {
1400 if (!(WndParent = UserGetWindowObject(IntGetDesktopWindow())))
1401 {
1402 return( NULL);
1403 }
1404 }
1405
1406 if (!(Wnd = UserGetWindowObject(hWndChild)))
1407 {
1408 ERR("UserSetParent Bad Child!\n");
1409 return( NULL);
1410 }
1411
1412 UserRefObjectCo(Wnd, &Ref);
1413 UserRefObjectCo(WndParent, &ParentRef);
1414 //ERR("Enter co_IntSetParent\n");
1415 WndOldParent = co_IntSetParent(Wnd, WndParent);
1416 //ERR("Leave co_IntSetParent\n");
1417 UserDerefObjectCo(WndParent);
1418 UserDerefObjectCo(Wnd);
1419
1420 if (WndOldParent)
1421 {
1422 hWndOldParent = WndOldParent->head.h;
1423 UserDereferenceObject(WndOldParent);
1424 }
1425
1426 return( hWndOldParent);
1427 }
1428
1429 BOOL FASTCALL
1430 IntSetSystemMenu(PWND Window, PMENU Menu)
1431 {
1432 PMENU OldMenu;
1433 if(Window->SystemMenu)
1434 {
1435 OldMenu = IntGetMenuObject(Window->SystemMenu);
1436 if(OldMenu)
1437 {
1438 OldMenu->fFlags &= ~ MNF_SYSDESKMN;
1439 IntReleaseMenuObject(OldMenu);
1440 }
1441 }
1442
1443 if(Menu)
1444 {
1445 /* FIXME: Check window style, propably return FALSE? */
1446 Window->SystemMenu = Menu->head.h;
1447 Menu->fFlags |= MNF_SYSDESKMN;
1448 }
1449 else // Use spmenuSys too!
1450 Window->SystemMenu = (HMENU)0;
1451
1452 return TRUE;
1453 }
1454
1455 /* Unlink the window from siblings. children and parent are kept in place. */
1456 VOID FASTCALL
1457 IntUnlinkWindow(PWND Wnd)
1458 {
1459 if (Wnd->spwndNext)
1460 Wnd->spwndNext->spwndPrev = Wnd->spwndPrev;
1461
1462 if (Wnd->spwndPrev)
1463 Wnd->spwndPrev->spwndNext = Wnd->spwndNext;
1464
1465 if (Wnd->spwndParent && Wnd->spwndParent->spwndChild == Wnd)
1466 Wnd->spwndParent->spwndChild = Wnd->spwndNext;
1467
1468 Wnd->spwndPrev = Wnd->spwndNext = NULL;
1469 }
1470
1471 /* FUNCTIONS *****************************************************************/
1472
1473 /*
1474 * As best as I can figure, this function is used by EnumWindows,
1475 * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
1476 *
1477 * It's supposed to build a list of HWNDs to return to the caller.
1478 * We can figure out what kind of list by what parameters are
1479 * passed to us.
1480 */
1481 /*
1482 * @implemented
1483 */
1484 NTSTATUS
1485 APIENTRY
1486 NtUserBuildHwndList(
1487 HDESK hDesktop,
1488 HWND hwndParent,
1489 BOOLEAN bChildren,
1490 ULONG dwThreadId,
1491 ULONG lParam,
1492 HWND* pWnd,
1493 ULONG* pBufSize)
1494 {
1495 NTSTATUS Status;
1496 ULONG dwCount = 0;
1497
1498 if (pBufSize == 0)
1499 return ERROR_INVALID_PARAMETER;
1500
1501 if (hwndParent || !dwThreadId)
1502 {
1503 PDESKTOP Desktop;
1504 PWND Parent, Window;
1505
1506 if(!hwndParent)
1507 {
1508 if(hDesktop == NULL && !(Desktop = IntGetActiveDesktop()))
1509 {
1510 return ERROR_INVALID_HANDLE;
1511 }
1512
1513 if(hDesktop)
1514 {
1515 Status = IntValidateDesktopHandle(hDesktop,
1516 UserMode,
1517 0,
1518 &Desktop);
1519 if(!NT_SUCCESS(Status))
1520 {
1521 return ERROR_INVALID_HANDLE;
1522 }
1523 }
1524 hwndParent = Desktop->DesktopWindow;
1525 }
1526 else
1527 {
1528 hDesktop = 0;
1529 }
1530
1531 if((Parent = UserGetWindowObject(hwndParent)) &&
1532 (Window = Parent->spwndChild))
1533 {
1534 BOOL bGoDown = TRUE;
1535
1536 Status = STATUS_SUCCESS;
1537 while(TRUE)
1538 {
1539 if (bGoDown)
1540 {
1541 if(dwCount++ < *pBufSize && pWnd)
1542 {
1543 _SEH2_TRY
1544 {
1545 ProbeForWrite(pWnd, sizeof(HWND), 1);
1546 *pWnd = Window->head.h;
1547 pWnd++;
1548 }
1549 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1550 {
1551 Status = _SEH2_GetExceptionCode();
1552 }
1553 _SEH2_END
1554 if(!NT_SUCCESS(Status))
1555 {
1556 SetLastNtError(Status);
1557 break;
1558 }
1559 }
1560 if (Window->spwndChild && bChildren)
1561 {
1562 Window = Window->spwndChild;
1563 continue;
1564 }
1565 bGoDown = FALSE;
1566 }
1567 if (Window->spwndNext)
1568 {
1569 Window = Window->spwndNext;
1570 bGoDown = TRUE;
1571 continue;
1572 }
1573 Window = Window->spwndParent;
1574 if (Window == Parent)
1575 {
1576 break;
1577 }
1578 }
1579 }
1580
1581 if(hDesktop)
1582 {
1583 ObDereferenceObject(Desktop);
1584 }
1585 }
1586 else // Build EnumThreadWindows list!
1587 {
1588 PETHREAD Thread;
1589 PTHREADINFO W32Thread;
1590 PLIST_ENTRY Current;
1591 PWND Window;
1592
1593 Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
1594 if (!NT_SUCCESS(Status))
1595 {
1596 ERR("Thread Id is not valid!\n");
1597 return ERROR_INVALID_PARAMETER;
1598 }
1599 if (!(W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread))
1600 {
1601 ObDereferenceObject(Thread);
1602 ERR("Thread is not initialized!\n");
1603 return ERROR_INVALID_PARAMETER;
1604 }
1605
1606 Current = W32Thread->WindowListHead.Flink;
1607 while (Current != &(W32Thread->WindowListHead))
1608 {
1609 Window = CONTAINING_RECORD(Current, WND, ThreadListEntry);
1610 ASSERT(Window);
1611
1612 if (dwCount < *pBufSize && pWnd)
1613 {
1614 _SEH2_TRY
1615 {
1616 ProbeForWrite(pWnd, sizeof(HWND), 1);
1617 *pWnd = Window->head.h;
1618 pWnd++;
1619 }
1620 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1621 {
1622 Status = _SEH2_GetExceptionCode();
1623 }
1624 _SEH2_END
1625 if (!NT_SUCCESS(Status))
1626 {
1627 ERR("Failure to build window list!\n");
1628 SetLastNtError(Status);
1629 break;
1630 }
1631 }
1632 dwCount++;
1633 Current = Window->ThreadListEntry.Flink;
1634 }
1635
1636 ObDereferenceObject(Thread);
1637 }
1638
1639 *pBufSize = dwCount;
1640 return STATUS_SUCCESS;
1641 }
1642
1643 static void IntSendParentNotify( PWND pWindow, UINT msg )
1644 {
1645 if ( (pWindow->style & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
1646 !(pWindow->style & WS_EX_NOPARENTNOTIFY))
1647 {
1648 if (pWindow->spwndParent && pWindow->spwndParent != UserGetDesktopWindow())
1649 {
1650 USER_REFERENCE_ENTRY Ref;
1651 UserRefObjectCo(pWindow->spwndParent, &Ref);
1652 co_IntSendMessage( pWindow->spwndParent->head.h,
1653 WM_PARENTNOTIFY,
1654 MAKEWPARAM( msg, pWindow->IDMenu),
1655 (LPARAM)pWindow->head.h );
1656 UserDerefObjectCo(pWindow->spwndParent);
1657 }
1658 }
1659 }
1660
1661 void FASTCALL
1662 IntFixWindowCoordinates(CREATESTRUCTW* Cs, PWND ParentWindow, DWORD* dwShowMode)
1663 {
1664 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1665
1666 /* default positioning for overlapped windows */
1667 if(!(Cs->style & (WS_POPUP | WS_CHILD)))
1668 {
1669 PMONITOR pMonitor;
1670 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
1671
1672 pMonitor = UserGetPrimaryMonitor();
1673
1674 /* Check if we don't have a monitor attached yet */
1675 if(pMonitor == NULL)
1676 {
1677 Cs->x = Cs->y = 0;
1678 Cs->cx = 800;
1679 Cs->cy = 600;
1680 return;
1681 }
1682
1683 ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
1684
1685 if (IS_DEFAULT(Cs->x))
1686 {
1687 if (!IS_DEFAULT(Cs->y)) *dwShowMode = Cs->y;
1688
1689 if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
1690 {
1691 Cs->x = ProcessParams->StartingX;
1692 Cs->y = ProcessParams->StartingY;
1693 }
1694 else
1695 {
1696 Cs->x = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CXSIZE) + UserGetSystemMetrics(SM_CXFRAME));
1697 Cs->y = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CYSIZE) + UserGetSystemMetrics(SM_CYFRAME));
1698 if (Cs->x > ((pMonitor->rcWork.right - pMonitor->rcWork.left) / 4) ||
1699 Cs->y > ((pMonitor->rcWork.bottom - pMonitor->rcWork.top) / 4))
1700 {
1701 /* reset counter and position */
1702 Cs->x = 0;
1703 Cs->y = 0;
1704 pMonitor->cWndStack = 0;
1705 }
1706 pMonitor->cWndStack++;
1707 }
1708 }
1709
1710 if (IS_DEFAULT(Cs->cx))
1711 {
1712 if (ProcessParams->WindowFlags & STARTF_USEPOSITION)
1713 {
1714 Cs->cx = ProcessParams->CountX;
1715 Cs->cy = ProcessParams->CountY;
1716 }
1717 else
1718 {
1719 Cs->cx = (pMonitor->rcWork.right - pMonitor->rcWork.left) * 3 / 4;
1720 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1721 }
1722 }
1723 /* neither x nor cx are default. Check the y values .
1724 * In the trace we see Outlook and Outlook Express using
1725 * cy set to CW_USEDEFAULT when opening the address book.
1726 */
1727 else if (IS_DEFAULT(Cs->cy))
1728 {
1729 TRACE("Strange use of CW_USEDEFAULT in nHeight\n");
1730 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1731 }
1732 }
1733 else
1734 {
1735 /* if CW_USEDEFAULT is set for non-overlapped windows, both values are set to zero */
1736 if(IS_DEFAULT(Cs->x))
1737 {
1738 Cs->x = 0;
1739 Cs->y = 0;
1740 }
1741 if(IS_DEFAULT(Cs->cx))
1742 {
1743 Cs->cx = 0;
1744 Cs->cy = 0;
1745 }
1746 }
1747
1748 #undef IS_DEFAULT
1749 }
1750
1751 /* Allocates and initializes a window */
1752 PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
1753 PLARGE_STRING WindowName,
1754 PCLS Class,
1755 PWND ParentWindow,
1756 PWND OwnerWindow,
1757 PVOID acbiBuffer,
1758 PDESKTOP pdeskCreated)
1759 {
1760 PWND pWnd = NULL;
1761 HWND hWnd;
1762 PTHREADINFO pti = NULL;
1763 PMENU SystemMenu;
1764 BOOL MenuChanged;
1765 BOOL bUnicodeWindow;
1766
1767 pti = pdeskCreated ? gptiDesktopThread : GetW32ThreadInfo();
1768
1769 if (!(Cs->dwExStyle & WS_EX_LAYOUTRTL))
1770 { // Need both here for wine win.c test_CreateWindow.
1771 //if (Cs->hwndParent && ParentWindow)
1772 if (ParentWindow) // It breaks more tests..... WIP.
1773 {
1774 if ( (Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD &&
1775 ParentWindow->ExStyle & WS_EX_LAYOUTRTL &&
1776 !(ParentWindow->ExStyle & WS_EX_NOINHERITLAYOUT) )
1777 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1778 }
1779 else
1780 { /*
1781 * Note from MSDN <http://msdn.microsoft.com/en-us/library/aa913269.aspx>:
1782 *
1783 * Dialog boxes and message boxes do not inherit layout, so you must
1784 * set the layout explicitly.
1785 */
1786 if ( Class->fnid != FNID_DIALOG )
1787 {
1788 if (pti->ppi->dwLayout & LAYOUT_RTL)
1789 {
1790 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1791 }
1792 }
1793 }
1794 }
1795
1796 /* Automatically add WS_EX_WINDOWEDGE */
1797 if ((Cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1798 ((!(Cs->dwExStyle & WS_EX_STATICEDGE)) &&
1799 (Cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1800 Cs->dwExStyle |= WS_EX_WINDOWEDGE;
1801 else
1802 Cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1803
1804 /* Is it a unicode window? */
1805 bUnicodeWindow =!(Cs->dwExStyle & WS_EX_SETANSICREATOR);
1806 Cs->dwExStyle &= ~WS_EX_SETANSICREATOR;
1807
1808 /* Allocate the new window */
1809 pWnd = (PWND) UserCreateObject( gHandleTable,
1810 pdeskCreated ? pdeskCreated : pti->rpdesk,
1811 pti,
1812 (PHANDLE)&hWnd,
1813 TYPE_WINDOW,
1814 sizeof(WND) + Class->cbwndExtra);
1815
1816 if (!pWnd)
1817 {
1818 goto AllocError;
1819 }
1820
1821 TRACE("Created window object with handle %p\n", hWnd);
1822
1823 if (pdeskCreated && pdeskCreated->DesktopWindow == NULL )
1824 { /* HACK: Helper for win32csr/desktopbg.c */
1825 /* If there is no desktop window yet, we must be creating it */
1826 TRACE("CreateWindow setting desktop.\n");
1827 pdeskCreated->DesktopWindow = hWnd;
1828 pdeskCreated->pDeskInfo->spwnd = pWnd;
1829 }
1830
1831 /*
1832 * Fill out the structure describing it.
1833 */
1834 /* Remember, pWnd->head is setup in object.c ... */
1835 pWnd->spwndParent = ParentWindow;
1836 pWnd->spwndOwner = OwnerWindow;
1837 pWnd->fnid = 0;
1838 pWnd->spwndLastActive = pWnd;
1839 pWnd->state2 |= WNDS2_WIN40COMPAT; // FIXME!!!
1840 pWnd->pcls = Class;
1841 pWnd->hModule = Cs->hInstance;
1842 pWnd->style = Cs->style & ~WS_VISIBLE;
1843 pWnd->ExStyle = Cs->dwExStyle;
1844 pWnd->cbwndExtra = pWnd->pcls->cbwndExtra;
1845 pWnd->pActCtx = acbiBuffer;
1846 pWnd->InternalPos.MaxPos.x = pWnd->InternalPos.MaxPos.y = -1;
1847 pWnd->InternalPos.IconPos.x = pWnd->InternalPos.IconPos.y = -1;
1848
1849 if (pWnd->spwndParent != NULL && Cs->hwndParent != 0)
1850 {
1851 pWnd->HideFocus = pWnd->spwndParent->HideFocus;
1852 pWnd->HideAccel = pWnd->spwndParent->HideAccel;
1853 }
1854
1855 pWnd->head.pti->cWindows++;
1856
1857 if (Class->hIcon && !Class->hIconSm)
1858 {
1859 Class->hIconSmIntern = co_IntCopyImage( Class->hIcon, IMAGE_ICON,
1860 UserGetSystemMetrics( SM_CXSMICON ),
1861 UserGetSystemMetrics( SM_CYSMICON ), 0 );
1862 TRACE("IntCreateWindow hIconSmIntern %p\n",Class->hIconSmIntern);
1863 Class->CSF_flags |= CSF_CACHEDSMICON;
1864 }
1865
1866 if (pWnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
1867 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
1868
1869 /* BugBoy Comments: Comment below say that System classes are always created
1870 as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
1871 sets the window to ansi as verified by testing with IsUnicodeWindow API.
1872
1873 No where can I see in code or through testing does the window change back
1874 to ANSI after being created as UNICODE in ROS. I didnt do more testing to
1875 see what problems this would cause. */
1876
1877 // Set WndProc from Class.
1878 pWnd->lpfnWndProc = pWnd->pcls->lpfnWndProc;
1879
1880 // GetWindowProc, test for non server side default classes and set WndProc.
1881 if ( pWnd->pcls->fnid <= FNID_GHOST && pWnd->pcls->fnid >= FNID_BUTTON )
1882 {
1883 if (bUnicodeWindow)
1884 {
1885 if (GETPFNCLIENTA(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1886 pWnd->lpfnWndProc = GETPFNCLIENTW(pWnd->pcls->fnid);
1887 }
1888 else
1889 {
1890 if (GETPFNCLIENTW(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1891 pWnd->lpfnWndProc = GETPFNCLIENTA(pWnd->pcls->fnid);
1892 }
1893 }
1894
1895 // If not an Unicode caller, set Ansi creator bit.
1896 if (!bUnicodeWindow) pWnd->state |= WNDS_ANSICREATOR;
1897
1898 // Clone Class Ansi/Unicode proc type.
1899 if (pWnd->pcls->CSF_flags & CSF_ANSIPROC)
1900 {
1901 pWnd->state |= WNDS_ANSIWINDOWPROC;
1902 pWnd->Unicode = FALSE;
1903 }
1904 else
1905 { /*
1906 * It seems there can be both an Ansi creator and Unicode Class Window
1907 * WndProc, unless the following overriding conditions occur:
1908 */
1909 if ( !bUnicodeWindow &&
1910 ( Class->atomClassName == gpsi->atomSysClass[ICLS_BUTTON] ||
1911 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX] ||
1912 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOLBOX] ||
1913 Class->atomClassName == gpsi->atomSysClass[ICLS_DIALOG] ||
1914 Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT] ||
1915 Class->atomClassName == gpsi->atomSysClass[ICLS_IME] ||
1916 Class->atomClassName == gpsi->atomSysClass[ICLS_LISTBOX] ||
1917 Class->atomClassName == gpsi->atomSysClass[ICLS_MDICLIENT] ||
1918 Class->atomClassName == gpsi->atomSysClass[ICLS_STATIC] ) )
1919 { // Override Class and set the window Ansi WndProc.
1920 pWnd->state |= WNDS_ANSIWINDOWPROC;
1921 pWnd->Unicode = FALSE;
1922 }
1923 else
1924 { // Set the window Unicode WndProc.
1925 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
1926 pWnd->Unicode = TRUE;
1927 }
1928 }
1929
1930 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
1931 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
1932 Dont understand why it does this. */
1933 if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT])
1934 {
1935 PCALLPROCDATA CallProc;
1936 CallProc = CreateCallProc(NULL, pWnd->lpfnWndProc, pWnd->Unicode , pWnd->head.pti->ppi);
1937
1938 if (!CallProc)
1939 {
1940 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1941 ERR("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %p\n", hWnd);
1942 }
1943 else
1944 {
1945 UserAddCallProcToClass(pWnd->pcls, CallProc);
1946 }
1947 }
1948
1949 InitializeListHead(&pWnd->PropListHead);
1950
1951 if ( WindowName->Buffer != NULL && WindowName->Length > 0 )
1952 {
1953 pWnd->strName.Buffer = DesktopHeapAlloc(pWnd->head.rpdesk,
1954 WindowName->Length + sizeof(UNICODE_NULL));
1955 if (pWnd->strName.Buffer == NULL)
1956 {
1957 goto AllocError;
1958 }
1959
1960 RtlCopyMemory(pWnd->strName.Buffer, WindowName->Buffer, WindowName->Length);
1961 pWnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
1962 pWnd->strName.Length = WindowName->Length;
1963 pWnd->strName.MaximumLength = WindowName->Length + sizeof(UNICODE_NULL);
1964 }
1965
1966 /* Correct the window style. */
1967 if ((pWnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1968 {
1969 pWnd->style |= WS_CLIPSIBLINGS;
1970 if (!(pWnd->style & WS_POPUP))
1971 {
1972 pWnd->style |= WS_CAPTION;
1973 }
1974 }
1975
1976 /* WS_EX_WINDOWEDGE depends on some other styles */
1977 if (pWnd->ExStyle & WS_EX_DLGMODALFRAME)
1978 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1979 else if (pWnd->style & (WS_DLGFRAME | WS_THICKFRAME))
1980 {
1981 if (!((pWnd->ExStyle & WS_EX_STATICEDGE) &&
1982 (pWnd->style & (WS_CHILD | WS_POPUP))))
1983 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1984 }
1985 else
1986 pWnd->ExStyle &= ~WS_EX_WINDOWEDGE;
1987
1988 if (!(pWnd->style & (WS_CHILD | WS_POPUP)))
1989 pWnd->state |= WNDS_SENDSIZEMOVEMSGS;
1990
1991 /* Create system menu */
1992 if ((Cs->style & WS_SYSMENU)) // && (dwStyle & WS_CAPTION) == WS_CAPTION)
1993 {
1994 SystemMenu = IntGetSystemMenu(pWnd, TRUE, TRUE);
1995 if(SystemMenu)
1996 { // spmenuSys
1997 pWnd->SystemMenu = SystemMenu->head.h;
1998 IntReleaseMenuObject(SystemMenu);
1999 }
2000 }
2001
2002 /* Set the window menu */
2003 if ((Cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
2004 {
2005 if (Cs->hMenu)
2006 IntSetMenu(pWnd, Cs->hMenu, &MenuChanged);
2007 else if (pWnd->pcls->lpszMenuName) // Take it from the parent.
2008 {
2009 UNICODE_STRING MenuName;
2010 HMENU hMenu;
2011
2012 if (IS_INTRESOURCE(pWnd->pcls->lpszMenuName))
2013 {
2014 MenuName.Length = 0;
2015 MenuName.MaximumLength = 0;
2016 MenuName.Buffer = pWnd->pcls->lpszMenuName;
2017 }
2018 else
2019 {
2020 RtlInitUnicodeString( &MenuName, pWnd->pcls->lpszMenuName);
2021 }
2022 hMenu = co_IntCallLoadMenu( pWnd->pcls->hModule, &MenuName);
2023 if (hMenu) IntSetMenu(pWnd, hMenu, &MenuChanged);
2024 }
2025 }
2026 else // Not a child
2027 pWnd->IDMenu = (UINT) Cs->hMenu;
2028
2029
2030 if ( ParentWindow &&
2031 ParentWindow != ParentWindow->head.rpdesk->spwndMessage &&
2032 ParentWindow != ParentWindow->head.rpdesk->pDeskInfo->spwnd )
2033 {
2034 PWND Owner = IntGetNonChildAncestor(ParentWindow);
2035
2036 if (!IntValidateOwnerDepth(pWnd, Owner))
2037 {
2038 EngSetLastError(ERROR_INVALID_PARAMETER);
2039 goto Error;
2040 }
2041 if ( pWnd->spwndOwner &&
2042 pWnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
2043 {
2044 pWnd->ExStyle |= WS_EX_TOPMOST;
2045 }
2046 if ( pWnd->spwndOwner &&
2047 Class->atomClassName != gpsi->atomSysClass[ICLS_IME] &&
2048 pti != pWnd->spwndOwner->head.pti)
2049 {
2050 //ERR("CreateWindow Owner in.\n");
2051 UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE);
2052 }
2053 }
2054
2055 /* Insert the window into the thread's window list. */
2056 InsertTailList (&pti->WindowListHead, &pWnd->ThreadListEntry);
2057
2058 /* Handle "CS_CLASSDC", it is tested first. */
2059 if ( (pWnd->pcls->style & CS_CLASSDC) && !(pWnd->pcls->pdce) )
2060 { /* One DCE per class to have CLASS. */
2061 pWnd->pcls->pdce = DceAllocDCE( pWnd, DCE_CLASS_DC );
2062 }
2063 else if ( pWnd->pcls->style & CS_OWNDC)
2064 { /* Allocate a DCE for this window. */
2065 DceAllocDCE(pWnd, DCE_WINDOW_DC);
2066 }
2067
2068 return pWnd;
2069
2070 AllocError:
2071 ERR("IntCreateWindow Allocation Error.\n");
2072 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
2073 Error:
2074 if(pWnd)
2075 UserDereferenceObject(pWnd);
2076 return NULL;
2077 }
2078
2079 /*
2080 * @implemented
2081 */
2082 PWND FASTCALL
2083 co_UserCreateWindowEx(CREATESTRUCTW* Cs,
2084 PUNICODE_STRING ClassName,
2085 PLARGE_STRING WindowName,
2086 PVOID acbiBuffer)
2087 {
2088 ULONG style;
2089 PWND Window = NULL, ParentWindow = NULL, OwnerWindow;
2090 HWND hWnd, hWndParent, hWndOwner, hwndInsertAfter;
2091 PWINSTATION_OBJECT WinSta;
2092 PCLS Class = NULL;
2093 SIZE Size;
2094 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
2095 CBT_CREATEWNDW * pCbtCreate;
2096 LRESULT Result;
2097 USER_REFERENCE_ENTRY ParentRef, Ref;
2098 PTHREADINFO pti;
2099 DWORD dwShowMode = SW_SHOW;
2100 CREATESTRUCTW *pCsw = NULL;
2101 PVOID pszClass = NULL, pszName = NULL;
2102 PWND ret = NULL;
2103
2104 /* Get the current window station and reference it */
2105 pti = GetW32ThreadInfo();
2106 if (pti == NULL || pti->rpdesk == NULL)
2107 {
2108 ERR("Thread is not attached to a desktop! Cannot create window!\n");
2109 return NULL; // There is nothing to cleanup.
2110 }
2111 WinSta = pti->rpdesk->rpwinstaParent;
2112 ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
2113
2114 pCsw = NULL;
2115 pCbtCreate = NULL;
2116
2117 /* Get the class and reference it */
2118 Class = IntGetAndReferenceClass(ClassName, Cs->hInstance, FALSE);
2119 if(!Class)
2120 {
2121 ERR("Failed to find class %wZ\n", ClassName);
2122 goto cleanup;
2123 }
2124
2125 /* Now find the parent and the owner window */
2126 hWndParent = pti->rpdesk->pDeskInfo->spwnd->head.h;
2127 hWndOwner = NULL;
2128
2129 if (Cs->hwndParent == HWND_MESSAGE)
2130 {
2131 Cs->hwndParent = hWndParent = pti->rpdesk->spwndMessage->head.h;
2132 }
2133 else if (Cs->hwndParent)
2134 {
2135 if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
2136 hWndOwner = Cs->hwndParent;
2137 else
2138 hWndParent = Cs->hwndParent;
2139 }
2140 else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2141 {
2142 ERR("Cannot create a child window without a parrent!\n");
2143 EngSetLastError(ERROR_TLW_WITH_WSCHILD);
2144 goto cleanup; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
2145 }
2146
2147 ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
2148 OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
2149
2150 /* FIXME: Is this correct? */
2151 if(OwnerWindow)
2152 OwnerWindow = UserGetAncestor(OwnerWindow, GA_ROOT);
2153
2154 /* Fix the position and the size of the window */
2155 if (ParentWindow)
2156 {
2157 UserRefObjectCo(ParentWindow, &ParentRef);
2158 IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode);
2159 }
2160
2161 /* Allocate and initialize the new window */
2162 Window = IntCreateWindow(Cs,
2163 WindowName,
2164 Class,
2165 ParentWindow,
2166 OwnerWindow,
2167 acbiBuffer,
2168 NULL);
2169 if(!Window)
2170 {
2171 ERR("IntCreateWindow failed!\n");
2172 goto cleanup;
2173 }
2174
2175 hWnd = UserHMGetHandle(Window);
2176 hwndInsertAfter = HWND_TOP;
2177
2178 UserRefObjectCo(Window, &Ref);
2179 UserDereferenceObject(Window);
2180 ObDereferenceObject(WinSta);
2181
2182 //// Check for a hook to eliminate overhead. ////
2183 if ( ISITHOOKED(WH_CBT) || (pti->rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)) )
2184 {
2185 // Allocate the calling structures Justin Case this goes Global.
2186 pCsw = ExAllocatePoolWithTag(NonPagedPool, sizeof(CREATESTRUCTW), TAG_HOOK);
2187 pCbtCreate = ExAllocatePoolWithTag(NonPagedPool, sizeof(CBT_CREATEWNDW), TAG_HOOK);
2188 if (!pCsw || !pCbtCreate)
2189 {
2190 ERR("UserHeapAlloc() failed!\n");
2191 goto cleanup;
2192 }
2193
2194 /* Fill the new CREATESTRUCTW */
2195 RtlCopyMemory(pCsw, Cs, sizeof(CREATESTRUCTW));
2196 pCsw->style = Window->style; /* HCBT_CREATEWND needs the real window style */
2197
2198 // Based on the assumption this is from "unicode source" user32, ReactOS, answer is yes.
2199 if (!IS_ATOM(ClassName->Buffer))
2200 {
2201 if (Window->state & WNDS_ANSICREATOR)
2202 {
2203 ANSI_STRING AnsiString;
2204 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(ClassName)+sizeof(CHAR);
2205 pszClass = UserHeapAlloc(AnsiString.MaximumLength);
2206 if (!pszClass)
2207 {
2208 ERR("UserHeapAlloc() failed!\n");
2209 goto cleanup;
2210 }
2211 RtlZeroMemory(pszClass, AnsiString.MaximumLength);
2212 AnsiString.Buffer = (PCHAR)pszClass;
2213 RtlUnicodeStringToAnsiString(&AnsiString, ClassName, FALSE);
2214 }
2215 else
2216 {
2217 UNICODE_STRING UnicodeString;
2218 UnicodeString.MaximumLength = ClassName->Length + sizeof(UNICODE_NULL);
2219 pszClass = UserHeapAlloc(UnicodeString.MaximumLength);
2220 if (!pszClass)
2221 {
2222 ERR("UserHeapAlloc() failed!\n");
2223 goto cleanup;
2224 }
2225 RtlZeroMemory(pszClass, UnicodeString.MaximumLength);
2226 UnicodeString.Buffer = (PWSTR)pszClass;
2227 RtlCopyUnicodeString(&UnicodeString, ClassName);
2228 }
2229 pCsw->lpszClass = UserHeapAddressToUser(pszClass);
2230 }
2231 if (WindowName->Length)
2232 {
2233 UNICODE_STRING Name;
2234 Name.Buffer = WindowName->Buffer;
2235 Name.Length = (USHORT)min(WindowName->Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2236 Name.MaximumLength = (USHORT)min(WindowName->MaximumLength, MAXUSHORT);
2237
2238 if (Window->state & WNDS_ANSICREATOR)
2239 {
2240 ANSI_STRING AnsiString;
2241 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(&Name) + sizeof(CHAR);
2242 pszName = UserHeapAlloc(AnsiString.MaximumLength);
2243 if (!pszName)
2244 {
2245 ERR("UserHeapAlloc() failed!\n");
2246 goto cleanup;
2247 }
2248 RtlZeroMemory(pszName, AnsiString.MaximumLength);
2249 AnsiString.Buffer = (PCHAR)pszName;
2250 RtlUnicodeStringToAnsiString(&AnsiString, &Name, FALSE);
2251 }
2252 else
2253 {
2254 UNICODE_STRING UnicodeString;
2255 UnicodeString.MaximumLength = Name.Length + sizeof(UNICODE_NULL);
2256 pszName = UserHeapAlloc(UnicodeString.MaximumLength);
2257 if (!pszName)
2258 {
2259 ERR("UserHeapAlloc() failed!\n");
2260 goto cleanup;
2261 }
2262 RtlZeroMemory(pszName, UnicodeString.MaximumLength);
2263 UnicodeString.Buffer = (PWSTR)pszName;
2264 RtlCopyUnicodeString(&UnicodeString, &Name);
2265 }
2266 pCsw->lpszName = UserHeapAddressToUser(pszName);
2267 }
2268
2269 pCbtCreate->lpcs = pCsw;
2270 pCbtCreate->hwndInsertAfter = hwndInsertAfter;
2271
2272 //// Call the WH_CBT hook ////
2273 Result = co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) pCbtCreate);
2274 if (Result != 0)
2275 {
2276 ERR("WH_CBT HCBT_CREATEWND hook failed! 0x%x\n", Result);
2277 goto cleanup;
2278 }
2279 // Write back changes.
2280 Cs->cx = pCsw->cx;
2281 Cs->cy = pCsw->cy;
2282 Cs->x = pCsw->x;
2283 Cs->y = pCsw->y;
2284 hwndInsertAfter = pCbtCreate->hwndInsertAfter;
2285 }
2286
2287 /* NCCREATE and WM_NCCALCSIZE need the original values */
2288 Cs->lpszName = (LPCWSTR) WindowName;
2289 Cs->lpszClass = (LPCWSTR) ClassName;
2290
2291 if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2292 {
2293 if (ParentWindow != co_GetDesktopWindow(Window))
2294 {
2295 Cs->x += ParentWindow->rcClient.left;
2296 Cs->y += ParentWindow->rcClient.top;
2297 }
2298 }
2299
2300 /* Send the WM_GETMINMAXINFO message */
2301 Size.cx = Cs->cx;
2302 Size.cy = Cs->cy;
2303
2304 if ((Cs->style & WS_THICKFRAME) || !(Cs->style & (WS_POPUP | WS_CHILD)))
2305 {
2306 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
2307 if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
2308 if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
2309 if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
2310 if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
2311 }
2312
2313 Window->rcWindow.left = Cs->x;
2314 Window->rcWindow.top = Cs->y;
2315 Window->rcWindow.right = Cs->x + Size.cx;
2316 Window->rcWindow.bottom = Cs->y + Size.cy;
2317 /*
2318 if (0 != (Window->style & WS_CHILD) && ParentWindow)
2319 {
2320 // ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
2321 RECTL_vOffsetRect(&Window->rcWindow,
2322 ParentWindow->rcClient.left,
2323 ParentWindow->rcClient.top);
2324 }
2325 */
2326 /* correct child window coordinates if mirroring on parent is enabled */
2327 if (ParentWindow != NULL)
2328 {
2329 if ( ((Cs->style & WS_CHILD) == WS_CHILD) &&
2330 ((ParentWindow->ExStyle & WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL))
2331 {
2332 Window->rcWindow.right = ParentWindow->rcClient.right - (Window->rcWindow.left - ParentWindow->rcClient.left);
2333 Window->rcWindow.left = Window->rcWindow.right - Size.cx;
2334 }
2335 }
2336
2337 Window->rcClient = Window->rcWindow;
2338
2339 /* Link the window */
2340 if (NULL != ParentWindow)
2341 {
2342 /* Link the window into the siblings list */
2343 if ((Cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2344 IntLinkHwnd(Window, HWND_BOTTOM);
2345 else
2346 IntLinkHwnd(Window, hwndInsertAfter);
2347 }
2348
2349 if (!(Window->state2 & WNDS2_WIN31COMPAT))
2350 {
2351 if (Class->style & CS_PARENTDC && !(ParentWindow->style & WS_CLIPCHILDREN))
2352 Window->style &= ~(WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
2353 }
2354
2355 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2356 {
2357 if ( !IntIsTopLevelWindow(Window) )
2358 {
2359 if (pti != Window->spwndParent->head.pti)
2360 {
2361 //ERR("CreateWindow Parent in.\n");
2362 UserAttachThreadInput(pti, Window->spwndParent->head.pti, TRUE);
2363 }
2364 }
2365 }
2366
2367 /* Send the NCCREATE message */
2368 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_NCCREATE, 0, (LPARAM) Cs);
2369 if (!Result)
2370 {
2371 ERR("co_UserCreateWindowEx(): NCCREATE message failed\n");
2372 goto cleanup;
2373 }
2374
2375 /* Send the WM_NCCALCSIZE message */
2376 {
2377 // RECT rc;
2378 MaxPos.x = Window->rcWindow.left;
2379 MaxPos.y = Window->rcWindow.top;
2380
2381 Result = co_WinPosGetNonClientSize(Window, &Window->rcWindow, &Window->rcClient);
2382 //rc = Window->rcWindow;
2383 //Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM)&rc);
2384 //Window->rcClient = rc;
2385
2386 RECTL_vOffsetRect(&Window->rcWindow, MaxPos.x - Window->rcWindow.left,
2387 MaxPos.y - Window->rcWindow.top);
2388 }
2389
2390 /* Send the WM_CREATE message. */
2391 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_CREATE, 0, (LPARAM) Cs);
2392 if (Result == (LRESULT)-1)
2393 {
2394 ERR("co_UserCreateWindowEx(): WM_CREATE message failed\n");
2395 goto cleanup;
2396 }
2397
2398 /* Send the EVENT_OBJECT_CREATE event */
2399 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2400
2401 /* By setting the flag below it can be examined to determine if the window
2402 was created successfully and a valid pwnd was passed back to caller since
2403 from here the function has to succeed. */
2404 Window->state2 |= WNDS2_WMCREATEMSGPROCESSED;
2405
2406 /* Send the WM_SIZE and WM_MOVE messages. */
2407 if (!(Window->state & WNDS_SENDSIZEMOVEMSGS))
2408 {
2409 co_WinPosSendSizeMove(Window);
2410 }
2411
2412 /* Show or maybe minimize or maximize the window. */
2413
2414 style = IntSetStyle( Window, 0, WS_MAXIMIZE | WS_MINIMIZE );
2415 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2416 {
2417 RECTL NewPos;
2418 UINT SwFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
2419
2420 SwFlag = co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2421 SwFlag |= SWP_NOZORDER|SWP_FRAMECHANGED; /* Frame always gets changed */
2422 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || UserGetActiveWindow()) SwFlag |= SWP_NOACTIVATE;
2423 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2424 NewPos.right, NewPos.bottom, SwFlag);
2425 }
2426
2427 /* Send the WM_PARENTNOTIFY message */
2428 IntSendParentNotify(Window, WM_CREATE);
2429
2430 /* Notify the shell that a new window was created */
2431 if ((!hWndParent) && (!hWndOwner))
2432 {
2433 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0);
2434 }
2435
2436 /* Initialize and show the window's scrollbars */
2437 if (Window->style & WS_VSCROLL)
2438 {
2439 co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE);
2440 }
2441 if (Window->style & WS_HSCROLL)
2442 {
2443 co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE);
2444 }
2445
2446 /* Show the new window */
2447 if (Cs->style & WS_VISIBLE)
2448 {
2449 if (Window->style & WS_MAXIMIZE)
2450 dwShowMode = SW_SHOW;
2451 else if (Window->style & WS_MINIMIZE)
2452 dwShowMode = SW_SHOWMINIMIZED;
2453
2454 co_WinPosShowWindow(Window, dwShowMode);
2455
2456 if (Window->ExStyle & WS_EX_MDICHILD)
2457 {
2458 ASSERT(ParentWindow);
2459 if(!ParentWindow)
2460 goto cleanup;
2461 co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0);
2462 /* ShowWindow won't activate child windows */
2463 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2464 }
2465 }
2466
2467 TRACE("co_UserCreateWindowEx(): Created window %p\n", hWnd);
2468 ret = Window;
2469
2470 cleanup:
2471 if (!ret)
2472 {
2473 TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2474 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2475 if (Window)
2476 co_UserDestroyWindow(Window);
2477 else if (Class)
2478 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2479 }
2480
2481 if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
2482 if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
2483 if (pszName) UserHeapFree(pszName);
2484 if (pszClass) UserHeapFree(pszClass);
2485
2486 if (Window)
2487 {
2488 UserDerefObjectCo(Window);
2489 }
2490 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2491
2492 return ret;
2493 }
2494
2495 NTSTATUS
2496 NTAPI
2497 ProbeAndCaptureLargeString(
2498 OUT PLARGE_STRING plstrSafe,
2499 IN PLARGE_STRING plstrUnsafe)
2500 {
2501 LARGE_STRING lstrTemp;
2502 PVOID pvBuffer = NULL;
2503
2504 _SEH2_TRY
2505 {
2506 /* Probe and copy the string */
2507 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2508 lstrTemp = *plstrUnsafe;
2509 }
2510 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2511 {
2512 /* Fail */
2513 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2514 }
2515 _SEH2_END
2516
2517 if (lstrTemp.Length != 0)
2518 {
2519 /* Allocate a buffer from paged pool */
2520 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2521 if (!pvBuffer)
2522 {
2523 return STATUS_NO_MEMORY;
2524 }
2525
2526 _SEH2_TRY
2527 {
2528 /* Probe and copy the buffer */
2529 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2530 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2531 }
2532 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2533 {
2534 /* Cleanup and fail */
2535 ExFreePoolWithTag(pvBuffer, TAG_STRING);
2536 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2537 }
2538 _SEH2_END
2539 }
2540
2541 /* Set the output string */
2542 plstrSafe->Buffer = pvBuffer;
2543 plstrSafe->Length = lstrTemp.Length;
2544 plstrSafe->MaximumLength = lstrTemp.Length;
2545
2546 return STATUS_SUCCESS;
2547 }
2548
2549 /**
2550 * \todo Allow passing plstrClassName as ANSI.
2551 */
2552 HWND
2553 NTAPI
2554 NtUserCreateWindowEx(
2555 DWORD dwExStyle,
2556 PLARGE_STRING plstrClassName,
2557 PLARGE_STRING plstrClsVersion,
2558 PLARGE_STRING plstrWindowName,
2559 DWORD dwStyle,
2560 int x,
2561 int y,
2562 int nWidth,
2563 int nHeight,
2564 HWND hWndParent,
2565 HMENU hMenu,
2566 HINSTANCE hInstance,
2567 LPVOID lpParam,
2568 DWORD dwFlags,
2569 PVOID acbiBuffer)
2570 {
2571 NTSTATUS Status;
2572 LARGE_STRING lstrWindowName;
2573 LARGE_STRING lstrClassName;
2574 UNICODE_STRING ustrClassName;
2575 CREATESTRUCTW Cs;
2576 HWND hwnd = NULL;
2577 PWND pwnd;
2578
2579 lstrWindowName.Buffer = NULL;
2580 lstrClassName.Buffer = NULL;
2581
2582 ASSERT(plstrWindowName);
2583
2584 if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2585 {
2586 /* check hMenu is valid handle */
2587 if (hMenu && !ValidateHandle(hMenu, TYPE_MENU))
2588 {
2589 /* error is set in ValidateHandle */
2590 return NULL;
2591 }
2592 }
2593
2594 /* Copy the window name to kernel mode */
2595 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2596 if (!NT_SUCCESS(Status))
2597 {
2598 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2599 SetLastNtError(Status);
2600 return NULL;
2601 }
2602
2603 plstrWindowName = &lstrWindowName;
2604
2605 /* Check if the class is an atom */
2606 if (IS_ATOM(plstrClassName))
2607 {
2608 /* It is, pass the atom in the UNICODE_STRING */
2609 ustrClassName.Buffer = (PVOID)plstrClassName;
2610 ustrClassName.Length = 0;
2611 ustrClassName.MaximumLength = 0;
2612 }
2613 else
2614 {
2615 /* It's not, capture the class name */
2616 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2617 if (!NT_SUCCESS(Status))
2618 {
2619 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2620 /* Set last error, cleanup and return */
2621 SetLastNtError(Status);
2622 goto cleanup;
2623 }
2624
2625 /* We pass it on as a UNICODE_STRING */
2626 ustrClassName.Buffer = lstrClassName.Buffer;
2627 ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2628 ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
2629 }
2630
2631 /* Fill the CREATESTRUCTW */
2632 /* we will keep here the original parameters */
2633 Cs.style = dwStyle;
2634 Cs.lpCreateParams = lpParam;
2635 Cs.hInstance = hInstance;
2636 Cs.hMenu = hMenu;
2637 Cs.hwndParent = hWndParent;
2638 Cs.cx = nWidth;
2639 Cs.cy = nHeight;
2640 Cs.x = x;
2641 Cs.y = y;
2642 Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
2643 if (IS_ATOM(plstrClassName))
2644 Cs.lpszClass = (LPCWSTR) plstrClassName;
2645 else
2646 Cs.lpszClass = (LPCWSTR) plstrClassName->Buffer;
2647 Cs.dwExStyle = dwExStyle;
2648
2649 UserEnterExclusive();
2650
2651 /* Call the internal function */
2652 pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName, acbiBuffer);
2653
2654 if(!pwnd)
2655 {
2656 ERR("co_UserCreateWindowEx failed!\n");
2657 }
2658 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2659
2660 UserLeave();
2661
2662 cleanup:
2663 if (lstrWindowName.Buffer)
2664 {
2665 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2666 }
2667 if (lstrClassName.Buffer)
2668 {
2669 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2670 }
2671
2672 return hwnd;
2673 }
2674
2675
2676 BOOLEAN FASTCALL co_UserDestroyWindow(PWND Window)
2677 {
2678 HWND hWnd;
2679 PWND pwndTemp;
2680 PTHREADINFO ti;
2681 MSG msg;
2682
2683 ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
2684
2685 hWnd = Window->head.h;
2686 ti = PsGetCurrentThreadWin32Thread();
2687
2688 TRACE("co_UserDestroyWindow \n");
2689
2690 /* Check for owner thread */
2691 if ( Window->head.pti != PsGetCurrentThreadWin32Thread())
2692 {
2693 /* Check if we are destroying the desktop window */
2694 if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
2695 {
2696 EngSetLastError(ERROR_ACCESS_DENIED);
2697 return FALSE;
2698 }
2699 }
2700
2701 /* If window was created successfully and it is hooked */
2702 if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
2703 {
2704 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0))
2705 {
2706 ERR("Destroy Window WH_CBT Call Hook return!\n");
2707 return FALSE;
2708 }
2709 }
2710
2711 if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
2712 {
2713 if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2714 {
2715 if (Window->spwndOwner)
2716 {
2717 //ERR("DestroyWindow Owner out.\n");
2718 UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2719 }
2720 }
2721 }
2722
2723 /* Inform the parent */
2724 if (Window->style & WS_CHILD)
2725 {
2726 IntSendParentNotify(Window, WM_DESTROY);
2727 }
2728
2729 /* Look whether the focus is within the tree of windows we will
2730 * be destroying.
2731 */
2732 if (!co_WinPosShowWindow(Window, SW_HIDE))
2733 { // Rule #1.
2734 if (ti->MessageQueue->spwndActive == Window && ti->MessageQueue == IntGetFocusMessageQueue())
2735 {
2736 co_WinPosActivateOtherWindow(Window);
2737 }
2738 }
2739
2740 // Adjust last active.
2741 if ((pwndTemp = Window->spwndOwner))
2742 {
2743 while (pwndTemp->spwndOwner)
2744 pwndTemp = pwndTemp->spwndOwner;
2745
2746 if (pwndTemp->spwndLastActive == Window)
2747 pwndTemp->spwndLastActive = Window->spwndOwner;
2748 }
2749
2750 if (Window->spwndParent && IntIsWindow(Window->head.h))
2751 {
2752 if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
2753 {
2754 if (!IntIsTopLevelWindow(Window))
2755 {
2756 //ERR("DestroyWindow Parent out.\n");
2757 UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2758 }
2759 }
2760 }
2761
2762 if (Window->head.pti->MessageQueue->spwndActive == Window)
2763 Window->head.pti->MessageQueue->spwndActive = NULL;
2764 if (Window->head.pti->MessageQueue->spwndFocus == Window)
2765 Window->head.pti->MessageQueue->spwndFocus = NULL;
2766 if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
2767 Window->head.pti->MessageQueue->spwndActivePrev = NULL;
2768 if (Window->head.pti->MessageQueue->spwndCapture == Window)
2769 Window->head.pti->MessageQueue->spwndCapture = NULL;
2770
2771 /*
2772 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2773 */
2774
2775 if ((ti != NULL) && (ti->pDeskInfo != NULL))
2776 {
2777 if (ti->pDeskInfo->hShellWindow == hWnd)
2778 {
2779 ERR("Destroying the ShellWindow!\n");
2780 ti->pDeskInfo->hShellWindow = NULL;
2781 }
2782 }
2783
2784 IntEngWindowChanged(Window, WOC_DELETE);
2785
2786 if (!IntIsWindow(Window->head.h))
2787 {
2788 return TRUE;
2789 }
2790
2791 /* Recursively destroy owned windows */
2792
2793 if (! (Window->style & WS_CHILD))
2794 {
2795 for (;;)
2796 {
2797 BOOL GotOne = FALSE;
2798 HWND *Children;
2799 HWND *ChildHandle;
2800 PWND Child, Desktop;
2801
2802 Desktop = IntIsDesktopWindow(Window) ? Window :
2803 UserGetWindowObject(IntGetDesktopWindow());
2804 Children = IntWinListChildren(Desktop);
2805
2806 if (Children)
2807 {
2808 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2809 {
2810 Child = UserGetWindowObject(*ChildHandle);
2811 if (Child == NULL)
2812 continue;
2813 if (Child->spwndOwner != Window)
2814 {
2815 continue;
2816 }
2817
2818 if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
2819 {
2820 USER_REFERENCE_ENTRY ChildRef;
2821 UserRefObjectCo(Child, &ChildRef); // Temp HACK?
2822 co_UserDestroyWindow(Child);
2823 UserDerefObjectCo(Child); // Temp HACK?
2824
2825 GotOne = TRUE;
2826 continue;
2827 }
2828
2829 if (Child->spwndOwner != NULL)
2830 {
2831 Child->spwndOwner = NULL;
2832 }
2833
2834 }
2835 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
2836 }
2837 if (! GotOne)
2838 {
2839 break;
2840 }
2841 }
2842 }
2843
2844 /* Generate mouse move message for the next window */
2845 msg.message = WM_MOUSEMOVE;
2846 msg.wParam = UserGetMouseButtonsState();
2847 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2848 msg.pt = gpsi->ptCursor;
2849 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2850
2851 if (!IntIsWindow(Window->head.h))
2852 {
2853 return TRUE;
2854 }
2855
2856 /* Destroy the window storage */
2857 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2858
2859 return TRUE;
2860 }
2861
2862
2863 /*
2864 * @implemented
2865 */
2866 BOOLEAN APIENTRY
2867 NtUserDestroyWindow(HWND Wnd)
2868 {
2869 PWND Window;
2870 DECLARE_RETURN(BOOLEAN);
2871 BOOLEAN ret;
2872 USER_REFERENCE_ENTRY Ref;
2873
2874 TRACE("Enter NtUserDestroyWindow\n");
2875 UserEnterExclusive();
2876
2877 if (!(Window = UserGetWindowObject(Wnd)))
2878 {
2879 RETURN(FALSE);
2880 }
2881
2882 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
2883 ret = co_UserDestroyWindow(Window);
2884 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
2885
2886 RETURN(ret);
2887
2888 CLEANUP:
2889 TRACE("Leave NtUserDestroyWindow, ret=%u\n", _ret_);
2890 UserLeave();
2891 END_CLEANUP;
2892 }
2893
2894
2895 static HWND FASTCALL
2896 IntFindWindow(PWND Parent,
2897 PWND ChildAfter,
2898 RTL_ATOM ClassAtom,
2899 PUNICODE_STRING WindowName)
2900 {
2901 BOOL CheckWindowName;
2902 HWND *List, *phWnd;
2903 HWND Ret = NULL;
2904 UNICODE_STRING CurrentWindowName;
2905
2906 ASSERT(Parent);
2907
2908 CheckWindowName = WindowName->Buffer != 0;
2909
2910 if((List = IntWinListChildren(Parent)))
2911 {
2912 phWnd = List;
2913 if(ChildAfter)
2914 {
2915 /* skip handles before and including ChildAfter */
2916 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2917 ;
2918 }
2919
2920 /* search children */
2921 while(*phWnd)
2922 {
2923 PWND Child;
2924 if(!(Child = UserGetWindowObject(*(phWnd++))))
2925 {
2926 continue;
2927 }
2928
2929 /* Do not send WM_GETTEXT messages in the kernel mode version!
2930 The user mode version however calls GetWindowText() which will
2931 send WM_GETTEXT messages to windows belonging to its processes */
2932 if (!ClassAtom || Child->pcls->atomClassName == ClassAtom)
2933 {
2934 // FIXME: LARGE_STRING truncated
2935 CurrentWindowName.Buffer = Child->strName.Buffer;
2936 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
2937 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
2938 if(!CheckWindowName ||
2939 (Child->strName.Length < 0xFFFF &&
2940 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
2941 {
2942 Ret = Child->head.h;
2943 break;
2944 }
2945 }
2946 }
2947 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2948 }
2949
2950 return Ret;
2951 }
2952
2953 /*
2954 * FUNCTION:
2955 * Searches a window's children for a window with the specified
2956 * class and name
2957 * ARGUMENTS:
2958 * hwndParent = The window whose childs are to be searched.
2959 * NULL = desktop
2960 * HWND_MESSAGE = message-only windows
2961 *
2962 * hwndChildAfter = Search starts after this child window.
2963 * NULL = start from beginning
2964 *
2965 * ucClassName = Class name to search for
2966 * Reguired parameter.
2967 *
2968 * ucWindowName = Window name
2969 * ->Buffer == NULL = don't care
2970 *
2971 * RETURNS:
2972 * The HWND of the window if it was found, otherwise NULL
2973 */
2974 /*
2975 * @implemented
2976 */
2977 HWND APIENTRY
2978 NtUserFindWindowEx(HWND hwndParent,
2979 HWND hwndChildAfter,
2980 PUNICODE_STRING ucClassName,
2981 PUNICODE_STRING ucWindowName,
2982 DWORD dwUnknown)
2983 {
2984 PWND Parent, ChildAfter;
2985 UNICODE_STRING ClassName = {0}, WindowName = {0};
2986 HWND Desktop, Ret = NULL;
2987 BOOL DoMessageWnd = FALSE;
2988 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2989 DECLARE_RETURN(HWND);
2990
2991 TRACE("Enter NtUserFindWindowEx\n");
2992 UserEnterShared();
2993
2994 if (ucClassName != NULL || ucWindowName != NULL)
2995 {
2996 _SEH2_TRY
2997 {
2998 if (ucClassName != NULL)
2999 {
3000 ClassName = ProbeForReadUnicodeString(ucClassName);
3001 if (ClassName.Length != 0)
3002 {
3003 ProbeForRead(ClassName.Buffer,
3004 ClassName.Length,
3005 sizeof(WCHAR));
3006 }
3007 else if (!IS_ATOM(ClassName.Buffer))
3008 {
3009 EngSetLastError(ERROR_INVALID_PARAMETER);
3010 _SEH2_LEAVE;
3011 }
3012
3013 if (!IntGetAtomFromStringOrAtom(&ClassName,
3014 &ClassAtom))
3015 {
3016 _SEH2_LEAVE;
3017 }
3018 }
3019
3020 if (ucWindowName != NULL)
3021 {
3022 WindowName = ProbeForReadUnicodeString(ucWindowName);
3023 if (WindowName.Length != 0)
3024 {
3025 ProbeForRead(WindowName.Buffer,
3026 WindowName.Length,
3027 sizeof(WCHAR));
3028 }
3029 }
3030 }
3031 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3032 {
3033 SetLastNtError(_SEH2_GetExceptionCode());
3034 _SEH2_YIELD(RETURN(NULL));
3035 }
3036 _SEH2_END;
3037
3038 if (ucClassName != NULL)
3039 {
3040 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
3041 !IS_ATOM(ClassName.Buffer))
3042 {
3043 EngSetLastError(ERROR_INVALID_PARAMETER);
3044 RETURN(NULL);
3045 }
3046 else if (ClassAtom == (RTL_ATOM)0)
3047 {
3048 /* LastError code was set by IntGetAtomFromStringOrAtom */
3049 RETURN(NULL);
3050 }
3051 }
3052 }
3053
3054 Desktop = IntGetCurrentThreadDesktopWindow();
3055
3056 if(hwndParent == NULL)
3057 {
3058 hwndParent = Desktop;
3059 DoMessageWnd = TRUE;
3060 }
3061 else if(hwndParent == HWND_MESSAGE)
3062 {
3063 hwndParent = IntGetMessageWindow();
3064 }
3065
3066 if(!(Parent = UserGetWindowObject(hwndParent)))
3067 {
3068 RETURN( NULL);
3069 }
3070
3071 ChildAfter = NULL;
3072 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
3073 {
3074 RETURN( NULL);
3075 }
3076
3077 _SEH2_TRY
3078 {
3079 if(Parent->head.h == Desktop)
3080 {
3081 HWND *List, *phWnd;
3082 PWND TopLevelWindow;
3083 BOOLEAN CheckWindowName;
3084 BOOLEAN WindowMatches;
3085 BOOLEAN ClassMatches;
3086
3087 /* windows searches through all top-level windows if the parent is the desktop
3088 window */
3089
3090 if((List = IntWinListChildren(Parent)))
3091 {
3092 phWnd = List;
3093
3094 if(ChildAfter)
3095 {
3096 /* skip handles before and including ChildAfter */
3097 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
3098 ;
3099 }
3100
3101 CheckWindowName = WindowName.Buffer != 0;
3102
3103 /* search children */
3104 while(*phWnd)
3105 {
3106 UNICODE_STRING ustr;
3107
3108 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
3109 {
3110 continue;
3111 }
3112
3113 /* Do not send WM_GETTEXT messages in the kernel mode version!
3114 The user mode version however calls GetWindowText() which will
3115 send WM_GETTEXT messages to windows belonging to its processes */
3116 ustr.Buffer = TopLevelWindow->strName.Buffer;
3117 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
3118 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
3119 WindowMatches = !CheckWindowName ||
3120 (TopLevelWindow->strName.Length < 0xFFFF &&
3121 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
3122 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
3123 ClassAtom == TopLevelWindow->pcls->atomClassName;
3124
3125 if (WindowMatches && ClassMatches)
3126 {
3127 Ret = TopLevelWindow->head.h;
3128 break;
3129 }
3130
3131 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
3132 {
3133 /* window returns the handle of the top-level window, in case it found
3134 the child window */
3135 Ret = TopLevelWindow->head.h;
3136 break;
3137 }
3138
3139 }
3140 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
3141 }
3142 }
3143 else
3144 {
3145 ERR("FindWindowEx: Not Desktop Parent!\n");
3146 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
3147 }
3148
3149 if (Ret == NULL && DoMessageWnd)
3150 {
3151 PWND MsgWindows;
3152
3153 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3154 {
3155 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3156 }
3157 }
3158 }
3159 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3160 {
3161 SetLastNtError(_SEH2_GetExceptionCode());
3162 Ret = NULL;
3163 }
3164 _SEH2_END;
3165
3166 RETURN( Ret);
3167
3168 CLEANUP:
3169 TRACE("Leave NtUserFindWindowEx, ret %p\n", _ret_);
3170 UserLeave();
3171 END_CLEANUP;
3172 }
3173
3174
3175 /*
3176 * @implemented
3177 */
3178 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
3179 {
3180 PWND WndAncestor, Parent;
3181
3182 if (Wnd->head.h == IntGetDesktopWindow())
3183 {
3184 return NULL;
3185 }
3186
3187 switch (Type)
3188 {
3189 case GA_PARENT:
3190 {
3191 WndAncestor = Wnd->spwndParent;
3192 break;
3193 }
3194
3195 case GA_ROOT:
3196 {
3197 WndAncestor = Wnd;
3198 Parent = NULL;
3199
3200 for(;;)
3201 {
3202 if(!(Parent = WndAncestor->spwndParent))
3203 {
3204 break;
3205 }
3206 if(IntIsDesktopWindow(Parent))
3207 {
3208 break;
3209 }
3210
3211 WndAncestor = Parent;
3212 }
3213 break;
3214 }
3215
3216 case GA_ROOTOWNER:
3217 {
3218 WndAncestor = Wnd;
3219
3220 for (;;)
3221 {
3222 Parent = IntGetParent(WndAncestor);
3223
3224 if (!Parent)
3225 {
3226 break;
3227 }
3228
3229 WndAncestor = Parent;
3230 }
3231 break;
3232 }
3233
3234 default:
3235 {
3236 return NULL;
3237 }
3238 }
3239
3240 return WndAncestor;
3241 }
3242
3243 /*
3244 * @implemented
3245 */
3246 HWND APIENTRY
3247 NtUserGetAncestor(HWND hWnd, UINT Type)
3248 {
3249 PWND Window, Ancestor;
3250 DECLARE_RETURN(HWND);
3251
3252 TRACE("Enter NtUserGetAncestor\n");
3253 UserEnterExclusive();
3254
3255 if (!(Window = UserGetWindowObject(hWnd)))
3256 {
3257 RETURN(NULL);
3258 }
3259
3260 Ancestor = UserGetAncestor(Window, Type);
3261 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3262
3263 RETURN(Ancestor ? Ancestor->head.h : NULL);
3264
3265 CLEANUP:
3266 TRACE("Leave NtUserGetAncestor, ret=%p\n", _ret_);
3267 UserLeave();
3268 END_CLEANUP;
3269 }
3270
3271 ////
3272 //// ReactOS work around! Keep it the sames as in Combo.c and Controls.h
3273 ////
3274 /* combo state struct */
3275 typedef struct
3276 {
3277 HWND self;
3278 HWND owner;
3279 UINT dwStyle;
3280 HWND hWndEdit;
3281 HWND hWndLBox;
3282 UINT wState;
3283 HFONT hFont;
3284 RECT textRect;
3285 RECT buttonRect;
3286 RECT droppedRect;
3287 INT droppedIndex;
3288 INT fixedOwnerDrawHeight;
3289 INT droppedWidth; /* last two are not used unless set */
3290 INT editHeight; /* explicitly */
3291 LONG UIState;
3292 } HEADCOMBO,*LPHEADCOMBO;