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