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