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