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