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