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