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