[Win32SS] Support Module Versioning.
[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 DWORD dwVer )
1620 {
1621 PWND pWnd = NULL;
1622 HWND hWnd;
1623 PTHREADINFO pti = NULL;
1624 BOOL MenuChanged;
1625 BOOL bUnicodeWindow;
1626
1627 pti = pdeskCreated ? gptiDesktopThread : GetW32ThreadInfo();
1628
1629 if (!(Cs->dwExStyle & WS_EX_LAYOUTRTL))
1630 { // Need both here for wine win.c test_CreateWindow.
1631 //if (Cs->hwndParent && ParentWindow)
1632 if (ParentWindow) // It breaks more tests..... WIP.
1633 {
1634 if ( (Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD &&
1635 ParentWindow->ExStyle & WS_EX_LAYOUTRTL &&
1636 !(ParentWindow->ExStyle & WS_EX_NOINHERITLAYOUT) )
1637 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1638 }
1639 else
1640 { /*
1641 * Note from MSDN <http://msdn.microsoft.com/en-us/library/aa913269.aspx>:
1642 *
1643 * Dialog boxes and message boxes do not inherit layout, so you must
1644 * set the layout explicitly.
1645 */
1646 if ( Class->fnid != FNID_DIALOG )
1647 {
1648 if (pti->ppi->dwLayout & LAYOUT_RTL)
1649 {
1650 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1651 }
1652 }
1653 }
1654 }
1655
1656 /* Automatically add WS_EX_WINDOWEDGE */
1657 if ((Cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1658 ((!(Cs->dwExStyle & WS_EX_STATICEDGE)) &&
1659 (Cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1660 Cs->dwExStyle |= WS_EX_WINDOWEDGE;
1661 else
1662 Cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1663
1664 /* Is it a unicode window? */
1665 bUnicodeWindow =!(Cs->dwExStyle & WS_EX_SETANSICREATOR);
1666 Cs->dwExStyle &= ~WS_EX_SETANSICREATOR;
1667
1668 /* Allocate the new window */
1669 pWnd = (PWND) UserCreateObject( gHandleTable,
1670 pdeskCreated ? pdeskCreated : pti->rpdesk,
1671 pti,
1672 (PHANDLE)&hWnd,
1673 TYPE_WINDOW,
1674 sizeof(WND) + Class->cbwndExtra);
1675
1676 if (!pWnd)
1677 {
1678 goto AllocError;
1679 }
1680
1681 TRACE("Created window object with handle %p\n", hWnd);
1682
1683 if (pdeskCreated && pdeskCreated->DesktopWindow == NULL )
1684 { /* HACK: Helper for win32csr/desktopbg.c */
1685 /* If there is no desktop window yet, we must be creating it */
1686 TRACE("CreateWindow setting desktop.\n");
1687 pdeskCreated->DesktopWindow = hWnd;
1688 pdeskCreated->pDeskInfo->spwnd = pWnd;
1689 }
1690
1691 /*
1692 * Fill out the structure describing it.
1693 */
1694 /* Remember, pWnd->head is setup in object.c ... */
1695 pWnd->spwndParent = ParentWindow;
1696 pWnd->spwndOwner = OwnerWindow;
1697 pWnd->fnid = 0;
1698 pWnd->spwndLastActive = pWnd;
1699 // Ramp up compatible version sets.
1700 if ( dwVer >= WINVER_WIN31 )
1701 {
1702 pWnd->state2 |= WNDS2_WIN31COMPAT;
1703 if ( dwVer >= WINVER_WINNT4 )
1704 {
1705 pWnd->state2 |= WNDS2_WIN40COMPAT;
1706 if ( dwVer >= WINVER_WIN2K )
1707 {
1708 pWnd->state2 |= WNDS2_WIN50COMPAT;
1709 }
1710 }
1711 }
1712 pWnd->pcls = Class;
1713 pWnd->hModule = Cs->hInstance;
1714 pWnd->style = Cs->style & ~WS_VISIBLE;
1715 pWnd->ExStyle = Cs->dwExStyle;
1716 pWnd->cbwndExtra = pWnd->pcls->cbwndExtra;
1717 pWnd->pActCtx = acbiBuffer;
1718 pWnd->InternalPos.MaxPos.x = pWnd->InternalPos.MaxPos.y = -1;
1719 pWnd->InternalPos.IconPos.x = pWnd->InternalPos.IconPos.y = -1;
1720
1721 if (pWnd->spwndParent != NULL && Cs->hwndParent != 0)
1722 {
1723 pWnd->HideFocus = pWnd->spwndParent->HideFocus;
1724 pWnd->HideAccel = pWnd->spwndParent->HideAccel;
1725 }
1726
1727 pWnd->head.pti->cWindows++;
1728
1729 if (Class->spicn && !Class->spicnSm)
1730 {
1731 HICON IconSmHandle = NULL;
1732 if((Class->spicn->CURSORF_flags & (CURSORF_LRSHARED | CURSORF_FROMRESOURCE))
1733 == (CURSORF_LRSHARED | CURSORF_FROMRESOURCE))
1734 {
1735 IconSmHandle = co_IntCopyImage(
1736 UserHMGetHandle(Class->spicn),
1737 IMAGE_ICON,
1738 UserGetSystemMetrics( SM_CXSMICON ),
1739 UserGetSystemMetrics( SM_CYSMICON ),
1740 LR_COPYFROMRESOURCE);
1741 }
1742 if (!IconSmHandle)
1743 {
1744 /* Retry without copying from resource */
1745 IconSmHandle = co_IntCopyImage(
1746 UserHMGetHandle(Class->spicn),
1747 IMAGE_ICON,
1748 UserGetSystemMetrics( SM_CXSMICON ),
1749 UserGetSystemMetrics( SM_CYSMICON ),
1750 0);
1751 }
1752
1753 if (IconSmHandle)
1754 {
1755 Class->spicnSm = UserGetCurIconObject(IconSmHandle);
1756 Class->CSF_flags |= CSF_CACHEDSMICON;
1757 }
1758 }
1759
1760 if (pWnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
1761 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
1762
1763 /* BugBoy Comments: Comment below say that System classes are always created
1764 as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
1765 sets the window to ansi as verified by testing with IsUnicodeWindow API.
1766
1767 No where can I see in code or through testing does the window change back
1768 to ANSI after being created as UNICODE in ROS. I didnt do more testing to
1769 see what problems this would cause. */
1770
1771 // Set WndProc from Class.
1772 pWnd->lpfnWndProc = pWnd->pcls->lpfnWndProc;
1773
1774 // GetWindowProc, test for non server side default classes and set WndProc.
1775 if ( pWnd->pcls->fnid <= FNID_GHOST && pWnd->pcls->fnid >= FNID_BUTTON )
1776 {
1777 if (bUnicodeWindow)
1778 {
1779 if (GETPFNCLIENTA(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1780 pWnd->lpfnWndProc = GETPFNCLIENTW(pWnd->pcls->fnid);
1781 }
1782 else
1783 {
1784 if (GETPFNCLIENTW(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1785 pWnd->lpfnWndProc = GETPFNCLIENTA(pWnd->pcls->fnid);
1786 }
1787 }
1788
1789 // If not an Unicode caller, set Ansi creator bit.
1790 if (!bUnicodeWindow) pWnd->state |= WNDS_ANSICREATOR;
1791
1792 // Clone Class Ansi/Unicode proc type.
1793 if (pWnd->pcls->CSF_flags & CSF_ANSIPROC)
1794 {
1795 pWnd->state |= WNDS_ANSIWINDOWPROC;
1796 pWnd->Unicode = FALSE;
1797 }
1798 else
1799 { /*
1800 * It seems there can be both an Ansi creator and Unicode Class Window
1801 * WndProc, unless the following overriding conditions occur:
1802 */
1803 if ( !bUnicodeWindow &&
1804 ( Class->atomClassName == gpsi->atomSysClass[ICLS_BUTTON] ||
1805 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX] ||
1806 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOLBOX] ||
1807 Class->atomClassName == gpsi->atomSysClass[ICLS_DIALOG] ||
1808 Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT] ||
1809 Class->atomClassName == gpsi->atomSysClass[ICLS_IME] ||
1810 Class->atomClassName == gpsi->atomSysClass[ICLS_LISTBOX] ||
1811 Class->atomClassName == gpsi->atomSysClass[ICLS_MDICLIENT] ||
1812 Class->atomClassName == gpsi->atomSysClass[ICLS_STATIC] ) )
1813 { // Override Class and set the window Ansi WndProc.
1814 pWnd->state |= WNDS_ANSIWINDOWPROC;
1815 pWnd->Unicode = FALSE;
1816 }
1817 else
1818 { // Set the window Unicode WndProc.
1819 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
1820 pWnd->Unicode = TRUE;
1821 }
1822 }
1823
1824 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
1825 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
1826 Dont understand why it does this. */
1827 if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT])
1828 {
1829 PCALLPROCDATA CallProc;
1830 CallProc = CreateCallProc(pWnd->head.rpdesk, pWnd->lpfnWndProc, pWnd->Unicode , pWnd->head.pti->ppi);
1831
1832 if (!CallProc)
1833 {
1834 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1835 ERR("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %p\n", hWnd);
1836 }
1837 else
1838 {
1839 UserAddCallProcToClass(pWnd->pcls, CallProc);
1840 }
1841 }
1842
1843 InitializeListHead(&pWnd->PropListHead);
1844 pWnd->PropListItems = 0;
1845
1846 if ( WindowName->Buffer != NULL && WindowName->Length > 0 )
1847 {
1848 pWnd->strName.Buffer = DesktopHeapAlloc(pWnd->head.rpdesk,
1849 WindowName->Length + sizeof(UNICODE_NULL));
1850 if (pWnd->strName.Buffer == NULL)
1851 {
1852 goto AllocError;
1853 }
1854
1855 RtlCopyMemory(pWnd->strName.Buffer, WindowName->Buffer, WindowName->Length);
1856 pWnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
1857 pWnd->strName.Length = WindowName->Length;
1858 pWnd->strName.MaximumLength = WindowName->Length + sizeof(UNICODE_NULL);
1859 }
1860
1861 /* Correct the window style. */
1862 if ((pWnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1863 {
1864 pWnd->style |= WS_CLIPSIBLINGS;
1865 if (!(pWnd->style & WS_POPUP))
1866 {
1867 pWnd->style |= WS_CAPTION;
1868 }
1869 }
1870
1871 /* WS_EX_WINDOWEDGE depends on some other styles */
1872 if (pWnd->ExStyle & WS_EX_DLGMODALFRAME)
1873 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1874 else if (pWnd->style & (WS_DLGFRAME | WS_THICKFRAME))
1875 {
1876 if (!((pWnd->ExStyle & WS_EX_STATICEDGE) &&
1877 (pWnd->style & (WS_CHILD | WS_POPUP))))
1878 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1879 }
1880 else
1881 pWnd->ExStyle &= ~WS_EX_WINDOWEDGE;
1882
1883 if (!(pWnd->style & (WS_CHILD | WS_POPUP)))
1884 pWnd->state |= WNDS_SENDSIZEMOVEMSGS;
1885
1886 /* Set the window menu */
1887 if ((Cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1888 {
1889 if (Cs->hMenu)
1890 {
1891 IntSetMenu(pWnd, Cs->hMenu, &MenuChanged);
1892 }
1893 else if (pWnd->pcls->lpszMenuName) // Take it from the parent.
1894 {
1895 UNICODE_STRING MenuName;
1896 HMENU hMenu;
1897
1898 if (IS_INTRESOURCE(pWnd->pcls->lpszMenuName))
1899 {
1900 MenuName.Length = 0;
1901 MenuName.MaximumLength = 0;
1902 MenuName.Buffer = pWnd->pcls->lpszMenuName;
1903 }
1904 else
1905 {
1906 RtlInitUnicodeString( &MenuName, pWnd->pcls->lpszMenuName);
1907 }
1908 hMenu = co_IntCallLoadMenu( pWnd->pcls->hModule, &MenuName);
1909 if (hMenu) IntSetMenu(pWnd, hMenu, &MenuChanged);
1910 }
1911 }
1912 else // Not a child
1913 pWnd->IDMenu = (UINT_PTR)Cs->hMenu;
1914
1915
1916 if ( ParentWindow &&
1917 ParentWindow != ParentWindow->head.rpdesk->spwndMessage &&
1918 ParentWindow != ParentWindow->head.rpdesk->pDeskInfo->spwnd )
1919 {
1920 PWND Owner = IntGetNonChildAncestor(ParentWindow);
1921
1922 if (!IntValidateOwnerDepth(pWnd, Owner))
1923 {
1924 EngSetLastError(ERROR_INVALID_PARAMETER);
1925 goto Error;
1926 }
1927 if ( pWnd->spwndOwner &&
1928 pWnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1929 {
1930 pWnd->ExStyle |= WS_EX_TOPMOST;
1931 }
1932 if ( pWnd->spwndOwner &&
1933 Class->atomClassName != gpsi->atomSysClass[ICLS_IME] &&
1934 pti != pWnd->spwndOwner->head.pti)
1935 {
1936 //ERR("CreateWindow Owner in.\n");
1937 UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE);
1938 }
1939 }
1940
1941 /* Insert the window into the thread's window list. */
1942 InsertTailList (&pti->WindowListHead, &pWnd->ThreadListEntry);
1943
1944 /* Handle "CS_CLASSDC", it is tested first. */
1945 if ( (pWnd->pcls->style & CS_CLASSDC) && !(pWnd->pcls->pdce) )
1946 { /* One DCE per class to have CLASS. */
1947 pWnd->pcls->pdce = DceAllocDCE( pWnd, DCE_CLASS_DC );
1948 }
1949 else if ( pWnd->pcls->style & CS_OWNDC)
1950 { /* Allocate a DCE for this window. */
1951 DceAllocDCE(pWnd, DCE_WINDOW_DC);
1952 }
1953
1954 return pWnd;
1955
1956 AllocError:
1957 ERR("IntCreateWindow Allocation Error.\n");
1958 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1959 Error:
1960 if(pWnd)
1961 UserDereferenceObject(pWnd);
1962 return NULL;
1963 }
1964
1965 /*
1966 * @implemented
1967 */
1968 PWND FASTCALL
1969 co_UserCreateWindowEx(CREATESTRUCTW* Cs,
1970 PUNICODE_STRING ClassName,
1971 PLARGE_STRING WindowName,
1972 PVOID acbiBuffer,
1973 DWORD dwVer )
1974 {
1975 ULONG style;
1976 PWND Window = NULL, ParentWindow = NULL, OwnerWindow;
1977 HWND hWnd, hWndParent, hWndOwner, hwndInsertAfter;
1978 PWINSTATION_OBJECT WinSta;
1979 PCLS Class = NULL;
1980 SIZE Size;
1981 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
1982 CBT_CREATEWNDW * pCbtCreate;
1983 LRESULT Result;
1984 USER_REFERENCE_ENTRY ParentRef, Ref;
1985 PTHREADINFO pti;
1986 DWORD dwShowMode = SW_SHOW;
1987 CREATESTRUCTW *pCsw = NULL;
1988 PVOID pszClass = NULL, pszName = NULL;
1989 PWND ret = NULL;
1990
1991 /* Get the current window station and reference it */
1992 pti = GetW32ThreadInfo();
1993 if (pti == NULL || pti->rpdesk == NULL)
1994 {
1995 ERR("Thread is not attached to a desktop! Cannot create window!\n");
1996 return NULL; // There is nothing to cleanup.
1997 }
1998 WinSta = pti->rpdesk->rpwinstaParent;
1999 ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
2000
2001 pCsw = NULL;
2002 pCbtCreate = NULL;
2003
2004 /* Get the class and reference it */
2005 Class = IntGetAndReferenceClass(ClassName, Cs->hInstance, FALSE);
2006 if(!Class)
2007 {
2008 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS);
2009 ERR("Failed to find class %wZ\n", ClassName);
2010 goto cleanup;
2011 }
2012
2013 /* Now find the parent and the owner window */
2014 hWndParent = pti->rpdesk->pDeskInfo->spwnd->head.h;
2015 hWndOwner = NULL;
2016
2017 if (Cs->hwndParent == HWND_MESSAGE)
2018 {
2019 Cs->hwndParent = hWndParent = pti->rpdesk->spwndMessage->head.h;
2020 }
2021 else if (Cs->hwndParent)
2022 {
2023 if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
2024 hWndOwner = Cs->hwndParent;
2025 else
2026 hWndParent = Cs->hwndParent;
2027 }
2028 else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2029 {
2030 ERR("Cannot create a child window without a parent!\n");
2031 EngSetLastError(ERROR_TLW_WITH_WSCHILD);
2032 goto cleanup; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
2033 }
2034 else if (Cs->lpszClass != (LPCWSTR)MAKEINTATOM(gpsi->atomSysClass[ICLS_DESKTOP]) &&
2035 (IS_INTRESOURCE(Cs->lpszClass) ||
2036 Cs->lpszClass != (LPCWSTR)MAKEINTATOM(gpsi->atomSysClass[ICLS_HWNDMESSAGE]) ||
2037 _wcsicmp(Cs->lpszClass, L"Message") != 0))
2038 {
2039 if (pti->ppi->dwLayout & LAYOUT_RTL)
2040 {
2041 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
2042 }
2043 }
2044
2045 ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
2046 OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
2047
2048 if (hWndParent && !ParentWindow)
2049 {
2050 ERR("Got invalid parent window handle\n");
2051 goto cleanup;
2052 }
2053 else if (hWndOwner && !OwnerWindow)
2054 {
2055 ERR("Got invalid owner window handle\n");
2056 ParentWindow = NULL;
2057 goto cleanup;
2058 }
2059
2060 if(OwnerWindow)
2061 {
2062 if (IntIsDesktopWindow(OwnerWindow)) OwnerWindow = NULL;
2063 else if (ParentWindow && !IntIsDesktopWindow(ParentWindow))
2064 {
2065 ERR("an owned window must be created as top-level\n");
2066 EngSetLastError( STATUS_ACCESS_DENIED );
2067 goto cleanup;
2068 }
2069 else /* owner must be a top-level window */
2070 {
2071 while ((OwnerWindow->style & (WS_POPUP|WS_CHILD)) == WS_CHILD && !IntIsDesktopWindow(OwnerWindow->spwndParent))
2072 OwnerWindow = OwnerWindow->spwndParent;
2073 }
2074 }
2075
2076 /* Fix the position and the size of the window */
2077 if (ParentWindow)
2078 {
2079 UserRefObjectCo(ParentWindow, &ParentRef);
2080 IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode);
2081 }
2082
2083 /* Allocate and initialize the new window */
2084 Window = IntCreateWindow(Cs,
2085 WindowName,
2086 Class,
2087 ParentWindow,
2088 OwnerWindow,
2089 acbiBuffer,
2090 NULL,
2091 dwVer );
2092 if(!Window)
2093 {
2094 ERR("IntCreateWindow failed!\n");
2095 goto cleanup;
2096 }
2097
2098 hWnd = UserHMGetHandle(Window);
2099 hwndInsertAfter = HWND_TOP;
2100
2101 UserRefObjectCo(Window, &Ref);
2102 UserDereferenceObject(Window);
2103 ObDereferenceObject(WinSta);
2104
2105 //// Check for a hook to eliminate overhead. ////
2106 if ( ISITHOOKED(WH_CBT) || (pti->rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)) )
2107 {
2108 // Allocate the calling structures Justin Case this goes Global.
2109 pCsw = ExAllocatePoolWithTag(NonPagedPool, sizeof(CREATESTRUCTW), TAG_HOOK);
2110 pCbtCreate = ExAllocatePoolWithTag(NonPagedPool, sizeof(CBT_CREATEWNDW), TAG_HOOK);
2111 if (!pCsw || !pCbtCreate)
2112 {
2113 ERR("UserHeapAlloc() failed!\n");
2114 goto cleanup;
2115 }
2116
2117 /* Fill the new CREATESTRUCTW */
2118 RtlCopyMemory(pCsw, Cs, sizeof(CREATESTRUCTW));
2119 pCsw->style = Window->style; /* HCBT_CREATEWND needs the real window style */
2120
2121 // Based on the assumption this is from "unicode source" user32, ReactOS, answer is yes.
2122 if (!IS_ATOM(ClassName->Buffer))
2123 {
2124 if (Window->state & WNDS_ANSICREATOR)
2125 {
2126 ANSI_STRING AnsiString;
2127 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(ClassName)+sizeof(CHAR);
2128 pszClass = UserHeapAlloc(AnsiString.MaximumLength);
2129 if (!pszClass)
2130 {
2131 ERR("UserHeapAlloc() failed!\n");
2132 goto cleanup;
2133 }
2134 RtlZeroMemory(pszClass, AnsiString.MaximumLength);
2135 AnsiString.Buffer = (PCHAR)pszClass;
2136 RtlUnicodeStringToAnsiString(&AnsiString, ClassName, FALSE);
2137 }
2138 else
2139 {
2140 UNICODE_STRING UnicodeString;
2141 UnicodeString.MaximumLength = ClassName->Length + sizeof(UNICODE_NULL);
2142 pszClass = UserHeapAlloc(UnicodeString.MaximumLength);
2143 if (!pszClass)
2144 {
2145 ERR("UserHeapAlloc() failed!\n");
2146 goto cleanup;
2147 }
2148 RtlZeroMemory(pszClass, UnicodeString.MaximumLength);
2149 UnicodeString.Buffer = (PWSTR)pszClass;
2150 RtlCopyUnicodeString(&UnicodeString, ClassName);
2151 }
2152 pCsw->lpszClass = UserHeapAddressToUser(pszClass);
2153 }
2154 if (WindowName->Length)
2155 {
2156 UNICODE_STRING Name;
2157 Name.Buffer = WindowName->Buffer;
2158 Name.Length = (USHORT)min(WindowName->Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2159 Name.MaximumLength = (USHORT)min(WindowName->MaximumLength, MAXUSHORT);
2160
2161 if (Window->state & WNDS_ANSICREATOR)
2162 {
2163 ANSI_STRING AnsiString;
2164 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(&Name) + sizeof(CHAR);
2165 pszName = UserHeapAlloc(AnsiString.MaximumLength);
2166 if (!pszName)
2167 {
2168 ERR("UserHeapAlloc() failed!\n");
2169 goto cleanup;
2170 }
2171 RtlZeroMemory(pszName, AnsiString.MaximumLength);
2172 AnsiString.Buffer = (PCHAR)pszName;
2173 RtlUnicodeStringToAnsiString(&AnsiString, &Name, FALSE);
2174 }
2175 else
2176 {
2177 UNICODE_STRING UnicodeString;
2178 UnicodeString.MaximumLength = Name.Length + sizeof(UNICODE_NULL);
2179 pszName = UserHeapAlloc(UnicodeString.MaximumLength);
2180 if (!pszName)
2181 {
2182 ERR("UserHeapAlloc() failed!\n");
2183 goto cleanup;
2184 }
2185 RtlZeroMemory(pszName, UnicodeString.MaximumLength);
2186 UnicodeString.Buffer = (PWSTR)pszName;
2187 RtlCopyUnicodeString(&UnicodeString, &Name);
2188 }
2189 pCsw->lpszName = UserHeapAddressToUser(pszName);
2190 }
2191
2192 pCbtCreate->lpcs = pCsw;
2193 pCbtCreate->hwndInsertAfter = hwndInsertAfter;
2194
2195 //// Call the WH_CBT hook ////
2196 Result = co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) pCbtCreate);
2197 if (Result != 0)
2198 {
2199 ERR("WH_CBT HCBT_CREATEWND hook failed! 0x%x\n", Result);
2200 goto cleanup;
2201 }
2202 // Write back changes.
2203 Cs->cx = pCsw->cx;
2204 Cs->cy = pCsw->cy;
2205 Cs->x = pCsw->x;
2206 Cs->y = pCsw->y;
2207 hwndInsertAfter = pCbtCreate->hwndInsertAfter;
2208 }
2209
2210 /* NCCREATE and WM_NCCALCSIZE need the original values */
2211 Cs->lpszName = (LPCWSTR) WindowName;
2212 Cs->lpszClass = (LPCWSTR) ClassName;
2213
2214 if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2215 {
2216 if (ParentWindow != co_GetDesktopWindow(Window))
2217 {
2218 Cs->x += ParentWindow->rcClient.left;
2219 Cs->y += ParentWindow->rcClient.top;
2220 }
2221 }
2222
2223 /* Send the WM_GETMINMAXINFO message */
2224 Size.cx = Cs->cx;
2225 Size.cy = Cs->cy;
2226
2227 if ((Cs->style & WS_THICKFRAME) || !(Cs->style & (WS_POPUP | WS_CHILD)))
2228 {
2229 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
2230 if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
2231 if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
2232 if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
2233 if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
2234 }
2235
2236 Window->rcWindow.left = Cs->x;
2237 Window->rcWindow.top = Cs->y;
2238 Window->rcWindow.right = Cs->x + Size.cx;
2239 Window->rcWindow.bottom = Cs->y + Size.cy;
2240 /*
2241 if (0 != (Window->style & WS_CHILD) && ParentWindow)
2242 {
2243 ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
2244 RECTL_vOffsetRect(&Window->rcWindow,
2245 ParentWindow->rcClient.left,
2246 ParentWindow->rcClient.top);
2247 }
2248 */
2249 /* correct child window coordinates if mirroring on parent is enabled */
2250 if (ParentWindow != NULL)
2251 {
2252 if ( ((Cs->style & WS_CHILD) == WS_CHILD) &&
2253 ((ParentWindow->ExStyle & WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL))
2254 {
2255 Window->rcWindow.right = ParentWindow->rcClient.right - (Window->rcWindow.left - ParentWindow->rcClient.left);
2256 Window->rcWindow.left = Window->rcWindow.right - Size.cx;
2257 }
2258 }
2259
2260 Window->rcClient = Window->rcWindow;
2261
2262 /* Link the window */
2263 if (NULL != ParentWindow)
2264 {
2265 /* Link the window into the siblings list */
2266 if ((Cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2267 IntLinkHwnd(Window, HWND_BOTTOM);
2268 else
2269 IntLinkHwnd(Window, hwndInsertAfter);
2270 }
2271
2272 if (!(Window->state2 & WNDS2_WIN31COMPAT))
2273 {
2274 if (Class->style & CS_PARENTDC && !(ParentWindow->style & WS_CLIPCHILDREN))
2275 Window->style &= ~(WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
2276 }
2277
2278 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2279 {
2280 if ( !IntIsTopLevelWindow(Window) )
2281 {
2282 if (pti != Window->spwndParent->head.pti)
2283 {
2284 //ERR("CreateWindow Parent in.\n");
2285 UserAttachThreadInput(pti, Window->spwndParent->head.pti, TRUE);
2286 }
2287 }
2288 }
2289
2290 /* Send the NCCREATE message */
2291 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_NCCREATE, 0, (LPARAM) Cs);
2292 if (!Result)
2293 {
2294 ERR("co_UserCreateWindowEx(): NCCREATE message failed\n");
2295 goto cleanup;
2296 }
2297
2298 /* Send the WM_NCCALCSIZE message */
2299 {
2300 // RECT rc;
2301 MaxPos.x = Window->rcWindow.left;
2302 MaxPos.y = Window->rcWindow.top;
2303
2304 Result = co_WinPosGetNonClientSize(Window, &Window->rcWindow, &Window->rcClient);
2305 //rc = Window->rcWindow;
2306 //Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM)&rc);
2307 //Window->rcClient = rc;
2308
2309 RECTL_vOffsetRect(&Window->rcWindow, MaxPos.x - Window->rcWindow.left,
2310 MaxPos.y - Window->rcWindow.top);
2311 }
2312
2313 /* Send the WM_CREATE message. */
2314 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_CREATE, 0, (LPARAM) Cs);
2315 if (Result == (LRESULT)-1)
2316 {
2317 ERR("co_UserCreateWindowEx(): WM_CREATE message failed\n");
2318 goto cleanup;
2319 }
2320
2321 /* Send the EVENT_OBJECT_CREATE event */
2322 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2323
2324 /* By setting the flag below it can be examined to determine if the window
2325 was created successfully and a valid pwnd was passed back to caller since
2326 from here the function has to succeed. */
2327 Window->state2 |= WNDS2_WMCREATEMSGPROCESSED;
2328
2329 /* Send the WM_SIZE and WM_MOVE messages. */
2330 if (!(Window->state & WNDS_SENDSIZEMOVEMSGS))
2331 {
2332 co_WinPosSendSizeMove(Window);
2333 }
2334
2335 /* Show or maybe minimize or maximize the window. */
2336
2337 style = IntSetStyle( Window, 0, WS_MAXIMIZE | WS_MINIMIZE );
2338 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2339 {
2340 RECTL NewPos;
2341 UINT SwFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
2342
2343 SwFlag = co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2344 SwFlag |= SWP_NOZORDER|SWP_FRAMECHANGED; /* Frame always gets changed */
2345 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || UserGetActiveWindow()) SwFlag |= SWP_NOACTIVATE;
2346 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2347 NewPos.right, NewPos.bottom, SwFlag);
2348 }
2349
2350 /* Send the WM_PARENTNOTIFY message */
2351 IntSendParentNotify(Window, WM_CREATE);
2352
2353 /* Notify the shell that a new window was created */
2354 if (UserIsDesktopWindow(Window->spwndParent) &&
2355 Window->spwndOwner == NULL &&
2356 (Window->style & WS_VISIBLE) &&
2357 (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
2358 (Window->ExStyle & WS_EX_APPWINDOW)))
2359 {
2360 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0);
2361 }
2362
2363 /* Initialize and show the window's scrollbars */
2364 if (Window->style & WS_VSCROLL)
2365 {
2366 co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE);
2367 }
2368 if (Window->style & WS_HSCROLL)
2369 {
2370 co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE);
2371 }
2372
2373 /* Show the new window */
2374 if (Cs->style & WS_VISIBLE)
2375 {
2376 if (Window->style & WS_MAXIMIZE)
2377 dwShowMode = SW_SHOW;
2378 else if (Window->style & WS_MINIMIZE)
2379 dwShowMode = SW_SHOWMINIMIZED;
2380
2381 co_WinPosShowWindow(Window, dwShowMode);
2382
2383 if (Window->ExStyle & WS_EX_MDICHILD)
2384 {
2385 ASSERT(ParentWindow);
2386 if(!ParentWindow)
2387 goto cleanup;
2388 co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0);
2389 /* ShowWindow won't activate child windows */
2390 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2391 }
2392 }
2393
2394 if (Class->atomClassName == gaGuiConsoleWndClass)
2395 {
2396 /* Count only console windows manually */
2397 co_IntUserManualGuiCheck(TRUE);
2398 }
2399
2400 TRACE("co_UserCreateWindowEx(): Created window %p\n", hWnd);
2401 ret = Window;
2402
2403 cleanup:
2404 if (!ret)
2405 {
2406 TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2407 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2408 if (Window)
2409 co_UserDestroyWindow(Window);
2410 else if (Class)
2411 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2412 }
2413
2414 if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
2415 if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
2416 if (pszName) UserHeapFree(pszName);
2417 if (pszClass) UserHeapFree(pszClass);
2418
2419 if (Window)
2420 {
2421 UserDerefObjectCo(Window);
2422 }
2423 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2424
2425 // See CORE-13717, not setting error on success.
2426 if (ret)
2427 EngSetLastError(ERROR_SUCCESS);
2428
2429 return ret;
2430 }
2431
2432 NTSTATUS
2433 NTAPI
2434 ProbeAndCaptureLargeString(
2435 OUT PLARGE_STRING plstrSafe,
2436 IN PLARGE_STRING plstrUnsafe)
2437 {
2438 LARGE_STRING lstrTemp;
2439 PVOID pvBuffer = NULL;
2440
2441 _SEH2_TRY
2442 {
2443 /* Probe and copy the string */
2444 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2445 lstrTemp = *plstrUnsafe;
2446 }
2447 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2448 {
2449 /* Fail */
2450 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2451 }
2452 _SEH2_END
2453
2454 if (lstrTemp.Length != 0)
2455 {
2456 /* Allocate a buffer from paged pool */
2457 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2458 if (!pvBuffer)
2459 {
2460 return STATUS_NO_MEMORY;
2461 }
2462
2463 _SEH2_TRY
2464 {
2465 /* Probe and copy the buffer */
2466 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2467 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2468 }
2469 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2470 {
2471 /* Cleanup and fail */
2472 ExFreePoolWithTag(pvBuffer, TAG_STRING);
2473 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2474 }
2475 _SEH2_END
2476 }
2477
2478 /* Set the output string */
2479 plstrSafe->Buffer = pvBuffer;
2480 plstrSafe->Length = lstrTemp.Length;
2481 plstrSafe->MaximumLength = lstrTemp.Length;
2482
2483 return STATUS_SUCCESS;
2484 }
2485
2486 /**
2487 * \todo Allow passing plstrClassName as ANSI.
2488 */
2489 HWND
2490 NTAPI
2491 NtUserCreateWindowEx(
2492 DWORD dwExStyle,
2493 PLARGE_STRING plstrClassName,
2494 PLARGE_STRING plstrClsVersion,
2495 PLARGE_STRING plstrWindowName,
2496 DWORD dwStyle,
2497 int x,
2498 int y,
2499 int nWidth,
2500 int nHeight,
2501 HWND hWndParent,
2502 HMENU hMenu,
2503 HINSTANCE hInstance,
2504 LPVOID lpParam,
2505 DWORD dwFlags,
2506 PVOID acbiBuffer)
2507 {
2508 NTSTATUS Status;
2509 LARGE_STRING lstrWindowName;
2510 LARGE_STRING lstrClassName;
2511 LARGE_STRING lstrClsVersion;
2512 UNICODE_STRING ustrClassName;
2513 UNICODE_STRING ustrClsVersion;
2514 CREATESTRUCTW Cs;
2515 HWND hwnd = NULL;
2516 PWND pwnd;
2517
2518 lstrWindowName.Buffer = NULL;
2519 lstrClassName.Buffer = NULL;
2520 lstrClsVersion.Buffer = NULL;
2521
2522 ASSERT(plstrWindowName);
2523
2524 if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2525 {
2526 /* check hMenu is valid handle */
2527 if (hMenu && !UserGetMenuObject(hMenu))
2528 {
2529 ERR("NtUserCreateWindowEx: Got an invalid menu handle!\n");
2530 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
2531 return NULL;
2532 }
2533 }
2534
2535 /* Copy the window name to kernel mode */
2536 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2537 if (!NT_SUCCESS(Status))
2538 {
2539 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2540 SetLastNtError(Status);
2541 return NULL;
2542 }
2543
2544 plstrWindowName = &lstrWindowName;
2545
2546 /* Check if the class is an atom */
2547 if (IS_ATOM(plstrClassName))
2548 {
2549 /* It is, pass the atom in the UNICODE_STRING */
2550 ustrClassName.Buffer = (PVOID)plstrClassName;
2551 ustrClassName.Length = 0;
2552 ustrClassName.MaximumLength = 0;
2553 }
2554 else
2555 {
2556 /* It's not, capture the class name */
2557 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2558 if (!NT_SUCCESS(Status))
2559 {
2560 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2561 /* Set last error, cleanup and return */
2562 SetLastNtError(Status);
2563 goto cleanup;
2564 }
2565
2566 /* We pass it on as a UNICODE_STRING */
2567 ustrClassName.Buffer = lstrClassName.Buffer;
2568 ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2569 ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
2570 }
2571
2572 /* Check if the class version is an atom */
2573 if (IS_ATOM(plstrClsVersion))
2574 {
2575 /* It is, pass the atom in the UNICODE_STRING */
2576 ustrClsVersion.Buffer = (PVOID)plstrClsVersion;
2577 ustrClsVersion.Length = 0;
2578 ustrClsVersion.MaximumLength = 0;
2579 }
2580 else
2581 {
2582 /* It's not, capture the class name */
2583 Status = ProbeAndCaptureLargeString(&lstrClsVersion, plstrClsVersion);
2584 if (!NT_SUCCESS(Status))
2585 {
2586 ERR("NtUserCreateWindowEx: failed to capture plstrClsVersion\n");
2587 /* Set last error, cleanup and return */
2588 SetLastNtError(Status);
2589 goto cleanup;
2590 }
2591
2592 /* We pass it on as a UNICODE_STRING */
2593 ustrClsVersion.Buffer = lstrClsVersion.Buffer;
2594 ustrClsVersion.Length = (USHORT)min(lstrClsVersion.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2595 ustrClsVersion.MaximumLength = (USHORT)min(lstrClsVersion.MaximumLength, MAXUSHORT);
2596 }
2597
2598 /* Fill the CREATESTRUCTW */
2599 /* we will keep here the original parameters */
2600 Cs.style = dwStyle;
2601 Cs.lpCreateParams = lpParam;
2602 Cs.hInstance = hInstance;
2603 Cs.hMenu = hMenu;
2604 Cs.hwndParent = hWndParent;
2605 Cs.cx = nWidth;
2606 Cs.cy = nHeight;
2607 Cs.x = x;
2608 Cs.y = y;
2609 Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
2610 Cs.lpszClass = ustrClassName.Buffer;
2611 Cs.dwExStyle = dwExStyle;
2612
2613 UserEnterExclusive();
2614
2615 /* Call the internal function */
2616 pwnd = co_UserCreateWindowEx(&Cs, &ustrClsVersion, plstrWindowName, acbiBuffer, dwFlags);
2617
2618 if(!pwnd)
2619 {
2620 ERR("co_UserCreateWindowEx failed!\n");
2621 }
2622 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2623
2624 UserLeave();
2625
2626 cleanup:
2627 if (lstrWindowName.Buffer)
2628 {
2629 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2630 }
2631 if (lstrClassName.Buffer)
2632 {
2633 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2634 }
2635 if (lstrClsVersion.Buffer)
2636 {
2637 ExFreePoolWithTag(lstrClsVersion.Buffer, TAG_STRING);
2638 }
2639
2640 return hwnd;
2641 }
2642
2643
2644 BOOLEAN co_UserDestroyWindow(PVOID Object)
2645 {
2646 HWND hWnd;
2647 PWND pwndTemp;
2648 PTHREADINFO ti;
2649 MSG msg;
2650 PWND Window = Object;
2651
2652 ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
2653
2654 hWnd = Window->head.h;
2655 ti = PsGetCurrentThreadWin32Thread();
2656
2657 TRACE("co_UserDestroyWindow(Window = 0x%p, hWnd = 0x%p)\n", Window, hWnd);
2658
2659 /* Check for owner thread */
2660 if ( Window->head.pti != PsGetCurrentThreadWin32Thread())
2661 {
2662 /* Check if we are destroying the desktop window */
2663 if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
2664 {
2665 EngSetLastError(ERROR_ACCESS_DENIED);
2666 return FALSE;
2667 }
2668 }
2669
2670 /* If window was created successfully and it is hooked */
2671 if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
2672 {
2673 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0))
2674 {
2675 ERR("Destroy Window WH_CBT Call Hook return!\n");
2676 return FALSE;
2677 }
2678 }
2679
2680 if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
2681 {
2682 if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2683 {
2684 if (Window->spwndOwner)
2685 {
2686 //ERR("DestroyWindow Owner out.\n");
2687 UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2688 }
2689 }
2690 }
2691
2692 /* Inform the parent */
2693 if (Window->style & WS_CHILD)
2694 {
2695 IntSendParentNotify(Window, WM_DESTROY);
2696 }
2697
2698 if (!Window->spwndOwner && !IntGetParent(Window))
2699 {
2700 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM) hWnd, 0);
2701 }
2702
2703 /* Hide the window */
2704 if (Window->style & WS_VISIBLE)
2705 {
2706 if (Window->style & WS_CHILD)
2707 {
2708 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
2709 co_WinPosShowWindow(Window, SW_HIDE);
2710 }
2711 else
2712 {
2713 co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_HIDEWINDOW );
2714 }
2715 }
2716
2717 /* Adjust last active */
2718 if ((pwndTemp = Window->spwndOwner))
2719 {
2720 while (pwndTemp->spwndOwner)
2721 pwndTemp = pwndTemp->spwndOwner;
2722
2723 if (pwndTemp->spwndLastActive == Window)
2724 pwndTemp->spwndLastActive = Window->spwndOwner;
2725 }
2726
2727 if (Window->spwndParent && IntIsWindow(UserHMGetHandle(Window)))
2728 {
2729 if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
2730 {
2731 if (!IntIsTopLevelWindow(Window))
2732 {
2733 //ERR("DestroyWindow Parent out.\n");
2734 UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2735 }
2736 }
2737 }
2738
2739 if (Window->head.pti->MessageQueue->spwndActive == Window)
2740 Window->head.pti->MessageQueue->spwndActive = NULL;
2741 if (Window->head.pti->MessageQueue->spwndFocus == Window)
2742 Window->head.pti->MessageQueue->spwndFocus = NULL;
2743 if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
2744 Window->head.pti->MessageQueue->spwndActivePrev = NULL;
2745 if (Window->head.pti->MessageQueue->spwndCapture == Window)
2746 Window->head.pti->MessageQueue->spwndCapture = NULL;
2747
2748 /*
2749 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2750 */
2751
2752 if ((ti != NULL) && (ti->pDeskInfo != NULL))
2753 {
2754 if (ti->pDeskInfo->hShellWindow == hWnd)
2755 {
2756 ERR("Destroying the ShellWindow!\n");
2757 ti->pDeskInfo->hShellWindow = NULL;
2758 }
2759 }
2760
2761 IntEngWindowChanged(Window, WOC_DELETE);
2762
2763 if (!IntIsWindow(UserHMGetHandle(Window)))
2764 {
2765 return TRUE;
2766 }
2767
2768 /* Recursively destroy owned windows */
2769 if (!(Window->style & WS_CHILD))
2770 {
2771 HWND* List;
2772 HWND* phWnd;
2773 PWND pWnd;
2774
2775 List = IntWinListOwnedPopups(Window);
2776 if (List)
2777 {
2778 for (phWnd = List; *phWnd; ++phWnd)
2779 {
2780 pWnd = ValidateHwndNoErr(*phWnd);
2781 if (pWnd == NULL)
2782 continue;
2783 ASSERT(pWnd->spwndOwner == Window);
2784 ASSERT(pWnd != Window);
2785
2786 pWnd->spwndOwner = NULL;
2787 if (IntWndBelongsToThread(pWnd, PsGetCurrentThreadWin32Thread()))
2788 {
2789 USER_REFERENCE_ENTRY Ref;
2790 UserRefObjectCo(pWnd, &Ref); // Temp HACK?
2791 co_UserDestroyWindow(pWnd);
2792 UserDerefObjectCo(pWnd); // Temp HACK?
2793 }
2794 else
2795 {
2796 ERR("IntWndBelongsToThread(0x%p) is FALSE, ignoring.\n", pWnd);
2797 }
2798 }
2799
2800 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2801 }
2802 }
2803
2804 /* Generate mouse move message for the next window */
2805 msg.message = WM_MOUSEMOVE;
2806 msg.wParam = UserGetMouseButtonsState();
2807 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2808 msg.pt = gpsi->ptCursor;
2809 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2810
2811 IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2812
2813 /* Send destroy messages */
2814 IntSendDestroyMsg(UserHMGetHandle(Window));
2815
2816 if (!IntIsWindow(UserHMGetHandle(Window)))
2817 {
2818 return TRUE;
2819 }
2820
2821 /* Destroy the window storage */
2822 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2823
2824 return TRUE;
2825 }
2826
2827
2828 /*
2829 * @implemented
2830 */
2831 BOOLEAN APIENTRY
2832 NtUserDestroyWindow(HWND Wnd)
2833 {
2834 PWND Window;
2835 DECLARE_RETURN(BOOLEAN);
2836 BOOLEAN ret;
2837 USER_REFERENCE_ENTRY Ref;
2838
2839 TRACE("Enter NtUserDestroyWindow\n");
2840 UserEnterExclusive();
2841
2842 if (!(Window = UserGetWindowObject(Wnd)))
2843 {
2844 RETURN(FALSE);
2845 }
2846
2847 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
2848 ret = co_UserDestroyWindow(Window);
2849 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
2850
2851 RETURN(ret);
2852
2853 CLEANUP:
2854 TRACE("Leave NtUserDestroyWindow, ret=%u\n", _ret_);
2855 UserLeave();
2856 END_CLEANUP;
2857 }
2858
2859
2860 static HWND FASTCALL
2861 IntFindWindow(PWND Parent,
2862 PWND ChildAfter,
2863 RTL_ATOM ClassAtom,
2864 PUNICODE_STRING WindowName)
2865 {
2866 BOOL CheckWindowName;
2867 HWND *List, *phWnd;
2868 HWND Ret = NULL;
2869 UNICODE_STRING CurrentWindowName;
2870
2871 ASSERT(Parent);
2872
2873 CheckWindowName = WindowName->Buffer != 0;
2874
2875 if((List = IntWinListChildren(Parent)))
2876 {
2877 phWnd = List;
2878 if(ChildAfter)
2879 {
2880 /* skip handles before and including ChildAfter */
2881 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2882 ;
2883 }
2884
2885 /* search children */
2886 while(*phWnd)
2887 {
2888 PWND Child;
2889 if(!(Child = UserGetWindowObject(*(phWnd++))))
2890 {
2891 continue;
2892 }
2893
2894 /* Do not send WM_GETTEXT messages in the kernel mode version!
2895 The user mode version however calls GetWindowText() which will
2896 send WM_GETTEXT messages to windows belonging to its processes */
2897 if (!ClassAtom || Child->pcls->atomNVClassName == ClassAtom)
2898 {
2899 // FIXME: LARGE_STRING truncated
2900 CurrentWindowName.Buffer = Child->strName.Buffer;
2901 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
2902 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
2903 if(!CheckWindowName ||
2904 (Child->strName.Length < 0xFFFF &&
2905 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
2906 {
2907 Ret = Child->head.h;
2908 break;
2909 }
2910 }
2911 }
2912 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2913 }
2914
2915 return Ret;
2916 }
2917
2918 /*
2919 * FUNCTION:
2920 * Searches a window's children for a window with the specified
2921 * class and name
2922 * ARGUMENTS:
2923 * hwndParent = The window whose childs are to be searched.
2924 * NULL = desktop
2925 * HWND_MESSAGE = message-only windows
2926 *
2927 * hwndChildAfter = Search starts after this child window.
2928 * NULL = start from beginning
2929 *
2930 * ucClassName = Class name to search for
2931 * Reguired parameter.
2932 *
2933 * ucWindowName = Window name
2934 * ->Buffer == NULL = don't care
2935 *
2936 * RETURNS:
2937 * The HWND of the window if it was found, otherwise NULL
2938 */
2939 /*
2940 * @implemented
2941 */
2942 HWND APIENTRY
2943 NtUserFindWindowEx(HWND hwndParent,
2944 HWND hwndChildAfter,
2945 PUNICODE_STRING ucClassName,
2946 PUNICODE_STRING ucWindowName,
2947 DWORD dwUnknown)
2948 {
2949 PWND Parent, ChildAfter;
2950 UNICODE_STRING ClassName = {0}, WindowName = {0};
2951 HWND Desktop, Ret = NULL;
2952 BOOL DoMessageWnd = FALSE;
2953 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2954 DECLARE_RETURN(HWND);
2955
2956 TRACE("Enter NtUserFindWindowEx\n");
2957 UserEnterShared();
2958
2959 if (ucClassName != NULL || ucWindowName != NULL)
2960 {
2961 _SEH2_TRY
2962 {
2963 if (ucClassName != NULL)
2964 {
2965 ClassName = ProbeForReadUnicodeString(ucClassName);
2966 if (ClassName.Length != 0)
2967 {
2968 ProbeForRead(ClassName.Buffer,
2969 ClassName.Length,
2970 sizeof(WCHAR));
2971 }
2972 else if (!IS_ATOM(ClassName.Buffer))
2973 {
2974 EngSetLastError(ERROR_INVALID_PARAMETER);
2975 _SEH2_LEAVE;
2976 }
2977
2978 if (!IntGetAtomFromStringOrAtom(&ClassName,
2979 &ClassAtom))
2980 {
2981 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS);
2982 _SEH2_LEAVE;
2983 }
2984 }
2985
2986 if (ucWindowName != NULL)
2987 {
2988 WindowName = ProbeForReadUnicodeString(ucWindowName);
2989 if (WindowName.Length != 0)
2990 {
2991 ProbeForRead(WindowName.Buffer,
2992 WindowName.Length,
2993 sizeof(WCHAR));
2994 }
2995 }
2996 }
2997 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2998 {
2999 SetLastNtError(_SEH2_GetExceptionCode());
3000 _SEH2_YIELD(RETURN(NULL));
3001 }
3002 _SEH2_END;
3003
3004 if (ucClassName != NULL)
3005 {
3006 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
3007 !IS_ATOM(ClassName.Buffer))
3008 {
3009 EngSetLastError(ERROR_INVALID_PARAMETER);
3010 RETURN(NULL);
3011 }
3012 else if (ClassAtom == (RTL_ATOM)0)
3013 {
3014 /* LastError code was set by IntGetAtomFromStringOrAtom */
3015 RETURN(NULL);
3016 }
3017 }
3018 }
3019
3020 Desktop = IntGetCurrentThreadDesktopWindow();
3021
3022 if(hwndParent == NULL)
3023 {
3024 hwndParent = Desktop;
3025 DoMessageWnd = TRUE;
3026 }
3027 else if(hwndParent == HWND_MESSAGE)
3028 {
3029 hwndParent = IntGetMessageWindow();
3030 }
3031
3032 if(!(Parent = UserGetWindowObject(hwndParent)))
3033 {
3034 RETURN( NULL);
3035 }
3036
3037 ChildAfter = NULL;
3038 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
3039 {
3040 RETURN( NULL);
3041 }
3042
3043 _SEH2_TRY
3044 {
3045 if(Parent->head.h == Desktop)
3046 {
3047 HWND *List, *phWnd;
3048 PWND TopLevelWindow;
3049 BOOLEAN CheckWindowName;
3050 BOOLEAN WindowMatches;
3051 BOOLEAN ClassMatches;
3052
3053 /* windows searches through all top-level windows if the parent is the desktop
3054 window */
3055
3056 if((List = IntWinListChildren(Parent)))
3057 {
3058 phWnd = List;
3059
3060 if(ChildAfter)
3061 {
3062 /* skip handles before and including ChildAfter */
3063 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
3064 ;
3065 }
3066
3067 CheckWindowName = WindowName.Buffer != 0;
3068
3069 /* search children */
3070 while(*phWnd)
3071 {
3072 UNICODE_STRING ustr;
3073
3074 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
3075 {
3076 continue;
3077 }
3078
3079 /* Do not send WM_GETTEXT messages in the kernel mode version!
3080 The user mode version however calls GetWindowText() which will
3081 send WM_GETTEXT messages to windows belonging to its processes */
3082 ustr.Buffer = TopLevelWindow->strName.Buffer;
3083 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
3084 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
3085 WindowMatches = !CheckWindowName ||
3086 (TopLevelWindow->strName.Length < 0xFFFF &&
3087 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
3088 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
3089 ClassAtom == TopLevelWindow->pcls->atomNVClassName;
3090
3091 if (WindowMatches && ClassMatches)
3092 {
3093 Ret = TopLevelWindow->head.h;
3094 break;
3095 }
3096
3097 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
3098 {
3099 /* window returns the handle of the top-level window, in case it found
3100 the child window */
3101 Ret = TopLevelWindow->head.h;
3102 break;
3103 }
3104
3105 }
3106 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
3107 }
3108 }
3109 else
3110 {
3111 TRACE("FindWindowEx: Not Desktop Parent!\n");
3112 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
3113 }
3114
3115 if (Ret == NULL && DoMessageWnd)
3116 {
3117 PWND MsgWindows;
3118
3119 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3120 {
3121 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3122 }
3123 }
3124 }
3125 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3126 {
3127 SetLastNtError(_SEH2_GetExceptionCode());
3128 Ret = NULL;
3129 }
3130 _SEH2_END;
3131
3132 RETURN( Ret);
3133
3134 CLEANUP:
3135 TRACE("Leave NtUserFindWindowEx, ret %p\n", _ret_);
3136 UserLeave();
3137 END_CLEANUP;
3138 }
3139
3140
3141 /*
3142 * @implemented
3143 */
3144 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
3145 {
3146 PWND WndAncestor, Parent;
3147
3148 if (Wnd->head.h == IntGetDesktopWindow())
3149 {
3150 return NULL;
3151 }
3152
3153 switch (Type)
3154 {
3155 case GA_PARENT:
3156 {
3157 WndAncestor = Wnd->spwndParent;
3158 break;
3159 }
3160
3161 case GA_ROOT:
3162 {
3163 WndAncestor = Wnd;
3164 Parent = NULL;
3165
3166 for(;;)
3167 {
3168 if(!(Parent = WndAncestor->spwndParent))
3169 {
3170 break;
3171 }
3172 if(IntIsDesktopWindow(Parent))
3173 {
3174 break;
3175 }
3176
3177 WndAncestor = Parent;
3178 }
3179 break;
3180 }
3181
3182 case GA_ROOTOWNER:
3183 {
3184 WndAncestor = Wnd;
3185
3186 for (;;)
3187 {
3188 Parent = IntGetParent(WndAncestor);
3189
3190 if (!Parent)
3191 {
3192 break;
3193 }
3194
3195 WndAncestor = Parent;
3196 }
3197 break;
3198 }
3199
3200 default:
3201 {
3202 return NULL;
3203 }
3204 }
3205
3206 return WndAncestor;
3207 }
3208
3209 /*
3210 * @implemented
3211 */
3212 HWND APIENTRY
3213 NtUserGetAncestor(HWND hWnd, UINT Type)
3214 {
3215 PWND Window, Ancestor;
3216 DECLARE_RETURN(HWND);
3217
3218 TRACE("Enter NtUserGetAncestor\n");
3219 UserEnterExclusive();
3220
3221 if (!(Window = UserGetWindowObject(hWnd)))
3222 {
3223 RETURN(NULL);
3224 }
3225
3226 Ancestor = UserGetAncestor(Window, Type);
3227 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3228
3229 RETURN(Ancestor ? Ancestor->head.h : NULL);
3230
3231 CLEANUP:
3232 TRACE("Leave NtUserGetAncestor, ret=%p\n", _ret_);
3233 UserLeave();
3234 END_CLEANUP;
3235 }
3236
3237 ////
3238 //// ReactOS work around! Keep it the sames as in Combo.c and Controls.h
3239 ////
3240 /* combo state struct */
3241 typedef struct
3242 {
3243 HWND self;
3244 HWND owner;
3245 UINT dwStyle;
3246 HWND hWndEdit;
3247 HWND hWndLBox;
3248 UINT wState;
3249 HFONT hFont;
3250 RECT textRect;
3251 RECT buttonRect;
3252 RECT droppedRect;
3253 INT droppedIndex;
3254 INT fixedOwnerDrawHeight;
3255 INT droppedWidth; /* last two are not used unless set */
3256 INT editHeight; /* explicitly */
3257 LONG UIState;
3258 } HEADCOMBO,*LPHEADCOMBO;
3259
3260 // Window Extra data container.
3261 typedef struct _WND2CBOX
3262 {
3263 WND;
3264 LPHEADCOMBO pCBox;
3265 } WND2CBOX, *PWND2CBOX;
3266
3267 #define CBF_BUTTONDOWN 0x0002
3268 ////
3269 ////
3270 ////
3271 BOOL
3272 APIENTRY
3273 NtUserGetComboBoxInfo(
3274 HWND hWnd,
3275 PCOMBOBOXINFO pcbi)
3276 {
3277 PWND Wnd;
3278 PPROCESSINFO ppi;
3279 BOOL NotSameppi = FALSE;
3280 BOOL Ret = TRUE;
3281 DECLARE_RETURN(BOOL);
3282
3283 TRACE("Enter NtUserGetComboBoxInfo\n");
3284 UserEnterShared();
3285
3286 if (!(Wnd = UserGetWindowObject(hWnd)))
3287 {
3288 RETURN( FALSE );
3289 }
3290 _SEH2_TRY
3291 {
3292 ProbeForWrite(pcbi, sizeof(COMBOBOXINFO), 1);
3293 }
3294 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3295 {
3296 SetLastNtError(_SEH2_GetExceptionCode());
3297 _SEH2_YIELD(RETURN(FALSE));
3298 }
3299 _SEH2_END;
3300
3301 if (pcbi->cbSize < sizeof(COMBOBOXINFO))
3302 {
3303 EngSetLastError(ERROR_INVALID_PARAMETER);
3304 RETURN(FALSE);
3305 }
3306
3307 // Pass the user pointer, it was already probed.
3308 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_COMBOBOX]) && Wnd->fnid != FNID_COMBOBOX)
3309 {
3310 RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3311 }
3312
3313 ppi = PsGetCurrentProcessWin32Process();
3314 NotSameppi = ppi != Wnd->head.pti->ppi;
3315 if (NotSameppi)
3316 {
3317 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3318 }
3319
3320 _SEH2_TRY
3321 {
3322 LPHEADCOMBO lphc = ((PWND2CBOX)Wnd)->pCBox;
3323 pcbi->rcItem = lphc->textRect;
3324 pcbi->rcButton = lphc->buttonRect;
3325 pcbi->stateButton = 0;
3326 if (lphc->wState & CBF_BUTTONDOWN)
3327 pcbi->stateButton |= STATE_SYSTEM_PRESSED;
3328 if (RECTL_bIsEmptyRect(&lphc->buttonRect))
3329 pcbi->stateButton |= STATE_SYSTEM_INVISIBLE;
3330 pcbi->hwndCombo = lphc->self;
3331 pcbi->hwndItem = lphc->hWndEdit;
3332 pcbi->hwndList = lphc->hWndLBox;
3333 }
3334 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3335 {
3336 Ret = FALSE;
3337 SetLastNtError(_SEH2_GetExceptionCode());
3338 }
3339 _SEH2_END;
3340
3341 RETURN( Ret);
3342
3343 CLEANUP:
3344 if (NotSameppi) KeDetachProcess();
3345 TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3346 UserLeave();
3347 END_CLEANUP;
3348 }
3349
3350 ////
3351 //// ReactOS work around! Keep it the sames as in Listbox.c
3352 ////
3353 /* Listbox structure */
3354 typedef struct
3355 {
3356 HWND self; /* Our own window handle */
3357 HWND owner; /* Owner window to send notifications to */
3358 UINT style; /* Window style */
3359 INT width; /* Window width */
3360 INT height; /* Window height */
3361 VOID *items; /* Array of items */
3362 INT nb_items; /* Number of items */
3363 INT top_item; /* Top visible item */
3364 INT selected_item; /* Selected item */
3365 INT focus_item; /* Item that has the focus */
3366 INT anchor_item; /* Anchor item for extended selection */
3367 INT item_height; /* Default item height */
3368 INT page_size; /* Items per listbox page */
3369 INT column_width; /* Column width for multi-column listboxes */
3370 } LB_DESCR;
3371
3372 // Window Extra data container.
3373 typedef struct _WND2LB
3374 {
3375 WND;
3376 LB_DESCR * pLBiv;
3377 } WND2LB, *PWND2LB;
3378 ////
3379 ////
3380 ////
3381 DWORD
3382 APIENTRY
3383 NtUserGetListBoxInfo(
3384 HWND hWnd)
3385 {
3386 PWND Wnd;
3387 PPROCESSINFO ppi;
3388 BOOL NotSameppi = FALSE;
3389 DWORD Ret = 0;
3390 DECLARE_RETURN(DWORD);
3391
3392 TRACE("Enter NtUserGetListBoxInfo\n");
3393 UserEnterShared();
3394
3395 if (!(Wnd = UserGetWindowObject(hWnd)))
3396 {
3397 RETURN( 0 );
3398 }
3399
3400 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && Wnd->fnid != FNID_LISTBOX)
3401 {
3402 RETURN( (DWORD) co_IntSendMessage( Wnd->head.h, LB_GETLISTBOXINFO, 0, 0 ));
3403 }
3404
3405 // wine lisbox:test_GetListBoxInfo lb_getlistboxinfo = 0, should not send a message!
3406 ppi = PsGetCurrentProcessWin32Process();
3407 NotSameppi = ppi != Wnd->head.pti->ppi;
3408 if (NotSameppi)
3409 {
3410 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3411 }
3412
3413 _SEH2_TRY
3414 {
3415 LB_DESCR *descr = ((PWND2LB)Wnd)->pLBiv;
3416 // See Controls ListBox.c:LB_GETLISTBOXINFO must match...
3417 if (descr->style & LBS_MULTICOLUMN) //// ReactOS
3418 Ret = descr->page_size * descr->column_width;
3419 else
3420 Ret = descr->page_size;
3421 }
3422 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3423 {
3424 Ret = 0;
3425 SetLastNtError(_SEH2_GetExceptionCode());
3426 }
3427 _SEH2_END;
3428
3429 RETURN( Ret);
3430
3431 CLEANUP:
3432 if (NotSameppi) KeDetachProcess();
3433 TRACE("Leave NtUserGetListBoxInfo, ret=%lu\n", _ret_);
3434 UserLeave();
3435 END_CLEANUP;
3436 }
3437
3438 /*
3439 * NtUserSetParent
3440 *
3441 * The NtUserSetParent function changes the parent window of the specified
3442 * child window.
3443 *
3444 * Remarks
3445 * The new parent window and the child window must belong to the same
3446 * application. If the window identified by the hWndChild parameter is
3447 * visible, the system performs the appropriate redrawing and repainting.
3448 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3449 * or WS_POPUP window styles of the window whose parent is being changed.
3450 *
3451 * Status
3452 * @implemented
3453 */
3454
3455 HWND APIENTRY
3456 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3457 {
3458 DECLARE_RETURN(HWND);
3459
3460 TRACE("Enter NtUserSetParent\n");
3461 UserEnterExclusive();
3462
3463 /*
3464 Check Parent first from user space, set it here.
3465 */
3466 if (!hWndNewParent)
3467 {
3468 hWndNewParent = IntGetDesktopWindow();
3469 }
3470 else if (hWndNewParent == HWND_MESSAGE)
3471 {
3472 hWndNewParent = IntGetMessageWindow();
3473 }
3474
3475 RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3476
3477 CLEANUP:
3478 TRACE("Leave NtUserSetParent, ret=%p\n", _ret_);
3479 UserLeave();
3480 END_CLEANUP;
3481 }
3482
3483 /*
3484 * UserGetShellWindow
3485 *
3486 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3487 *
3488 * Status
3489 * @implemented
3490 */
3491 HWND FASTCALL UserGetShellWindow(VOID)
3492 {
3493 PWINSTATION_OBJECT WinStaObject;
3494 HWND Ret;
3495
3496 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3497 UserMode,
3498 0,
3499 &WinStaObject,
3500 0);
3501
3502 if (!NT_SUCCESS(Status))
3503 {
3504 SetLastNtError(Status);
3505 return( (HWND)0);
3506 }
3507
3508 Ret = (HWND)WinStaObject->ShellWindow;
3509
3510 ObDereferenceObject(WinStaObject);
3511 return( Ret);
3512 }
3513
3514 /*
3515 * NtUserSetShellWindowEx
3516 *
3517 * This is undocumented function to set global shell window. The global
3518 * shell window has special handling of window position.
3519 *
3520 * Status
3521 * @implemented
3522 */
3523 BOOL APIENTRY
3524 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3525 {
3526 PWINSTATION_OBJECT WinStaObject;
3527 PWND WndShell, WndListView;
3528 DECLARE_RETURN(BOOL);
3529 USER_REFERENCE_ENTRY Ref;
3530 NTSTATUS Status;
3531 PTHREADINFO ti;
3532
3533 TRACE("Enter NtUserSetShellWindowEx\n");
3534 UserEnterExclusive();
3535
3536 if (!(WndShell = UserGetWindowObject(hwndShell)))
3537 {
3538 RETURN(FALSE);
3539 }
3540
3541 if (!(WndListView = UserGetWindowObject(hwndListView)))
3542 {
3543 RETURN(FALSE);
3544 }
3545
3546 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3547 UserMode,
3548 0,
3549 &WinStaObject,
3550 0);
3551
3552 if (!NT_SUCCESS(Status))
3553 {
3554 SetLastNtError(Status);
3555 RETURN( FALSE);
3556 }
3557
3558 /*
3559 * Test if we are permitted to change the shell window.
3560 */
3561 if (WinStaObject->ShellWindow)
3562 {
3563 ObDereferenceObject(WinStaObject);
3564 RETURN( FALSE);
3565 }
3566
3567 /*
3568 * Move shell window into background.
3569 */
3570 if (hwndListView && hwndListView != hwndShell)
3571 {
3572 /*
3573 * Disabled for now to get Explorer working.
3574 * -- Filip, 01/nov/2003
3575 */
3576 #if 0
3577 co_WinPosSetWindowPos(WndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3578 #endif
3579
3580 if (WndListView->ExStyle & WS_EX_TOPMOST)
3581 {
3582 ObDereferenceObject(WinStaObject);
3583 RETURN( FALSE);
3584 }
3585 }
3586
3587 if (WndShell->ExStyle & WS_EX_TOPMOST)
3588 {
3589 ObDereferenceObject(WinStaObject);
3590 RETURN( FALSE);
3591 }
3592
3593 UserRefObjectCo(WndShell, &Ref);
3594 WndShell->state2 |= WNDS2_BOTTOMMOST;
3595 co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3596
3597 WinStaObject->ShellWindow = hwndShell;
3598 WinStaObject->ShellListView = hwndListView;
3599
3600 ti = GetW32ThreadInfo();
3601 if (ti->pDeskInfo)
3602 {
3603 ti->pDeskInfo->hShellWindow = hwndShell;
3604 ti->pDeskInfo->spwndShell = WndShell;
3605 ti->pDeskInfo->spwndBkGnd = WndListView;
3606 ti->pDeskInfo->ppiShellProcess = ti->ppi;
3607 }
3608
3609 UserRegisterHotKey(WndShell, SC_TASKLIST, MOD_CONTROL, VK_ESCAPE);
3610
3611 UserDerefObjectCo(WndShell);
3612
3613 ObDereferenceObject(WinStaObject);
3614 RETURN( TRUE);
3615
3616 CLEANUP:
3617 TRACE("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3618 UserLeave();
3619 END_CLEANUP;
3620 }
3621
3622 // Fixes wine Win test_window_styles and todo tests...
3623 static BOOL FASTCALL
3624 IntCheckFrameEdge(ULONG Style, ULONG ExStyle)
3625 {
3626 if (ExStyle & WS_EX_DLGMODALFRAME)
3627 return TRUE;
3628 else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME)))
3629 return TRUE;
3630 else
3631 return FALSE;
3632 }
3633
3634 static LONG_PTR
3635 co_IntSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi, ULONG Size, BOOL bAlter)
3636 {
3637 PWND Window, Parent;
3638 PWINSTATION_OBJECT WindowStation;
3639 LONG_PTR OldValue;
3640 STYLESTRUCT Style;
3641
3642 if (!(Window = UserGetWindowObject(hWnd)))
3643 {
3644 return( 0);
3645 }
3646
3647 if ((INT)Index >= 0)
3648 {
3649 if ((Index + Size) > Window->cbwndExtra)
3650 {
3651 EngSetLastError(ERROR_INVALID_INDEX);
3652 return( 0);
3653 }
3654
3655 #ifdef _WIN64
3656 if (Size == sizeof(LONG))
3657 {
3658 OldValue = *((LONG *)((PCHAR)(Window + 1) + Index));
3659 *((LONG*)((PCHAR)(Window + 1) + Index)) = (LONG)NewValue;
3660 }
3661 else
3662 #endif
3663 {
3664 OldValue = *((LONG_PTR *)((PCHAR)(Window + 1) + Index));
3665 /*
3666 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3667 {
3668 OldValue = (LONG_PTR)IntSetWindowProc( Wnd, (WNDPROC)NewValue, Ansi);
3669 if (!OldValue) return 0;
3670 }
3671 */
3672 *((LONG_PTR*)((PCHAR)(Window + 1) + Index)) = NewValue;
3673 }
3674
3675 }
3676 else
3677 {
3678 #ifdef _WIN64
3679 if (Size == sizeof(LONG))
3680 {
3681 if ((Index != GWL_STYLE) &&
3682 (Index != GWL_EXSTYLE) &&
3683 (Index != GWL_ID) &&
3684 (Index != GWL_USERDATA))
3685 {
3686 ERR("NtUserSetWindowLong(): Index requires pointer size: %lu\n", Index);
3687 EngSetLastError(ERROR_INVALID_INDEX);
3688 return 0;
3689 }
3690 }
3691 #endif
3692
3693 switch (Index)
3694 {
3695 case GWL_EXSTYLE: // LONG
3696 OldValue = (LONG) Window->ExStyle;
3697 Style.styleOld = OldValue;
3698 Style.styleNew = NewValue;
3699
3700 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3701
3702 /*
3703 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3704 */
3705 WindowStation = Window->head.pti->rpdesk->rpwinstaParent;
3706 if(WindowStation)
3707 {
3708 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3709 Style.styleNew &= ~WS_EX_TOPMOST;
3710 }
3711 /* WS_EX_WINDOWEDGE depends on some other styles */
3712 if (IntCheckFrameEdge(Window->style, NewValue))
3713 Style.styleNew |= WS_EX_WINDOWEDGE;
3714 else
3715 Style.styleNew &= ~WS_EX_WINDOWEDGE;
3716
3717 if (!(Window->ExStyle & WS_EX_LAYERED))
3718 {
3719 SetLayeredStatus(Window, 0);
3720 }
3721
3722 Window->ExStyle = (DWORD)Style.styleNew;
3723
3724 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3725 break;
3726
3727 case GWL_STYLE: // LONG
3728 OldValue = (LONG) Window->style;
3729 Style.styleOld = OldValue;
3730 Style.styleNew = NewValue;
3731
3732 if (!bAlter)
3733 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3734
3735 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
3736 if (UserIsDesktopWindow(Window->spwndParent)) Style.styleNew |= WS_CLIPSIBLINGS;
3737 /* WS_MINIMIZE can't be reset */
3738 if (OldValue & WS_MINIMIZE) Style.styleNew |= WS_MINIMIZE;
3739 /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */
3740 if (IntCheckFrameEdge(NewValue, Window->ExStyle))
3741 Window->ExStyle |= WS_EX_WINDOWEDGE;
3742 else
3743 Window->ExStyle &= ~WS_EX_WINDOWEDGE;
3744
3745 if ((OldValue & (WS_CHILD | WS_POPUP)) == WS_CHILD)
3746 {
3747 if ((NewValue & (WS_CHILD | WS_POPUP)) != WS_CHILD)
3748 {
3749 //// From child to non-child it should be null already.
3750 ERR("IDMenu going null! %d\n",Window->IDMenu);
3751 Window->IDMenu = 0; // Window->spmenu = 0;
3752 }
3753 }
3754 else
3755 {
3756 if ((NewValue & (WS_CHILD | WS_POPUP)) == WS_CHILD)
3757 {
3758 PMENU pMenu = UserGetMenuObject(UlongToHandle(Window->IDMenu));
3759 Window->state &= ~WNDS_HASMENU;
3760 if (pMenu)
3761 {
3762 ERR("IDMenu released 0x%p\n",pMenu);
3763 // ROS may not hold a lock after setting menu to window. But it should!
3764 //IntReleaseMenuObject(pMenu);
3765 }
3766 }
3767 }
3768
3769 if ((Style.styleOld ^ Style.styleNew) & WS_VISIBLE)
3770 {
3771 if (Style.styleOld & WS_VISIBLE) Window->head.pti->cVisWindows--;
3772 if (Style.styleNew & WS_VISIBLE) Window->head.pti->cVisWindows++;
3773 DceResetActiveDCEs( Window );
3774 }
3775 Window->style = (DWORD)Style.styleNew;
3776
3777 if (!bAlter)
3778 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3779 break;
3780
3781 case GWLP_WNDPROC: // LONG_PTR
3782 {
3783 if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
3784 Window->fnid & FNID_FREED)
3785 {
3786 EngSetLastError(ERROR_ACCESS_DENIED);
3787 return( 0);
3788 }
3789 OldValue = (LONG_PTR)IntSetWindowProc(Window,
3790 (WNDPROC)NewValue,
3791 Ansi);
3792 break;
3793 }
3794
3795 case GWLP_HINSTANCE: // LONG_PTR
3796 OldValue = (LONG_PTR) Window->hModule;
3797 Window->hModule = (HINSTANCE) NewValue;
3798 break;
3799
3800 case GWLP_HWNDPARENT: // LONG_PTR
3801 Parent = Window->spwndParent;
3802 if (Parent && (Parent->head.h == IntGetDesktopWindow()))
3803 OldValue = (LONG_PTR) IntSetOwner(Window->head.h, (HWND) NewValue);
3804 else
3805 OldValue = (LONG_PTR) co_UserSetParent(Window->head.h, (HWND) NewValue);
3806 break;
3807
3808 case GWLP_ID: // LONG
3809 OldValue = (LONG) Window->IDMenu;
3810 Window->IDMenu = (UINT) NewValue;
3811 break;
3812
3813 case GWLP_USERDATA: // LONG or LONG_PTR
3814 OldValue = Window->dwUserData;
3815 Window->dwUserData = NewValue;
3816 break;
3817
3818 default:
3819 ERR("NtUserSetWindowLong(): Unsupported index %lu\n", Index);
3820 EngSetLastError(ERROR_INVALID_INDEX);
3821 OldValue = 0;
3822 break;
3823 }
3824 }
3825
3826 return( OldValue);
3827 }
3828
3829 LONG FASTCALL
3830 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3831 {
3832 return (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE);
3833 }
3834
3835 LONG_PTR FASTCALL
3836 co_UserSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi)
3837 {
3838 return co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE);
3839 }
3840
3841 /*
3842 * NtUserSetWindowLong
3843 *
3844 * The NtUserSetWindowLong function changes an attribute of the specified
3845 * window. The function also sets the 32-bit (long) value at the specified
3846 * offset into the extra window memory.
3847 *
3848 * Status
3849 * @implemented
3850 */
3851
3852 LONG APIENTRY
3853 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3854 {
3855 LONG ret;
3856
3857 UserEnterExclusive();
3858
3859 if (hWnd == IntGetDesktopWindow())
3860 {
3861 EngSetLastError(STATUS_ACCESS_DENIED);
3862 UserLeave();
3863 return 0;
3864 }
3865
3866 ret = (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE);
3867
3868 UserLeave();
3869
3870 return ret;
3871 }
3872
3873 #ifdef _WIN64
3874 LONG_PTR APIENTRY
3875 NtUserSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi)
3876 {
3877 LONG_PTR ret;
3878
3879 UserEnterExclusive();
3880
3881 if (hWnd == IntGetDesktopWindow())
3882 {
3883 EngSetLastError(STATUS_ACCESS_DENIED);
3884 UserLeave();
3885 return 0;
3886 }
3887
3888 ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE);
3889
3890 UserLeave();
3891
3892 return ret;
3893 }
3894 #endif // _WIN64
3895
3896 DWORD APIENTRY
3897 NtUserAlterWindowStyle(HWND hWnd, DWORD Index, LONG NewValue)
3898 {
3899 LONG ret;
3900
3901 UserEnterExclusive();
3902
3903 if (hWnd == IntGetDesktopWindow())
3904 {
3905 EngSetLastError(STATUS_ACCESS_DENIED);
3906 UserLeave();
3907 return 0;
3908 }
3909
3910 ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, FALSE, sizeof(LONG), TRUE);
3911
3912 UserLeave();
3913
3914 return ret;
3915 }
3916
3917
3918 /*
3919 * NtUserSetWindowWord
3920 *
3921 * Legacy function similar to NtUserSetWindowLong.
3922 *
3923 * Status
3924 * @implemented
3925 */
3926
3927 WORD APIENTRY
3928 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
3929 {
3930 PWND Window;
3931 WORD OldValue;
3932 DECLARE_RETURN(WORD);
3933
3934 TRACE("Enter NtUserSetWindowWord\n");
3935 UserEnterExclusive();
3936
3937 if (hWnd == IntGetDesktopWindow())
3938 {
3939 EngSetLastError(STATUS_ACCESS_DENIED);
3940 RETURN( 0);
3941 }
3942
3943 if (!(Window = UserGetWindowObject(hWnd)))
3944 {
3945 RETURN( 0);
3946 }
3947
3948 switch (Index)
3949 {
3950 case GWL_ID:
3951 case GWL_HINSTANCE:
3952 case GWL_HWNDPARENT:
3953 RETURN( (WORD)co_UserSetWindowLong(UserHMGetHandle(Window), Index, (UINT)NewValue, TRUE));
3954 default:
3955 if (Index < 0)
3956 {
3957 EngSetLastError(ERROR_INVALID_INDEX);
3958 RETURN( 0);
3959 }
3960 }
3961
3962 if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD)))
3963 {
3964 EngSetLastError(ERROR_INVALID_PARAMETER);
3965 RETURN( 0);
3966 }
3967
3968 OldValue = *((WORD *)((PCHAR)(Window + 1) + Index));
3969 *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue;
3970
3971 RETURN( OldValue);
3972
3973 CLEANUP:
3974 TRACE("Leave NtUserSetWindowWord, ret=%u\n", _ret_);
3975 UserLeave();
3976 END_CLEANUP;
3977 }
3978
3979 /*
3980 QueryWindow based on KJK::Hyperion and James Tabor.
3981
3982 0 = QWUniqueProcessId
3983 1 = QWUniqueThreadId
3984 2 = QWActiveWindow
3985 3 = QWFocusWindow
3986 4 = QWIsHung Implements IsHungAppWindow found
3987 by KJK::Hyperion.
3988
3989 9 = QWKillWindow When I called this with hWnd ==
3990 DesktopWindow, it shutdown the system
3991 and rebooted.
3992 */
3993 /*
3994 * @implemented
3995 */
3996 DWORD_PTR APIENTRY
3997 NtUserQueryWindow(HWND hWnd, DWORD Index)
3998 {
3999 /* Console Leader Process CID Window offsets */
4000 #define GWLP_CONSOLE_LEADER_PID 0
4001 #define GWLP_CONSOLE_LEADER_TID 4
4002
4003 PWND pWnd;
4004 DWORD_PTR Result;
4005 DECLARE_RETURN(UINT);
4006
4007 TRACE("Enter NtUserQueryWindow\n");
4008 UserEnterShared();
4009
4010 if (!(pWnd = UserGetWindowObject(hWnd)))
4011 {
4012 RETURN( 0);
4013 }
4014
4015 switch(Index)
4016 {
4017 case QUERY_WINDOW_UNIQUE_PROCESS_ID:
4018 {
4019 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
4020 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
4021 {
4022 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_PID)
4023 Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_PID)));
4024 }
4025 else
4026 {
4027 Result = (DWORD_PTR)IntGetWndProcessId(pWnd);
4028 }
4029 break;
4030 }
4031
4032 case QUERY_WINDOW_UNIQUE_THREAD_ID:
4033 {
4034 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
4035 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
4036 {
4037 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_TID)
4038 Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_TID)));
4039 }
4040 else
4041 {
4042 Result = (DWORD_PTR)IntGetWndThreadId(pWnd);
4043 }
4044 break;
4045 }
4046
4047 case QUERY_WINDOW_ACTIVE:
4048 Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndActive ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndActive) : 0);
4049 break;
4050
4051 case QUERY_WINDOW_FOCUS:
4052 Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndFocus ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndFocus) : 0);
4053 break;
4054
4055 case QUERY_WINDOW_ISHUNG:
4056 Result = (DWORD_PTR)MsqIsHung(pWnd->head.pti);
4057 break;
4058
4059 case QUERY_WINDOW_REAL_ID:
4060 Result = (DWORD_PTR)pWnd->head.pti->pEThread->Cid.UniqueProcess;
4061 break;
4062
4063 case QUERY_WINDOW_FOREGROUND:
4064 Result = (pWnd->head.pti->MessageQueue == gpqForeground);
4065 break;
4066
4067 default:
4068 Result = 0;
4069 break;
4070 }
4071
4072 RETURN( Result);
4073
4074 CLEANUP:
4075 TRACE("Leave NtUserQueryWindow, ret=%u\n", _ret_);
4076 UserLeave();
4077 END_CLEANUP;
4078 }
4079
4080 /*
4081 * @implemented
4082 */
4083 UINT APIENTRY
4084 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
4085 {
4086 UNICODE_STRING SafeMessageName;
4087 NTSTATUS Status;
4088 UINT Ret;
4089 DECLARE_RETURN(UINT);
4090
4091 TRACE("Enter NtUserRegisterWindowMessage\n");
4092 UserEnterExclusive();
4093
4094 if(MessageNameUnsafe == NULL)
4095 {
4096 EngSetLastError(ERROR_INVALID_PARAMETER);
4097 RETURN( 0);
4098 }
4099
4100 Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
4101 if(!NT_SUCCESS(Status))
4102 {
4103 SetLastNtError(Status);
4104 RETURN( 0);
4105 }
4106
4107 Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
4108 if (SafeMessageName.Buffer)
4109 ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING);
4110 RETURN( Ret);
4111
4112 CLEANUP:
4113 TRACE("Leave NtUserRegisterWindowMessage, ret=%u\n", _ret_);
4114 UserLeave();
4115 END_CLEANUP;
4116 }
4117
4118 /*
4119 * @implemented
4120 */
4121 BOOL APIENTRY
4122 NtUserSetWindowFNID(HWND hWnd,
4123 WORD fnID)
4124 {
4125 PWND Wnd;
4126 DECLARE_RETURN(BOOL);
4127
4128 TRACE("Enter NtUserSetWindowFNID\n");
4129 UserEnterExclusive();
4130
4131 if (!(Wnd = UserGetWindowObject(hWnd)))
4132 {
4133 RETURN( FALSE);
4134 }
4135
4136 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
4137 {
4138 EngSetLastError(ERROR_ACCESS_DENIED);
4139 RETURN( FALSE);
4140 }
4141
4142 // From user land we only set these.
4143 if (fnID != FNID_DESTROY)
4144 {
4145 /* HACK: The minimum should be FNID_BUTTON, but menu code relies on this */
4146 if (fnID < FNID_FIRST || fnID > FNID_GHOST ||
4147 Wnd->fnid != 0)
4148 {
4149 EngSetLastError(ERROR_INVALID_PARAMETER);
4150 RETURN( FALSE);
4151 }
4152 }
4153
4154 Wnd->fnid |= fnID;
4155 RETURN( TRUE);
4156
4157 CLEANUP:
4158 TRACE("Leave NtUserSetWindowFNID\n");
4159 UserLeave();
4160 END_CLEANUP;
4161 }
4162
4163 BOOL APIENTRY
4164 DefSetText(PWND Wnd, PCWSTR WindowText)
4165 {
4166 UNICODE_STRING UnicodeString;
4167 BOOL Ret = FALSE;
4168
4169 RtlInitUnicodeString(&UnicodeString, WindowText);
4170
4171 if (UnicodeString.Length != 0)
4172 {
4173 if (Wnd->strName.MaximumLength > 0 &&
4174 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4175 {
4176 ASSERT(Wnd->strName.Buffer != NULL);
4177
4178 Wnd->strName.Length = UnicodeString.Length;
4179 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4180 RtlCopyMemory(Wnd->strName.Buffer,
4181 UnicodeString.Buffer,
4182 UnicodeString.Length);
4183 }
4184 else
4185 {
4186 PWCHAR buf;
4187 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4188 buf = Wnd->strName.Buffer;
4189 Wnd->strName.Buffer = NULL;
4190 if (buf != NULL)
4191 {
4192 DesktopHeapFree(Wnd->head.rpdesk, buf);
4193 }
4194
4195 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4196 UnicodeString.Length + sizeof(UNICODE_NULL));
4197 if (Wnd->strName.Buffer != NULL)
4198 {
4199 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4200 RtlCopyMemory(Wnd->strName.Buffer,
4201 UnicodeString.Buffer,
4202 UnicodeString.Length);
4203 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4204 Wnd->strName.Length = UnicodeString.Length;
4205 }
4206 else
4207 {
4208 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4209 goto Exit;
4210 }
4211 }
4212 }
4213 else
4214 {
4215 Wnd->strName.Length = 0;
4216 if (Wnd->strName.Buffer != NULL)
4217 Wnd->strName.Buffer[0] = L'\0';
4218 }
4219
4220 // FIXME: HAX! Windows does not do this in here!
4221 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4222 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4223 /* Send shell notifications */
4224 if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4225 {
4226 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) UserHMGetHandle(Wnd), FALSE); // FIXME Flashing?
4227 }
4228
4229 Ret = TRUE;
4230 Exit:
4231 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4232 return Ret;
4233 }
4234
4235 /*
4236 * NtUserDefSetText
4237 *
4238 * Undocumented function that is called from DefWindowProc to set
4239 * window text.
4240 *
4241 * Status
4242 * @implemented
4243 */
4244 BOOL APIENTRY
4245 NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText)
4246 {
4247 PWND Wnd;
4248 LARGE_STRING SafeText;
4249 UNICODE_STRING UnicodeString;
4250 BOOL Ret = TRUE;
4251
4252 TRACE("Enter NtUserDefSetText\n");
4253
4254 if (WindowText != NULL)
4255 {
4256 _SEH2_TRY
4257 {
4258 SafeText = ProbeForReadLargeString(WindowText);
4259 }
4260 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4261 {
4262 Ret = FALSE;
4263 SetLastNtError(_SEH2_GetExceptionCode());
4264 }
4265 _SEH2_END;
4266
4267 if (!Ret)
4268 return FALSE;
4269 }
4270 else
4271 return TRUE;
4272
4273 UserEnterExclusive();
4274
4275 if(!(Wnd = UserGetWindowObject(hWnd)))
4276 {
4277 UserLeave();
4278 return FALSE;
4279 }
4280
4281 // ReactOS uses Unicode and not mixed. Up/Down converting will take time.
4282 // Brought to you by: The Wine Project! Dysfunctional Thought Processes!
4283 // Now we know what the bAnsi is for.
4284 RtlInitUnicodeString(&UnicodeString, NULL);
4285 if (SafeText.Buffer)
4286 {
4287 _SEH2_TRY
4288 {
4289 if (SafeText.bAnsi)
4290 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR));
4291 else
4292 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR));
4293 Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText);
4294 }
4295 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4296 {
4297 Ret = FALSE;
4298 SetLastNtError(_SEH2_GetExceptionCode());
4299 }
4300 _SEH2_END;
4301 if (!Ret) goto Exit;
4302 }
4303
4304 if (UnicodeString.Length != 0)
4305 {
4306 if (Wnd->strName.MaximumLength > 0 &&
4307 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4308 {
4309 ASSERT(Wnd->strName.Buffer != NULL);
4310
4311 Wnd->strName.Length = UnicodeString.Length;
4312 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4313 RtlCopyMemory(Wnd->strName.Buffer,
4314 UnicodeString.Buffer,
4315 UnicodeString.Length);
4316 }
4317 else
4318 {
4319 PWCHAR buf;
4320 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4321 buf = Wnd->strName.Buffer;
4322 Wnd->strName.Buffer = NULL;
4323 if (buf != NULL)
4324 {
4325 DesktopHeapFree(Wnd->head.rpdesk, buf);
4326 }
4327
4328 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4329 UnicodeString.Length + sizeof(UNICODE_NULL));
4330 if (Wnd->strName.Buffer != NULL)
4331 {
4332 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4333 RtlCopyMemory(Wnd->strName.Buffer,
4334 UnicodeString.Buffer,
4335 UnicodeString.Length);
4336 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4337 Wnd->strName.Length = UnicodeString.Length;
4338 }
4339 else
4340 {
4341 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4342 Ret = FALSE;
4343 goto Exit;
4344 }
4345 }
4346 }
4347 else
4348 {
4349 Wnd->strName.Length = 0;
4350 if (Wnd->strName.Buffer != NULL)
4351 Wnd->strName.Buffer[0] = L'\0';
4352 }
4353
4354 // FIXME: HAX! Windows does not do this in here!
4355 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4356 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4357 /* Send shell notifications */
4358 if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4359 {
4360 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) hWnd, FALSE); // FIXME Flashing?
4361 }
4362
4363 Ret = TRUE;
4364 Exit:
4365 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4366 TRACE("Leave NtUserDefSetText, ret=%i\n", Ret);
4367 UserLeave();
4368 return Ret;
4369 }
4370
4371 /*
4372 * NtUserInternalGetWindowText
4373 *
4374 * Status
4375 * @implemented
4376 */
4377
4378 INT APIENTRY
4379 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount)
4380 {
4381 PWND Wnd;
4382 NTSTATUS Status;
4383 INT Result;
4384 DECLARE_RETURN(INT);
4385
4386 TRACE("Enter NtUserInternalGetWindowText\n");
4387 UserEnterShared();
4388
4389 if(lpString && (nMaxCount <= 1))
4390 {
4391 EngSetLastError(ERROR_INVALID_PARAMETER);
4392 RETURN( 0);
4393 }
4394
4395 if(!(Wnd = UserGetWindowObject(hWnd)))
4396 {
4397 RETURN( 0);
4398 }
4399
4400 Result = Wnd->strName.Length / sizeof(WCHAR);
4401 if(lpString)
4402 {
4403 const WCHAR Terminator = L'\0';
4404 INT Copy;
4405 WCHAR *Buffer = (WCHAR*)lpString;
4406
4407 Copy = min(nMaxCount - 1, Result);
4408 if(Copy > 0)
4409 {
4410 Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR));
4411 if(!NT_SUCCESS(Status))
4412 {
4413 SetLastNtError(Status);
4414 RETURN( 0);
4415 }
4416 Buffer += Copy;
4417 }
4418
4419 Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
4420 if(!NT_SUCCESS(Status))
4421 {
4422 SetLastNtError(Status);
4423 RETURN( 0);
4424 }
4425
4426 Result = Copy;
4427 }
4428
4429 RETURN( Result);
4430
4431 CLEANUP:
4432 TRACE("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_);
4433 UserLeave();
4434 END_CLEANUP;
4435 }
4436
4437 /*
4438 API Call
4439 */
4440 BOOL
4441 FASTCALL
4442 IntShowOwnedPopups(PWND OwnerWnd, BOOL fShow )
4443 {
4444 int count = 0;
4445 PWND pWnd;
4446 HWND *win_array;
4447
4448 // ASSERT(OwnerWnd);
4449
4450 TRACE("Enter ShowOwnedPopups Show: %s\n", (fShow ? "TRUE" : "FALSE"));
4451
4452 /* NOTE: Popups are not children */
4453 win_array = IntWinListOwnedPopups(OwnerWnd);
4454
4455 if (!win_array)
4456 return TRUE;
4457
4458 while (win_array[count])
4459 count++;
4460 while (--count >= 0)
4461 {
4462 if (!(pWnd = ValidateHwndNoErr( win_array[count] )))
4463 continue;
4464 if (pWnd->spwndOwner != OwnerWnd)
4465 continue;
4466
4467 if (fShow)
4468 {
4469 if (pWnd->state & WNDS_HIDDENPOPUP)
4470 {
4471 /* In Windows, ShowOwnedPopups(TRUE) generates
4472 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
4473 * regardless of the state of the owner
4474 */
4475 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
4476 pWnd->state &= ~WNDS_HIDDENPOPUP;
4477 continue;
4478 }
4479 }
4480 else
4481 {
4482 if (pWnd->style & WS_VISIBLE)
4483 {
4484 /* In Windows, ShowOwnedPopups(FALSE) generates
4485 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
4486 * regardless of the state of the owner
4487 */
4488 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
4489 pWnd->state |= WNDS_HIDDENPOPUP;
4490 continue;
4491 }
4492 }
4493 }
4494 ExFreePoolWithTag(win_array, USERTAG_WINDOWLIST);
4495 TRACE("Leave ShowOwnedPopups\n");
4496 return TRUE;
4497 }
4498
4499 /* EOF */