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