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