[BROWSEUI]
[reactos.git] / 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 (Window->spwndParent == UserGetDesktopWindow() &&
2456 Window->spwndOwner == NULL &&
2457 (Window->style & WS_VISIBLE) &&
2458 (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
2459 (Window->ExStyle & WS_EX_APPWINDOW)))
2460 {
2461 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0);
2462 }
2463
2464 /* Initialize and show the window's scrollbars */
2465 if (Window->style & WS_VSCROLL)
2466 {
2467 co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE);
2468 }
2469 if (Window->style & WS_HSCROLL)
2470 {
2471 co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE);
2472 }
2473
2474 /* Show the new window */
2475 if (Cs->style & WS_VISIBLE)
2476 {
2477 if (Window->style & WS_MAXIMIZE)
2478 dwShowMode = SW_SHOW;
2479 else if (Window->style & WS_MINIMIZE)
2480 dwShowMode = SW_SHOWMINIMIZED;
2481
2482 co_WinPosShowWindow(Window, dwShowMode);
2483
2484 if (Window->ExStyle & WS_EX_MDICHILD)
2485 {
2486 ASSERT(ParentWindow);
2487 if(!ParentWindow)
2488 goto cleanup;
2489 co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0);
2490 /* ShowWindow won't activate child windows */
2491 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2492 }
2493 }
2494
2495 TRACE("co_UserCreateWindowEx(): Created window %p\n", hWnd);
2496 ret = Window;
2497
2498 cleanup:
2499 if (!ret)
2500 {
2501 TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2502 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2503 if (Window)
2504 co_UserDestroyWindow(Window);
2505 else if (Class)
2506 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2507 }
2508
2509 if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
2510 if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
2511 if (pszName) UserHeapFree(pszName);
2512 if (pszClass) UserHeapFree(pszClass);
2513
2514 if (Window)
2515 {
2516 UserDerefObjectCo(Window);
2517 }
2518 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2519
2520 return ret;
2521 }
2522
2523 NTSTATUS
2524 NTAPI
2525 ProbeAndCaptureLargeString(
2526 OUT PLARGE_STRING plstrSafe,
2527 IN PLARGE_STRING plstrUnsafe)
2528 {
2529 LARGE_STRING lstrTemp;
2530 PVOID pvBuffer = NULL;
2531
2532 _SEH2_TRY
2533 {
2534 /* Probe and copy the string */
2535 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2536 lstrTemp = *plstrUnsafe;
2537 }
2538 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2539 {
2540 /* Fail */
2541 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2542 }
2543 _SEH2_END
2544
2545 if (lstrTemp.Length != 0)
2546 {
2547 /* Allocate a buffer from paged pool */
2548 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2549 if (!pvBuffer)
2550 {
2551 return STATUS_NO_MEMORY;
2552 }
2553
2554 _SEH2_TRY
2555 {
2556 /* Probe and copy the buffer */
2557 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2558 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2559 }
2560 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2561 {
2562 /* Cleanup and fail */
2563 ExFreePoolWithTag(pvBuffer, TAG_STRING);
2564 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2565 }
2566 _SEH2_END
2567 }
2568
2569 /* Set the output string */
2570 plstrSafe->Buffer = pvBuffer;
2571 plstrSafe->Length = lstrTemp.Length;
2572 plstrSafe->MaximumLength = lstrTemp.Length;
2573
2574 return STATUS_SUCCESS;
2575 }
2576
2577 /**
2578 * \todo Allow passing plstrClassName as ANSI.
2579 */
2580 HWND
2581 NTAPI
2582 NtUserCreateWindowEx(
2583 DWORD dwExStyle,
2584 PLARGE_STRING plstrClassName,
2585 PLARGE_STRING plstrClsVersion,
2586 PLARGE_STRING plstrWindowName,
2587 DWORD dwStyle,
2588 int x,
2589 int y,
2590 int nWidth,
2591 int nHeight,
2592 HWND hWndParent,
2593 HMENU hMenu,
2594 HINSTANCE hInstance,
2595 LPVOID lpParam,
2596 DWORD dwFlags,
2597 PVOID acbiBuffer)
2598 {
2599 NTSTATUS Status;
2600 LARGE_STRING lstrWindowName;
2601 LARGE_STRING lstrClassName;
2602 UNICODE_STRING ustrClassName;
2603 CREATESTRUCTW Cs;
2604 HWND hwnd = NULL;
2605 PWND pwnd;
2606
2607 lstrWindowName.Buffer = NULL;
2608 lstrClassName.Buffer = NULL;
2609
2610 ASSERT(plstrWindowName);
2611
2612 if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2613 {
2614 /* check hMenu is valid handle */
2615 if (hMenu && !ValidateHandle(hMenu, TYPE_MENU))
2616 {
2617 /* error is set in ValidateHandle */
2618 return NULL;
2619 }
2620 }
2621
2622 /* Copy the window name to kernel mode */
2623 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2624 if (!NT_SUCCESS(Status))
2625 {
2626 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2627 SetLastNtError(Status);
2628 return NULL;
2629 }
2630
2631 plstrWindowName = &lstrWindowName;
2632
2633 /* Check if the class is an atom */
2634 if (IS_ATOM(plstrClassName))
2635 {
2636 /* It is, pass the atom in the UNICODE_STRING */
2637 ustrClassName.Buffer = (PVOID)plstrClassName;
2638 ustrClassName.Length = 0;
2639 ustrClassName.MaximumLength = 0;
2640 }
2641 else
2642 {
2643 /* It's not, capture the class name */
2644 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2645 if (!NT_SUCCESS(Status))
2646 {
2647 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2648 /* Set last error, cleanup and return */
2649 SetLastNtError(Status);
2650 goto cleanup;
2651 }
2652
2653 /* We pass it on as a UNICODE_STRING */
2654 ustrClassName.Buffer = lstrClassName.Buffer;
2655 ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2656 ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
2657 }
2658
2659 /* Fill the CREATESTRUCTW */
2660 /* we will keep here the original parameters */
2661 Cs.style = dwStyle;
2662 Cs.lpCreateParams = lpParam;
2663 Cs.hInstance = hInstance;
2664 Cs.hMenu = hMenu;
2665 Cs.hwndParent = hWndParent;
2666 Cs.cx = nWidth;
2667 Cs.cy = nHeight;
2668 Cs.x = x;
2669 Cs.y = y;
2670 Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
2671 if (IS_ATOM(plstrClassName))
2672 Cs.lpszClass = (LPCWSTR) plstrClassName;
2673 else
2674 Cs.lpszClass = (LPCWSTR) plstrClassName->Buffer;
2675 Cs.dwExStyle = dwExStyle;
2676
2677 UserEnterExclusive();
2678
2679 /* Call the internal function */
2680 pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName, acbiBuffer);
2681
2682 if(!pwnd)
2683 {
2684 ERR("co_UserCreateWindowEx failed!\n");
2685 }
2686 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2687
2688 UserLeave();
2689
2690 cleanup:
2691 if (lstrWindowName.Buffer)
2692 {
2693 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2694 }
2695 if (lstrClassName.Buffer)
2696 {
2697 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2698 }
2699
2700 return hwnd;
2701 }
2702
2703
2704 BOOLEAN FASTCALL co_UserDestroyWindow(PWND Window)
2705 {
2706 HWND hWnd;
2707 PWND pwndTemp;
2708 PTHREADINFO ti;
2709 MSG msg;
2710
2711 ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
2712
2713 hWnd = Window->head.h;
2714 ti = PsGetCurrentThreadWin32Thread();
2715
2716 TRACE("co_UserDestroyWindow \n");
2717
2718 /* Check for owner thread */
2719 if ( Window->head.pti != PsGetCurrentThreadWin32Thread())
2720 {
2721 /* Check if we are destroying the desktop window */
2722 if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
2723 {
2724 EngSetLastError(ERROR_ACCESS_DENIED);
2725 return FALSE;
2726 }
2727 }
2728
2729 /* If window was created successfully and it is hooked */
2730 if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
2731 {
2732 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0))
2733 {
2734 ERR("Destroy Window WH_CBT Call Hook return!\n");
2735 return FALSE;
2736 }
2737 }
2738
2739 if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
2740 {
2741 if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2742 {
2743 if (Window->spwndOwner)
2744 {
2745 //ERR("DestroyWindow Owner out.\n");
2746 UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2747 }
2748 }
2749 }
2750
2751 /* Inform the parent */
2752 if (Window->style & WS_CHILD)
2753 {
2754 IntSendParentNotify(Window, WM_DESTROY);
2755 }
2756
2757 /* Look whether the focus is within the tree of windows we will
2758 * be destroying.
2759 */
2760 if (!co_WinPosShowWindow(Window, SW_HIDE))
2761 { // Rule #1.
2762 if (ti->MessageQueue->spwndActive == Window && ti->MessageQueue == IntGetFocusMessageQueue())
2763 {
2764 co_WinPosActivateOtherWindow(Window);
2765 }
2766 }
2767
2768 // Adjust last active.
2769 if ((pwndTemp = Window->spwndOwner))
2770 {
2771 while (pwndTemp->spwndOwner)
2772 pwndTemp = pwndTemp->spwndOwner;
2773
2774 if (pwndTemp->spwndLastActive == Window)
2775 pwndTemp->spwndLastActive = Window->spwndOwner;
2776 }
2777
2778 if (Window->spwndParent && IntIsWindow(Window->head.h))
2779 {
2780 if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
2781 {
2782 if (!IntIsTopLevelWindow(Window))
2783 {
2784 //ERR("DestroyWindow Parent out.\n");
2785 UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2786 }
2787 }
2788 }
2789
2790 if (Window->head.pti->MessageQueue->spwndActive == Window)
2791 Window->head.pti->MessageQueue->spwndActive = NULL;
2792 if (Window->head.pti->MessageQueue->spwndFocus == Window)
2793 Window->head.pti->MessageQueue->spwndFocus = NULL;
2794 if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
2795 Window->head.pti->MessageQueue->spwndActivePrev = NULL;
2796 if (Window->head.pti->MessageQueue->spwndCapture == Window)
2797 Window->head.pti->MessageQueue->spwndCapture = NULL;
2798
2799 /*
2800 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2801 */
2802
2803 if ((ti != NULL) && (ti->pDeskInfo != NULL))
2804 {
2805 if (ti->pDeskInfo->hShellWindow == hWnd)
2806 {
2807 ERR("Destroying the ShellWindow!\n");
2808 ti->pDeskInfo->hShellWindow = NULL;
2809 }
2810 }
2811
2812 IntEngWindowChanged(Window, WOC_DELETE);
2813
2814 if (!IntIsWindow(Window->head.h))
2815 {
2816 return TRUE;
2817 }
2818
2819 /* Recursively destroy owned windows */
2820
2821 if (! (Window->style & WS_CHILD))
2822 {
2823 for (;;)
2824 {
2825 BOOL GotOne = FALSE;
2826 HWND *Children;
2827 HWND *ChildHandle;
2828 PWND Child, Desktop;
2829
2830 Desktop = IntIsDesktopWindow(Window) ? Window :
2831 UserGetWindowObject(IntGetDesktopWindow());
2832 Children = IntWinListChildren(Desktop);
2833
2834 if (Children)
2835 {
2836 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2837 {
2838 Child = UserGetWindowObject(*ChildHandle);
2839 if (Child == NULL)
2840 continue;
2841 if (Child->spwndOwner != Window)
2842 {
2843 continue;
2844 }
2845
2846 if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
2847 {
2848 USER_REFERENCE_ENTRY ChildRef;
2849 UserRefObjectCo(Child, &ChildRef); // Temp HACK?
2850 co_UserDestroyWindow(Child);
2851 UserDerefObjectCo(Child); // Temp HACK?
2852
2853 GotOne = TRUE;
2854 continue;
2855 }
2856
2857 if (Child->spwndOwner != NULL)
2858 {
2859 Child->spwndOwner = NULL;
2860 }
2861
2862 }
2863 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
2864 }
2865 if (! GotOne)
2866 {
2867 break;
2868 }
2869 }
2870 }
2871
2872 /* Generate mouse move message for the next window */
2873 msg.message = WM_MOUSEMOVE;
2874 msg.wParam = UserGetMouseButtonsState();
2875 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2876 msg.pt = gpsi->ptCursor;
2877 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2878
2879 if (!IntIsWindow(Window->head.h))
2880 {
2881 return TRUE;
2882 }
2883
2884 /* Destroy the window storage */
2885 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2886
2887 return TRUE;
2888 }
2889
2890
2891 /*
2892 * @implemented
2893 */
2894 BOOLEAN APIENTRY
2895 NtUserDestroyWindow(HWND Wnd)
2896 {
2897 PWND Window;
2898 DECLARE_RETURN(BOOLEAN);
2899 BOOLEAN ret;
2900 USER_REFERENCE_ENTRY Ref;
2901
2902 TRACE("Enter NtUserDestroyWindow\n");
2903 UserEnterExclusive();
2904
2905 if (!(Window = UserGetWindowObject(Wnd)))
2906 {
2907 RETURN(FALSE);
2908 }
2909
2910 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
2911 ret = co_UserDestroyWindow(Window);
2912 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
2913
2914 RETURN(ret);
2915
2916 CLEANUP:
2917 TRACE("Leave NtUserDestroyWindow, ret=%u\n", _ret_);
2918 UserLeave();
2919 END_CLEANUP;
2920 }
2921
2922
2923 static HWND FASTCALL
2924 IntFindWindow(PWND Parent,
2925 PWND ChildAfter,
2926 RTL_ATOM ClassAtom,
2927 PUNICODE_STRING WindowName)
2928 {
2929 BOOL CheckWindowName;
2930 HWND *List, *phWnd;
2931 HWND Ret = NULL;
2932 UNICODE_STRING CurrentWindowName;
2933
2934 ASSERT(Parent);
2935
2936 CheckWindowName = WindowName->Buffer != 0;
2937
2938 if((List = IntWinListChildren(Parent)))
2939 {
2940 phWnd = List;
2941 if(ChildAfter)
2942 {
2943 /* skip handles before and including ChildAfter */
2944 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2945 ;
2946 }
2947
2948 /* search children */
2949 while(*phWnd)
2950 {
2951 PWND Child;
2952 if(!(Child = UserGetWindowObject(*(phWnd++))))
2953 {
2954 continue;
2955 }
2956
2957 /* Do not send WM_GETTEXT messages in the kernel mode version!
2958 The user mode version however calls GetWindowText() which will
2959 send WM_GETTEXT messages to windows belonging to its processes */
2960 if (!ClassAtom || Child->pcls->atomClassName == ClassAtom)
2961 {
2962 // FIXME: LARGE_STRING truncated
2963 CurrentWindowName.Buffer = Child->strName.Buffer;
2964 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
2965 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
2966 if(!CheckWindowName ||
2967 (Child->strName.Length < 0xFFFF &&
2968 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
2969 {
2970 Ret = Child->head.h;
2971 break;
2972 }
2973 }
2974 }
2975 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2976 }
2977
2978 return Ret;
2979 }
2980
2981 /*
2982 * FUNCTION:
2983 * Searches a window's children for a window with the specified
2984 * class and name
2985 * ARGUMENTS:
2986 * hwndParent = The window whose childs are to be searched.
2987 * NULL = desktop
2988 * HWND_MESSAGE = message-only windows
2989 *
2990 * hwndChildAfter = Search starts after this child window.
2991 * NULL = start from beginning
2992 *
2993 * ucClassName = Class name to search for
2994 * Reguired parameter.
2995 *
2996 * ucWindowName = Window name
2997 * ->Buffer == NULL = don't care
2998 *
2999 * RETURNS:
3000 * The HWND of the window if it was found, otherwise NULL
3001 */
3002 /*
3003 * @implemented
3004 */
3005 HWND APIENTRY
3006 NtUserFindWindowEx(HWND hwndParent,
3007 HWND hwndChildAfter,
3008 PUNICODE_STRING ucClassName,
3009 PUNICODE_STRING ucWindowName,
3010 DWORD dwUnknown)
3011 {
3012 PWND Parent, ChildAfter;
3013 UNICODE_STRING ClassName = {0}, WindowName = {0};
3014 HWND Desktop, Ret = NULL;
3015 BOOL DoMessageWnd = FALSE;
3016 RTL_ATOM ClassAtom = (RTL_ATOM)0;
3017 DECLARE_RETURN(HWND);
3018
3019 TRACE("Enter NtUserFindWindowEx\n");
3020 UserEnterShared();
3021
3022 if (ucClassName != NULL || ucWindowName != NULL)
3023 {
3024 _SEH2_TRY
3025 {
3026 if (ucClassName != NULL)
3027 {
3028 ClassName = ProbeForReadUnicodeString(ucClassName);
3029 if (ClassName.Length != 0)
3030 {
3031 ProbeForRead(ClassName.Buffer,
3032 ClassName.Length,
3033 sizeof(WCHAR));
3034 }
3035 else if (!IS_ATOM(ClassName.Buffer))
3036 {
3037 EngSetLastError(ERROR_INVALID_PARAMETER);
3038 _SEH2_LEAVE;
3039 }
3040
3041 if (!IntGetAtomFromStringOrAtom(&ClassName,
3042 &ClassAtom))
3043 {
3044 _SEH2_LEAVE;
3045 }
3046 }
3047
3048 if (ucWindowName != NULL)
3049 {
3050 WindowName = ProbeForReadUnicodeString(ucWindowName);
3051 if (WindowName.Length != 0)
3052 {
3053 ProbeForRead(WindowName.Buffer,
3054 WindowName.Length,
3055 sizeof(WCHAR));
3056 }
3057 }
3058 }
3059 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3060 {
3061 SetLastNtError(_SEH2_GetExceptionCode());
3062 _SEH2_YIELD(RETURN(NULL));
3063 }
3064 _SEH2_END;
3065
3066 if (ucClassName != NULL)
3067 {
3068 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
3069 !IS_ATOM(ClassName.Buffer))
3070 {
3071 EngSetLastError(ERROR_INVALID_PARAMETER);
3072 RETURN(NULL);
3073 }
3074 else if (ClassAtom == (RTL_ATOM)0)
3075 {
3076 /* LastError code was set by IntGetAtomFromStringOrAtom */
3077 RETURN(NULL);
3078 }
3079 }
3080 }
3081
3082 Desktop = IntGetCurrentThreadDesktopWindow();
3083
3084 if(hwndParent == NULL)
3085 {
3086 hwndParent = Desktop;
3087 DoMessageWnd = TRUE;
3088 }
3089 else if(hwndParent == HWND_MESSAGE)
3090 {
3091 hwndParent = IntGetMessageWindow();
3092 }
3093
3094 if(!(Parent = UserGetWindowObject(hwndParent)))
3095 {
3096 RETURN( NULL);
3097 }
3098
3099 ChildAfter = NULL;
3100 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
3101 {
3102 RETURN( NULL);
3103 }
3104
3105 _SEH2_TRY
3106 {
3107 if(Parent->head.h == Desktop)
3108 {
3109 HWND *List, *phWnd;
3110 PWND TopLevelWindow;
3111 BOOLEAN CheckWindowName;
3112 BOOLEAN WindowMatches;
3113 BOOLEAN ClassMatches;
3114
3115 /* windows searches through all top-level windows if the parent is the desktop
3116 window */
3117
3118 if((List = IntWinListChildren(Parent)))
3119 {
3120 phWnd = List;
3121
3122 if(ChildAfter)
3123 {
3124 /* skip handles before and including ChildAfter */
3125 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
3126 ;
3127 }
3128
3129 CheckWindowName = WindowName.Buffer != 0;
3130
3131 /* search children */
3132 while(*phWnd)
3133 {
3134 UNICODE_STRING ustr;
3135
3136 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
3137 {
3138 continue;
3139 }
3140
3141 /* Do not send WM_GETTEXT messages in the kernel mode version!
3142 The user mode version however calls GetWindowText() which will
3143 send WM_GETTEXT messages to windows belonging to its processes */
3144 ustr.Buffer = TopLevelWindow->strName.Buffer;
3145 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
3146 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
3147 WindowMatches = !CheckWindowName ||
3148 (TopLevelWindow->strName.Length < 0xFFFF &&
3149 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
3150 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
3151 ClassAtom == TopLevelWindow->pcls->atomClassName;
3152
3153 if (WindowMatches && ClassMatches)
3154 {
3155 Ret = TopLevelWindow->head.h;
3156 break;
3157 }
3158
3159 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
3160 {
3161 /* window returns the handle of the top-level window, in case it found
3162 the child window */
3163 Ret = TopLevelWindow->head.h;
3164 break;
3165 }
3166
3167 }
3168 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
3169 }
3170 }
3171 else
3172 {
3173 ERR("FindWindowEx: Not Desktop Parent!\n");
3174 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
3175 }
3176
3177 if (Ret == NULL && DoMessageWnd)
3178 {
3179 PWND MsgWindows;
3180
3181 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3182 {
3183 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3184 }
3185 }
3186 }
3187 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3188 {
3189 SetLastNtError(_SEH2_GetExceptionCode());
3190 Ret = NULL;
3191 }
3192 _SEH2_END;
3193
3194 RETURN( Ret);
3195
3196 CLEANUP:
3197 TRACE("Leave NtUserFindWindowEx, ret %p\n", _ret_);
3198 UserLeave();
3199 END_CLEANUP;
3200 }
3201
3202
3203 /*
3204 * @implemented
3205 */
3206 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
3207 {
3208 PWND WndAncestor, Parent;
3209
3210 if (Wnd->head.h == IntGetDesktopWindow())
3211 {
3212 return NULL;
3213 }
3214
3215 switch (Type)
3216 {
3217 case GA_PARENT:
3218 {
3219 WndAncestor = Wnd->spwndParent;
3220 break;
3221 }
3222
3223 case GA_ROOT:
3224 {
3225 WndAncestor = Wnd;
3226 Parent = NULL;
3227
3228 for(;;)
3229 {
3230 if(!(Parent = WndAncestor->spwndParent))
3231 {
3232 break;
3233 }
3234 if(IntIsDesktopWindow(Parent))
3235 {
3236 break;
3237 }
3238
3239 WndAncestor = Parent;
3240 }
3241 break;
3242 }
3243
3244 case GA_ROOTOWNER:
3245 {
3246 WndAncestor = Wnd;
3247
3248 for (;;)
3249 {
3250 Parent = IntGetParent(WndAncestor);
3251
3252 if (!Parent)
3253 {
3254 break;
3255 }
3256
3257 WndAncestor = Parent;
3258 }
3259 break;
3260 }
3261
3262 default:
3263 {
3264 return NULL;
3265 }
3266 }
3267
3268 return WndAncestor;
3269 }
3270
3271 /*
3272 * @implemented
3273 */
3274 HWND APIENTRY
3275 NtUserGetAncestor(HWND hWnd, UINT Type)
3276 {
3277 PWND Window, Ancestor;
3278 DECLARE_RETURN(HWND);
3279
3280 TRACE("Enter NtUserGetAncestor\n");
3281 UserEnterExclusive();
3282
3283 if (!(Window = UserGetWindowObject(hWnd)))
3284 {
3285 RETURN(NULL);
3286 }
3287
3288 Ancestor = UserGetAncestor(Window, Type);
3289 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3290
3291 RETURN(Ancestor ? Ancestor->head.h : NULL);
3292
3293 CLEANUP:
3294 TRACE("Leave NtUserGetAncestor, ret=%p\n", _ret_);
3295 UserLeave();
3296 END_CLEANUP;
3297 }
3298
3299 ////
3300 //// ReactOS work around! Keep it the sames as in Combo.c and Controls.h
3301 ////
3302 /* combo state struct */
3303 typedef struct
3304 {
3305 HWND self;
3306 HWND owner;
3307 UINT dwStyle;
3308 HWND hWndEdit;
3309 HWND hWndLBox;
3310 UINT wState;
3311 HFONT hFont;
3312 RECT textRect;
3313 RECT buttonRect;
3314 RECT droppedRect;
3315 INT droppedIndex;
3316 INT fixedOwnerDrawHeight;
3317 INT droppedWidth; /* last two are not used unless set */
3318 INT editHeight; /* explicitly */
3319 LONG UIState;
3320 } HEADCOMBO,*LPHEADCOMBO;
3321
3322 // Window Extra data container.
3323 typedef struct _WND2CBOX
3324 {
3325 WND;
3326 LPHEADCOMBO pCBox;
3327 } WND2CBOX, *PWND2CBOX;
3328
3329 #define CBF_BUTTONDOWN 0x0002
3330 ////
3331 ////
3332 ////
3333 BOOL
3334 APIENTRY
3335 NtUserGetComboBoxInfo(
3336 HWND hWnd,
3337 PCOMBOBOXINFO pcbi)
3338 {
3339 PWND Wnd;
3340 PPROCESSINFO ppi;
3341 BOOL NotSameppi = FALSE;
3342 BOOL Ret = TRUE;
3343 DECLARE_RETURN(BOOL);
3344
3345 TRACE("Enter NtUserGetComboBoxInfo\n");
3346 UserEnterShared();
3347
3348 if (!(Wnd = UserGetWindowObject(hWnd)))
3349 {
3350 RETURN( FALSE );
3351 }
3352 _SEH2_TRY
3353 {
3354 if(pcbi)
3355 {
3356 ProbeForWrite(pcbi,
3357 sizeof(COMBOBOXINFO),
3358 1);
3359 }
3360 }
3361 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3362 {
3363 SetLastNtError(_SEH2_GetExceptionCode());
3364 _SEH2_YIELD(RETURN(FALSE));
3365 }
3366 _SEH2_END;
3367
3368 if (pcbi->cbSize < sizeof(COMBOBOXINFO))
3369 {
3370 EngSetLastError(ERROR_INVALID_PARAMETER);
3371 RETURN(FALSE);
3372 }
3373
3374 // Pass the user pointer, it was already probed.
3375 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_COMBOBOX]) && Wnd->fnid != FNID_COMBOBOX)
3376 {
3377 RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));