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