de3b4bd0c3459c304a39bf0dfa2ea0da72a115a7
[reactos.git] / reactos / 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, TRUE);
591 Window->IDMenu = 0;
592 }
593
594 if(Window->SystemMenu
595 && (Menu = UserGetMenuObject(Window->SystemMenu)))
596 {
597 IntDestroyMenuObject(Menu, TRUE, 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 VOID FASTCALL
865 co_DestroyThreadWindows(struct _ETHREAD *Thread)
866 {
867 PTHREADINFO WThread;
868 PLIST_ENTRY Current;
869 PWND Wnd;
870 USER_REFERENCE_ENTRY Ref;
871 WThread = (PTHREADINFO)Thread->Tcb.Win32Thread;
872
873 while (!IsListEmpty(&WThread->WindowListHead))
874 {
875 Current = WThread->WindowListHead.Flink;
876 Wnd = CONTAINING_RECORD(Current, WND, ThreadListEntry);
877
878 TRACE("thread cleanup: while destroy wnds, wnd=%p\n", Wnd);
879
880 /* Window removes itself from the list */
881
882 /*
883 * FIXME: It is critical that the window removes itself! If now, we will loop
884 * here forever...
885 */
886
887 //ASSERT(co_UserDestroyWindow(Wnd));
888
889 UserRefObjectCo(Wnd, &Ref); // FIXME: Temp HACK??
890 if (!co_UserDestroyWindow(Wnd))
891 {
892 ERR("Unable to destroy window %p at thread cleanup... This is _VERY_ bad!\n", Wnd);
893 }
894 UserDerefObjectCo(Wnd); // FIXME: Temp HACK??
895 }
896 }
897
898 BOOL FASTCALL
899 IntIsChildWindow(PWND Parent, PWND BaseWindow)
900 {
901 PWND Window;
902
903 Window = BaseWindow;
904 while (Window && ((Window->style & (WS_POPUP|WS_CHILD)) == WS_CHILD))
905 {
906 if (Window == Parent)
907 {
908 return(TRUE);
909 }
910
911 Window = Window->spwndParent;
912 }
913
914 return(FALSE);
915 }
916
917 /*
918 Link the window into siblings list
919 children and parent are kept in place.
920 */
921 VOID FASTCALL
922 IntLinkWindow(
923 PWND Wnd,
924 PWND WndInsertAfter /* set to NULL if top sibling */
925 )
926 {
927 if ((Wnd->spwndPrev = WndInsertAfter))
928 {
929 /* link after WndInsertAfter */
930 if ((Wnd->spwndNext = WndInsertAfter->spwndNext))
931 Wnd->spwndNext->spwndPrev = Wnd;
932
933 Wnd->spwndPrev->spwndNext = Wnd;
934 }
935 else
936 {
937 /* link at top */
938 if ((Wnd->spwndNext = Wnd->spwndParent->spwndChild))
939 Wnd->spwndNext->spwndPrev = Wnd;
940
941 Wnd->spwndParent->spwndChild = Wnd;
942 }
943 }
944
945 /*
946 Note: Wnd->spwndParent can be null if it is the desktop.
947 */
948 VOID FASTCALL IntLinkHwnd(PWND Wnd, HWND hWndPrev)
949 {
950 if (hWndPrev == HWND_NOTOPMOST)
951 {
952 if (!(Wnd->ExStyle & WS_EX_TOPMOST) &&
953 (Wnd->ExStyle2 & WS_EX2_LINKED)) return; /* nothing to do */
954 Wnd->ExStyle &= ~WS_EX_TOPMOST;
955 hWndPrev = HWND_TOP; /* fallback to the HWND_TOP case */
956 }
957
958 IntUnlinkWindow(Wnd); /* unlink it from the previous location */
959
960 if (hWndPrev == HWND_BOTTOM)
961 {
962 /* Link in the bottom of the list */
963 PWND WndInsertAfter;
964
965 WndInsertAfter = Wnd->spwndParent->spwndChild;
966 while( WndInsertAfter && WndInsertAfter->spwndNext)
967 WndInsertAfter = WndInsertAfter->spwndNext;
968
969 IntLinkWindow(Wnd, WndInsertAfter);
970 Wnd->ExStyle &= ~WS_EX_TOPMOST;
971 }
972 else if (hWndPrev == HWND_TOPMOST)
973 {
974 /* Link in the top of the list */
975 IntLinkWindow(Wnd, NULL);
976
977 Wnd->ExStyle |= WS_EX_TOPMOST;
978 }
979 else if (hWndPrev == HWND_TOP)
980 {
981 /* Link it after the last topmost window */
982 PWND WndInsertBefore;
983
984 WndInsertBefore = Wnd->spwndParent->spwndChild;
985
986 if (!(Wnd->ExStyle & WS_EX_TOPMOST)) /* put it above the first non-topmost window */
987 {
988 while (WndInsertBefore != NULL && WndInsertBefore->spwndNext != NULL)
989 {
990 if (!(WndInsertBefore->ExStyle & WS_EX_TOPMOST)) break;
991 if (WndInsertBefore == Wnd->spwndOwner) /* keep it above owner */
992 {
993 Wnd->ExStyle |= WS_EX_TOPMOST;
994 break;
995 }
996 WndInsertBefore = WndInsertBefore->spwndNext;
997 }
998 }
999
1000 IntLinkWindow(Wnd, WndInsertBefore ? WndInsertBefore->spwndPrev : NULL);
1001 }
1002 else
1003 {
1004 /* Link it after hWndPrev */
1005 PWND WndInsertAfter;
1006
1007 WndInsertAfter = UserGetWindowObject(hWndPrev);
1008 /* Are we called with an erroneous handle */
1009 if(WndInsertAfter == NULL)
1010 {
1011 /* Link in a default position */
1012 IntLinkHwnd(Wnd, HWND_TOP);
1013 return;
1014 }
1015
1016 IntLinkWindow(Wnd, WndInsertAfter);
1017
1018 /* Fix the WS_EX_TOPMOST flag */
1019 if (!(WndInsertAfter->ExStyle & WS_EX_TOPMOST))
1020 {
1021 Wnd->ExStyle &= ~WS_EX_TOPMOST;
1022 }
1023 else
1024 {
1025 if(WndInsertAfter->spwndNext &&
1026 WndInsertAfter->spwndNext->ExStyle & WS_EX_TOPMOST)
1027 {
1028 Wnd->ExStyle |= WS_EX_TOPMOST;
1029 }
1030 }
1031 }
1032 Wnd->ExStyle2 |= WS_EX2_LINKED;
1033 }
1034
1035 VOID FASTCALL
1036 IntProcessOwnerSwap(PWND Wnd, PWND WndNewOwner, PWND WndOldOwner)
1037 {
1038 if (WndOldOwner)
1039 {
1040 if (Wnd->head.pti != WndOldOwner->head.pti)
1041 {
1042 if (!WndNewOwner ||
1043 Wnd->head.pti == WndNewOwner->head.pti ||
1044 WndOldOwner->head.pti != WndNewOwner->head.pti )
1045 {
1046 //ERR("ProcessOwnerSwap Old out.\n");
1047 UserAttachThreadInput(Wnd->head.pti, WndOldOwner->head.pti, FALSE);
1048 }
1049 }
1050 }
1051 if (WndNewOwner)
1052 {
1053 if (Wnd->head.pti != WndNewOwner->head.pti)
1054 {
1055 if (!WndOldOwner ||
1056 WndOldOwner->head.pti != WndNewOwner->head.pti )
1057 {
1058 //ERR("ProcessOwnerSwap New in.\n");
1059 UserAttachThreadInput(Wnd->head.pti, WndNewOwner->head.pti, TRUE);
1060 }
1061 }
1062 }
1063 // FIXME: System Tray checks.
1064 }
1065
1066 HWND FASTCALL
1067 IntSetOwner(HWND hWnd, HWND hWndNewOwner)
1068 {
1069 PWND Wnd, WndOldOwner, WndNewOwner;
1070 HWND ret;
1071
1072 Wnd = IntGetWindowObject(hWnd);
1073 if(!Wnd)
1074 return NULL;
1075
1076 WndOldOwner = Wnd->spwndOwner;
1077
1078 ret = WndOldOwner ? UserHMGetHandle(WndOldOwner) : 0;
1079 WndNewOwner = UserGetWindowObject(hWndNewOwner);
1080
1081 if (!WndNewOwner && hWndNewOwner)
1082 {
1083 EngSetLastError(ERROR_INVALID_PARAMETER);
1084 ret = NULL;
1085 goto Error;
1086 }
1087
1088 /* if parent belongs to a different thread and the window isn't */
1089 /* top-level, attach the two threads */
1090 IntProcessOwnerSwap(Wnd, WndNewOwner, WndOldOwner);
1091
1092 if (IntValidateOwnerDepth(Wnd, WndNewOwner))
1093 {
1094 if (WndNewOwner)
1095 {
1096 Wnd->spwndOwner= WndNewOwner;
1097 }
1098 else
1099 {
1100 Wnd->spwndOwner = NULL;
1101 }
1102 }
1103 else
1104 {
1105 IntProcessOwnerSwap(Wnd, WndOldOwner, WndNewOwner);
1106 EngSetLastError(ERROR_INVALID_PARAMETER);
1107 ret = NULL;
1108 }
1109 Error:
1110 UserDereferenceObject(Wnd);
1111 return ret;
1112 }
1113
1114 PWND FASTCALL
1115 co_IntSetParent(PWND Wnd, PWND WndNewParent)
1116 {
1117 PWND WndOldParent, pWndExam;
1118 BOOL WasVisible;
1119 POINT pt;
1120 int swFlags = SWP_NOSIZE|SWP_NOZORDER;
1121
1122 ASSERT(Wnd);
1123 ASSERT(WndNewParent);
1124 ASSERT_REFS_CO(Wnd);
1125 ASSERT_REFS_CO(WndNewParent);
1126
1127 if (Wnd == Wnd->head.rpdesk->spwndMessage)
1128 {
1129 EngSetLastError(ERROR_ACCESS_DENIED);
1130 return( NULL);
1131 }
1132
1133 /* Some applications try to set a child as a parent */
1134 if (IntIsChildWindow(Wnd, WndNewParent))
1135 {
1136 TRACE("IntSetParent try to set a child as a parent.\n");
1137 EngSetLastError( ERROR_INVALID_PARAMETER );
1138 return NULL;
1139 }
1140
1141 pWndExam = WndNewParent; // Load parent Window to examine.
1142 // Now test for set parent to parent hit.
1143 while (pWndExam)
1144 {
1145 if (Wnd == pWndExam)
1146 {
1147 TRACE("IntSetParent Failed Test for set parent to parent!\n");
1148 EngSetLastError(ERROR_INVALID_PARAMETER);
1149 return NULL;
1150 }
1151 pWndExam = pWndExam->spwndParent;
1152 }
1153
1154 /*
1155 * Windows hides the window first, then shows it again
1156 * including the WM_SHOWWINDOW messages and all
1157 */
1158 WasVisible = co_WinPosShowWindow(Wnd, SW_HIDE);
1159
1160 /* Window must belong to current process */
1161 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
1162 {
1163 ERR("IntSetParent Window must belong to current process!\n");
1164 return NULL;
1165 }
1166
1167 WndOldParent = Wnd->spwndParent;
1168
1169 if ( WndOldParent &&
1170 WndOldParent->ExStyle & WS_EX_LAYOUTRTL)
1171 pt.x = Wnd->rcWindow.right;
1172 else
1173 pt.x = Wnd->rcWindow.left;
1174 pt.y = Wnd->rcWindow.top;
1175
1176 IntScreenToClient(WndOldParent, &pt);
1177
1178 if (WndOldParent) UserReferenceObject(WndOldParent); /* Caller must deref */
1179
1180 if (WndNewParent != WndOldParent)
1181 {
1182 /* Unlink the window from the siblings list */
1183 IntUnlinkWindow(Wnd);
1184 Wnd->ExStyle2 &= ~WS_EX2_LINKED;
1185
1186 /* Set the new parent */
1187 Wnd->spwndParent = WndNewParent;
1188
1189 if ( Wnd->style & WS_CHILD &&
1190 Wnd->spwndOwner &&
1191 Wnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1192 {
1193 ERR("SetParent Top Most from Pop up!\n");
1194 Wnd->ExStyle |= WS_EX_TOPMOST;
1195 }
1196
1197 /* Link the window with its new siblings */
1198 IntLinkHwnd( Wnd,
1199 ((0 == (Wnd->ExStyle & WS_EX_TOPMOST) &&
1200 WndNewParent == UserGetDesktopWindow() ) ? HWND_TOP : HWND_TOPMOST ) );
1201
1202 }
1203
1204 if ( WndNewParent == co_GetDesktopWindow(Wnd) &&
1205 !(Wnd->style & WS_CLIPSIBLINGS) )
1206 {
1207 Wnd->style |= WS_CLIPSIBLINGS;
1208 DceResetActiveDCEs(Wnd);
1209 }
1210
1211 /* if parent belongs to a different thread and the window isn't */
1212 /* top-level, attach the two threads */
1213 if ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1214 {
1215 if ( Wnd->spwndParent != co_GetDesktopWindow(Wnd))
1216 {
1217 if (Wnd->head.pti != WndOldParent->head.pti)
1218 {
1219 //ERR("SetParent Old out.\n");
1220 UserAttachThreadInput(Wnd->head.pti, WndOldParent->head.pti, FALSE);
1221 }
1222 }
1223 if ( WndNewParent != co_GetDesktopWindow(Wnd))
1224 {
1225 if (Wnd->head.pti != WndNewParent->head.pti)
1226 {
1227 //ERR("SetParent New in.\n");
1228 UserAttachThreadInput(Wnd->head.pti, WndNewParent->head.pti, TRUE);
1229 }
1230 }
1231 }
1232
1233 if (WndOldParent == UserGetMessageWindow() || WndNewParent == UserGetMessageWindow())
1234 swFlags |= SWP_NOACTIVATE;
1235
1236 IntNotifyWinEvent(EVENT_OBJECT_PARENTCHANGE, Wnd ,OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1237 /*
1238 * SetParent additionally needs to make hwnd the top window
1239 * in the z-order and send the expected WM_WINDOWPOSCHANGING and
1240 * WM_WINDOWPOSCHANGED notification messages.
1241 */
1242 //ERR("IntSetParent SetWindowPos 1\n");
1243 co_WinPosSetWindowPos( Wnd,
1244 (0 == (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
1245 pt.x, pt.y, 0, 0, swFlags);
1246 //ERR("IntSetParent SetWindowPos 2 X %d Y %d\n",pt.x, pt.y);
1247 if (WasVisible) co_WinPosShowWindow(Wnd, SW_SHOWNORMAL);
1248
1249 return WndOldParent;
1250 }
1251
1252 HWND FASTCALL
1253 co_UserSetParent(HWND hWndChild, HWND hWndNewParent)
1254 {
1255 PWND Wnd = NULL, WndParent = NULL, WndOldParent;
1256 HWND hWndOldParent = NULL;
1257 USER_REFERENCE_ENTRY Ref, ParentRef;
1258
1259 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
1260 {
1261 EngSetLastError(ERROR_INVALID_PARAMETER);
1262 return( NULL);
1263 }
1264
1265 if (hWndChild == IntGetDesktopWindow())
1266 {
1267 ERR("UserSetParent Access Denied!\n");
1268 EngSetLastError(ERROR_ACCESS_DENIED);
1269 return( NULL);
1270 }
1271
1272 if (hWndNewParent)
1273 {
1274 if (!(WndParent = UserGetWindowObject(hWndNewParent)))
1275 {
1276 ERR("UserSetParent Bad New Parent!\n");
1277 return( NULL);
1278 }
1279 }
1280 else
1281 {
1282 if (!(WndParent = UserGetWindowObject(IntGetDesktopWindow())))
1283 {
1284 return( NULL);
1285 }
1286 }
1287
1288 if (!(Wnd = UserGetWindowObject(hWndChild)))
1289 {
1290 ERR("UserSetParent Bad Child!\n");
1291 return( NULL);
1292 }
1293
1294 UserRefObjectCo(Wnd, &Ref);
1295 UserRefObjectCo(WndParent, &ParentRef);
1296 //ERR("Enter co_IntSetParent\n");
1297 WndOldParent = co_IntSetParent(Wnd, WndParent);
1298 //ERR("Leave co_IntSetParent\n");
1299 UserDerefObjectCo(WndParent);
1300 UserDerefObjectCo(Wnd);
1301
1302 if (WndOldParent)
1303 {
1304 hWndOldParent = WndOldParent->head.h;
1305 UserDereferenceObject(WndOldParent);
1306 }
1307
1308 return( hWndOldParent);
1309 }
1310
1311 /* Unlink the window from siblings. children and parent are kept in place. */
1312 VOID FASTCALL
1313 IntUnlinkWindow(PWND Wnd)
1314 {
1315 if (Wnd->spwndNext)
1316 Wnd->spwndNext->spwndPrev = Wnd->spwndPrev;
1317
1318 if (Wnd->spwndPrev)
1319 Wnd->spwndPrev->spwndNext = Wnd->spwndNext;
1320
1321 if (Wnd->spwndParent && Wnd->spwndParent->spwndChild == Wnd)
1322 Wnd->spwndParent->spwndChild = Wnd->spwndNext;
1323
1324 Wnd->spwndPrev = Wnd->spwndNext = NULL;
1325 }
1326
1327 /* FUNCTIONS *****************************************************************/
1328
1329 /*
1330 * As best as I can figure, this function is used by EnumWindows,
1331 * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
1332 *
1333 * It's supposed to build a list of HWNDs to return to the caller.
1334 * We can figure out what kind of list by what parameters are
1335 * passed to us.
1336 */
1337 /*
1338 * @implemented
1339 */
1340 NTSTATUS
1341 APIENTRY
1342 NtUserBuildHwndList(
1343 HDESK hDesktop,
1344 HWND hwndParent,
1345 BOOLEAN bChildren,
1346 ULONG dwThreadId,
1347 ULONG lParam,
1348 HWND* pWnd,
1349 ULONG* pBufSize)
1350 {
1351 NTSTATUS Status;
1352 ULONG dwCount = 0;
1353
1354 if (pBufSize == 0)
1355 return ERROR_INVALID_PARAMETER;
1356
1357 if (hwndParent || !dwThreadId)
1358 {
1359 PDESKTOP Desktop;
1360 PWND Parent, Window;
1361
1362 if(!hwndParent)
1363 {
1364 if(hDesktop == NULL && !(Desktop = IntGetActiveDesktop()))
1365 {
1366 return ERROR_INVALID_HANDLE;
1367 }
1368
1369 if(hDesktop)
1370 {
1371 Status = IntValidateDesktopHandle(hDesktop,
1372 UserMode,
1373 0,
1374 &Desktop);
1375 if(!NT_SUCCESS(Status))
1376 {
1377 return ERROR_INVALID_HANDLE;
1378 }
1379 }
1380 hwndParent = Desktop->DesktopWindow;
1381 }
1382 else
1383 {
1384 hDesktop = 0;
1385 }
1386
1387 if((Parent = UserGetWindowObject(hwndParent)) &&
1388 (Window = Parent->spwndChild))
1389 {
1390 BOOL bGoDown = TRUE;
1391
1392 Status = STATUS_SUCCESS;
1393 while(TRUE)
1394 {
1395 if (bGoDown)
1396 {
1397 if(dwCount++ < *pBufSize && pWnd)
1398 {
1399 _SEH2_TRY
1400 {
1401 ProbeForWrite(pWnd, sizeof(HWND), 1);
1402 *pWnd = Window->head.h;
1403 pWnd++;
1404 }
1405 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1406 {
1407 Status = _SEH2_GetExceptionCode();
1408 }
1409 _SEH2_END
1410 if(!NT_SUCCESS(Status))
1411 {
1412 SetLastNtError(Status);
1413 break;
1414 }
1415 }
1416 if (Window->spwndChild && bChildren)
1417 {
1418 Window = Window->spwndChild;
1419 continue;
1420 }
1421 bGoDown = FALSE;
1422 }
1423 if (Window->spwndNext)
1424 {
1425 Window = Window->spwndNext;
1426 bGoDown = TRUE;
1427 continue;
1428 }
1429 Window = Window->spwndParent;
1430 if (Window == Parent)
1431 {
1432 break;
1433 }
1434 }
1435 }
1436
1437 if(hDesktop)
1438 {
1439 ObDereferenceObject(Desktop);
1440 }
1441 }
1442 else // Build EnumThreadWindows list!
1443 {
1444 PETHREAD Thread;
1445 PTHREADINFO W32Thread;
1446 PLIST_ENTRY Current;
1447 PWND Window;
1448
1449 Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
1450 if (!NT_SUCCESS(Status))
1451 {
1452 ERR("Thread Id is not valid!\n");
1453 return ERROR_INVALID_PARAMETER;
1454 }
1455 if (!(W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread))
1456 {
1457 ObDereferenceObject(Thread);
1458 ERR("Thread is not initialized!\n");
1459 return ERROR_INVALID_PARAMETER;
1460 }
1461
1462 Current = W32Thread->WindowListHead.Flink;
1463 while (Current != &(W32Thread->WindowListHead))
1464 {
1465 Window = CONTAINING_RECORD(Current, WND, ThreadListEntry);
1466 ASSERT(Window);
1467
1468 if (dwCount < *pBufSize && pWnd)
1469 {
1470 _SEH2_TRY
1471 {
1472 ProbeForWrite(pWnd, sizeof(HWND), 1);
1473 *pWnd = Window->head.h;
1474 pWnd++;
1475 }
1476 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1477 {
1478 Status = _SEH2_GetExceptionCode();
1479 }
1480 _SEH2_END
1481 if (!NT_SUCCESS(Status))
1482 {
1483 ERR("Failure to build window list!\n");
1484 SetLastNtError(Status);
1485 break;
1486 }
1487 }
1488 dwCount++;
1489 Current = Window->ThreadListEntry.Flink;
1490 }
1491
1492 ObDereferenceObject(Thread);
1493 }
1494
1495 *pBufSize = dwCount;
1496 return STATUS_SUCCESS;
1497 }
1498
1499 static void IntSendParentNotify( PWND pWindow, UINT msg )
1500 {
1501 if ( (pWindow->style & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
1502 !(pWindow->style & WS_EX_NOPARENTNOTIFY))
1503 {
1504 if (pWindow->spwndParent && pWindow->spwndParent != UserGetDesktopWindow())
1505 {
1506 USER_REFERENCE_ENTRY Ref;
1507 UserRefObjectCo(pWindow->spwndParent, &Ref);
1508 co_IntSendMessage( pWindow->spwndParent->head.h,
1509 WM_PARENTNOTIFY,
1510 MAKEWPARAM( msg, pWindow->IDMenu),
1511 (LPARAM)pWindow->head.h );
1512 UserDerefObjectCo(pWindow->spwndParent);
1513 }
1514 }
1515 }
1516
1517 void FASTCALL
1518 IntFixWindowCoordinates(CREATESTRUCTW* Cs, PWND ParentWindow, DWORD* dwShowMode)
1519 {
1520 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1521
1522 /* default positioning for overlapped windows */
1523 if(!(Cs->style & (WS_POPUP | WS_CHILD)))
1524 {
1525 PMONITOR pMonitor;
1526 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
1527
1528 pMonitor = UserGetPrimaryMonitor();
1529
1530 /* Check if we don't have a monitor attached yet */
1531 if(pMonitor == NULL)
1532 {
1533 Cs->x = Cs->y = 0;
1534 Cs->cx = 800;
1535 Cs->cy = 600;
1536 return;
1537 }
1538
1539 ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
1540
1541 if (IS_DEFAULT(Cs->x))
1542 {
1543 if (!IS_DEFAULT(Cs->y)) *dwShowMode = Cs->y;
1544
1545 if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
1546 {
1547 Cs->x = ProcessParams->StartingX;
1548 Cs->y = ProcessParams->StartingY;
1549 }
1550 else
1551 {
1552 Cs->x = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CXSIZE) + UserGetSystemMetrics(SM_CXFRAME));
1553 Cs->y = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CYSIZE) + UserGetSystemMetrics(SM_CYFRAME));
1554 if (Cs->x > ((pMonitor->rcWork.right - pMonitor->rcWork.left) / 4) ||
1555 Cs->y > ((pMonitor->rcWork.bottom - pMonitor->rcWork.top) / 4))
1556 {
1557 /* reset counter and position */
1558 Cs->x = 0;
1559 Cs->y = 0;
1560 pMonitor->cWndStack = 0;
1561 }
1562 pMonitor->cWndStack++;
1563 }
1564 }
1565
1566 if (IS_DEFAULT(Cs->cx))
1567 {
1568 if (ProcessParams->WindowFlags & STARTF_USEPOSITION)
1569 {
1570 Cs->cx = ProcessParams->CountX;
1571 Cs->cy = ProcessParams->CountY;
1572 }
1573 else
1574 {
1575 Cs->cx = (pMonitor->rcWork.right - pMonitor->rcWork.left) * 3 / 4;
1576 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1577 }
1578 }
1579 /* neither x nor cx are default. Check the y values .
1580 * In the trace we see Outlook and Outlook Express using
1581 * cy set to CW_USEDEFAULT when opening the address book.
1582 */
1583 else if (IS_DEFAULT(Cs->cy))
1584 {
1585 TRACE("Strange use of CW_USEDEFAULT in nHeight\n");
1586 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1587 }
1588 }
1589 else
1590 {
1591 /* if CW_USEDEFAULT is set for non-overlapped windows, both values are set to zero */
1592 if(IS_DEFAULT(Cs->x))
1593 {
1594 Cs->x = 0;
1595 Cs->y = 0;
1596 }
1597 if(IS_DEFAULT(Cs->cx))
1598 {
1599 Cs->cx = 0;
1600 Cs->cy = 0;
1601 }
1602 }
1603
1604 #undef IS_DEFAULT
1605 }
1606
1607 /* Allocates and initializes a window */
1608 PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
1609 PLARGE_STRING WindowName,
1610 PCLS Class,
1611 PWND ParentWindow,
1612 PWND OwnerWindow,
1613 PVOID acbiBuffer,
1614 PDESKTOP pdeskCreated)
1615 {
1616 PWND pWnd = NULL;
1617 HWND hWnd;
1618 PTHREADINFO pti = NULL;
1619 BOOL MenuChanged;
1620 BOOL bUnicodeWindow;
1621
1622 pti = pdeskCreated ? gptiDesktopThread : GetW32ThreadInfo();
1623
1624 if (!(Cs->dwExStyle & WS_EX_LAYOUTRTL))
1625 { // Need both here for wine win.c test_CreateWindow.
1626 //if (Cs->hwndParent && ParentWindow)
1627 if (ParentWindow) // It breaks more tests..... WIP.
1628 {
1629 if ( (Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD &&
1630 ParentWindow->ExStyle & WS_EX_LAYOUTRTL &&
1631 !(ParentWindow->ExStyle & WS_EX_NOINHERITLAYOUT) )
1632 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1633 }
1634 else
1635 { /*
1636 * Note from MSDN <http://msdn.microsoft.com/en-us/library/aa913269.aspx>:
1637 *
1638 * Dialog boxes and message boxes do not inherit layout, so you must
1639 * set the layout explicitly.
1640 */
1641 if ( Class->fnid != FNID_DIALOG )
1642 {
1643 if (pti->ppi->dwLayout & LAYOUT_RTL)
1644 {
1645 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1646 }
1647 }
1648 }
1649 }
1650
1651 /* Automatically add WS_EX_WINDOWEDGE */
1652 if ((Cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1653 ((!(Cs->dwExStyle & WS_EX_STATICEDGE)) &&
1654 (Cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1655 Cs->dwExStyle |= WS_EX_WINDOWEDGE;
1656 else
1657 Cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1658
1659 /* Is it a unicode window? */
1660 bUnicodeWindow =!(Cs->dwExStyle & WS_EX_SETANSICREATOR);
1661 Cs->dwExStyle &= ~WS_EX_SETANSICREATOR;
1662
1663 /* Allocate the new window */
1664 pWnd = (PWND) UserCreateObject( gHandleTable,
1665 pdeskCreated ? pdeskCreated : pti->rpdesk,
1666 pti,
1667 (PHANDLE)&hWnd,
1668 TYPE_WINDOW,
1669 sizeof(WND) + Class->cbwndExtra);
1670
1671 if (!pWnd)
1672 {
1673 goto AllocError;
1674 }
1675
1676 TRACE("Created window object with handle %p\n", hWnd);
1677
1678 if (pdeskCreated && pdeskCreated->DesktopWindow == NULL )
1679 { /* HACK: Helper for win32csr/desktopbg.c */
1680 /* If there is no desktop window yet, we must be creating it */
1681 TRACE("CreateWindow setting desktop.\n");
1682 pdeskCreated->DesktopWindow = hWnd;
1683 pdeskCreated->pDeskInfo->spwnd = pWnd;
1684 }
1685
1686 /*
1687 * Fill out the structure describing it.
1688 */
1689 /* Remember, pWnd->head is setup in object.c ... */
1690 pWnd->spwndParent = ParentWindow;
1691 pWnd->spwndOwner = OwnerWindow;
1692 pWnd->fnid = 0;
1693 pWnd->spwndLastActive = pWnd;
1694 pWnd->state2 |= WNDS2_WIN40COMPAT; // FIXME!!!
1695 pWnd->pcls = Class;
1696 pWnd->hModule = Cs->hInstance;
1697 pWnd->style = Cs->style & ~WS_VISIBLE;
1698 pWnd->ExStyle = Cs->dwExStyle;
1699 pWnd->cbwndExtra = pWnd->pcls->cbwndExtra;
1700 pWnd->pActCtx = acbiBuffer;
1701 pWnd->InternalPos.MaxPos.x = pWnd->InternalPos.MaxPos.y = -1;
1702 pWnd->InternalPos.IconPos.x = pWnd->InternalPos.IconPos.y = -1;
1703
1704 if (pWnd->spwndParent != NULL && Cs->hwndParent != 0)
1705 {
1706 pWnd->HideFocus = pWnd->spwndParent->HideFocus;
1707 pWnd->HideAccel = pWnd->spwndParent->HideAccel;
1708 }
1709
1710 pWnd->head.pti->cWindows++;
1711
1712 if (Class->hIcon && !Class->hIconSm)
1713 {
1714 Class->hIconSmIntern = co_IntCopyImage( Class->hIcon, IMAGE_ICON,
1715 UserGetSystemMetrics( SM_CXSMICON ),
1716 UserGetSystemMetrics( SM_CYSMICON ), 0 );
1717 TRACE("IntCreateWindow hIconSmIntern %p\n",Class->hIconSmIntern);
1718 Class->CSF_flags |= CSF_CACHEDSMICON;
1719 }
1720
1721 if (pWnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
1722 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
1723
1724 /* BugBoy Comments: Comment below say that System classes are always created
1725 as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
1726 sets the window to ansi as verified by testing with IsUnicodeWindow API.
1727
1728 No where can I see in code or through testing does the window change back
1729 to ANSI after being created as UNICODE in ROS. I didnt do more testing to
1730 see what problems this would cause. */
1731
1732 // Set WndProc from Class.
1733 pWnd->lpfnWndProc = pWnd->pcls->lpfnWndProc;
1734
1735 // GetWindowProc, test for non server side default classes and set WndProc.
1736 if ( pWnd->pcls->fnid <= FNID_GHOST && pWnd->pcls->fnid >= FNID_BUTTON )
1737 {
1738 if (bUnicodeWindow)
1739 {
1740 if (GETPFNCLIENTA(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1741 pWnd->lpfnWndProc = GETPFNCLIENTW(pWnd->pcls->fnid);
1742 }
1743 else
1744 {
1745 if (GETPFNCLIENTW(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1746 pWnd->lpfnWndProc = GETPFNCLIENTA(pWnd->pcls->fnid);
1747 }
1748 }
1749
1750 // If not an Unicode caller, set Ansi creator bit.
1751 if (!bUnicodeWindow) pWnd->state |= WNDS_ANSICREATOR;
1752
1753 // Clone Class Ansi/Unicode proc type.
1754 if (pWnd->pcls->CSF_flags & CSF_ANSIPROC)
1755 {
1756 pWnd->state |= WNDS_ANSIWINDOWPROC;
1757 pWnd->Unicode = FALSE;
1758 }
1759 else
1760 { /*
1761 * It seems there can be both an Ansi creator and Unicode Class Window
1762 * WndProc, unless the following overriding conditions occur:
1763 */
1764 if ( !bUnicodeWindow &&
1765 ( Class->atomClassName == gpsi->atomSysClass[ICLS_BUTTON] ||
1766 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX] ||
1767 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOLBOX] ||
1768 Class->atomClassName == gpsi->atomSysClass[ICLS_DIALOG] ||
1769 Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT] ||
1770 Class->atomClassName == gpsi->atomSysClass[ICLS_IME] ||
1771 Class->atomClassName == gpsi->atomSysClass[ICLS_LISTBOX] ||
1772 Class->atomClassName == gpsi->atomSysClass[ICLS_MDICLIENT] ||
1773 Class->atomClassName == gpsi->atomSysClass[ICLS_STATIC] ) )
1774 { // Override Class and set the window Ansi WndProc.
1775 pWnd->state |= WNDS_ANSIWINDOWPROC;
1776 pWnd->Unicode = FALSE;
1777 }
1778 else
1779 { // Set the window Unicode WndProc.
1780 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
1781 pWnd->Unicode = TRUE;
1782 }
1783 }
1784
1785 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
1786 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
1787 Dont understand why it does this. */
1788 if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT])
1789 {
1790 PCALLPROCDATA CallProc;
1791 CallProc = CreateCallProc(NULL, pWnd->lpfnWndProc, pWnd->Unicode , pWnd->head.pti->ppi);
1792
1793 if (!CallProc)
1794 {
1795 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1796 ERR("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %p\n", hWnd);
1797 }
1798 else
1799 {
1800 UserAddCallProcToClass(pWnd->pcls, CallProc);
1801 }
1802 }
1803
1804 InitializeListHead(&pWnd->PropListHead);
1805
1806 if ( WindowName->Buffer != NULL && WindowName->Length > 0 )
1807 {
1808 pWnd->strName.Buffer = DesktopHeapAlloc(pWnd->head.rpdesk,
1809 WindowName->Length + sizeof(UNICODE_NULL));
1810 if (pWnd->strName.Buffer == NULL)
1811 {
1812 goto AllocError;
1813 }
1814
1815 RtlCopyMemory(pWnd->strName.Buffer, WindowName->Buffer, WindowName->Length);
1816 pWnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
1817 pWnd->strName.Length = WindowName->Length;
1818 pWnd->strName.MaximumLength = WindowName->Length + sizeof(UNICODE_NULL);
1819 }
1820
1821 /* Correct the window style. */
1822 if ((pWnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1823 {
1824 pWnd->style |= WS_CLIPSIBLINGS;
1825 if (!(pWnd->style & WS_POPUP))
1826 {
1827 pWnd->style |= WS_CAPTION;
1828 }
1829 }
1830
1831 /* WS_EX_WINDOWEDGE depends on some other styles */
1832 if (pWnd->ExStyle & WS_EX_DLGMODALFRAME)
1833 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1834 else if (pWnd->style & (WS_DLGFRAME | WS_THICKFRAME))
1835 {
1836 if (!((pWnd->ExStyle & WS_EX_STATICEDGE) &&
1837 (pWnd->style & (WS_CHILD | WS_POPUP))))
1838 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1839 }
1840 else
1841 pWnd->ExStyle &= ~WS_EX_WINDOWEDGE;
1842
1843 if (!(pWnd->style & (WS_CHILD | WS_POPUP)))
1844 pWnd->state |= WNDS_SENDSIZEMOVEMSGS;
1845
1846 /* Set the window menu */
1847 if ((Cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1848 {
1849 if (Cs->hMenu)
1850 {
1851 IntSetMenu(pWnd, Cs->hMenu, &MenuChanged);
1852 }
1853 else if (pWnd->pcls->lpszMenuName) // Take it from the parent.
1854 {
1855 UNICODE_STRING MenuName;
1856 HMENU hMenu;
1857
1858 if (IS_INTRESOURCE(pWnd->pcls->lpszMenuName))
1859 {
1860 MenuName.Length = 0;
1861 MenuName.MaximumLength = 0;
1862 MenuName.Buffer = pWnd->pcls->lpszMenuName;
1863 }
1864 else
1865 {
1866 RtlInitUnicodeString( &MenuName, pWnd->pcls->lpszMenuName);
1867 }
1868 hMenu = co_IntCallLoadMenu( pWnd->pcls->hModule, &MenuName);
1869 if (hMenu) IntSetMenu(pWnd, hMenu, &MenuChanged);
1870 }
1871 }
1872 else // Not a child
1873 pWnd->IDMenu = (UINT) Cs->hMenu;
1874
1875
1876 if ( ParentWindow &&
1877 ParentWindow != ParentWindow->head.rpdesk->spwndMessage &&
1878 ParentWindow != ParentWindow->head.rpdesk->pDeskInfo->spwnd )
1879 {
1880 PWND Owner = IntGetNonChildAncestor(ParentWindow);
1881
1882 if (!IntValidateOwnerDepth(pWnd, Owner))
1883 {
1884 EngSetLastError(ERROR_INVALID_PARAMETER);
1885 goto Error;
1886 }
1887 if ( pWnd->spwndOwner &&
1888 pWnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1889 {
1890 pWnd->ExStyle |= WS_EX_TOPMOST;
1891 }
1892 if ( pWnd->spwndOwner &&
1893 Class->atomClassName != gpsi->atomSysClass[ICLS_IME] &&
1894 pti != pWnd->spwndOwner->head.pti)
1895 {
1896 //ERR("CreateWindow Owner in.\n");
1897 UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE);
1898 }
1899 }
1900
1901 /* Insert the window into the thread's window list. */
1902 InsertTailList (&pti->WindowListHead, &pWnd->ThreadListEntry);
1903
1904 /* Handle "CS_CLASSDC", it is tested first. */
1905 if ( (pWnd->pcls->style & CS_CLASSDC) && !(pWnd->pcls->pdce) )
1906 { /* One DCE per class to have CLASS. */
1907 pWnd->pcls->pdce = DceAllocDCE( pWnd, DCE_CLASS_DC );
1908 }
1909 else if ( pWnd->pcls->style & CS_OWNDC)
1910 { /* Allocate a DCE for this window. */
1911 DceAllocDCE(pWnd, DCE_WINDOW_DC);
1912 }
1913
1914 return pWnd;
1915
1916 AllocError:
1917 ERR("IntCreateWindow Allocation Error.\n");
1918 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1919 Error:
1920 if(pWnd)
1921 UserDereferenceObject(pWnd);
1922 return NULL;
1923 }
1924
1925 /*
1926 * @implemented
1927 */
1928 PWND FASTCALL
1929 co_UserCreateWindowEx(CREATESTRUCTW* Cs,
1930 PUNICODE_STRING ClassName,
1931 PLARGE_STRING WindowName,
1932 PVOID acbiBuffer)
1933 {
1934 ULONG style;
1935 PWND Window = NULL, ParentWindow = NULL, OwnerWindow;
1936 HWND hWnd, hWndParent, hWndOwner, hwndInsertAfter;
1937 PWINSTATION_OBJECT WinSta;
1938 PCLS Class = NULL;
1939 SIZE Size;
1940 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
1941 CBT_CREATEWNDW * pCbtCreate;
1942 LRESULT Result;
1943 USER_REFERENCE_ENTRY ParentRef, Ref;
1944 PTHREADINFO pti;
1945 DWORD dwShowMode = SW_SHOW;
1946 CREATESTRUCTW *pCsw = NULL;
1947 PVOID pszClass = NULL, pszName = NULL;
1948 PWND ret = NULL;
1949
1950 /* Get the current window station and reference it */
1951 pti = GetW32ThreadInfo();
1952 if (pti == NULL || pti->rpdesk == NULL)
1953 {
1954 ERR("Thread is not attached to a desktop! Cannot create window!\n");
1955 return NULL; // There is nothing to cleanup.
1956 }
1957 WinSta = pti->rpdesk->rpwinstaParent;
1958 ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
1959
1960 pCsw = NULL;
1961 pCbtCreate = NULL;
1962
1963 /* Get the class and reference it */
1964 Class = IntGetAndReferenceClass(ClassName, Cs->hInstance, FALSE);
1965 if(!Class)
1966 {
1967 ERR("Failed to find class %wZ\n", ClassName);
1968 goto cleanup;
1969 }
1970
1971 /* Now find the parent and the owner window */
1972 hWndParent = pti->rpdesk->pDeskInfo->spwnd->head.h;
1973 hWndOwner = NULL;
1974
1975 if (Cs->hwndParent == HWND_MESSAGE)
1976 {
1977 Cs->hwndParent = hWndParent = pti->rpdesk->spwndMessage->head.h;
1978 }
1979 else if (Cs->hwndParent)
1980 {
1981 if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1982 hWndOwner = Cs->hwndParent;
1983 else
1984 hWndParent = Cs->hwndParent;
1985 }
1986 else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1987 {
1988 ERR("Cannot create a child window without a parrent!\n");
1989 EngSetLastError(ERROR_TLW_WITH_WSCHILD);
1990 goto cleanup; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1991 }
1992
1993 ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
1994 OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
1995
1996 /* FIXME: Is this correct? */
1997 if(OwnerWindow)
1998 OwnerWindow = UserGetAncestor(OwnerWindow, GA_ROOT);
1999
2000 /* Fix the position and the size of the window */
2001 if (ParentWindow)
2002 {
2003 UserRefObjectCo(ParentWindow, &ParentRef);
2004 IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode);
2005 }
2006
2007 /* Allocate and initialize the new window */
2008 Window = IntCreateWindow(Cs,
2009 WindowName,
2010 Class,
2011 ParentWindow,
2012 OwnerWindow,
2013 acbiBuffer,
2014 NULL);
2015 if(!Window)
2016 {
2017 ERR("IntCreateWindow failed!\n");
2018 goto cleanup;
2019 }
2020
2021 hWnd = UserHMGetHandle(Window);
2022 hwndInsertAfter = HWND_TOP;
2023
2024 UserRefObjectCo(Window, &Ref);
2025 UserDereferenceObject(Window);
2026 ObDereferenceObject(WinSta);
2027
2028 //// Check for a hook to eliminate overhead. ////
2029 if ( ISITHOOKED(WH_CBT) || (pti->rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)) )
2030 {
2031 // Allocate the calling structures Justin Case this goes Global.
2032 pCsw = ExAllocatePoolWithTag(NonPagedPool, sizeof(CREATESTRUCTW), TAG_HOOK);
2033 pCbtCreate = ExAllocatePoolWithTag(NonPagedPool, sizeof(CBT_CREATEWNDW), TAG_HOOK);
2034 if (!pCsw || !pCbtCreate)
2035 {
2036 ERR("UserHeapAlloc() failed!\n");
2037 goto cleanup;
2038 }
2039
2040 /* Fill the new CREATESTRUCTW */
2041 RtlCopyMemory(pCsw, Cs, sizeof(CREATESTRUCTW));
2042 pCsw->style = Window->style; /* HCBT_CREATEWND needs the real window style */
2043
2044 // Based on the assumption this is from "unicode source" user32, ReactOS, answer is yes.
2045 if (!IS_ATOM(ClassName->Buffer))
2046 {
2047 if (Window->state & WNDS_ANSICREATOR)
2048 {
2049 ANSI_STRING AnsiString;
2050 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(ClassName)+sizeof(CHAR);
2051 pszClass = UserHeapAlloc(AnsiString.MaximumLength);
2052 if (!pszClass)
2053 {
2054 ERR("UserHeapAlloc() failed!\n");
2055 goto cleanup;
2056 }
2057 RtlZeroMemory(pszClass, AnsiString.MaximumLength);
2058 AnsiString.Buffer = (PCHAR)pszClass;
2059 RtlUnicodeStringToAnsiString(&AnsiString, ClassName, FALSE);
2060 }
2061 else
2062 {
2063 UNICODE_STRING UnicodeString;
2064 UnicodeString.MaximumLength = ClassName->Length + sizeof(UNICODE_NULL);
2065 pszClass = UserHeapAlloc(UnicodeString.MaximumLength);
2066 if (!pszClass)
2067 {
2068 ERR("UserHeapAlloc() failed!\n");
2069 goto cleanup;
2070 }
2071 RtlZeroMemory(pszClass, UnicodeString.MaximumLength);
2072 UnicodeString.Buffer = (PWSTR)pszClass;
2073 RtlCopyUnicodeString(&UnicodeString, ClassName);
2074 }
2075 pCsw->lpszClass = UserHeapAddressToUser(pszClass);
2076 }
2077 if (WindowName->Length)
2078 {
2079 UNICODE_STRING Name;
2080 Name.Buffer = WindowName->Buffer;
2081 Name.Length = (USHORT)min(WindowName->Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2082 Name.MaximumLength = (USHORT)min(WindowName->MaximumLength, MAXUSHORT);
2083
2084 if (Window->state & WNDS_ANSICREATOR)
2085 {
2086 ANSI_STRING AnsiString;
2087 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(&Name) + sizeof(CHAR);
2088 pszName = UserHeapAlloc(AnsiString.MaximumLength);
2089 if (!pszName)
2090 {
2091 ERR("UserHeapAlloc() failed!\n");
2092 goto cleanup;
2093 }
2094 RtlZeroMemory(pszName, AnsiString.MaximumLength);
2095 AnsiString.Buffer = (PCHAR)pszName;
2096 RtlUnicodeStringToAnsiString(&AnsiString, &Name, FALSE);
2097 }
2098 else
2099 {
2100 UNICODE_STRING UnicodeString;
2101 UnicodeString.MaximumLength = Name.Length + sizeof(UNICODE_NULL);
2102 pszName = UserHeapAlloc(UnicodeString.MaximumLength);
2103 if (!pszName)
2104 {
2105 ERR("UserHeapAlloc() failed!\n");
2106 goto cleanup;
2107 }
2108 RtlZeroMemory(pszName, UnicodeString.MaximumLength);
2109 UnicodeString.Buffer = (PWSTR)pszName;
2110 RtlCopyUnicodeString(&UnicodeString, &Name);
2111 }
2112 pCsw->lpszName = UserHeapAddressToUser(pszName);
2113 }
2114
2115 pCbtCreate->lpcs = pCsw;
2116 pCbtCreate->hwndInsertAfter = hwndInsertAfter;
2117
2118 //// Call the WH_CBT hook ////
2119 Result = co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) pCbtCreate);
2120 if (Result != 0)
2121 {
2122 ERR("WH_CBT HCBT_CREATEWND hook failed! 0x%x\n", Result);
2123 goto cleanup;
2124 }
2125 // Write back changes.
2126 Cs->cx = pCsw->cx;
2127 Cs->cy = pCsw->cy;
2128 Cs->x = pCsw->x;
2129 Cs->y = pCsw->y;
2130 hwndInsertAfter = pCbtCreate->hwndInsertAfter;
2131 }
2132
2133 /* NCCREATE and WM_NCCALCSIZE need the original values */
2134 Cs->lpszName = (LPCWSTR) WindowName;
2135 Cs->lpszClass = (LPCWSTR) ClassName;
2136
2137 if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2138 {
2139 if (ParentWindow != co_GetDesktopWindow(Window))
2140 {
2141 Cs->x += ParentWindow->rcClient.left;
2142 Cs->y += ParentWindow->rcClient.top;
2143 }
2144 }
2145
2146 /* Send the WM_GETMINMAXINFO message */
2147 Size.cx = Cs->cx;
2148 Size.cy = Cs->cy;
2149
2150 if ((Cs->style & WS_THICKFRAME) || !(Cs->style & (WS_POPUP | WS_CHILD)))
2151 {
2152 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
2153 if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
2154 if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
2155 if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
2156 if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
2157 }
2158
2159 Window->rcWindow.left = Cs->x;
2160 Window->rcWindow.top = Cs->y;
2161 Window->rcWindow.right = Cs->x + Size.cx;
2162 Window->rcWindow.bottom = Cs->y + Size.cy;
2163 /*
2164 if (0 != (Window->style & WS_CHILD) && ParentWindow)
2165 {
2166 ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
2167 RECTL_vOffsetRect(&Window->rcWindow,
2168 ParentWindow->rcClient.left,
2169 ParentWindow->rcClient.top);
2170 }
2171 */
2172 /* correct child window coordinates if mirroring on parent is enabled */
2173 if (ParentWindow != NULL)
2174 {
2175 if ( ((Cs->style & WS_CHILD) == WS_CHILD) &&
2176 ((ParentWindow->ExStyle & WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL))
2177 {
2178 Window->rcWindow.right = ParentWindow->rcClient.right - (Window->rcWindow.left - ParentWindow->rcClient.left);
2179 Window->rcWindow.left = Window->rcWindow.right - Size.cx;
2180 }
2181 }
2182
2183 Window->rcClient = Window->rcWindow;
2184
2185 /* Link the window */
2186 if (NULL != ParentWindow)
2187 {
2188 /* Link the window into the siblings list */
2189 if ((Cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2190 IntLinkHwnd(Window, HWND_BOTTOM);
2191 else
2192 IntLinkHwnd(Window, hwndInsertAfter);
2193 }
2194
2195 if (!(Window->state2 & WNDS2_WIN31COMPAT))
2196 {
2197 if (Class->style & CS_PARENTDC && !(ParentWindow->style & WS_CLIPCHILDREN))
2198 Window->style &= ~(WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
2199 }
2200
2201 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2202 {
2203 if ( !IntIsTopLevelWindow(Window) )
2204 {
2205 if (pti != Window->spwndParent->head.pti)
2206 {
2207 //ERR("CreateWindow Parent in.\n");
2208 UserAttachThreadInput(pti, Window->spwndParent->head.pti, TRUE);
2209 }
2210 }
2211 }
2212
2213 /* Send the NCCREATE message */
2214 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_NCCREATE, 0, (LPARAM) Cs);
2215 if (!Result)
2216 {
2217 ERR("co_UserCreateWindowEx(): NCCREATE message failed\n");
2218 goto cleanup;
2219 }
2220
2221 /* Send the WM_NCCALCSIZE message */
2222 {
2223 // RECT rc;
2224 MaxPos.x = Window->rcWindow.left;
2225 MaxPos.y = Window->rcWindow.top;
2226
2227 Result = co_WinPosGetNonClientSize(Window, &Window->rcWindow, &Window->rcClient);
2228 //rc = Window->rcWindow;
2229 //Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM)&rc);
2230 //Window->rcClient = rc;
2231
2232 RECTL_vOffsetRect(&Window->rcWindow, MaxPos.x - Window->rcWindow.left,
2233 MaxPos.y - Window->rcWindow.top);
2234 }
2235
2236 /* Send the WM_CREATE message. */
2237 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_CREATE, 0, (LPARAM) Cs);
2238 if (Result == (LRESULT)-1)
2239 {
2240 ERR("co_UserCreateWindowEx(): WM_CREATE message failed\n");
2241 goto cleanup;
2242 }
2243
2244 /* Send the EVENT_OBJECT_CREATE event */
2245 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2246
2247 /* By setting the flag below it can be examined to determine if the window
2248 was created successfully and a valid pwnd was passed back to caller since
2249 from here the function has to succeed. */
2250 Window->state2 |= WNDS2_WMCREATEMSGPROCESSED;
2251
2252 /* Send the WM_SIZE and WM_MOVE messages. */
2253 if (!(Window->state & WNDS_SENDSIZEMOVEMSGS))
2254 {
2255 co_WinPosSendSizeMove(Window);
2256 }
2257
2258 /* Show or maybe minimize or maximize the window. */
2259
2260 style = IntSetStyle( Window, 0, WS_MAXIMIZE | WS_MINIMIZE );
2261 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2262 {
2263 RECTL NewPos;
2264 UINT SwFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
2265
2266 SwFlag = co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2267 SwFlag |= SWP_NOZORDER|SWP_FRAMECHANGED; /* Frame always gets changed */
2268 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || UserGetActiveWindow()) SwFlag |= SWP_NOACTIVATE;
2269 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2270 NewPos.right, NewPos.bottom, SwFlag);
2271 }
2272
2273 /* Send the WM_PARENTNOTIFY message */
2274 IntSendParentNotify(Window, WM_CREATE);
2275
2276 /* Notify the shell that a new window was created */
2277 if ((!hWndParent) && (!hWndOwner))
2278 {
2279 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0);
2280 }
2281
2282 /* Initialize and show the window's scrollbars */
2283 if (Window->style & WS_VSCROLL)
2284 {
2285 co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE);
2286 }
2287 if (Window->style & WS_HSCROLL)
2288 {
2289 co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE);
2290 }
2291
2292 /* Show the new window */
2293 if (Cs->style & WS_VISIBLE)
2294 {
2295 if (Window->style & WS_MAXIMIZE)
2296 dwShowMode = SW_SHOW;
2297 else if (Window->style & WS_MINIMIZE)
2298 dwShowMode = SW_SHOWMINIMIZED;
2299
2300 co_WinPosShowWindow(Window, dwShowMode);
2301
2302 if (Window->ExStyle & WS_EX_MDICHILD)
2303 {
2304 ASSERT(ParentWindow);
2305 if(!ParentWindow)
2306 goto cleanup;
2307 co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0);
2308 /* ShowWindow won't activate child windows */
2309 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2310 }
2311 }
2312
2313 TRACE("co_UserCreateWindowEx(): Created window %p\n", hWnd);
2314 ret = Window;
2315
2316 cleanup:
2317 if (!ret)
2318 {
2319 TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2320 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2321 if (Window)
2322 co_UserDestroyWindow(Window);
2323 else if (Class)
2324 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2325 }
2326
2327 if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
2328 if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
2329 if (pszName) UserHeapFree(pszName);
2330 if (pszClass) UserHeapFree(pszClass);
2331
2332 if (Window)
2333 {
2334 UserDerefObjectCo(Window);
2335 }
2336 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2337
2338 return ret;
2339 }
2340
2341 NTSTATUS
2342 NTAPI
2343 ProbeAndCaptureLargeString(
2344 OUT PLARGE_STRING plstrSafe,
2345 IN PLARGE_STRING plstrUnsafe)
2346 {
2347 LARGE_STRING lstrTemp;
2348 PVOID pvBuffer = NULL;
2349
2350 _SEH2_TRY
2351 {
2352 /* Probe and copy the string */
2353 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2354 lstrTemp = *plstrUnsafe;
2355 }
2356 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2357 {
2358 /* Fail */
2359 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2360 }
2361 _SEH2_END
2362
2363 if (lstrTemp.Length != 0)
2364 {
2365 /* Allocate a buffer from paged pool */
2366 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2367 if (!pvBuffer)
2368 {
2369 return STATUS_NO_MEMORY;
2370 }
2371
2372 _SEH2_TRY
2373 {
2374 /* Probe and copy the buffer */
2375 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2376 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2377 }
2378 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2379 {
2380 /* Cleanup and fail */
2381 ExFreePoolWithTag(pvBuffer, TAG_STRING);
2382 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2383 }
2384 _SEH2_END
2385 }
2386
2387 /* Set the output string */
2388 plstrSafe->Buffer = pvBuffer;
2389 plstrSafe->Length = lstrTemp.Length;
2390 plstrSafe->MaximumLength = lstrTemp.Length;
2391
2392 return STATUS_SUCCESS;
2393 }
2394
2395 /**
2396 * \todo Allow passing plstrClassName as ANSI.
2397 */
2398 HWND
2399 NTAPI
2400 NtUserCreateWindowEx(
2401 DWORD dwExStyle,
2402 PLARGE_STRING plstrClassName,
2403 PLARGE_STRING plstrClsVersion,
2404 PLARGE_STRING plstrWindowName,
2405 DWORD dwStyle,
2406 int x,
2407 int y,
2408 int nWidth,
2409 int nHeight,
2410 HWND hWndParent,
2411 HMENU hMenu,
2412 HINSTANCE hInstance,
2413 LPVOID lpParam,
2414 DWORD dwFlags,
2415 PVOID acbiBuffer)
2416 {
2417 NTSTATUS Status;
2418 LARGE_STRING lstrWindowName;
2419 LARGE_STRING lstrClassName;
2420 UNICODE_STRING ustrClassName;
2421 CREATESTRUCTW Cs;
2422 HWND hwnd = NULL;
2423 PWND pwnd;
2424
2425 lstrWindowName.Buffer = NULL;
2426 lstrClassName.Buffer = NULL;
2427
2428 ASSERT(plstrWindowName);
2429
2430 if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2431 {
2432 /* check hMenu is valid handle */
2433 if (hMenu && !ValidateHandle(hMenu, TYPE_MENU))
2434 {
2435 /* error is set in ValidateHandle */
2436 return NULL;
2437 }
2438 }
2439
2440 /* Copy the window name to kernel mode */
2441 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2442 if (!NT_SUCCESS(Status))
2443 {
2444 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2445 SetLastNtError(Status);
2446 return NULL;
2447 }
2448
2449 plstrWindowName = &lstrWindowName;
2450
2451 /* Check if the class is an atom */
2452 if (IS_ATOM(plstrClassName))
2453 {
2454 /* It is, pass the atom in the UNICODE_STRING */
2455 ustrClassName.Buffer = (PVOID)plstrClassName;
2456 ustrClassName.Length = 0;
2457 ustrClassName.MaximumLength = 0;
2458 }
2459 else
2460 {
2461 /* It's not, capture the class name */
2462 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2463 if (!NT_SUCCESS(Status))
2464 {
2465 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2466 /* Set last error, cleanup and return */
2467 SetLastNtError(Status);
2468 goto cleanup;
2469 }
2470
2471 /* We pass it on as a UNICODE_STRING */
2472 ustrClassName.Buffer = lstrClassName.Buffer;
2473 ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2474 ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
2475 }
2476
2477 /* Fill the CREATESTRUCTW */
2478 /* we will keep here the original parameters */
2479 Cs.style = dwStyle;
2480 Cs.lpCreateParams = lpParam;
2481 Cs.hInstance = hInstance;
2482 Cs.hMenu = hMenu;
2483 Cs.hwndParent = hWndParent;
2484 Cs.cx = nWidth;
2485 Cs.cy = nHeight;
2486 Cs.x = x;
2487 Cs.y = y;
2488 Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
2489 if (IS_ATOM(plstrClassName))
2490 Cs.lpszClass = (LPCWSTR) plstrClassName;
2491 else
2492 Cs.lpszClass = (LPCWSTR) plstrClassName->Buffer;
2493 Cs.dwExStyle = dwExStyle;
2494
2495 UserEnterExclusive();
2496
2497 /* Call the internal function */
2498 pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName, acbiBuffer);
2499
2500 if(!pwnd)
2501 {
2502 ERR("co_UserCreateWindowEx failed!\n");
2503 }
2504 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2505
2506 UserLeave();
2507
2508 cleanup:
2509 if (lstrWindowName.Buffer)
2510 {
2511 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2512 }
2513 if (lstrClassName.Buffer)
2514 {
2515 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2516 }
2517
2518 return hwnd;
2519 }
2520
2521
2522 BOOLEAN FASTCALL co_UserDestroyWindow(PWND Window)
2523 {
2524 HWND hWnd;
2525 PWND pwndTemp;
2526 PTHREADINFO ti;
2527 MSG msg;
2528
2529 ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
2530
2531 hWnd = Window->head.h;
2532 ti = PsGetCurrentThreadWin32Thread();
2533
2534 TRACE("co_UserDestroyWindow \n");
2535
2536 /* Check for owner thread */
2537 if ( Window->head.pti != PsGetCurrentThreadWin32Thread())
2538 {
2539 /* Check if we are destroying the desktop window */
2540 if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
2541 {
2542 EngSetLastError(ERROR_ACCESS_DENIED);
2543 return FALSE;
2544 }
2545 }
2546
2547 /* If window was created successfully and it is hooked */
2548 if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
2549 {
2550 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0))
2551 {
2552 ERR("Destroy Window WH_CBT Call Hook return!\n");
2553 return FALSE;
2554 }
2555 }
2556
2557 if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
2558 {
2559 if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2560 {
2561 if (Window->spwndOwner)
2562 {
2563 //ERR("DestroyWindow Owner out.\n");
2564 UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2565 }
2566 }
2567 }
2568
2569 /* Inform the parent */
2570 if (Window->style & WS_CHILD)
2571 {
2572 IntSendParentNotify(Window, WM_DESTROY);
2573 }
2574
2575 /* Look whether the focus is within the tree of windows we will
2576 * be destroying.
2577 */
2578 if (!co_WinPosShowWindow(Window, SW_HIDE))
2579 { // Rule #1.
2580 if (ti->MessageQueue->spwndActive == Window && ti->MessageQueue == IntGetFocusMessageQueue())
2581 {
2582 co_WinPosActivateOtherWindow(Window);
2583 }
2584 }
2585
2586 // Adjust last active.
2587 if ((pwndTemp = Window->spwndOwner))
2588 {
2589 while (pwndTemp->spwndOwner)
2590 pwndTemp = pwndTemp->spwndOwner;
2591
2592 if (pwndTemp->spwndLastActive == Window)
2593 pwndTemp->spwndLastActive = Window->spwndOwner;
2594 }
2595
2596 if (Window->spwndParent && IntIsWindow(Window->head.h))
2597 {
2598 if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
2599 {
2600 if (!IntIsTopLevelWindow(Window))
2601 {
2602 //ERR("DestroyWindow Parent out.\n");
2603 UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2604 }
2605 }
2606 }
2607
2608 if (Window->head.pti->MessageQueue->spwndActive == Window)
2609 Window->head.pti->MessageQueue->spwndActive = NULL;
2610 if (Window->head.pti->MessageQueue->spwndFocus == Window)
2611 Window->head.pti->MessageQueue->spwndFocus = NULL;
2612 if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
2613 Window->head.pti->MessageQueue->spwndActivePrev = NULL;
2614 if (Window->head.pti->MessageQueue->spwndCapture == Window)
2615 Window->head.pti->MessageQueue->spwndCapture = NULL;
2616
2617 /*
2618 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2619 */
2620
2621 if ((ti != NULL) && (ti->pDeskInfo != NULL))
2622 {
2623 if (ti->pDeskInfo->hShellWindow == hWnd)
2624 {
2625 ERR("Destroying the ShellWindow!\n");
2626 ti->pDeskInfo->hShellWindow = NULL;
2627 }
2628 }
2629
2630 IntEngWindowChanged(Window, WOC_DELETE);
2631
2632 if (!IntIsWindow(Window->head.h))
2633 {
2634 return TRUE;
2635 }
2636
2637 /* Recursively destroy owned windows */
2638
2639 if (! (Window->style & WS_CHILD))
2640 {
2641 for (;;)
2642 {
2643 BOOL GotOne = FALSE;
2644 HWND *Children;
2645 HWND *ChildHandle;
2646 PWND Child, Desktop;
2647
2648 Desktop = IntIsDesktopWindow(Window) ? Window :
2649 UserGetWindowObject(IntGetDesktopWindow());
2650 Children = IntWinListChildren(Desktop);
2651
2652 if (Children)
2653 {
2654 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2655 {
2656 Child = UserGetWindowObject(*ChildHandle);
2657 if (Child == NULL)
2658 continue;
2659 if (Child->spwndOwner != Window)
2660 {
2661 continue;
2662 }
2663
2664 if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
2665 {
2666 USER_REFERENCE_ENTRY ChildRef;
2667 UserRefObjectCo(Child, &ChildRef); // Temp HACK?
2668 co_UserDestroyWindow(Child);
2669 UserDerefObjectCo(Child); // Temp HACK?
2670
2671 GotOne = TRUE;
2672 continue;
2673 }
2674
2675 if (Child->spwndOwner != NULL)
2676 {
2677 Child->spwndOwner = NULL;
2678 }
2679
2680 }
2681 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
2682 }
2683 if (! GotOne)
2684 {
2685 break;
2686 }
2687 }
2688 }
2689
2690 /* Generate mouse move message for the next window */
2691 msg.message = WM_MOUSEMOVE;
2692 msg.wParam = UserGetMouseButtonsState();
2693 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2694 msg.pt = gpsi->ptCursor;
2695 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2696
2697 if (!IntIsWindow(Window->head.h))
2698 {
2699 return TRUE;
2700 }
2701
2702 /* Destroy the window storage */
2703 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2704
2705 return TRUE;
2706 }
2707
2708
2709 /*
2710 * @implemented
2711 */
2712 BOOLEAN APIENTRY
2713 NtUserDestroyWindow(HWND Wnd)
2714 {
2715 PWND Window;
2716 DECLARE_RETURN(BOOLEAN);
2717 BOOLEAN ret;
2718 USER_REFERENCE_ENTRY Ref;
2719
2720 TRACE("Enter NtUserDestroyWindow\n");
2721 UserEnterExclusive();
2722
2723 if (!(Window = UserGetWindowObject(Wnd)))
2724 {
2725 RETURN(FALSE);
2726 }
2727
2728 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
2729 ret = co_UserDestroyWindow(Window);
2730 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
2731
2732 RETURN(ret);
2733
2734 CLEANUP:
2735 TRACE("Leave NtUserDestroyWindow, ret=%u\n", _ret_);
2736 UserLeave();
2737 END_CLEANUP;
2738 }
2739
2740
2741 static HWND FASTCALL
2742 IntFindWindow(PWND Parent,
2743 PWND ChildAfter,
2744 RTL_ATOM ClassAtom,
2745 PUNICODE_STRING WindowName)
2746 {
2747 BOOL CheckWindowName;
2748 HWND *List, *phWnd;
2749 HWND Ret = NULL;
2750 UNICODE_STRING CurrentWindowName;
2751
2752 ASSERT(Parent);
2753
2754 CheckWindowName = WindowName->Buffer != 0;
2755
2756 if((List = IntWinListChildren(Parent)))
2757 {
2758 phWnd = List;
2759 if(ChildAfter)
2760 {
2761 /* skip handles before and including ChildAfter */
2762 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2763 ;
2764 }
2765
2766 /* search children */
2767 while(*phWnd)
2768 {
2769 PWND Child;
2770 if(!(Child = UserGetWindowObject(*(phWnd++))))
2771 {
2772 continue;
2773 }
2774
2775 /* Do not send WM_GETTEXT messages in the kernel mode version!
2776 The user mode version however calls GetWindowText() which will
2777 send WM_GETTEXT messages to windows belonging to its processes */
2778 if (!ClassAtom || Child->pcls->atomClassName == ClassAtom)
2779 {
2780 // FIXME: LARGE_STRING truncated
2781 CurrentWindowName.Buffer = Child->strName.Buffer;
2782 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
2783 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
2784 if(!CheckWindowName ||
2785 (Child->strName.Length < 0xFFFF &&
2786 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
2787 {
2788 Ret = Child->head.h;
2789 break;
2790 }
2791 }
2792 }
2793 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2794 }
2795
2796 return Ret;
2797 }
2798
2799 /*
2800 * FUNCTION:
2801 * Searches a window's children for a window with the specified
2802 * class and name
2803 * ARGUMENTS:
2804 * hwndParent = The window whose childs are to be searched.
2805 * NULL = desktop
2806 * HWND_MESSAGE = message-only windows
2807 *
2808 * hwndChildAfter = Search starts after this child window.
2809 * NULL = start from beginning
2810 *
2811 * ucClassName = Class name to search for
2812 * Reguired parameter.
2813 *
2814 * ucWindowName = Window name
2815 * ->Buffer == NULL = don't care
2816 *
2817 * RETURNS:
2818 * The HWND of the window if it was found, otherwise NULL
2819 */
2820 /*
2821 * @implemented
2822 */
2823 HWND APIENTRY
2824 NtUserFindWindowEx(HWND hwndParent,
2825 HWND hwndChildAfter,
2826 PUNICODE_STRING ucClassName,
2827 PUNICODE_STRING ucWindowName,
2828 DWORD dwUnknown)
2829 {
2830 PWND Parent, ChildAfter;
2831 UNICODE_STRING ClassName = {0}, WindowName = {0};
2832 HWND Desktop, Ret = NULL;
2833 BOOL DoMessageWnd = FALSE;
2834 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2835 DECLARE_RETURN(HWND);
2836
2837 TRACE("Enter NtUserFindWindowEx\n");
2838 UserEnterShared();
2839
2840 if (ucClassName != NULL || ucWindowName != NULL)
2841 {
2842 _SEH2_TRY
2843 {
2844 if (ucClassName != NULL)
2845 {
2846 ClassName = ProbeForReadUnicodeString(ucClassName);
2847 if (ClassName.Length != 0)
2848 {
2849 ProbeForRead(ClassName.Buffer,
2850 ClassName.Length,
2851 sizeof(WCHAR));
2852 }
2853 else if (!IS_ATOM(ClassName.Buffer))
2854 {
2855 EngSetLastError(ERROR_INVALID_PARAMETER);
2856 _SEH2_LEAVE;
2857 }
2858
2859 if (!IntGetAtomFromStringOrAtom(&ClassName,
2860 &ClassAtom))
2861 {
2862 _SEH2_LEAVE;
2863 }
2864 }
2865
2866 if (ucWindowName != NULL)
2867 {
2868 WindowName = ProbeForReadUnicodeString(ucWindowName);
2869 if (WindowName.Length != 0)
2870 {
2871 ProbeForRead(WindowName.Buffer,
2872 WindowName.Length,
2873 sizeof(WCHAR));
2874 }
2875 }
2876 }
2877 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2878 {
2879 SetLastNtError(_SEH2_GetExceptionCode());
2880 _SEH2_YIELD(RETURN(NULL));
2881 }
2882 _SEH2_END;
2883
2884 if (ucClassName != NULL)
2885 {
2886 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
2887 !IS_ATOM(ClassName.Buffer))
2888 {
2889 EngSetLastError(ERROR_INVALID_PARAMETER);
2890 RETURN(NULL);
2891 }
2892 else if (ClassAtom == (RTL_ATOM)0)
2893 {
2894 /* LastError code was set by IntGetAtomFromStringOrAtom */
2895 RETURN(NULL);
2896 }
2897 }
2898 }
2899
2900 Desktop = IntGetCurrentThreadDesktopWindow();
2901
2902 if(hwndParent == NULL)
2903 {
2904 hwndParent = Desktop;
2905 DoMessageWnd = TRUE;
2906 }
2907 else if(hwndParent == HWND_MESSAGE)
2908 {
2909 hwndParent = IntGetMessageWindow();
2910 }
2911
2912 if(!(Parent = UserGetWindowObject(hwndParent)))
2913 {
2914 RETURN( NULL);
2915 }
2916
2917 ChildAfter = NULL;
2918 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
2919 {
2920 RETURN( NULL);
2921 }
2922
2923 _SEH2_TRY
2924 {
2925 if(Parent->head.h == Desktop)
2926 {
2927 HWND *List, *phWnd;
2928 PWND TopLevelWindow;
2929 BOOLEAN CheckWindowName;
2930 BOOLEAN WindowMatches;
2931 BOOLEAN ClassMatches;
2932
2933 /* windows searches through all top-level windows if the parent is the desktop
2934 window */
2935
2936 if((List = IntWinListChildren(Parent)))
2937 {
2938 phWnd = List;
2939
2940 if(ChildAfter)
2941 {
2942 /* skip handles before and including ChildAfter */
2943 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2944 ;
2945 }
2946
2947 CheckWindowName = WindowName.Buffer != 0;
2948
2949 /* search children */
2950 while(*phWnd)
2951 {
2952 UNICODE_STRING ustr;
2953
2954 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
2955 {
2956 continue;
2957 }
2958
2959 /* Do not send WM_GETTEXT messages in the kernel mode version!
2960 The user mode version however calls GetWindowText() which will
2961 send WM_GETTEXT messages to windows belonging to its processes */
2962 ustr.Buffer = TopLevelWindow->strName.Buffer;
2963 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
2964 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
2965 WindowMatches = !CheckWindowName ||
2966 (TopLevelWindow->strName.Length < 0xFFFF &&
2967 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
2968 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
2969 ClassAtom == TopLevelWindow->pcls->atomClassName;
2970
2971 if (WindowMatches && ClassMatches)
2972 {
2973 Ret = TopLevelWindow->head.h;
2974 break;
2975 }
2976
2977 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
2978 {
2979 /* window returns the handle of the top-level window, in case it found
2980 the child window */
2981 Ret = TopLevelWindow->head.h;
2982 break;
2983 }
2984
2985 }
2986 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2987 }
2988 }
2989 else
2990 {
2991 ERR("FindWindowEx: Not Desktop Parent!\n");
2992 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
2993 }
2994
2995 if (Ret == NULL && DoMessageWnd)
2996 {
2997 PWND MsgWindows;
2998
2999 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3000 {
3001 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3002 }
3003 }
3004 }
3005 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3006 {
3007 SetLastNtError(_SEH2_GetExceptionCode());
3008 Ret = NULL;
3009 }
3010 _SEH2_END;
3011
3012 RETURN( Ret);
3013
3014 CLEANUP:
3015 TRACE("Leave NtUserFindWindowEx, ret %p\n", _ret_);
3016 UserLeave();
3017 END_CLEANUP;
3018 }
3019
3020
3021 /*
3022 * @implemented
3023 */
3024 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
3025 {
3026 PWND WndAncestor, Parent;
3027
3028 if (Wnd->head.h == IntGetDesktopWindow())
3029 {
3030 return NULL;
3031 }
3032
3033 switch (Type)
3034 {
3035 case GA_PARENT:
3036 {
3037 WndAncestor = Wnd->spwndParent;
3038 break;
3039 }
3040
3041 case GA_ROOT:
3042 {
3043 WndAncestor = Wnd;
3044 Parent = NULL;
3045
3046 for(;;)
3047 {
3048 if(!(Parent = WndAncestor->spwndParent))
3049 {
3050 break;
3051 }
3052 if(IntIsDesktopWindow(Parent))
3053 {
3054 break;
3055 }
3056
3057 WndAncestor = Parent;
3058 }
3059 break;
3060 }
3061
3062 case GA_ROOTOWNER:
3063 {
3064 WndAncestor = Wnd;
3065
3066 for (;;)
3067 {
3068 Parent = IntGetParent(WndAncestor);
3069
3070 if (!Parent)
3071 {
3072 break;
3073 }
3074
3075 WndAncestor = Parent;
3076 }
3077 break;
3078 }
3079
3080 default:
3081 {
3082 return NULL;
3083 }
3084 }
3085
3086 return WndAncestor;
3087 }
3088
3089 /*
3090 * @implemented
3091 */
3092 HWND APIENTRY
3093 NtUserGetAncestor(HWND hWnd, UINT Type)
3094 {
3095 PWND Window, Ancestor;
3096 DECLARE_RETURN(HWND);
3097
3098 TRACE("Enter NtUserGetAncestor\n");
3099 UserEnterExclusive();
3100
3101 if (!(Window = UserGetWindowObject(hWnd)))
3102 {
3103 RETURN(NULL);
3104 }
3105
3106 Ancestor = UserGetAncestor(Window, Type);
3107 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3108
3109 RETURN(Ancestor ? Ancestor->head.h : NULL);
3110
3111 CLEANUP:
3112 TRACE("Leave NtUserGetAncestor, ret=%p\n", _ret_);
3113 UserLeave();
3114 END_CLEANUP;
3115 }
3116
3117 ////
3118 //// ReactOS work around! Keep it the sames as in Combo.c and Controls.h
3119 ////
3120 /* combo state struct */
3121 typedef struct
3122 {
3123 HWND self;
3124 HWND owner;
3125 UINT dwStyle;
3126 HWND hWndEdit;
3127 HWND hWndLBox;
3128 UINT wState;
3129 HFONT hFont;
3130 RECT textRect;
3131 RECT buttonRect;
3132 RECT droppedRect;
3133 INT droppedIndex;
3134 INT fixedOwnerDrawHeight;
3135 INT droppedWidth; /* last two are not used unless set */
3136 INT editHeight; /* explicitly */
3137 LONG UIState;
3138 } HEADCOMBO,*LPHEADCOMBO;
3139
3140 // Window Extra data container.
3141 typedef struct _WND2CBOX
3142 {
3143 WND;
3144 LPHEADCOMBO pCBox;
3145 } WND2CBOX, *PWND2CBOX;
3146
3147 #define CBF_BUTTONDOWN 0x0002
3148 ////
3149 ////
3150 ////
3151 BOOL
3152 APIENTRY
3153 NtUserGetComboBoxInfo(
3154 HWND hWnd,
3155 PCOMBOBOXINFO pcbi)
3156 {
3157 PWND Wnd;
3158 PPROCESSINFO ppi;
3159 BOOL NotSameppi = FALSE;
3160 BOOL Ret = TRUE;
3161 DECLARE_RETURN(BOOL);
3162
3163 TRACE("Enter NtUserGetComboBoxInfo\n");
3164 UserEnterShared();
3165
3166 if (!(Wnd = UserGetWindowObject(hWnd)))
3167 {
3168 RETURN( FALSE );
3169 }
3170 _SEH2_TRY
3171 {
3172 if(pcbi)
3173 {
3174 ProbeForWrite(pcbi,
3175 sizeof(COMBOBOXINFO),
3176 1);
3177 }
3178 }
3179 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3180 {
3181 SetLastNtError(_SEH2_GetExceptionCode());
3182 _SEH2_YIELD(RETURN(FALSE));
3183 }
3184 _SEH2_END;
3185
3186 if (pcbi->cbSize < sizeof(COMBOBOXINFO))
3187 {
3188 EngSetLastError(ERROR_INVALID_PARAMETER);
3189 RETURN(FALSE);
3190 }
3191
3192 // Pass the user pointer, it was already probed.
3193 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_COMBOBOX]) && Wnd->fnid != FNID_COMBOBOX)
3194 {
3195 RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3196 }
3197
3198 ppi = PsGetCurrentProcessWin32Process();
3199 NotSameppi = ppi != Wnd->head.pti->ppi;
3200 if (NotSameppi)
3201 {
3202 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3203 }
3204
3205 _SEH2_TRY
3206 {
3207 LPHEADCOMBO lphc = ((PWND2CBOX)Wnd)->pCBox;
3208 pcbi->rcItem = lphc->textRect;
3209 pcbi->rcButton = lphc->buttonRect;
3210 pcbi->stateButton = 0;
3211 if (lphc->wState & CBF_BUTTONDOWN)
3212 pcbi->stateButton |= STATE_SYSTEM_PRESSED;
3213 if (RECTL_bIsEmptyRect(&lphc->buttonRect))
3214 pcbi->stateButton |= STATE_SYSTEM_INVISIBLE;
3215 pcbi->hwndCombo = lphc->self;
3216 pcbi->hwndItem = lphc->hWndEdit;
3217 pcbi->hwndList = lphc->hWndLBox;
3218 }
3219 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3220 {
3221 Ret = FALSE;
3222 SetLastNtError(_SEH2_GetExceptionCode());
3223 }
3224 _SEH2_END;
3225
3226 RETURN( Ret);
3227
3228 CLEANUP:
3229 if (NotSameppi) KeDetachProcess();
3230 TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3231 UserLeave();
3232 END_CLEANUP;
3233 }
3234
3235 ////
3236 //// ReactOS work around! Keep it the sames as in Listbox.c
3237 ////
3238 /* Listbox structure */
3239 typedef struct
3240 {
3241 HWND self; /* Our own window handle */
3242 HWND owner; /* Owner window to send notifications to */
3243 UINT style; /* Window style */
3244 INT width; /* Window width */
3245 INT height; /* Window height */
3246 VOID *items; /* Array of items */
3247 INT nb_items; /* Number of items */
3248 INT top_item; /* Top visible item */
3249 INT selected_item; /* Selected item */
3250 INT focus_item; /* Item that has the focus */
3251 INT anchor_item; /* Anchor item for extended selection */
3252 INT item_height; /* Default item height */
3253 INT page_size; /* Items per listbox page */
3254 INT column_width; /* Column width for multi-column listboxes */
3255 } LB_DESCR;
3256
3257 // Window Extra data container.
3258 typedef struct _WND2LB
3259 {
3260 WND;
3261 LB_DESCR * pLBiv;
3262 } WND2LB, *PWND2LB;
3263 ////
3264 ////
3265 ////
3266 DWORD
3267 APIENTRY
3268 NtUserGetListBoxInfo(
3269 HWND hWnd)
3270 {
3271 PWND Wnd;
3272 PPROCESSINFO ppi;
3273 BOOL NotSameppi = FALSE;
3274 DWORD Ret = 0;
3275 DECLARE_RETURN(DWORD);
3276
3277 TRACE("Enter NtUserGetListBoxInfo\n");
3278 UserEnterShared();
3279
3280 if (!(Wnd = UserGetWindowObject(hWnd)))
3281 {
3282 RETURN( 0 );
3283 }
3284
3285 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && Wnd->fnid != FNID_LISTBOX)
3286 {
3287 RETURN( (DWORD) co_IntSendMessage( Wnd->head.h, LB_GETLISTBOXINFO, 0, 0 ));
3288 }
3289
3290 // wine lisbox:test_GetListBoxInfo lb_getlistboxinfo = 0, should not send a message!
3291 ppi = PsGetCurrentProcessWin32Process();
3292 NotSameppi = ppi != Wnd->head.pti->ppi;
3293 if (NotSameppi)
3294 {
3295 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3296 }
3297
3298 _SEH2_TRY
3299 {
3300 LB_DESCR *descr = ((PWND2LB)Wnd)->pLBiv;
3301 // See Controls ListBox.c:LB_GETLISTBOXINFO must match...
3302 if (descr->style & LBS_MULTICOLUMN) //// ReactOS
3303 Ret = descr->page_size * descr->column_width;
3304 else
3305 Ret = descr->page_size;
3306 }
3307 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3308 {
3309 Ret = 0;
3310 SetLastNtError(_SEH2_GetExceptionCode());
3311 }
3312 _SEH2_END;
3313
3314 RETURN( Ret);
3315
3316 CLEANUP:
3317 if (NotSameppi) KeDetachProcess();
3318 TRACE("Leave NtUserGetListBoxInfo, ret=%lu\n", _ret_);
3319 UserLeave();
3320 END_CLEANUP;
3321 }
3322
3323 /*
3324 * NtUserSetParent
3325 *
3326 * The NtUserSetParent function changes the parent window of the specified
3327 * child window.
3328 *
3329 * Remarks
3330 * The new parent window and the child window must belong to the same
3331 * application. If the window identified by the hWndChild parameter is
3332 * visible, the system performs the appropriate redrawing and repainting.
3333 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3334 * or WS_POPUP window styles of the window whose parent is being changed.
3335 *
3336 * Status
3337 * @implemented
3338 */
3339
3340 HWND APIENTRY
3341 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3342 {
3343 DECLARE_RETURN(HWND);
3344
3345 TRACE("Enter NtUserSetParent\n");
3346 UserEnterExclusive();
3347
3348 /*
3349 Check Parent first from user space, set it here.
3350 */
3351 if (!hWndNewParent)
3352 {
3353 hWndNewParent = IntGetDesktopWindow();
3354 }
3355 else if (hWndNewParent == HWND_MESSAGE)
3356 {
3357 hWndNewParent = IntGetMessageWindow();
3358 }
3359
3360 RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3361
3362 CLEANUP:
3363 TRACE("Leave NtUserSetParent, ret=%p\n", _ret_);
3364 UserLeave();
3365 END_CLEANUP;
3366 }
3367
3368 /*
3369 * UserGetShellWindow
3370 *
3371 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3372 *
3373 * Status
3374 * @implemented
3375 */
3376 HWND FASTCALL UserGetShellWindow(VOID)
3377 {
3378 PWINSTATION_OBJECT WinStaObject;
3379 HWND Ret;
3380
3381 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3382 KernelMode,
3383 0,
3384 &WinStaObject);
3385
3386 if (!NT_SUCCESS(Status))
3387 {
3388 SetLastNtError(Status);
3389 return( (HWND)0);
3390 }
3391
3392 Ret = (HWND)WinStaObject->ShellWindow;
3393
3394 ObDereferenceObject(WinStaObject);
3395 return( Ret);
3396 }
3397
3398 /*
3399 * NtUserSetShellWindowEx
3400 *
3401 * This is undocumented function to set global shell window. The global
3402 * shell window has special handling of window position.
3403 *
3404 * Status
3405 * @implemented
3406 */
3407 BOOL APIENTRY
3408 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3409 {
3410 PWINSTATION_OBJECT WinStaObject;
3411 PWND WndShell, WndListView;
3412 DECLARE_RETURN(BOOL);
3413 USER_REFERENCE_ENTRY Ref;
3414 NTSTATUS Status;
3415 PTHREADINFO ti;
3416
3417 TRACE("Enter NtUserSetShellWindowEx\n");
3418 UserEnterExclusive();
3419
3420 if (!(WndShell = UserGetWindowObject(hwndShell)))
3421 {
3422 RETURN(FALSE);
3423 }
3424
3425 if(!(WndListView = UserGetWindowObject(hwndListView)))
3426 {
3427 RETURN(FALSE);
3428 }
3429
3430 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3431 KernelMode,
3432 0,
3433 &WinStaObject);
3434
3435 if (!NT_SUCCESS(Status))
3436 {
3437 SetLastNtError(Status);
3438 RETURN( FALSE);
3439 }
3440
3441 /*
3442 * Test if we are permitted to change the shell window.
3443 */
3444 if (WinStaObject->ShellWindow)
3445 {
3446 ObDereferenceObject(WinStaObject);
3447 RETURN( FALSE);
3448 }
3449
3450 /*
3451 * Move shell window into background.
3452 */
3453 if (hwndListView && hwndListView != hwndShell)
3454 {
3455 /*
3456 * Disabled for now to get Explorer working.
3457 * -- Filip, 01/nov/2003
3458 */
3459 #if 0
3460 co_WinPosSetWindowPos(WndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3461 #endif
3462
3463 if (WndListView->ExStyle & WS_EX_TOPMOST)
3464 {
3465 ObDereferenceObject(WinStaObject);
3466 RETURN( FALSE);
3467 }
3468 }
3469
3470 if (WndShell->ExStyle & WS_EX_TOPMOST)
3471 {
3472 ObDereferenceObject(WinStaObject);
3473 RETURN( FALSE);
3474 }
3475
3476 UserRefObjectCo(WndShell, &Ref);
3477 WndShell->state2 |= WNDS2_BOTTOMMOST;
3478 co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3479
3480 WinStaObject->ShellWindow = hwndShell;
3481 WinStaObject->ShellListView = hwndListView;
3482
3483 ti = GetW32ThreadInfo();
3484 if (ti->pDeskInfo)
3485 {
3486 ti->pDeskInfo->hShellWindow = hwndShell;
3487 ti->pDeskInfo->spwndShell = WndShell;
3488 ti->pDeskInfo->ppiShellProcess = ti->ppi;
3489 }
3490
3491 UserRegisterHotKey(WndShell, SC_TASKLIST, MOD_CONTROL, VK_ESCAPE);
3492
3493 UserDerefObjectCo(WndShell);
3494
3495 ObDereferenceObject(WinStaObject);
3496 RETURN( TRUE);
3497
3498 CLEANUP:
3499 TRACE("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3500 UserLeave();
3501 END_CLEANUP;
3502 }
3503
3504 // Fixes wine Win test_window_styles and todo tests...
3505 static BOOL FASTCALL
3506 IntCheckFrameEdge(ULONG Style, ULONG ExStyle)
3507 {
3508 if (ExStyle & WS_EX_DLGMODALFRAME)
3509 return TRUE;
3510 else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME)))
3511 return TRUE;
3512 else
3513 return FALSE;
3514 }
3515
3516 LONG FASTCALL
3517 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3518 {
3519 PWND Window, Parent;
3520 PWINSTATION_OBJECT WindowStation;
3521 LONG OldValue;
3522 STYLESTRUCT Style;
3523
3524 if (!(Window = UserGetWindowObject(hWnd)))
3525 {
3526 return( 0);
3527 }
3528
3529 if ((INT)Index >= 0)
3530 {
3531 if ((Index + sizeof(LONG)) > Window->cbwndExtra)
3532 {
3533 EngSetLastError(ERROR_INVALID_INDEX);
3534 return( 0);
3535 }
3536
3537 OldValue = *((LONG *)((PCHAR)(Window + 1) + Index));
3538 /*
3539 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3540 {
3541 OldValue = (LONG)IntSetWindowProc( Wnd,
3542 (WNDPROC)NewValue,
3543 Ansi);
3544 if (!OldValue) return 0;
3545 }
3546 */
3547 *((LONG *)((PCHAR)(Window + 1) + Index)) = NewValue;
3548 }
3549 else
3550 {
3551 switch (Index)
3552 {
3553 case GWL_EXSTYLE:
3554 OldValue = (LONG) Window->ExStyle;
3555 Style.styleOld = OldValue;
3556 Style.styleNew = NewValue;
3557
3558 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3559
3560 /*
3561 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3562 */
3563 WindowStation = Window->head.pti->rpdesk->rpwinstaParent;
3564 if(WindowStation)
3565 {
3566 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3567 Style.styleNew &= ~WS_EX_TOPMOST;
3568 }
3569 /* WS_EX_WINDOWEDGE depends on some other styles */
3570 if (IntCheckFrameEdge(Window->style, NewValue))
3571 Style.styleNew |= WS_EX_WINDOWEDGE;
3572 else
3573 Style.styleNew &= ~WS_EX_WINDOWEDGE;
3574
3575 Window->ExStyle = (DWORD)Style.styleNew;
3576 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3577 break;
3578
3579 case GWL_STYLE:
3580 OldValue = (LONG) Window->style;
3581 Style.styleOld = OldValue;
3582 Style.styleNew = NewValue;
3583 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3584
3585 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
3586 if (Window->spwndParent == UserGetDesktopWindow()) Style.styleNew |= WS_CLIPSIBLINGS;
3587 /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */
3588 if (IntCheckFrameEdge(NewValue, Window->ExStyle))
3589 Window->ExStyle |= WS_EX_WINDOWEDGE;
3590 else
3591 Window->ExStyle &= ~WS_EX_WINDOWEDGE;
3592
3593 if ((Style.styleOld ^ Style.styleNew) & WS_VISIBLE)
3594 {
3595 if (Style.styleOld & WS_VISIBLE) Window->head.pti->cVisWindows--;
3596 if (Style.styleNew & WS_VISIBLE) Window->head.pti->cVisWindows++;
3597 DceResetActiveDCEs( Window );
3598 }
3599 Window->style = (DWORD)Style.styleNew;
3600 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3601 break;
3602
3603 case GWL_WNDPROC:
3604 {
3605 if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
3606 Window->fnid & FNID_FREED)
3607 {
3608 EngSetLastError(ERROR_ACCESS_DENIED);
3609 return( 0);
3610 }
3611 OldValue = (LONG)IntSetWindowProc(Window,
3612 (WNDPROC)NewValue,
3613 Ansi);
3614 break;
3615 }
3616
3617 case GWL_HINSTANCE:
3618 OldValue = (LONG) Window->hModule;
3619 Window->hModule = (HINSTANCE) NewValue;
3620 break;
3621
3622 case GWL_HWNDPARENT:
3623 Parent = Window->spwndParent;
3624 if (Parent && (Parent->head.h == IntGetDesktopWindow()))
3625 OldValue = (LONG) IntSetOwner(Window->head.h, (HWND) NewValue);
3626 else
3627 OldValue = (LONG) co_UserSetParent(Window->head.h, (HWND) NewValue);
3628 break;
3629
3630 case GWL_ID:
3631 OldValue = (LONG) Window->IDMenu;
3632 Window->IDMenu = (UINT) NewValue;
3633 break;
3634
3635 case GWL_USERDATA:
3636 OldValue = Window->dwUserData;
3637 Window->dwUserData = NewValue;
3638 break;
3639
3640 default:
3641 ERR("NtUserSetWindowLong(): Unsupported index %lu\n", Index);
3642 EngSetLastError(ERROR_INVALID_INDEX);
3643 OldValue = 0;
3644 break;
3645 }
3646 }
3647
3648 return( OldValue);
3649 }
3650
3651 /*
3652 * NtUserSetWindowLong
3653 *
3654 * The NtUserSetWindowLong function changes an attribute of the specified
3655 * window. The function also sets the 32-bit (long) value at the specified
3656 * offset into the extra window memory.
3657 *
3658 * Status
3659 * @implemented
3660 */
3661
3662 LONG APIENTRY
3663 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3664 {
3665 DECLARE_RETURN(LONG);
3666
3667 TRACE("Enter NtUserSetWindowLong\n");
3668 UserEnterExclusive();
3669
3670 if (hWnd == IntGetDesktopWindow())
3671 {
3672 EngSetLastError(STATUS_ACCESS_DENIED);
3673 RETURN( 0);
3674 }
3675
3676 RETURN( co_UserSetWindowLong(hWnd, Index, NewValue, Ansi));
3677
3678 CLEANUP:
3679 TRACE("Leave NtUserSetWindowLong, ret=%i\n",_ret_);
3680 UserLeave();
3681 END_CLEANUP;
3682 }
3683
3684 /*
3685 * NtUserSetWindowWord
3686 *
3687 * Legacy function similar to NtUserSetWindowLong.
3688 *
3689 * Status
3690 * @implemented
3691 */
3692
3693 WORD APIENTRY
3694 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
3695 {
3696 PWND Window;
3697 WORD OldValue;
3698 DECLARE_RETURN(WORD);
3699
3700 TRACE("Enter NtUserSetWindowWord\n");
3701 UserEnterExclusive();
3702
3703 if (hWnd == IntGetDesktopWindow())
3704 {
3705 EngSetLastError(STATUS_ACCESS_DENIED);
3706 RETURN( 0);
3707 }
3708
3709 if (!(Window = UserGetWindowObject(hWnd)))
3710 {
3711 RETURN( 0);
3712 }
3713
3714 switch (Index)
3715 {
3716 case GWL_ID:
3717 case GWL_HINSTANCE:
3718 case GWL_HWNDPARENT:
3719 RETURN( (WORD)co_UserSetWindowLong(UserHMGetHandle(Window), Index, (UINT)NewValue, TRUE));
3720 default:
3721 if (Index < 0)
3722 {
3723 EngSetLastError(ERROR_INVALID_INDEX);
3724 RETURN( 0);
3725 }
3726 }
3727
3728 if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD)))
3729 {
3730 EngSetLastError(ERROR_INVALID_PARAMETER);
3731 RETURN( 0);
3732 }
3733
3734 OldValue = *((WORD *)((PCHAR)(Window + 1) + Index));
3735 *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue;
3736
3737 RETURN( OldValue);
3738
3739 CLEANUP:
3740 TRACE("Leave NtUserSetWindowWord, ret=%u\n", _ret_);
3741 UserLeave();
3742 END_CLEANUP;
3743 }
3744
3745 /*
3746 QueryWindow based on KJK::Hyperion and James Tabor.
3747
3748 0 = QWUniqueProcessId
3749 1 = QWUniqueThreadId
3750 2 = QWActiveWindow
3751 3 = QWFocusWindow
3752 4 = QWIsHung Implements IsHungAppWindow found
3753 by KJK::Hyperion.
3754
3755 9 = QWKillWindow When I called this with hWnd ==
3756 DesktopWindow, it shutdown the system
3757 and rebooted.
3758 */
3759 /*
3760 * @implemented
3761 */
3762 DWORD APIENTRY
3763 NtUserQueryWindow(HWND hWnd, DWORD Index)
3764 {
3765 /* Console Leader Process CID Window offsets */
3766 #define GWLP_CONSOLE_LEADER_PID 0
3767 #define GWLP_CONSOLE_LEADER_TID 4
3768
3769 PWND pWnd;
3770 DWORD Result;
3771 DECLARE_RETURN(UINT);
3772
3773 TRACE("Enter NtUserQueryWindow\n");
3774 UserEnterShared();
3775
3776 if (!(pWnd = UserGetWindowObject(hWnd)))
3777 {
3778 RETURN( 0);
3779 }
3780
3781 switch(Index)
3782 {
3783 case QUERY_WINDOW_UNIQUE_PROCESS_ID:
3784 {
3785 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
3786 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
3787 {
3788 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_PID)
3789 Result = (DWORD)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_PID)));
3790 }
3791 else
3792 {
3793 Result = (DWORD)IntGetWndProcessId(pWnd);
3794 }
3795 break;
3796 }
3797
3798 case QUERY_WINDOW_UNIQUE_THREAD_ID:
3799 {
3800 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
3801 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
3802 {
3803 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_TID)
3804 Result = (DWORD)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_TID)));
3805 }
3806 else
3807 {
3808 Result = (DWORD)IntGetWndThreadId(pWnd);
3809 }
3810 break;
3811 }
3812
3813 case QUERY_WINDOW_ACTIVE:
3814 Result = (DWORD)(pWnd->head.pti->MessageQueue->spwndActive ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndActive) : 0);
3815 break;
3816
3817 case QUERY_WINDOW_FOCUS:
3818 Result = (DWORD)(pWnd->head.pti->MessageQueue->spwndFocus ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndFocus) : 0);
3819 break;
3820
3821 case QUERY_WINDOW_ISHUNG:
3822 Result = (DWORD)MsqIsHung(pWnd->head.pti);
3823 break;
3824
3825 case QUERY_WINDOW_REAL_ID:
3826 Result = (DWORD)pWnd->head.pti->pEThread->Cid.UniqueProcess;
3827 break;
3828
3829 case QUERY_WINDOW_FOREGROUND:
3830 Result = (pWnd->head.pti->MessageQueue == gpqForeground);
3831 break;
3832
3833 default:
3834 Result = (DWORD)NULL;
3835 break;
3836 }
3837
3838 RETURN( Result);
3839
3840 CLEANUP:
3841 TRACE("Leave NtUserQueryWindow, ret=%u\n", _ret_);