9505717328eff8c7de9339b18fa863c93a28b1d4
[reactos.git] / reactos / win32ss / user / ntuser / window.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Windows
5 * FILE: subsystems/win32/win32k/ntuser/window.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserWnd);
11
12 INT gNestedWindowLimit = 50;
13
14 /* HELPER FUNCTIONS ***********************************************************/
15
16 BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam)
17 {
18 WORD Action = LOWORD(wParam);
19 WORD Flags = HIWORD(wParam);
20
21 if (Flags & ~(UISF_HIDEFOCUS | UISF_HIDEACCEL | UISF_ACTIVE))
22 {
23 EngSetLastError(ERROR_INVALID_PARAMETER);
24 return FALSE;
25 }
26
27 switch (Action)
28 {
29 case UIS_INITIALIZE:
30 EngSetLastError(ERROR_INVALID_PARAMETER);
31 return FALSE;
32
33 case UIS_SET:
34 if (Flags & UISF_HIDEFOCUS)
35 Wnd->HideFocus = TRUE;
36 if (Flags & UISF_HIDEACCEL)
37 Wnd->HideAccel = TRUE;
38 break;
39
40 case UIS_CLEAR:
41 if (Flags & UISF_HIDEFOCUS)
42 Wnd->HideFocus = FALSE;
43 if (Flags & UISF_HIDEACCEL)
44 Wnd->HideAccel = FALSE;
45 break;
46 }
47
48 return TRUE;
49 }
50
51 PWND FASTCALL IntGetWindowObject(HWND hWnd)
52 {
53 PWND Window;
54
55 if (!hWnd) return NULL;
56
57 Window = UserGetWindowObject(hWnd);
58 if (Window)
59 Window->head.cLockObj++;
60
61 return Window;
62 }
63
64 PWND FASTCALL VerifyWnd(PWND pWnd)
65 {
66 HWND hWnd;
67 UINT State, State2;
68
69 if (!pWnd) return NULL;
70
71 _SEH2_TRY
72 {
73 hWnd = UserHMGetHandle(pWnd);
74 State = pWnd->state;
75 State2 = pWnd->state2;
76 }
77 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
78 {
79 _SEH2_YIELD(return NULL);
80 }
81 _SEH2_END
82
83 if ( UserObjectInDestroy(hWnd) ||
84 State & WNDS_DESTROYED ||
85 State2 & WNDS2_INDESTROY )
86 return NULL;
87
88 return pWnd;
89 }
90
91 PWND FASTCALL ValidateHwndNoErr(HWND hWnd)
92 {
93 if (hWnd) return (PWND)UserGetObjectNoErr(gHandleTable, hWnd, TYPE_WINDOW);
94 return NULL;
95 }
96
97 /* Temp HACK */
98 PWND FASTCALL UserGetWindowObject(HWND hWnd)
99 {
100 PWND Window;
101
102 if (!hWnd)
103 {
104 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
105 return NULL;
106 }
107
108 Window = (PWND)UserGetObject(gHandleTable, hWnd, TYPE_WINDOW);
109 if (!Window || 0 != (Window->state & WNDS_DESTROYED))
110 {
111 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
112 return NULL;
113 }
114
115 return Window;
116 }
117
118 ULONG FASTCALL
119 IntSetStyle( PWND pwnd, ULONG set_bits, ULONG clear_bits )
120 {
121 ULONG styleOld, styleNew;
122 styleOld = pwnd->style;
123 styleNew = (pwnd->style | set_bits) & ~clear_bits;
124 if (styleNew == styleOld) return styleNew;
125 pwnd->style = styleNew;
126 if ((styleOld ^ styleNew) & WS_VISIBLE) // State Change.
127 {
128 if (styleOld & WS_VISIBLE) pwnd->head.pti->cVisWindows--;
129 if (styleNew & WS_VISIBLE) pwnd->head.pti->cVisWindows++;
130 DceResetActiveDCEs( pwnd );
131 }
132 return styleOld;
133 }
134
135 /*
136 * IntIsWindow
137 *
138 * The function determines whether the specified window handle identifies
139 * an existing window.
140 *
141 * Parameters
142 * hWnd
143 * Handle to the window to test.
144 *
145 * Return Value
146 * If the window handle identifies an existing window, the return value
147 * is TRUE. If the window handle does not identify an existing window,
148 * the return value is FALSE.
149 */
150
151 BOOL FASTCALL
152 IntIsWindow(HWND hWnd)
153 {
154 PWND Window;
155
156 if (!(Window = UserGetWindowObject(hWnd)))
157 {
158 return FALSE;
159 }
160
161 return TRUE;
162 }
163
164 BOOL FASTCALL
165 IntIsWindowVisible(PWND Wnd)
166 {
167 PWND Temp = Wnd;
168 for (;;)
169 {
170 if (!Temp) return TRUE;
171 if (!(Temp->style & WS_VISIBLE)) break;
172 if (Temp->style & WS_MINIMIZE && Temp != Wnd) break;
173 if (Temp->fnid == FNID_DESKTOP) return TRUE;
174 Temp = Temp->spwndParent;
175 }
176 return FALSE;
177 }
178
179 PWND FASTCALL
180 IntGetParent(PWND Wnd)
181 {
182 if (Wnd->style & WS_POPUP)
183 {
184 return Wnd->spwndOwner;
185 }
186 else if (Wnd->style & WS_CHILD)
187 {
188 return Wnd->spwndParent;
189 }
190
191 return NULL;
192 }
193
194 BOOL
195 FASTCALL
196 IntEnableWindow( HWND hWnd, BOOL bEnable )
197 {
198 BOOL Update;
199 PWND pWnd;
200 UINT bIsDisabled;
201
202 if(!(pWnd = UserGetWindowObject(hWnd)))
203 {
204 return FALSE;
205 }
206
207 /* check if updating is needed */
208 bIsDisabled = !!(pWnd->style & WS_DISABLED);
209 Update = bIsDisabled;
210
211 if (bEnable)
212 {
213 IntSetStyle( pWnd, 0, WS_DISABLED );
214 }
215 else
216 {
217 Update = !bIsDisabled;
218
219 co_IntSendMessage( hWnd, WM_CANCELMODE, 0, 0);
220
221 /* Remove keyboard focus from that window if it had focus */
222 if (hWnd == IntGetThreadFocusWindow())
223 {
224 TRACE("IntEnableWindow SF NULL\n");
225 co_UserSetFocus(NULL);
226 }
227 IntSetStyle( pWnd, WS_DISABLED, 0 );
228 }
229
230 if (Update)
231 {
232 IntNotifyWinEvent(EVENT_OBJECT_STATECHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, 0);
233 co_IntSendMessage(hWnd, WM_ENABLE, (LPARAM)bEnable, 0);
234 }
235 // Return nonzero if it was disabled, or zero if it wasn't:
236 return bIsDisabled;
237 }
238
239 /*
240 * IntWinListChildren
241 *
242 * Compile a list of all child window handles from given window.
243 *
244 * Remarks
245 * This function is similar to Wine WIN_ListChildren. The caller
246 * must free the returned list with ExFreePool.
247 */
248
249 HWND* FASTCALL
250 IntWinListChildren(PWND Window)
251 {
252 PWND Child;
253 HWND *List;
254 UINT Index, NumChildren = 0;
255
256 if (!Window) return NULL;
257
258 for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
259 ++NumChildren;
260
261 List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), USERTAG_WINDOWLIST);
262 if(!List)
263 {
264 ERR("Failed to allocate memory for children array\n");
265 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
266 return NULL;
267 }
268 for (Child = Window->spwndChild, Index = 0;
269 Child != NULL;
270 Child = Child->spwndNext, ++Index)
271 List[Index] = Child->head.h;
272 List[Index] = NULL;
273
274 return List;
275 }
276
277 PWND FASTCALL
278 IntGetNonChildAncestor(PWND pWnd)
279 {
280 while(pWnd && (pWnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
281 pWnd = pWnd->spwndParent;
282 return pWnd;
283 }
284
285 BOOL FASTCALL
286 IntIsTopLevelWindow(PWND pWnd)
287 {
288 if ( pWnd->spwndParent &&
289 pWnd->spwndParent == co_GetDesktopWindow(pWnd) ) return TRUE;
290 return FALSE;
291 }
292
293 BOOL FASTCALL
294 IntValidateOwnerDepth(PWND Wnd, PWND Owner)
295 {
296 INT Depth = 1;
297 for (;;)
298 {
299 if ( !Owner ) return gNestedWindowLimit >= Depth;
300 if (Owner == Wnd) break;
301 Owner = Owner->spwndOwner;
302 Depth++;
303 }
304 return FALSE;
305 }
306
307 HWND FASTCALL
308 IntGetWindow(HWND hWnd,
309 UINT uCmd)
310 {
311 PWND Wnd, FoundWnd;
312 HWND Ret = NULL;
313
314 Wnd = ValidateHwndNoErr(hWnd);
315 if (!Wnd)
316 return NULL;
317
318 FoundWnd = NULL;
319 switch (uCmd)
320 {
321 case GW_OWNER:
322 if (Wnd->spwndOwner != NULL)
323 FoundWnd = Wnd->spwndOwner;
324 break;
325
326 case GW_HWNDFIRST:
327 if(Wnd->spwndParent != NULL)
328 {
329 FoundWnd = Wnd->spwndParent;
330 if (FoundWnd->spwndChild != NULL)
331 FoundWnd = FoundWnd->spwndChild;
332 }
333 break;
334 case GW_HWNDNEXT:
335 if (Wnd->spwndNext != NULL)
336 FoundWnd = Wnd->spwndNext;
337 break;
338
339 case GW_HWNDPREV:
340 if (Wnd->spwndPrev != NULL)
341 FoundWnd = Wnd->spwndPrev;
342 break;
343
344 case GW_CHILD:
345 if (Wnd->spwndChild != NULL)
346 FoundWnd = Wnd->spwndChild;
347 break;
348
349 case GW_HWNDLAST:
350 FoundWnd = Wnd;
351 while ( FoundWnd->spwndNext != NULL)
352 FoundWnd = FoundWnd->spwndNext;
353 break;
354
355 default:
356 Wnd = NULL;
357 break;
358 }
359
360 if (FoundWnd != NULL)
361 Ret = UserHMGetHandle(FoundWnd);
362 return Ret;
363 }
364
365 /***********************************************************************
366 * IntSendDestroyMsg
367 */
368 static void IntSendDestroyMsg(HWND hWnd)
369 {
370
371 PWND Window;
372 #if 0 /* FIXME */
373
374 GUITHREADINFO info;
375
376 if (GetGUIThreadInfo(GetCurrentThreadId(), &info))
377 {
378 if (hWnd == info.hwndCaret)
379 {
380 DestroyCaret();
381 }
382 }
383 #endif
384
385 Window = UserGetWindowObject(hWnd);
386 if (Window)
387 {
388 // USER_REFERENCE_ENTRY Ref;
389 // UserRefObjectCo(Window, &Ref);
390
391 if (!Window->spwndOwner && !IntGetParent(Window))
392 {
393 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM) hWnd, 0);
394 }
395
396 // UserDerefObjectCo(Window);
397 }
398
399 /* The window could already be destroyed here */
400
401 /*
402 * Send the WM_DESTROY to the window.
403 */
404
405 co_IntSendMessage(hWnd, WM_DESTROY, 0, 0);
406
407 /*
408 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
409 * make sure that the window still exists when we come back.
410 */
411 #if 0 /* FIXME */
412
413 if (IsWindow(Wnd))
414 {
415 HWND* pWndArray;
416 int i;
417
418 if (!(pWndArray = WIN_ListChildren( hwnd )))
419 return;
420
421 /* start from the end (FIXME: is this needed?) */
422 for (i = 0; pWndArray[i]; i++)
423 ;
424
425 while (--i >= 0)
426 {
427 if (IsWindow( pWndArray[i] ))
428 WIN_SendDestroyMsg( pWndArray[i] );
429 }
430 HeapFree(GetProcessHeap(), 0, pWndArray);
431 }
432 else
433 {
434 TRACE("destroyed itself while in WM_DESTROY!\n");
435 }
436 #endif
437 }
438
439 static VOID
440 UserFreeWindowInfo(PTHREADINFO ti, PWND Wnd)
441 {
442 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
443
444 if (!Wnd) return;
445
446 if (ClientInfo->CallbackWnd.pWnd == DesktopHeapAddressToUser(Wnd))
447 {
448 ClientInfo->CallbackWnd.hWnd = NULL;
449 ClientInfo->CallbackWnd.pWnd = NULL;
450 }
451
452 if (Wnd->strName.Buffer != NULL)
453 {
454 Wnd->strName.Length = 0;
455 Wnd->strName.MaximumLength = 0;
456 DesktopHeapFree(Wnd->head.rpdesk,
457 Wnd->strName.Buffer);
458 Wnd->strName.Buffer = NULL;
459 }
460
461 // DesktopHeapFree(Wnd->head.rpdesk, Wnd);
462 // WindowObject->hWnd = NULL;
463 }
464
465 /***********************************************************************
466 * IntDestroyWindow
467 *
468 * Destroy storage associated to a window. "Internals" p.358
469 *
470 * This is the "functional" DestroyWindows function ei. all stuff
471 * done in CreateWindow is undone here and not in DestroyWindow:-P
472
473 */
474 static LRESULT co_UserFreeWindow(PWND Window,
475 PPROCESSINFO ProcessData,
476 PTHREADINFO ThreadData,
477 BOOLEAN SendMessages)
478 {
479 HWND *Children;
480 HWND *ChildHandle;
481 PWND Child;
482 PMENU Menu;
483 BOOLEAN BelongsToThreadData;
484
485 ASSERT(Window);
486
487 if(Window->state2 & WNDS2_INDESTROY)
488 {
489 TRACE("Tried to call IntDestroyWindow() twice\n");
490 return 0;
491 }
492 Window->state2 |= WNDS2_INDESTROY;
493 Window->style &= ~WS_VISIBLE;
494 Window->head.pti->cVisWindows--;
495
496 IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Window, OBJID_WINDOW, CHILDID_SELF, 0);
497
498 /* remove the window already at this point from the thread window list so we
499 don't get into trouble when destroying the thread windows while we're still
500 in IntDestroyWindow() */
501 RemoveEntryList(&Window->ThreadListEntry);
502
503 BelongsToThreadData = IntWndBelongsToThread(Window, ThreadData);
504
505 IntDeRegisterShellHookWindow(Window->head.h);
506
507 if(SendMessages)
508 {
509 /* Send destroy messages */
510 IntSendDestroyMsg(Window->head.h);
511 }
512
513 /* free child windows */
514 Children = IntWinListChildren(Window);
515 if (Children)
516 {
517 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
518 {
519 if ((Child = IntGetWindowObject(*ChildHandle)))
520 {
521 if(!IntWndBelongsToThread(Child, ThreadData))
522 {
523 /* send WM_DESTROY messages to windows not belonging to the same thread */
524 IntSendDestroyMsg(Child->head.h);
525 }
526 else
527 co_UserFreeWindow(Child, ProcessData, ThreadData, SendMessages);
528
529 UserDereferenceObject(Child);
530 }
531 }
532 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
533 }
534
535 if(SendMessages)
536 {
537 /*
538 * Clear the update region to make sure no WM_PAINT messages will be
539 * generated for this window while processing the WM_NCDESTROY.
540 */
541 co_UserRedrawWindow(Window, NULL, 0,
542 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
543 RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
544 if(BelongsToThreadData)
545 co_IntSendMessage(Window->head.h, WM_NCDESTROY, 0, 0);
546 }
547
548 DestroyTimersForWindow(ThreadData, Window);
549
550 /* Unregister hot keys */
551 UnregisterWindowHotKeys (Window);
552
553 /* flush the message queue */
554 MsqRemoveWindowMessagesFromQueue(Window);
555
556 /* from now on no messages can be sent to this window anymore */
557 Window->state |= WNDS_DESTROYED;
558 Window->fnid |= FNID_FREED;
559
560 /* don't remove the WINDOWSTATUS_DESTROYING bit */
561
562 /* reset shell window handles */
563 if(ThreadData->rpdesk)
564 {
565 if (Window->head.h == ThreadData->rpdesk->rpwinstaParent->ShellWindow)
566 ThreadData->rpdesk->rpwinstaParent->ShellWindow = NULL;
567
568 if (Window->head.h == ThreadData->rpdesk->rpwinstaParent->ShellListView)
569 ThreadData->rpdesk->rpwinstaParent->ShellListView = NULL;
570 }
571
572 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
573
574 #if 0 /* FIXME */
575
576 WinPosCheckInternalPos(Window->head.h);
577 if (Window->head.h == GetCapture())
578 {
579 ReleaseCapture();
580 }
581
582 /* free resources associated with the window */
583 TIMER_RemoveWindowTimers(Window->head.h);
584 #endif
585
586 if ( ((Window->style & (WS_CHILD|WS_POPUP)) != WS_CHILD) &&
587 Window->IDMenu &&
588 (Menu = UserGetMenuObject((HMENU)Window->IDMenu)))
589 {
590 IntDestroyMenuObject(Menu, TRUE);
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 ((!hWndParent) && (!hWndOwner))
2245 {
2246 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0);
2247 }
2248
2249 /* Initialize and show the window's scrollbars */
2250 if (Window->style & WS_VSCROLL)
2251 {
2252 co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE);
2253 }
2254 if (Window->style & WS_HSCROLL)
2255 {
2256 co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE);
2257 }
2258
2259 /* Show the new window */
2260 if (Cs->style & WS_VISIBLE)
2261 {
2262 if (Window->style & WS_MAXIMIZE)
2263 dwShowMode = SW_SHOW;
2264 else if (Window->style & WS_MINIMIZE)
2265 dwShowMode = SW_SHOWMINIMIZED;
2266
2267 co_WinPosShowWindow(Window, dwShowMode);
2268
2269 if (Window->ExStyle & WS_EX_MDICHILD)
2270 {
2271 ASSERT(ParentWindow);
2272 if(!ParentWindow)
2273 goto cleanup;
2274 co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0);
2275 /* ShowWindow won't activate child windows */
2276 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2277 }
2278 }
2279
2280 TRACE("co_UserCreateWindowEx(): Created window %p\n", hWnd);
2281 ret = Window;
2282
2283 cleanup:
2284 if (!ret)
2285 {
2286 TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2287 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2288 if (Window)
2289 co_UserDestroyWindow(Window);
2290 else if (Class)
2291 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2292 }
2293
2294 if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
2295 if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
2296 if (pszName) UserHeapFree(pszName);
2297 if (pszClass) UserHeapFree(pszClass);
2298
2299 if (Window)
2300 {
2301 UserDerefObjectCo(Window);
2302 }
2303 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2304
2305 return ret;
2306 }
2307
2308 NTSTATUS
2309 NTAPI
2310 ProbeAndCaptureLargeString(
2311 OUT PLARGE_STRING plstrSafe,
2312 IN PLARGE_STRING plstrUnsafe)
2313 {
2314 LARGE_STRING lstrTemp;
2315 PVOID pvBuffer = NULL;
2316
2317 _SEH2_TRY
2318 {
2319 /* Probe and copy the string */
2320 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2321 lstrTemp = *plstrUnsafe;
2322 }
2323 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2324 {
2325 /* Fail */
2326 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2327 }
2328 _SEH2_END
2329
2330 if (lstrTemp.Length != 0)
2331 {
2332 /* Allocate a buffer from paged pool */
2333 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2334 if (!pvBuffer)
2335 {
2336 return STATUS_NO_MEMORY;
2337 }
2338
2339 _SEH2_TRY
2340 {
2341 /* Probe and copy the buffer */
2342 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2343 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2344 }
2345 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2346 {
2347 /* Cleanup and fail */
2348 ExFreePoolWithTag(pvBuffer, TAG_STRING);
2349 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2350 }
2351 _SEH2_END
2352 }
2353
2354 /* Set the output string */
2355 plstrSafe->Buffer = pvBuffer;
2356 plstrSafe->Length = lstrTemp.Length;
2357 plstrSafe->MaximumLength = lstrTemp.Length;
2358
2359 return STATUS_SUCCESS;
2360 }
2361
2362 /**
2363 * \todo Allow passing plstrClassName as ANSI.
2364 */
2365 HWND
2366 NTAPI
2367 NtUserCreateWindowEx(
2368 DWORD dwExStyle,
2369 PLARGE_STRING plstrClassName,
2370 PLARGE_STRING plstrClsVersion,
2371 PLARGE_STRING plstrWindowName,
2372 DWORD dwStyle,
2373 int x,
2374 int y,
2375 int nWidth,
2376 int nHeight,
2377 HWND hWndParent,
2378 HMENU hMenu,
2379 HINSTANCE hInstance,
2380 LPVOID lpParam,
2381 DWORD dwFlags,
2382 PVOID acbiBuffer)
2383 {
2384 NTSTATUS Status;
2385 LARGE_STRING lstrWindowName;
2386 LARGE_STRING lstrClassName;
2387 UNICODE_STRING ustrClassName;
2388 CREATESTRUCTW Cs;
2389 HWND hwnd = NULL;
2390 PWND pwnd;
2391
2392 lstrWindowName.Buffer = NULL;
2393 lstrClassName.Buffer = NULL;
2394
2395 ASSERT(plstrWindowName);
2396
2397 if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2398 {
2399 /* check hMenu is valid handle */
2400 if (hMenu && !UserGetMenuObject(hMenu))
2401 {
2402 ERR("NtUserCreateWindowEx: Got an invalid menu handle!\n");
2403 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
2404 return NULL;
2405 }
2406 }
2407
2408 /* Copy the window name to kernel mode */
2409 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2410 if (!NT_SUCCESS(Status))
2411 {
2412 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2413 SetLastNtError(Status);
2414 return NULL;
2415 }
2416
2417 plstrWindowName = &lstrWindowName;
2418
2419 /* Check if the class is an atom */
2420 if (IS_ATOM(plstrClassName))
2421 {
2422 /* It is, pass the atom in the UNICODE_STRING */
2423 ustrClassName.Buffer = (PVOID)plstrClassName;
2424 ustrClassName.Length = 0;
2425 ustrClassName.MaximumLength = 0;
2426 }
2427 else
2428 {
2429 /* It's not, capture the class name */
2430 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2431 if (!NT_SUCCESS(Status))
2432 {
2433 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2434 /* Set last error, cleanup and return */
2435 SetLastNtError(Status);
2436 goto cleanup;
2437 }
2438
2439 /* We pass it on as a UNICODE_STRING */
2440 ustrClassName.Buffer = lstrClassName.Buffer;
2441 ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2442 ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
2443 }
2444
2445 /* Fill the CREATESTRUCTW */
2446 /* we will keep here the original parameters */
2447 Cs.style = dwStyle;
2448 Cs.lpCreateParams = lpParam;
2449 Cs.hInstance = hInstance;
2450 Cs.hMenu = hMenu;
2451 Cs.hwndParent = hWndParent;
2452 Cs.cx = nWidth;
2453 Cs.cy = nHeight;
2454 Cs.x = x;
2455 Cs.y = y;
2456 Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
2457 if (IS_ATOM(plstrClassName))
2458 Cs.lpszClass = (LPCWSTR) plstrClassName;
2459 else
2460 Cs.lpszClass = (LPCWSTR) plstrClassName->Buffer;
2461 Cs.dwExStyle = dwExStyle;
2462
2463 UserEnterExclusive();
2464
2465 /* Call the internal function */
2466 pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName, acbiBuffer);
2467
2468 if(!pwnd)
2469 {
2470 ERR("co_UserCreateWindowEx failed!\n");
2471 }
2472 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2473
2474 UserLeave();
2475
2476 cleanup:
2477 if (lstrWindowName.Buffer)
2478 {
2479 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2480 }
2481 if (lstrClassName.Buffer)
2482 {
2483 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2484 }
2485
2486 return hwnd;
2487 }
2488
2489
2490 BOOLEAN co_UserDestroyWindow(PVOID Object)
2491 {
2492 HWND hWnd;
2493 PWND pwndTemp;
2494 PTHREADINFO ti;
2495 MSG msg;
2496 PWND Window = Object;
2497
2498 ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
2499
2500 hWnd = Window->head.h;
2501 ti = PsGetCurrentThreadWin32Thread();
2502
2503 TRACE("co_UserDestroyWindow \n");
2504
2505 /* Check for owner thread */
2506 if ( Window->head.pti != PsGetCurrentThreadWin32Thread())
2507 {
2508 /* Check if we are destroying the desktop window */
2509 if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
2510 {
2511 EngSetLastError(ERROR_ACCESS_DENIED);
2512 return FALSE;
2513 }
2514 }
2515
2516 /* If window was created successfully and it is hooked */
2517 if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
2518 {
2519 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0))
2520 {
2521 ERR("Destroy Window WH_CBT Call Hook return!\n");
2522 return FALSE;
2523 }
2524 }
2525
2526 if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
2527 {
2528 if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2529 {
2530 if (Window->spwndOwner)
2531 {
2532 //ERR("DestroyWindow Owner out.\n");
2533 UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2534 }
2535 }
2536 }
2537
2538 /* Inform the parent */
2539 if (Window->style & WS_CHILD)
2540 {
2541 IntSendParentNotify(Window, WM_DESTROY);
2542 }
2543
2544 /* Look whether the focus is within the tree of windows we will
2545 * be destroying.
2546 */
2547 if (!co_WinPosShowWindow(Window, SW_HIDE))
2548 { // Rule #1.
2549 if (ti->MessageQueue->spwndActive == Window && ti->MessageQueue == IntGetFocusMessageQueue())
2550 {
2551 co_WinPosActivateOtherWindow(Window);
2552 }
2553 }
2554
2555 // Adjust last active.
2556 if ((pwndTemp = Window->spwndOwner))
2557 {
2558 while (pwndTemp->spwndOwner)
2559 pwndTemp = pwndTemp->spwndOwner;
2560
2561 if (pwndTemp->spwndLastActive == Window)
2562 pwndTemp->spwndLastActive = Window->spwndOwner;
2563 }
2564
2565 if (Window->spwndParent && IntIsWindow(Window->head.h))
2566 {
2567 if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
2568 {
2569 if (!IntIsTopLevelWindow(Window))
2570 {
2571 //ERR("DestroyWindow Parent out.\n");
2572 UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2573 }
2574 }
2575 }
2576
2577 if (Window->head.pti->MessageQueue->spwndActive == Window)
2578 Window->head.pti->MessageQueue->spwndActive = NULL;
2579 if (Window->head.pti->MessageQueue->spwndFocus == Window)
2580 Window->head.pti->MessageQueue->spwndFocus = NULL;
2581 if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
2582 Window->head.pti->MessageQueue->spwndActivePrev = NULL;
2583 if (Window->head.pti->MessageQueue->spwndCapture == Window)
2584 Window->head.pti->MessageQueue->spwndCapture = NULL;
2585
2586 /*
2587 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2588 */
2589
2590 if ((ti != NULL) && (ti->pDeskInfo != NULL))
2591 {
2592 if (ti->pDeskInfo->hShellWindow == hWnd)
2593 {
2594 ERR("Destroying the ShellWindow!\n");
2595 ti->pDeskInfo->hShellWindow = NULL;
2596 }
2597 }
2598
2599 IntEngWindowChanged(Window, WOC_DELETE);
2600
2601 if (!IntIsWindow(Window->head.h))
2602 {
2603 return TRUE;
2604 }
2605
2606 /* Recursively destroy owned windows */
2607
2608 if (! (Window->style & WS_CHILD))
2609 {
2610 for (;;)
2611 {
2612 BOOL GotOne = FALSE;
2613 HWND *Children;
2614 HWND *ChildHandle;
2615 PWND Child, Desktop;
2616
2617 Desktop = IntIsDesktopWindow(Window) ? Window :
2618 UserGetWindowObject(IntGetDesktopWindow());
2619 Children = IntWinListChildren(Desktop);
2620
2621 if (Children)
2622 {
2623 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2624 {
2625 Child = UserGetWindowObject(*ChildHandle);
2626 if (Child == NULL)
2627 continue;
2628 if (Child->spwndOwner != Window)
2629 {
2630 continue;
2631 }
2632
2633 if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
2634 {
2635 USER_REFERENCE_ENTRY ChildRef;
2636 UserRefObjectCo(Child, &ChildRef); // Temp HACK?
2637 co_UserDestroyWindow(Child);
2638 UserDerefObjectCo(Child); // Temp HACK?
2639
2640 GotOne = TRUE;
2641 continue;
2642 }
2643
2644 if (Child->spwndOwner != NULL)
2645 {
2646 Child->spwndOwner = NULL;
2647 }
2648
2649 }
2650 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
2651 }
2652 if (! GotOne)
2653 {
2654 break;
2655 }
2656 }
2657 }
2658
2659 /* Generate mouse move message for the next window */
2660 msg.message = WM_MOUSEMOVE;
2661 msg.wParam = UserGetMouseButtonsState();
2662 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2663 msg.pt = gpsi->ptCursor;
2664 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2665
2666 if (!IntIsWindow(Window->head.h))
2667 {
2668 return TRUE;
2669 }
2670
2671 /* Destroy the window storage */
2672 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2673
2674 return TRUE;
2675 }
2676
2677
2678 /*
2679 * @implemented
2680 */
2681 BOOLEAN APIENTRY
2682 NtUserDestroyWindow(HWND Wnd)
2683 {
2684 PWND Window;
2685 DECLARE_RETURN(BOOLEAN);
2686 BOOLEAN ret;
2687 USER_REFERENCE_ENTRY Ref;
2688
2689 TRACE("Enter NtUserDestroyWindow\n");
2690 UserEnterExclusive();
2691
2692 if (!(Window = UserGetWindowObject(Wnd)))
2693 {
2694 RETURN(FALSE);
2695 }
2696
2697 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
2698 ret = co_UserDestroyWindow(Window);
2699 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
2700
2701 RETURN(ret);
2702
2703 CLEANUP:
2704 TRACE("Leave NtUserDestroyWindow, ret=%u\n", _ret_);
2705 UserLeave();
2706 END_CLEANUP;
2707 }
2708
2709
2710 static HWND FASTCALL
2711 IntFindWindow(PWND Parent,
2712 PWND ChildAfter,
2713 RTL_ATOM ClassAtom,
2714 PUNICODE_STRING WindowName)
2715 {
2716 BOOL CheckWindowName;
2717 HWND *List, *phWnd;
2718 HWND Ret = NULL;
2719 UNICODE_STRING CurrentWindowName;
2720
2721 ASSERT(Parent);
2722
2723 CheckWindowName = WindowName->Buffer != 0;
2724
2725 if((List = IntWinListChildren(Parent)))
2726 {
2727 phWnd = List;
2728 if(ChildAfter)
2729 {
2730 /* skip handles before and including ChildAfter */
2731 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2732 ;
2733 }
2734
2735 /* search children */
2736 while(*phWnd)
2737 {
2738 PWND Child;
2739 if(!(Child = UserGetWindowObject(*(phWnd++))))
2740 {
2741 continue;
2742 }
2743
2744 /* Do not send WM_GETTEXT messages in the kernel mode version!
2745 The user mode version however calls GetWindowText() which will
2746 send WM_GETTEXT messages to windows belonging to its processes */
2747 if (!ClassAtom || Child->pcls->atomClassName == ClassAtom)
2748 {
2749 // FIXME: LARGE_STRING truncated
2750 CurrentWindowName.Buffer = Child->strName.Buffer;
2751 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
2752 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
2753 if(!CheckWindowName ||
2754 (Child->strName.Length < 0xFFFF &&
2755 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
2756 {
2757 Ret = Child->head.h;
2758 break;
2759 }
2760 }
2761 }
2762 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2763 }
2764
2765 return Ret;
2766 }
2767
2768 /*
2769 * FUNCTION:
2770 * Searches a window's children for a window with the specified
2771 * class and name
2772 * ARGUMENTS:
2773 * hwndParent = The window whose childs are to be searched.
2774 * NULL = desktop
2775 * HWND_MESSAGE = message-only windows
2776 *
2777 * hwndChildAfter = Search starts after this child window.
2778 * NULL = start from beginning
2779 *
2780 * ucClassName = Class name to search for
2781 * Reguired parameter.
2782 *
2783 * ucWindowName = Window name
2784 * ->Buffer == NULL = don't care
2785 *
2786 * RETURNS:
2787 * The HWND of the window if it was found, otherwise NULL
2788 */
2789 /*
2790 * @implemented
2791 */
2792 HWND APIENTRY
2793 NtUserFindWindowEx(HWND hwndParent,
2794 HWND hwndChildAfter,
2795 PUNICODE_STRING ucClassName,
2796 PUNICODE_STRING ucWindowName,
2797 DWORD dwUnknown)
2798 {
2799 PWND Parent, ChildAfter;
2800 UNICODE_STRING ClassName = {0}, WindowName = {0};
2801 HWND Desktop, Ret = NULL;
2802 BOOL DoMessageWnd = FALSE;
2803 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2804 DECLARE_RETURN(HWND);
2805
2806 TRACE("Enter NtUserFindWindowEx\n");
2807 UserEnterShared();
2808
2809 if (ucClassName != NULL || ucWindowName != NULL)
2810 {
2811 _SEH2_TRY
2812 {
2813 if (ucClassName != NULL)
2814 {
2815 ClassName = ProbeForReadUnicodeString(ucClassName);
2816 if (ClassName.Length != 0)
2817 {
2818 ProbeForRead(ClassName.Buffer,
2819 ClassName.Length,
2820 sizeof(WCHAR));
2821 }
2822 else if (!IS_ATOM(ClassName.Buffer))
2823 {
2824 EngSetLastError(ERROR_INVALID_PARAMETER);
2825 _SEH2_LEAVE;
2826 }
2827
2828 if (!IntGetAtomFromStringOrAtom(&ClassName,
2829 &ClassAtom))
2830 {
2831 _SEH2_LEAVE;
2832 }
2833 }
2834
2835 if (ucWindowName != NULL)
2836 {
2837 WindowName = ProbeForReadUnicodeString(ucWindowName);
2838 if (WindowName.Length != 0)
2839 {
2840 ProbeForRead(WindowName.Buffer,
2841 WindowName.Length,
2842 sizeof(WCHAR));
2843 }
2844 }
2845 }
2846 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2847 {
2848 SetLastNtError(_SEH2_GetExceptionCode());
2849 _SEH2_YIELD(RETURN(NULL));
2850 }
2851 _SEH2_END;
2852
2853 if (ucClassName != NULL)
2854 {
2855 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
2856 !IS_ATOM(ClassName.Buffer))
2857 {
2858 EngSetLastError(ERROR_INVALID_PARAMETER);
2859 RETURN(NULL);
2860 }
2861 else if (ClassAtom == (RTL_ATOM)0)
2862 {
2863 /* LastError code was set by IntGetAtomFromStringOrAtom */
2864 RETURN(NULL);
2865 }
2866 }
2867 }
2868
2869 Desktop = IntGetCurrentThreadDesktopWindow();
2870
2871 if(hwndParent == NULL)
2872 {
2873 hwndParent = Desktop;
2874 DoMessageWnd = TRUE;
2875 }
2876 else if(hwndParent == HWND_MESSAGE)
2877 {
2878 hwndParent = IntGetMessageWindow();
2879 }
2880
2881 if(!(Parent = UserGetWindowObject(hwndParent)))
2882 {
2883 RETURN( NULL);
2884 }
2885
2886 ChildAfter = NULL;
2887 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
2888 {
2889 RETURN( NULL);
2890 }
2891
2892 _SEH2_TRY
2893 {
2894 if(Parent->head.h == Desktop)
2895 {
2896 HWND *List, *phWnd;
2897 PWND TopLevelWindow;
2898 BOOLEAN CheckWindowName;
2899 BOOLEAN WindowMatches;
2900 BOOLEAN ClassMatches;
2901
2902 /* windows searches through all top-level windows if the parent is the desktop
2903 window */
2904
2905 if((List = IntWinListChildren(Parent)))
2906 {
2907 phWnd = List;
2908
2909 if(ChildAfter)
2910 {
2911 /* skip handles before and including ChildAfter */
2912 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2913 ;
2914 }
2915
2916 CheckWindowName = WindowName.Buffer != 0;
2917
2918 /* search children */
2919 while(*phWnd)
2920 {
2921 UNICODE_STRING ustr;
2922
2923 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
2924 {
2925 continue;
2926 }
2927
2928 /* Do not send WM_GETTEXT messages in the kernel mode version!
2929 The user mode version however calls GetWindowText() which will
2930 send WM_GETTEXT messages to windows belonging to its processes */
2931 ustr.Buffer = TopLevelWindow->strName.Buffer;
2932 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
2933 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
2934 WindowMatches = !CheckWindowName ||
2935 (TopLevelWindow->strName.Length < 0xFFFF &&
2936 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
2937 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
2938 ClassAtom == TopLevelWindow->pcls->atomClassName;
2939
2940 if (WindowMatches && ClassMatches)
2941 {
2942 Ret = TopLevelWindow->head.h;
2943 break;
2944 }
2945
2946 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
2947 {
2948 /* window returns the handle of the top-level window, in case it found
2949 the child window */
2950 Ret = TopLevelWindow->head.h;
2951 break;
2952 }
2953
2954 }
2955 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2956 }
2957 }
2958 else
2959 {
2960 ERR("FindWindowEx: Not Desktop Parent!\n");
2961 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
2962 }
2963
2964 if (Ret == NULL && DoMessageWnd)
2965 {
2966 PWND MsgWindows;
2967
2968 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
2969 {
2970 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
2971 }
2972 }
2973 }
2974 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2975 {
2976 SetLastNtError(_SEH2_GetExceptionCode());
2977 Ret = NULL;
2978 }
2979 _SEH2_END;
2980
2981 RETURN( Ret);
2982
2983 CLEANUP:
2984 TRACE("Leave NtUserFindWindowEx, ret %p\n", _ret_);
2985 UserLeave();
2986 END_CLEANUP;
2987 }
2988
2989
2990 /*
2991 * @implemented
2992 */
2993 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
2994 {
2995 PWND WndAncestor, Parent;
2996
2997 if (Wnd->head.h == IntGetDesktopWindow())
2998 {
2999 return NULL;
3000 }
3001
3002 switch (Type)
3003 {
3004 case GA_PARENT:
3005 {
3006 WndAncestor = Wnd->spwndParent;
3007 break;
3008 }
3009
3010 case GA_ROOT:
3011 {
3012 WndAncestor = Wnd;
3013 Parent = NULL;
3014
3015 for(;;)
3016 {
3017 if(!(Parent = WndAncestor->spwndParent))
3018 {
3019 break;
3020 }
3021 if(IntIsDesktopWindow(Parent))
3022 {
3023 break;
3024 }
3025
3026 WndAncestor = Parent;
3027 }
3028 break;
3029 }
3030
3031 case GA_ROOTOWNER:
3032 {
3033 WndAncestor = Wnd;
3034
3035 for (;;)
3036 {
3037 Parent = IntGetParent(WndAncestor);
3038
3039 if (!Parent)
3040 {
3041 break;
3042 }
3043
3044 WndAncestor = Parent;
3045 }
3046 break;
3047 }
3048
3049 default:
3050 {
3051 return NULL;
3052 }
3053 }
3054
3055 return WndAncestor;
3056 }
3057
3058 /*
3059 * @implemented
3060 */
3061 HWND APIENTRY
3062 NtUserGetAncestor(HWND hWnd, UINT Type)
3063 {
3064 PWND Window, Ancestor;
3065 DECLARE_RETURN(HWND);
3066
3067 TRACE("Enter NtUserGetAncestor\n");
3068 UserEnterExclusive();
3069
3070 if (!(Window = UserGetWindowObject(hWnd)))
3071 {
3072 RETURN(NULL);
3073 }
3074
3075 Ancestor = UserGetAncestor(Window, Type);
3076 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3077
3078 RETURN(Ancestor ? Ancestor->head.h : NULL);
3079
3080 CLEANUP:
3081 TRACE("Leave NtUserGetAncestor, ret=%p\n", _ret_);
3082 UserLeave();
3083 END_CLEANUP;
3084 }
3085
3086 ////
3087 //// ReactOS work around! Keep it the sames as in Combo.c and Controls.h
3088 ////
3089 /* combo state struct */
3090 typedef struct
3091 {
3092 HWND self;
3093 HWND owner;
3094 UINT dwStyle;
3095 HWND hWndEdit;
3096 HWND hWndLBox;
3097 UINT wState;
3098 HFONT hFont;
3099 RECT textRect;
3100 RECT buttonRect;
3101 RECT droppedRect;
3102 INT droppedIndex;
3103 INT fixedOwnerDrawHeight;
3104 INT droppedWidth; /* last two are not used unless set */
3105 INT editHeight; /* explicitly */
3106 LONG UIState;
3107 } HEADCOMBO,*LPHEADCOMBO;
3108
3109 // Window Extra data container.
3110 typedef struct _WND2CBOX
3111 {
3112 WND;
3113 LPHEADCOMBO pCBox;
3114 } WND2CBOX, *PWND2CBOX;
3115
3116 #define CBF_BUTTONDOWN 0x0002
3117 ////
3118 ////
3119 ////
3120 BOOL
3121 APIENTRY
3122 NtUserGetComboBoxInfo(
3123 HWND hWnd,
3124 PCOMBOBOXINFO pcbi)
3125 {
3126 PWND Wnd;
3127 PPROCESSINFO ppi;
3128 BOOL NotSameppi = FALSE;
3129 BOOL Ret = TRUE;
3130 DECLARE_RETURN(BOOL);
3131
3132 TRACE("Enter NtUserGetComboBoxInfo\n");
3133 UserEnterShared();
3134
3135 if (!(Wnd = UserGetWindowObject(hWnd)))
3136 {
3137 RETURN( FALSE );
3138 }
3139 _SEH2_TRY
3140 {
3141 if(pcbi)
3142 {
3143 ProbeForWrite(pcbi,
3144 sizeof(COMBOBOXINFO),
3145 1);
3146 }
3147 }
3148 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3149 {
3150 SetLastNtError(_SEH2_GetExceptionCode());
3151 _SEH2_YIELD(RETURN(FALSE));
3152 }
3153 _SEH2_END;
3154
3155 if (pcbi->cbSize < sizeof(COMBOBOXINFO))
3156 {
3157 EngSetLastError(ERROR_INVALID_PARAMETER);
3158 RETURN(FALSE);
3159 }
3160
3161 // Pass the user pointer, it was already probed.
3162 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_COMBOBOX]) && Wnd->fnid != FNID_COMBOBOX)
3163 {
3164 RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3165 }
3166
3167 ppi = PsGetCurrentProcessWin32Process();
3168 NotSameppi = ppi != Wnd->head.pti->ppi;
3169 if (NotSameppi)
3170 {
3171 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3172 }
3173
3174 _SEH2_TRY
3175 {
3176 LPHEADCOMBO lphc = ((PWND2CBOX)Wnd)->pCBox;
3177 pcbi->rcItem = lphc->textRect;
3178 pcbi->rcButton = lphc->buttonRect;
3179 pcbi->stateButton = 0;
3180 if (lphc->wState & CBF_BUTTONDOWN)
3181 pcbi->stateButton |= STATE_SYSTEM_PRESSED;
3182 if (RECTL_bIsEmptyRect(&lphc->buttonRect))
3183 pcbi->stateButton |= STATE_SYSTEM_INVISIBLE;
3184 pcbi->hwndCombo = lphc->self;
3185 pcbi->hwndItem = lphc->hWndEdit;
3186 pcbi->hwndList = lphc->hWndLBox;
3187 }
3188 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3189 {
3190 Ret = FALSE;
3191 SetLastNtError(_SEH2_GetExceptionCode());
3192 }
3193 _SEH2_END;
3194
3195 RETURN( Ret);
3196
3197 CLEANUP:
3198 if (NotSameppi) KeDetachProcess();
3199 TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3200 UserLeave();
3201 END_CLEANUP;
3202 }
3203
3204 ////
3205 //// ReactOS work around! Keep it the sames as in Listbox.c
3206 ////
3207 /* Listbox structure */
3208 typedef struct
3209 {
3210 HWND self; /* Our own window handle */
3211 HWND owner; /* Owner window to send notifications to */
3212 UINT style; /* Window style */
3213 INT width; /* Window width */
3214 INT height; /* Window height */
3215 VOID *items; /* Array of items */
3216 INT nb_items; /* Number of items */
3217 INT top_item; /* Top visible item */
3218 INT selected_item; /* Selected item */
3219 INT focus_item; /* Item that has the focus */
3220 INT anchor_item; /* Anchor item for extended selection */
3221 INT item_height; /* Default item height */
3222 INT page_size; /* Items per listbox page */
3223 INT column_width; /* Column width for multi-column listboxes */
3224 } LB_DESCR;
3225
3226 // Window Extra data container.
3227 typedef struct _WND2LB
3228 {
3229 WND;
3230 LB_DESCR * pLBiv;
3231 } WND2LB, *PWND2LB;
3232 ////
3233 ////
3234 ////
3235 DWORD
3236 APIENTRY
3237 NtUserGetListBoxInfo(
3238 HWND hWnd)
3239 {
3240 PWND Wnd;
3241 PPROCESSINFO ppi;
3242 BOOL NotSameppi = FALSE;
3243 DWORD Ret = 0;
3244 DECLARE_RETURN(DWORD);
3245
3246 TRACE("Enter NtUserGetListBoxInfo\n");
3247 UserEnterShared();
3248
3249 if (!(Wnd = UserGetWindowObject(hWnd)))
3250 {
3251 RETURN( 0 );
3252 }
3253
3254 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && Wnd->fnid != FNID_LISTBOX)
3255 {
3256 RETURN( (DWORD) co_IntSendMessage( Wnd->head.h, LB_GETLISTBOXINFO, 0, 0 ));
3257 }
3258
3259 // wine lisbox:test_GetListBoxInfo lb_getlistboxinfo = 0, should not send a message!
3260 ppi = PsGetCurrentProcessWin32Process();
3261 NotSameppi = ppi != Wnd->head.pti->ppi;
3262 if (NotSameppi)
3263 {
3264 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3265 }
3266
3267 _SEH2_TRY
3268 {
3269 LB_DESCR *descr = ((PWND2LB)Wnd)->pLBiv;
3270 // See Controls ListBox.c:LB_GETLISTBOXINFO must match...
3271 if (descr->style & LBS_MULTICOLUMN) //// ReactOS
3272 Ret = descr->page_size * descr->column_width;
3273 else
3274 Ret = descr->page_size;
3275 }
3276 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3277 {
3278 Ret = 0;
3279 SetLastNtError(_SEH2_GetExceptionCode());
3280 }
3281 _SEH2_END;
3282
3283 RETURN( Ret);
3284
3285 CLEANUP:
3286 if (NotSameppi) KeDetachProcess();
3287 TRACE("Leave NtUserGetListBoxInfo, ret=%lu\n", _ret_);
3288 UserLeave();
3289 END_CLEANUP;
3290 }
3291
3292 /*
3293 * NtUserSetParent
3294 *
3295 * The NtUserSetParent function changes the parent window of the specified
3296 * child window.
3297 *
3298 * Remarks
3299 * The new parent window and the child window must belong to the same
3300 * application. If the window identified by the hWndChild parameter is
3301 * visible, the system performs the appropriate redrawing and repainting.
3302 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3303 * or WS_POPUP window styles of the window whose parent is being changed.
3304 *
3305 * Status
3306 * @implemented
3307 */
3308
3309 HWND APIENTRY
3310 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3311 {
3312 DECLARE_RETURN(HWND);
3313
3314 TRACE("Enter NtUserSetParent\n");
3315 UserEnterExclusive();
3316
3317 /*
3318 Check Parent first from user space, set it here.
3319 */
3320 if (!hWndNewParent)
3321 {
3322 hWndNewParent = IntGetDesktopWindow();
3323 }
3324 else if (hWndNewParent == HWND_MESSAGE)
3325 {
3326 hWndNewParent = IntGetMessageWindow();
3327 }
3328
3329 RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3330
3331 CLEANUP:
3332 TRACE("Leave NtUserSetParent, ret=%p\n", _ret_);
3333 UserLeave();
3334 END_CLEANUP;
3335 }
3336
3337 /*
3338 * UserGetShellWindow
3339 *
3340 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3341 *
3342 * Status
3343 * @implemented
3344 */
3345 HWND FASTCALL UserGetShellWindow(VOID)
3346 {
3347 PWINSTATION_OBJECT WinStaObject;
3348 HWND Ret;
3349
3350 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3351 KernelMode,
3352 0,
3353 &WinStaObject);
3354
3355 if (!NT_SUCCESS(Status))
3356 {
3357 SetLastNtError(Status);
3358 return( (HWND)0);
3359 }
3360
3361 Ret = (HWND)WinStaObject->ShellWindow;
3362
3363 ObDereferenceObject(WinStaObject);
3364 return( Ret);
3365 }
3366
3367 /*
3368 * NtUserSetShellWindowEx
3369 *
3370 * This is undocumented function to set global shell window. The global
3371 * shell window has special handling of window position.
3372 *
3373 * Status
3374 * @implemented
3375 */
3376 BOOL APIENTRY
3377 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3378 {
3379 PWINSTATION_OBJECT WinStaObject;
3380 PWND WndShell, WndListView;
3381 DECLARE_RETURN(BOOL);
3382 USER_REFERENCE_ENTRY Ref;
3383 NTSTATUS Status;
3384 PTHREADINFO ti;
3385
3386 TRACE("Enter NtUserSetShellWindowEx\n");
3387 UserEnterExclusive();
3388
3389 if (!(WndShell = UserGetWindowObject(hwndShell)))
3390 {
3391 RETURN(FALSE);
3392 }
3393
3394 if(!(WndListView = UserGetWindowObject(hwndListView)))
3395 {
3396 RETURN(FALSE);
3397 }
3398
3399 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3400 KernelMode,
3401 0,
3402 &WinStaObject);
3403
3404 if (!NT_SUCCESS(Status))
3405 {
3406 SetLastNtError(Status);
3407 RETURN( FALSE);
3408 }
3409
3410 /*
3411 * Test if we are permitted to change the shell window.
3412 */
3413 if (WinStaObject->ShellWindow)
3414 {
3415 ObDereferenceObject(WinStaObject);
3416 RETURN( FALSE);
3417 }
3418
3419 /*
3420 * Move shell window into background.
3421 */
3422 if (hwndListView && hwndListView != hwndShell)
3423 {
3424 /*
3425 * Disabled for now to get Explorer working.
3426 * -- Filip, 01/nov/2003
3427 */
3428 #if 0
3429 co_WinPosSetWindowPos(WndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3430 #endif
3431
3432 if (WndListView->ExStyle & WS_EX_TOPMOST)
3433 {
3434 ObDereferenceObject(WinStaObject);
3435 RETURN( FALSE);
3436 }
3437 }
3438
3439 if (WndShell->ExStyle & WS_EX_TOPMOST)
3440 {
3441 ObDereferenceObject(WinStaObject);
3442 RETURN( FALSE);
3443 }
3444
3445 UserRefObjectCo(WndShell, &Ref);
3446 WndShell->state2 |= WNDS2_BOTTOMMOST;
3447 co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3448
3449 WinStaObject->ShellWindow = hwndShell;
3450 WinStaObject->ShellListView = hwndListView;
3451
3452 ti = GetW32ThreadInfo();
3453 if (ti->pDeskInfo)
3454 {
3455 ti->pDeskInfo->hShellWindow = hwndShell;
3456 ti->pDeskInfo->spwndShell = WndShell;
3457 ti->pDeskInfo->ppiShellProcess = ti->ppi;
3458 }
3459
3460 UserRegisterHotKey(WndShell, SC_TASKLIST, MOD_CONTROL, VK_ESCAPE);
3461
3462 UserDerefObjectCo(WndShell);
3463
3464 ObDereferenceObject(WinStaObject);
3465 RETURN( TRUE);
3466
3467 CLEANUP:
3468 TRACE("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3469 UserLeave();
3470 END_CLEANUP;
3471 }
3472
3473 // Fixes wine Win test_window_styles and todo tests...
3474 static BOOL FASTCALL
3475 IntCheckFrameEdge(ULONG Style, ULONG ExStyle)
3476 {
3477 if (ExStyle & WS_EX_DLGMODALFRAME)
3478 return TRUE;
3479 else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME)))
3480 return TRUE;
3481 else
3482 return FALSE;
3483 }
3484
3485 LONG FASTCALL
3486 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3487 {
3488 PWND Window, Parent;
3489 PWINSTATION_OBJECT WindowStation;
3490 LONG OldValue;
3491 STYLESTRUCT Style;
3492
3493 if (!(Window = UserGetWindowObject(hWnd)))
3494 {
3495 return( 0);
3496 }
3497
3498 if ((INT)Index >= 0)
3499 {
3500 if ((Index + sizeof(LONG)) > Window->cbwndExtra)
3501 {
3502 EngSetLastError(ERROR_INVALID_INDEX);
3503 return( 0);
3504 }
3505
3506 OldValue = *((LONG *)((PCHAR)(Window + 1) + Index));
3507 /*
3508 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3509 {
3510 OldValue = (LONG)IntSetWindowProc( Wnd,
3511 (WNDPROC)NewValue,
3512 Ansi);
3513 if (!OldValue) return 0;
3514 }
3515 */
3516 *((LONG *)((PCHAR)(Window + 1) + Index)) = NewValue;
3517 }
3518 else
3519 {
3520 switch (Index)
3521 {
3522 case GWL_EXSTYLE:
3523 OldValue = (LONG) Window->ExStyle;
3524 Style.styleOld = OldValue;
3525 Style.styleNew = NewValue;
3526
3527 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3528
3529 /*
3530 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3531 */
3532 WindowStation = Window->head.pti->rpdesk->rpwinstaParent;
3533 if(WindowStation)
3534 {
3535 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3536 Style.styleNew &= ~WS_EX_TOPMOST;
3537 }
3538 /* WS_EX_WINDOWEDGE depends on some other styles */
3539 if (IntCheckFrameEdge(Window->style, NewValue))
3540 Style.styleNew |= WS_EX_WINDOWEDGE;
3541 else
3542 Style.styleNew &= ~WS_EX_WINDOWEDGE;
3543
3544 Window->ExStyle = (DWORD)Style.styleNew;
3545 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3546 break;
3547
3548 case GWL_STYLE:
3549 OldValue = (LONG) Window->style;
3550 Style.styleOld = OldValue;
3551 Style.styleNew = NewValue;
3552 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3553
3554 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
3555 if (Window->spwndParent == UserGetDesktopWindow()) Style.styleNew |= WS_CLIPSIBLINGS;
3556 /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */
3557 if (IntCheckFrameEdge(NewValue, Window->ExStyle))
3558 Window->ExStyle |= WS_EX_WINDOWEDGE;
3559 else
3560 Window->ExStyle &= ~WS_EX_WINDOWEDGE;
3561
3562 if ((Style.styleOld ^ Style.styleNew) & WS_VISIBLE)
3563 {
3564 if (Style.styleOld & WS_VISIBLE) Window->head.pti->cVisWindows--;
3565 if (Style.styleNew & WS_VISIBLE) Window->head.pti->cVisWindows++;
3566 DceResetActiveDCEs( Window );
3567 }
3568 Window->style = (DWORD)Style.styleNew;
3569 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3570 break;
3571
3572 case GWL_WNDPROC:
3573 {
3574 if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
3575 Window->fnid & FNID_FREED)
3576 {
3577 EngSetLastError(ERROR_ACCESS_DENIED);
3578 return( 0);
3579 }
3580 OldValue = (LONG)IntSetWindowProc(Window,
3581 (WNDPROC)NewValue,
3582 Ansi);
3583 break;
3584 }
3585
3586 case GWL_HINSTANCE:
3587 OldValue = (LONG) Window->hModule;
3588 Window->hModule = (HINSTANCE) NewValue;
3589 break;
3590
3591 case GWL_HWNDPARENT:
3592 Parent = Window->spwndParent;
3593 if (Parent && (Parent->head.h == IntGetDesktopWindow()))
3594 OldValue = (LONG) IntSetOwner(Window->head.h, (HWND) NewValue);
3595 else
3596 OldValue = (LONG) co_UserSetParent(Window->head.h, (HWND) NewValue);
3597 break;
3598
3599 case GWL_ID:
3600 OldValue = (LONG) Window->IDMenu;
3601 Window->IDMenu = (UINT) NewValue;
3602 break;
3603
3604 case GWL_USERDATA:
3605 OldValue = Window->dwUserData;
3606 Window->dwUserData = NewValue;
3607 break;
3608
3609 default:
3610 ERR("NtUserSetWindowLong(): Unsupported index %lu\n", Index);
3611 EngSetLastError(ERROR_INVALID_INDEX);
3612 OldValue = 0;
3613 break;
3614 }
3615 }
3616
3617 return( OldValue);
3618 }
3619
3620 /*
3621 * NtUserSetWindowLong
3622 *
3623 * The NtUserSetWindowLong function changes an attribute of the specified
3624 * window. The function also sets the 32-bit (long) value at the specified
3625 * offset into the extra window memory.
3626 *
3627 * Status
3628 * @implemented
3629 */
3630
3631 LONG APIENTRY
3632 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3633 {
3634 DECLARE_RETURN(LONG);
3635
3636 TRACE("Enter NtUserSetWindowLong\n");
3637 UserEnterExclusive();
3638
3639 if (hWnd == IntGetDesktopWindow())
3640 {
3641 EngSetLastError(STATUS_ACCESS_DENIED);
3642 RETURN( 0);
3643 }
3644
3645 RETURN( co_UserSetWindowLong(hWnd, Index, NewValue, Ansi));
3646
3647 CLEANUP:
3648 TRACE("Leave NtUserSetWindowLong, ret=%i\n",_ret_);
3649 UserLeave();
3650 END_CLEANUP;
3651 }
3652
3653 /*
3654 * NtUserSetWindowWord
3655 *
3656 * Legacy function similar to NtUserSetWindowLong.
3657 *
3658 * Status
3659 * @implemented
3660 */
3661
3662 WORD APIENTRY
3663 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
3664 {
3665 PWND Window;
3666 WORD OldValue;
3667 DECLARE_RETURN(WORD);
3668
3669 TRACE("Enter NtUserSetWindowWord\n");
3670 UserEnterExclusive();
3671
3672 if (hWnd == IntGetDesktopWindow())
3673 {
3674 EngSetLastError(STATUS_ACCESS_DENIED);
3675 RETURN( 0);
3676 }
3677
3678 if (!(Window = UserGetWindowObject(hWnd)))
3679 {
3680 RETURN( 0);
3681 }
3682
3683 switch (Index)
3684 {
3685 case GWL_ID:
3686 case GWL_HINSTANCE:
3687 case GWL_HWNDPARENT:
3688 RETURN( (WORD)co_UserSetWindowLong(UserHMGetHandle(Window), Index, (UINT)NewValue, TRUE));
3689 default:
3690 if (Index < 0)
3691 {
3692 EngSetLastError(ERROR_INVALID_INDEX);
3693 RETURN( 0);
3694 }
3695 }
3696
3697 if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD)))
3698 {
3699 EngSetLastError(ERROR_INVALID_PARAMETER);
3700 RETURN( 0);
3701 }
3702
3703 OldValue = *((WORD *)((PCHAR)(Window + 1) + Index));
3704 *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue;
3705
3706 RETURN( OldValue);
3707
3708 CLEANUP:
3709 TRACE("Leave NtUserSetWindowWord, ret=%u\n", _ret_);
3710 UserLeave();
3711 END_CLEANUP;
3712 }
3713
3714 /*
3715 QueryWindow based on KJK::Hyperion and James Tabor.
3716
3717 0 = QWUniqueProcessId
3718 1 = QWUniqueThreadId
3719 2 = QWActiveWindow
3720 3 = QWFocusWindow
3721 4 = QWIsHung Implements IsHungAppWindow found
3722 by KJK::Hyperion.
3723
3724 9 = QWKillWindow When I called this with hWnd ==
3725 DesktopWindow, it shutdown the system
3726 and rebooted.
3727 */
3728 /*
3729 * @implemented
3730 */
3731 DWORD APIENTRY
3732 NtUserQueryWindow(HWND hWnd, DWORD Index)
3733 {
3734 /* Console Leader Process CID Window offsets */
3735 #define GWLP_CONSOLE_LEADER_PID 0
3736 #define GWLP_CONSOLE_LEADER_TID 4
3737
3738 PWND pWnd;
3739 DWORD Result;
3740 DECLARE_RETURN(UINT);
3741
3742 TRACE("Enter NtUserQueryWindow\n");
3743 UserEnterShared();
3744
3745 if (!(pWnd = UserGetWindowObject(hWnd)))
3746 {
3747 RETURN( 0);
3748 }
3749
3750 switch(Index)
3751 {
3752 case QUERY_WINDOW_UNIQUE_PROCESS_ID:
3753 {
3754 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
3755 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
3756 {
3757 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_PID)
3758 Result = (DWORD)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_PID)));
3759 }
3760 else
3761 {
3762 Result = (DWORD)IntGetWndProcessId(pWnd);
3763 }
3764 break;
3765 }
3766
3767 case QUERY_WINDOW_UNIQUE_THREAD_ID:
3768 {
3769 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
3770 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
3771 {
3772 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_TID)
3773 Result = (DWORD)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_TID)));
3774 }
3775 else
3776 {
3777 Result = (DWORD)IntGetWndThreadId(pWnd);
3778 }
3779 break;
3780 }
3781
3782 case QUERY_WINDOW_ACTIVE:
3783 Result = (DWORD)(pWnd->head.pti->MessageQueue->spwndActive ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndActive) : 0);
3784 break;
3785
3786 case QUERY_WINDOW_FOCUS:
3787 Result = (DWORD)(pWnd->head.pti->MessageQueue->spwndFocus ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndFocus) : 0);
3788 break;
3789
3790 case QUERY_WINDOW_ISHUNG:
3791 Result = (DWORD)MsqIsHung(pWnd->head.pti);
3792 break;
3793
3794 case QUERY_WINDOW_REAL_ID:
3795 Result = (DWORD)pWnd->head.pti->pEThread->Cid.UniqueProcess;
3796 break;
3797
3798 case QUERY_WINDOW_FOREGROUND:
3799 Result = (pWnd->head.pti->MessageQueue == gpqForeground);
3800 break;
3801
3802 default:
3803 Result = (DWORD)NULL;
3804 break;
3805 }
3806
3807 RETURN( Result);
3808
3809 CLEANUP:
3810 TRACE("Leave NtUserQueryWindow, ret=%u\n", _ret_);
3811 UserLeave();
3812 END_CLEANUP;
3813 }
3814
3815
3816 /*
3817 * @implemented
3818 */
3819 UINT APIENTRY
3820 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
3821 {
3822 UNICODE_STRING SafeMessageName;
3823 NTSTATUS Status;
3824 UINT Ret;
3825 DECLARE_RETURN(UINT);
3826
3827 TRACE("Enter NtUserRegisterWindowMessage\n");
3828 UserEnterExclusive();
3829
3830 if(MessageNameUnsafe == NULL)
3831 {
3832 EngSetLastError(ERROR_INVALID_PARAMETER);
3833 RETURN( 0);
3834 }
3835
3836 Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
3837 if(!NT_SUCCESS(Status))
3838 {
3839 SetLastNtError(Status);
3840 RETURN( 0);
3841 }
3842
3843 Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
3844 if (SafeMessageName.Buffer)
3845 ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING);
3846 RETURN( Ret);
3847
3848 CLEANUP:
3849 TRACE("Leave NtUserRegisterWindowMessage, ret=%u\n", _ret_);
3850 UserLeave();
3851 END_CLEANUP;
3852 }
3853
3854
3855 /*
3856 * @implemented
3857 */
3858 BOOL APIENTRY
3859 NtUserSetMenu(
3860 HWND hWnd,
3861 HMENU Menu,
3862 BOOL Repaint)
3863 {
3864 PWND Window;
3865 BOOL Changed;
3866 DECLARE_RETURN(BOOL);
3867
3868 TRACE("Enter NtUserSetMenu\n");
3869 UserEnterExclusive();
3870
3871 if (!(Window = UserGetWindowObject(hWnd)))
3872 {
3873 RETURN( FALSE);
3874 }
3875
3876 if (! IntSetMenu(Window, Menu, &Changed))
3877 {
3878 RETURN( FALSE);
3879 }
3880
3881 if (Changed && Repaint)
3882 {
3883 USER_REFERENCE_ENTRY Ref;
3884
3885 UserRefObjectCo(Window, &Ref);
3886 co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3887 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
3888
3889 UserDerefObjectCo(Window);
3890 }
3891
3892 RETURN( TRUE);
3893
3894 CLEANUP:
3895 TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_);
3896 UserLeave();
3897 END_CLEANUP;
3898 }
3899
3900 /*
3901 * @implemented
3902 */
3903 BOOL APIENTRY
3904 NtUserSetWindowFNID(HWND hWnd,
3905 WORD fnID)
3906 {
3907 PWND Wnd;
3908 DECLARE_RETURN(BOOL);
3909
3910 TRACE("Enter NtUserSetWindowFNID\n");
3911 UserEnterExclusive();
3912
3913 if (!(Wnd = UserGetWindowObject(hWnd)))
3914 {
3915 RETURN( FALSE);
3916 }
3917
3918 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
3919 {
3920 EngSetLastError(ERROR_ACCESS_DENIED);
3921 RETURN( FALSE);
3922 }
3923
3924 // From user land we only set these.
3925 if (fnID != FNID_DESTROY)
3926 { // Hacked so we can mark desktop~!
3927 if ( (/*(fnID < FNID_BUTTON)*/ (fnID < FNID_FIRST) && (fnID > FNID_GHOST)) ||
3928 Wnd->fnid != 0 )
3929 {
3930 EngSetLastError(ERROR_INVALID_PARAMETER);
3931 RETURN( FALSE);
3932 }
3933 }
3934
3935 Wnd->fnid |= fnID;
3936 RETURN( TRUE);
3937
3938 CLEANUP:
3939 TRACE("Leave NtUserSetWindowFNID\n");
3940 UserLeave();
3941 END_CLEANUP;
3942 }
3943
3944 /*
3945 * NtUserDefSetText
3946 *
3947 * Undocumented function that is called from DefWindowProc to set
3948 * window text.
3949 *
3950 * Status
3951 * @implemented
3952 */
3953 BOOL APIENTRY
3954 NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText)
3955 {
3956 PWND Wnd;
3957 LARGE_STRING SafeText;
3958 UNICODE_STRING UnicodeString;
3959 BOOL Ret = TRUE;
3960
3961 TRACE("Enter NtUserDefSetText\n");
3962
3963 if (WindowText != NULL)
3964 {
3965 _SEH2_TRY
3966 {
3967 SafeText = ProbeForReadLargeString(WindowText);
3968 }
3969 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3970 {
3971 Ret = FALSE;
3972 SetLastNtError(_SEH2_GetExceptionCode());
3973 }
3974 _SEH2_END;
3975
3976 if (!Ret)
3977 return FALSE;
3978 }
3979 else
3980 return TRUE;
3981
3982 UserEnterExclusive();
3983
3984 if(!(Wnd = UserGetWindowObject(hWnd)))
3985 {
3986 UserLeave();
3987 return FALSE;
3988 }
3989
3990 // ReactOS uses Unicode and not mixed. Up/Down converting will take time.
3991 // Brought to you by: The Wine Project! Dysfunctional Thought Processes!
3992 // Now we know what the bAnsi is for.
3993 RtlInitUnicodeString(&UnicodeString, NULL);
3994 if (SafeText.Buffer)
3995 {
3996 _SEH2_TRY
3997 {
3998 if (SafeText.bAnsi)
3999 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR));
4000 else
4001 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR));
4002 Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText);
4003 }
4004 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4005 {
4006 Ret = FALSE;
4007 SetLastNtError(_SEH2_GetExceptionCode());
4008 }
4009 _SEH2_END;
4010 if (!Ret) goto Exit;
4011 }
4012
4013 if (UnicodeString.Length != 0)
4014 {
4015 if (Wnd->strName.MaximumLength > 0 &&
4016 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4017 {
4018 ASSERT(Wnd->strName.Buffer != NULL);
4019
4020 Wnd->strName.Length = UnicodeString.Length;
4021 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4022 RtlCopyMemory(Wnd->strName.Buffer,
4023 UnicodeString.Buffer,
4024 UnicodeString.Length);
4025 }
4026 else
4027 {
4028 PWCHAR buf;
4029 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4030 buf = Wnd->strName.Buffer;
4031 Wnd->strName.Buffer = NULL;
4032 if (buf != NULL)
4033 {
4034 DesktopHeapFree(Wnd->head.rpdesk, buf);
4035 }
4036
4037 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4038 UnicodeString.Length + sizeof(UNICODE_NULL));
4039 if (Wnd->strName.Buffer != NULL)
4040 {
4041 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4042 RtlCopyMemory(Wnd->strName.Buffer,
4043 UnicodeString.Buffer,
4044 UnicodeString.Length);
4045 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4046 Wnd->strName.Length = UnicodeString.Length;
4047 }
4048 else
4049 {
4050 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4051 Ret = FALSE;
4052 goto Exit;
4053 }
4054 }
4055 }
4056 else
4057 {
4058 Wnd->strName.Length = 0;
4059 if (Wnd->strName.Buffer != NULL)
4060 Wnd->strName.Buffer[0] = L'\0';
4061 }
4062
4063 // FIXME: HAX! Windows does not do this in here!
4064 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4065 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4066 /* Send shell notifications */
4067 if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4068 {
4069 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) hWnd, FALSE); // FIXME Flashing?
4070 }
4071
4072 Ret = TRUE;
4073 Exit:
4074 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4075 TRACE("Leave NtUserDefSetText, ret=%i\n", Ret);
4076 UserLeave();
4077 return Ret;
4078 }
4079
4080 /*
4081 * NtUserInternalGetWindowText
4082 *
4083 * Status
4084 * @implemented
4085 */
4086
4087 INT APIENTRY
4088 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount)
4089 {
4090 PWND Wnd;
4091 NTSTATUS Status;
4092 INT Result;
4093 DECLARE_RETURN(INT);
4094
4095 TRACE("Enter NtUserInternalGetWindowText\n");
4096 UserEnterShared();
4097
4098 if(lpString && (nMaxCount <= 1))
4099 {
4100 EngSetLastError(ERROR_INVALID_PARAMETER);
4101 RETURN( 0);
4102 }
4103
4104 if(!(Wnd = UserGetWindowObject(hWnd)))
4105 {
4106 RETURN( 0);
4107 }
4108
4109 Result = Wnd->strName.Length / sizeof(WCHAR);
4110 if(lpString)
4111 {
4112 const WCHAR Terminator = L'\0';
4113 INT Copy;
4114 WCHAR *Buffer = (WCHAR*)lpString;
4115
4116 Copy = min(nMaxCount - 1, Result);
4117 if(Copy > 0)
4118 {
4119 Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR));
4120 if(!NT_SUCCESS(Status))
4121 {
4122 SetLastNtError(Status);
4123 RETURN( 0);
4124 }
4125 Buffer += Copy;
4126 }
4127
4128 Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
4129 if(!NT_SUCCESS(Status))
4130 {
4131 SetLastNtError(Status);
4132 RETURN( 0);
4133 }
4134
4135 Result = Copy;
4136 }
4137
4138 RETURN( Result);
4139
4140 CLEANUP:
4141 TRACE("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_);
4142 UserLeave();
4143 END_CLEANUP;
4144 }
4145
4146 /*
4147 API Call
4148 */
4149 BOOL
4150 FASTCALL
4151 IntShowOwnedPopups(PWND OwnerWnd, BOOL fShow )
4152 {
4153 int count = 0;
4154 PWND pWnd;
4155 HWND *win_array;
4156
4157 // ASSERT(OwnerWnd);
4158
4159 TRACE("Enter ShowOwnedPopups Show: %s\n", (fShow ? "TRUE" : "FALSE"));
4160 win_array = IntWinListChildren(OwnerWnd);
4161
4162 if (!win_array)
4163 return TRUE;
4164
4165 while (win_array[count])
4166 count++;
4167 while (--count >= 0)
4168 {
4169 if (!(pWnd = ValidateHwndNoErr( win_array[count] )))
4170 continue;
4171 if (pWnd->spwndOwner != OwnerWnd)
4172 continue;
4173
4174 if (fShow)
4175 {
4176 if (pWnd->state & WNDS_HIDDENPOPUP)
4177 {
4178 /* In Windows, ShowOwnedPopups(TRUE) generates
4179 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
4180 * regardless of the state of the owner
4181 */
4182 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
4183 continue;
4184 }
4185 }
4186 else
4187 {
4188 if (pWnd->style & WS_VISIBLE)
4189 {
4190 /* In Windows, ShowOwnedPopups(FALSE) generates
4191 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
4192 * regardless of the state of the owner
4193 */
4194 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
4195 continue;
4196 }
4197 }
4198
4199 }
4200 ExFreePoolWithTag(win_array, USERTAG_WINDOWLIST);
4201 TRACE("Leave ShowOwnedPopups\n");
4202 return TRUE;
4203 }
4204
4205 /* EOF */