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