[WIN32K]
[reactos.git] / reactos / win32ss / user / ntuser / window.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Win32k subsystem
4 * PURPOSE: Windows
5 * FILE: subsystems/win32/win32k/ntuser/window.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserWnd);
11
12 INT gNestedWindowLimit = 50;
13
14 /* HELPER FUNCTIONS ***********************************************************/
15
16 BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam)
17 {
18 WORD Action = LOWORD(wParam);
19 WORD Flags = HIWORD(wParam);
20
21 if (Flags & ~(UISF_HIDEFOCUS | UISF_HIDEACCEL | UISF_ACTIVE))
22 {
23 EngSetLastError(ERROR_INVALID_PARAMETER);
24 return FALSE;
25 }
26
27 switch (Action)
28 {
29 case UIS_INITIALIZE:
30 EngSetLastError(ERROR_INVALID_PARAMETER);
31 return FALSE;
32
33 case UIS_SET:
34 if (Flags & UISF_HIDEFOCUS)
35 Wnd->HideFocus = TRUE;
36 if (Flags & UISF_HIDEACCEL)
37 Wnd->HideAccel = TRUE;
38 break;
39
40 case UIS_CLEAR:
41 if (Flags & UISF_HIDEFOCUS)
42 Wnd->HideFocus = FALSE;
43 if (Flags & UISF_HIDEACCEL)
44 Wnd->HideAccel = FALSE;
45 break;
46 }
47
48 return TRUE;
49 }
50
51 PWND FASTCALL IntGetWindowObject(HWND hWnd)
52 {
53 PWND Window;
54
55 if (!hWnd) return NULL;
56
57 Window = UserGetWindowObject(hWnd);
58 if (Window)
59 Window->head.cLockObj++;
60
61 return Window;
62 }
63
64 PWND FASTCALL VerifyWnd(PWND pWnd)
65 {
66 HWND hWnd;
67 UINT State, State2;
68
69 if (!pWnd) return NULL;
70
71 _SEH2_TRY
72 {
73 hWnd = UserHMGetHandle(pWnd);
74 State = pWnd->state;
75 State2 = pWnd->state2;
76 }
77 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
78 {
79 _SEH2_YIELD(return NULL);
80 }
81 _SEH2_END
82
83 if ( UserObjectInDestroy(hWnd) ||
84 State & WNDS_DESTROYED ||
85 State2 & WNDS2_INDESTROY )
86 return NULL;
87
88 return pWnd;
89 }
90
91 PWND FASTCALL ValidateHwndNoErr(HWND hWnd)
92 {
93 if (hWnd) return (PWND)UserGetObjectNoErr(gHandleTable, hWnd, TYPE_WINDOW);
94 return NULL;
95 }
96
97 /* Temp HACK */
98 PWND FASTCALL UserGetWindowObject(HWND hWnd)
99 {
100 PWND Window;
101
102 if (!hWnd)
103 {
104 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
105 return NULL;
106 }
107
108 Window = (PWND)UserGetObject(gHandleTable, hWnd, TYPE_WINDOW);
109 if (!Window || 0 != (Window->state & WNDS_DESTROYED))
110 {
111 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
112 return NULL;
113 }
114
115 return Window;
116 }
117
118 ULONG FASTCALL
119 IntSetStyle( PWND pwnd, ULONG set_bits, ULONG clear_bits )
120 {
121 ULONG styleOld, styleNew;
122 styleOld = pwnd->style;
123 styleNew = (pwnd->style | set_bits) & ~clear_bits;
124 if (styleNew == styleOld) return styleNew;
125 pwnd->style = styleNew;
126 if ((styleOld ^ styleNew) & WS_VISIBLE) // State Change.
127 {
128 if (styleOld & WS_VISIBLE) pwnd->head.pti->cVisWindows--;
129 if (styleNew & WS_VISIBLE) pwnd->head.pti->cVisWindows++;
130 DceResetActiveDCEs( pwnd );
131 }
132 return styleOld;
133 }
134
135 /*
136 * IntIsWindow
137 *
138 * The function determines whether the specified window handle identifies
139 * an existing window.
140 *
141 * Parameters
142 * hWnd
143 * Handle to the window to test.
144 *
145 * Return Value
146 * If the window handle identifies an existing window, the return value
147 * is TRUE. If the window handle does not identify an existing window,
148 * the return value is FALSE.
149 */
150
151 BOOL FASTCALL
152 IntIsWindow(HWND hWnd)
153 {
154 PWND Window;
155
156 if (!(Window = UserGetWindowObject(hWnd)))
157 {
158 return FALSE;
159 }
160
161 return TRUE;
162 }
163
164 BOOL FASTCALL
165 IntIsWindowVisible(PWND Wnd)
166 {
167 PWND Temp = Wnd;
168 for (;;)
169 {
170 if (!Temp) return TRUE;
171 if (!(Temp->style & WS_VISIBLE)) break;
172 if (Temp->style & WS_MINIMIZE && Temp != Wnd) break;
173 if (Temp->fnid == FNID_DESKTOP) return TRUE;
174 Temp = Temp->spwndParent;
175 }
176 return FALSE;
177 }
178
179 PWND FASTCALL
180 IntGetParent(PWND Wnd)
181 {
182 if (Wnd->style & WS_POPUP)
183 {
184 return Wnd->spwndOwner;
185 }
186 else if (Wnd->style & WS_CHILD)
187 {
188 return Wnd->spwndParent;
189 }
190
191 return NULL;
192 }
193
194 BOOL
195 FASTCALL
196 IntEnableWindow( HWND hWnd, BOOL bEnable )
197 {
198 BOOL Update;
199 PWND pWnd;
200 UINT bIsDisabled;
201
202 if(!(pWnd = UserGetWindowObject(hWnd)))
203 {
204 return FALSE;
205 }
206
207 /* check if updating is needed */
208 bIsDisabled = !!(pWnd->style & WS_DISABLED);
209 Update = bIsDisabled;
210
211 if (bEnable)
212 {
213 IntSetStyle( pWnd, 0, WS_DISABLED );
214 }
215 else
216 {
217 Update = !bIsDisabled;
218
219 co_IntSendMessage( hWnd, WM_CANCELMODE, 0, 0);
220
221 /* Remove keyboard focus from that window if it had focus */
222 if (hWnd == IntGetThreadFocusWindow())
223 {
224 TRACE("IntEnableWindow SF NULL\n");
225 co_UserSetFocus(NULL);
226 }
227 IntSetStyle( pWnd, WS_DISABLED, 0 );
228 }
229
230 if (Update)
231 {
232 IntNotifyWinEvent(EVENT_OBJECT_STATECHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, 0);
233 co_IntSendMessage(hWnd, WM_ENABLE, (LPARAM)bEnable, 0);
234 }
235 // Return nonzero if it was disabled, or zero if it wasn't:
236 return bIsDisabled;
237 }
238
239 /*
240 * IntWinListChildren
241 *
242 * Compile a list of all child window handles from given window.
243 *
244 * Remarks
245 * This function is similar to Wine WIN_ListChildren. The caller
246 * must free the returned list with ExFreePool.
247 */
248
249 HWND* FASTCALL
250 IntWinListChildren(PWND Window)
251 {
252 PWND Child;
253 HWND *List;
254 UINT Index, NumChildren = 0;
255
256 if (!Window) return NULL;
257
258 for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
259 ++NumChildren;
260
261 List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), USERTAG_WINDOWLIST);
262 if(!List)
263 {
264 ERR("Failed to allocate memory for children array\n");
265 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
266 return NULL;
267 }
268 for (Child = Window->spwndChild, Index = 0;
269 Child != NULL;
270 Child = Child->spwndNext, ++Index)
271 List[Index] = Child->head.h;
272 List[Index] = NULL;
273
274 return List;
275 }
276
277 PWND FASTCALL
278 IntGetNonChildAncestor(PWND pWnd)
279 {
280 while(pWnd && (pWnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
281 pWnd = pWnd->spwndParent;
282 return pWnd;
283 }
284
285 BOOL FASTCALL
286 IntIsTopLevelWindow(PWND pWnd)
287 {
288 if ( pWnd->spwndParent &&
289 pWnd->spwndParent == co_GetDesktopWindow(pWnd) ) return TRUE;
290 return FALSE;
291 }
292
293 BOOL FASTCALL
294 IntValidateOwnerDepth(PWND Wnd, PWND Owner)
295 {
296 INT Depth = 1;
297 for (;;)
298 {
299 if ( !Owner ) return gNestedWindowLimit >= Depth;
300 if (Owner == Wnd) break;
301 Owner = Owner->spwndOwner;
302 Depth++;
303 }
304 return FALSE;
305 }
306
307 HWND FASTCALL
308 IntGetWindow(HWND hWnd,
309 UINT uCmd)
310 {
311 PWND Wnd, FoundWnd;
312 HWND Ret = NULL;
313
314 Wnd = ValidateHwndNoErr(hWnd);
315 if (!Wnd)
316 return NULL;
317
318 FoundWnd = NULL;
319 switch (uCmd)
320 {
321 case GW_OWNER:
322 if (Wnd->spwndOwner != NULL)
323 FoundWnd = Wnd->spwndOwner;
324 break;
325
326 case GW_HWNDFIRST:
327 if(Wnd->spwndParent != NULL)
328 {
329 FoundWnd = Wnd->spwndParent;
330 if (FoundWnd->spwndChild != NULL)
331 FoundWnd = FoundWnd->spwndChild;
332 }
333 break;
334 case GW_HWNDNEXT:
335 if (Wnd->spwndNext != NULL)
336 FoundWnd = Wnd->spwndNext;
337 break;
338
339 case GW_HWNDPREV:
340 if (Wnd->spwndPrev != NULL)
341 FoundWnd = Wnd->spwndPrev;
342 break;
343
344 case GW_CHILD:
345 if (Wnd->spwndChild != NULL)
346 FoundWnd = Wnd->spwndChild;
347 break;
348
349 case GW_HWNDLAST:
350 FoundWnd = Wnd;
351 while ( FoundWnd->spwndNext != NULL)
352 FoundWnd = FoundWnd->spwndNext;
353 break;
354
355 default:
356 Wnd = NULL;
357 break;
358 }
359
360 if (FoundWnd != NULL)
361 Ret = UserHMGetHandle(FoundWnd);
362 return Ret;
363 }
364
365 /***********************************************************************
366 * IntSendDestroyMsg
367 */
368 static void IntSendDestroyMsg(HWND hWnd)
369 {
370
371 PWND Window;
372 #if 0 /* FIXME */
373
374 GUITHREADINFO info;
375
376 if (GetGUIThreadInfo(GetCurrentThreadId(), &info))
377 {
378 if (hWnd == info.hwndCaret)
379 {
380 DestroyCaret();
381 }
382 }
383 #endif
384
385 Window = UserGetWindowObject(hWnd);
386 if (Window)
387 {
388 // USER_REFERENCE_ENTRY Ref;
389 // UserRefObjectCo(Window, &Ref);
390
391 if (!Window->spwndOwner && !IntGetParent(Window))
392 {
393 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM) hWnd, 0);
394 }
395
396 // UserDerefObjectCo(Window);
397 }
398
399 /* The window could already be destroyed here */
400
401 /*
402 * Send the WM_DESTROY to the window.
403 */
404
405 co_IntSendMessage(hWnd, WM_DESTROY, 0, 0);
406
407 /*
408 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
409 * make sure that the window still exists when we come back.
410 */
411 #if 0 /* FIXME */
412
413 if (IsWindow(Wnd))
414 {
415 HWND* pWndArray;
416 int i;
417
418 if (!(pWndArray = WIN_ListChildren( hwnd )))
419 return;
420
421 /* start from the end (FIXME: is this needed?) */
422 for (i = 0; pWndArray[i]; i++)
423 ;
424
425 while (--i >= 0)
426 {
427 if (IsWindow( pWndArray[i] ))
428 WIN_SendDestroyMsg( pWndArray[i] );
429 }
430 HeapFree(GetProcessHeap(), 0, pWndArray);
431 }
432 else
433 {
434 TRACE("destroyed itself while in WM_DESTROY!\n");
435 }
436 #endif
437 }
438
439 static VOID
440 UserFreeWindowInfo(PTHREADINFO ti, PWND Wnd)
441 {
442 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
443
444 if (!Wnd) return;
445
446 if (ClientInfo->CallbackWnd.pWnd == DesktopHeapAddressToUser(Wnd))
447 {
448 ClientInfo->CallbackWnd.hWnd = NULL;
449 ClientInfo->CallbackWnd.pWnd = NULL;
450 }
451
452 if (Wnd->strName.Buffer != NULL)
453 {
454 Wnd->strName.Length = 0;
455 Wnd->strName.MaximumLength = 0;
456 DesktopHeapFree(Wnd->head.rpdesk,
457 Wnd->strName.Buffer);
458 Wnd->strName.Buffer = NULL;
459 }
460
461 // DesktopHeapFree(Wnd->head.rpdesk, Wnd);
462 // WindowObject->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 #ifdef NEW_CURSORICON
1678 if (Class->spicn && !Class->spicnSm)
1679 {
1680 HICON IconSmHandle = NULL;
1681 if((Class->spicn->CURSORF_flags & (CURSORF_LRSHARED | CURSORF_FROMRESOURCE))
1682 == (CURSORF_LRSHARED | CURSORF_FROMRESOURCE))
1683 {
1684 IconSmHandle = co_IntCopyImage(
1685 UserHMGetHandle(Class->spicn),
1686 IMAGE_ICON,
1687 UserGetSystemMetrics( SM_CXSMICON ),
1688 UserGetSystemMetrics( SM_CYSMICON ),
1689 LR_COPYFROMRESOURCE | LR_SHARED);
1690 }
1691 if (!IconSmHandle)
1692 {
1693 /* Retry without copying from resource */
1694 IconSmHandle = co_IntCopyImage(
1695 UserHMGetHandle(Class->spicn),
1696 IMAGE_ICON,
1697 UserGetSystemMetrics( SM_CXSMICON ),
1698 UserGetSystemMetrics( SM_CYSMICON ),
1699 LR_SHARED);
1700 }
1701
1702 if (IconSmHandle)
1703 {
1704 Class->spicnSm = UserGetCurIconObject(IconSmHandle);
1705 Class->CSF_flags |= CSF_CACHEDSMICON;
1706 }
1707 }
1708 #else
1709 if (Class->hIcon && !Class->hIconSm)
1710 {
1711 Class->hIconSmIntern = co_IntCopyImage( Class->hIcon, IMAGE_ICON,
1712 UserGetSystemMetrics( SM_CXSMICON ),
1713 UserGetSystemMetrics( SM_CYSMICON ), 0 );
1714 TRACE("IntCreateWindow hIconSmIntern %p\n",Class->hIconSmIntern);
1715 Class->CSF_flags |= CSF_CACHEDSMICON;
1716 }
1717 #endif
1718
1719 if (pWnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
1720 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
1721
1722 /* BugBoy Comments: Comment below say that System classes are always created
1723 as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
1724 sets the window to ansi as verified by testing with IsUnicodeWindow API.
1725
1726 No where can I see in code or through testing does the window change back
1727 to ANSI after being created as UNICODE in ROS. I didnt do more testing to
1728 see what problems this would cause. */
1729
1730 // Set WndProc from Class.
1731 pWnd->lpfnWndProc = pWnd->pcls->lpfnWndProc;
1732
1733 // GetWindowProc, test for non server side default classes and set WndProc.
1734 if ( pWnd->pcls->fnid <= FNID_GHOST && pWnd->pcls->fnid >= FNID_BUTTON )
1735 {
1736 if (bUnicodeWindow)
1737 {
1738 if (GETPFNCLIENTA(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1739 pWnd->lpfnWndProc = GETPFNCLIENTW(pWnd->pcls->fnid);
1740 }
1741 else
1742 {
1743 if (GETPFNCLIENTW(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1744 pWnd->lpfnWndProc = GETPFNCLIENTA(pWnd->pcls->fnid);
1745 }
1746 }
1747
1748 // If not an Unicode caller, set Ansi creator bit.
1749 if (!bUnicodeWindow) pWnd->state |= WNDS_ANSICREATOR;
1750
1751 // Clone Class Ansi/Unicode proc type.
1752 if (pWnd->pcls->CSF_flags & CSF_ANSIPROC)
1753 {
1754 pWnd->state |= WNDS_ANSIWINDOWPROC;
1755 pWnd->Unicode = FALSE;
1756 }
1757 else
1758 { /*
1759 * It seems there can be both an Ansi creator and Unicode Class Window
1760 * WndProc, unless the following overriding conditions occur:
1761 */
1762 if ( !bUnicodeWindow &&
1763 ( Class->atomClassName == gpsi->atomSysClass[ICLS_BUTTON] ||
1764 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX] ||
1765 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOLBOX] ||
1766 Class->atomClassName == gpsi->atomSysClass[ICLS_DIALOG] ||
1767 Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT] ||
1768 Class->atomClassName == gpsi->atomSysClass[ICLS_IME] ||
1769 Class->atomClassName == gpsi->atomSysClass[ICLS_LISTBOX] ||
1770 Class->atomClassName == gpsi->atomSysClass[ICLS_MDICLIENT] ||
1771 Class->atomClassName == gpsi->atomSysClass[ICLS_STATIC] ) )
1772 { // Override Class and set the window Ansi WndProc.
1773 pWnd->state |= WNDS_ANSIWINDOWPROC;
1774 pWnd->Unicode = FALSE;
1775 }
1776 else
1777 { // Set the window Unicode WndProc.
1778 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
1779 pWnd->Unicode = TRUE;
1780 }
1781 }
1782
1783 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
1784 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
1785 Dont understand why it does this. */
1786 if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT])
1787 {
1788 PCALLPROCDATA CallProc;
1789 CallProc = CreateCallProc(pWnd->head.rpdesk, pWnd->lpfnWndProc, pWnd->Unicode , pWnd->head.pti->ppi);
1790
1791 if (!CallProc)
1792 {
1793 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1794 ERR("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %p\n", hWnd);
1795 }
1796 else
1797 {
1798 UserAddCallProcToClass(pWnd->pcls, CallProc);
1799 }
1800 }
1801
1802 InitializeListHead(&pWnd->PropListHead);
1803 pWnd->PropListItems = 0;
1804
1805 if ( WindowName->Buffer != NULL && WindowName->Length > 0 )
1806 {
1807 pWnd->strName.Buffer = DesktopHeapAlloc(pWnd->head.rpdesk,
1808 WindowName->Length + sizeof(UNICODE_NULL));
1809 if (pWnd->strName.Buffer == NULL)
1810 {
1811 goto AllocError;
1812 }
1813
1814 RtlCopyMemory(pWnd->strName.Buffer, WindowName->Buffer, WindowName->Length);
1815 pWnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
1816 pWnd->strName.Length = WindowName->Length;
1817 pWnd->strName.MaximumLength = WindowName->Length + sizeof(UNICODE_NULL);
1818 }
1819
1820 /* Correct the window style. */
1821 if ((pWnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1822 {
1823 pWnd->style |= WS_CLIPSIBLINGS;
1824 if (!(pWnd->style & WS_POPUP))
1825 {
1826 pWnd->style |= WS_CAPTION;
1827 }
1828 }
1829
1830 /* WS_EX_WINDOWEDGE depends on some other styles */
1831 if (pWnd->ExStyle & WS_EX_DLGMODALFRAME)
1832 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1833 else if (pWnd->style & (WS_DLGFRAME | WS_THICKFRAME))
1834 {
1835 if (!((pWnd->ExStyle & WS_EX_STATICEDGE) &&
1836 (pWnd->style & (WS_CHILD | WS_POPUP))))
1837 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1838 }
1839 else
1840 pWnd->ExStyle &= ~WS_EX_WINDOWEDGE;
1841
1842 if (!(pWnd->style & (WS_CHILD | WS_POPUP)))
1843 pWnd->state |= WNDS_SENDSIZEMOVEMSGS;
1844
1845 /* Set the window menu */
1846 if ((Cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1847 {
1848 if (Cs->hMenu)
1849 {
1850 IntSetMenu(pWnd, Cs->hMenu, &MenuChanged);
1851 }
1852 else if (pWnd->pcls->lpszMenuName) // Take it from the parent.
1853 {
1854 UNICODE_STRING MenuName;
1855 HMENU hMenu;
1856
1857 if (IS_INTRESOURCE(pWnd->pcls->lpszMenuName))
1858 {
1859 MenuName.Length = 0;
1860 MenuName.MaximumLength = 0;
1861 MenuName.Buffer = pWnd->pcls->lpszMenuName;
1862 }
1863 else
1864 {
1865 RtlInitUnicodeString( &MenuName, pWnd->pcls->lpszMenuName);
1866 }
1867 hMenu = co_IntCallLoadMenu( pWnd->pcls->hModule, &MenuName);
1868 if (hMenu) IntSetMenu(pWnd, hMenu, &MenuChanged);
1869 }
1870 }
1871 else // Not a child
1872 pWnd->IDMenu = (UINT) Cs->hMenu;
1873
1874
1875 if ( ParentWindow &&
1876 ParentWindow != ParentWindow->head.rpdesk->spwndMessage &&
1877 ParentWindow != ParentWindow->head.rpdesk->pDeskInfo->spwnd )
1878 {
1879 PWND Owner = IntGetNonChildAncestor(ParentWindow);
1880
1881 if (!IntValidateOwnerDepth(pWnd, Owner))
1882 {
1883 EngSetLastError(ERROR_INVALID_PARAMETER);
1884 goto Error;
1885 }
1886 if ( pWnd->spwndOwner &&
1887 pWnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1888 {
1889 pWnd->ExStyle |= WS_EX_TOPMOST;
1890 }
1891 if ( pWnd->spwndOwner &&
1892 Class->atomClassName != gpsi->atomSysClass[ICLS_IME] &&
1893 pti != pWnd->spwndOwner->head.pti)
1894 {
1895 //ERR("CreateWindow Owner in.\n");
1896 UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE);
1897 }
1898 }
1899
1900 /* Insert the window into the thread's window list. */
1901 InsertTailList (&pti->WindowListHead, &pWnd->ThreadListEntry);
1902
1903 /* Handle "CS_CLASSDC", it is tested first. */
1904 if ( (pWnd->pcls->style & CS_CLASSDC) && !(pWnd->pcls->pdce) )
1905 { /* One DCE per class to have CLASS. */
1906 pWnd->pcls->pdce = DceAllocDCE( pWnd, DCE_CLASS_DC );
1907 }
1908 else if ( pWnd->pcls->style & CS_OWNDC)
1909 { /* Allocate a DCE for this window. */
1910 DceAllocDCE(pWnd, DCE_WINDOW_DC);
1911 }
1912
1913 return pWnd;
1914
1915 AllocError:
1916 ERR("IntCreateWindow Allocation Error.\n");
1917 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1918 Error:
1919 if(pWnd)
1920 UserDereferenceObject(pWnd);
1921 return NULL;
1922 }
1923
1924 /*
1925 * @implemented
1926 */
1927 PWND FASTCALL
1928 co_UserCreateWindowEx(CREATESTRUCTW* Cs,
1929 PUNICODE_STRING ClassName,
1930 PLARGE_STRING WindowName,
1931 PVOID acbiBuffer)
1932 {
1933 ULONG style;
1934 PWND Window = NULL, ParentWindow = NULL, OwnerWindow;
1935 HWND hWnd, hWndParent, hWndOwner, hwndInsertAfter;
1936 PWINSTATION_OBJECT WinSta;
1937 PCLS Class = NULL;
1938 SIZE Size;
1939 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
1940 CBT_CREATEWNDW * pCbtCreate;
1941 LRESULT Result;
1942 USER_REFERENCE_ENTRY ParentRef, Ref;
1943 PTHREADINFO pti;
1944 DWORD dwShowMode = SW_SHOW;
1945 CREATESTRUCTW *pCsw = NULL;
1946 PVOID pszClass = NULL, pszName = NULL;
1947 PWND ret = NULL;
1948
1949 /* Get the current window station and reference it */
1950 pti = GetW32ThreadInfo();
1951 if (pti == NULL || pti->rpdesk == NULL)
1952 {
1953 ERR("Thread is not attached to a desktop! Cannot create window!\n");
1954 return NULL; // There is nothing to cleanup.
1955 }
1956 WinSta = pti->rpdesk->rpwinstaParent;
1957 ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
1958
1959 pCsw = NULL;
1960 pCbtCreate = NULL;
1961
1962 /* Get the class and reference it */
1963 Class = IntGetAndReferenceClass(ClassName, Cs->hInstance, FALSE);
1964 if(!Class)
1965 {
1966 ERR("Failed to find class %wZ\n", ClassName);
1967 goto cleanup;
1968 }
1969
1970 /* Now find the parent and the owner window */
1971 hWndParent = pti->rpdesk->pDeskInfo->spwnd->head.h;
1972 hWndOwner = NULL;
1973
1974 if (Cs->hwndParent == HWND_MESSAGE)
1975 {
1976 Cs->hwndParent = hWndParent = pti->rpdesk->spwndMessage->head.h;
1977 }
1978 else if (Cs->hwndParent)
1979 {
1980 if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1981 hWndOwner = Cs->hwndParent;
1982 else
1983 hWndParent = Cs->hwndParent;
1984 }
1985 else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1986 {
1987 ERR("Cannot create a child window without a parrent!\n");
1988 EngSetLastError(ERROR_TLW_WITH_WSCHILD);
1989 goto cleanup; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1990 }
1991
1992 ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
1993 OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
1994
1995 /* FIXME: Is this correct? */
1996 if(OwnerWindow)
1997 OwnerWindow = UserGetAncestor(OwnerWindow, GA_ROOT);
1998
1999 /* Fix the position and the size of the window */
2000 if (ParentWindow)
2001 {
2002 UserRefObjectCo(ParentWindow, &ParentRef);
2003 IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode);
2004 }
2005
2006 /* Allocate and initialize the new window */
2007 Window = IntCreateWindow(Cs,
2008 WindowName,
2009 Class,
2010 ParentWindow,
2011 OwnerWindow,
2012 acbiBuffer,
2013 NULL);
2014 if(!Window)
2015 {
2016 ERR("IntCreateWindow failed!\n");
2017 goto cleanup;
2018 }
2019
2020 hWnd = UserHMGetHandle(Window);
2021 hwndInsertAfter = HWND_TOP;
2022
2023 UserRefObjectCo(Window, &Ref);
2024 UserDereferenceObject(Window);
2025 ObDereferenceObject(WinSta);
2026
2027 //// Check for a hook to eliminate overhead. ////
2028 if ( ISITHOOKED(WH_CBT) || (pti->rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)) )
2029 {
2030 // Allocate the calling structures Justin Case this goes Global.
2031 pCsw = ExAllocatePoolWithTag(NonPagedPool, sizeof(CREATESTRUCTW), TAG_HOOK);
2032 pCbtCreate = ExAllocatePoolWithTag(NonPagedPool, sizeof(CBT_CREATEWNDW), TAG_HOOK);
2033 if (!pCsw || !pCbtCreate)
2034 {
2035 ERR("UserHeapAlloc() failed!\n");
2036 goto cleanup;
2037 }
2038
2039 /* Fill the new CREATESTRUCTW */
2040 RtlCopyMemory(pCsw, Cs, sizeof(CREATESTRUCTW));
2041 pCsw->style = Window->style; /* HCBT_CREATEWND needs the real window style */
2042
2043 // Based on the assumption this is from "unicode source" user32, ReactOS, answer is yes.
2044 if (!IS_ATOM(ClassName->Buffer))
2045 {
2046 if (Window->state & WNDS_ANSICREATOR)
2047 {
2048 ANSI_STRING AnsiString;
2049 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(ClassName)+sizeof(CHAR);
2050 pszClass = UserHeapAlloc(AnsiString.MaximumLength);
2051 if (!pszClass)
2052 {
2053 ERR("UserHeapAlloc() failed!\n");
2054 goto cleanup;
2055 }
2056 RtlZeroMemory(pszClass, AnsiString.MaximumLength);
2057 AnsiString.Buffer = (PCHAR)pszClass;
2058 RtlUnicodeStringToAnsiString(&AnsiString, ClassName, FALSE);
2059 }
2060 else
2061 {
2062 UNICODE_STRING UnicodeString;
2063 UnicodeString.MaximumLength = ClassName->Length + sizeof(UNICODE_NULL);
2064 pszClass = UserHeapAlloc(UnicodeString.MaximumLength);
2065 if (!pszClass)
2066 {
2067 ERR("UserHeapAlloc() failed!\n");
2068 goto cleanup;
2069 }
2070 RtlZeroMemory(pszClass, UnicodeString.MaximumLength);
2071 UnicodeString.Buffer = (PWSTR)pszClass;
2072 RtlCopyUnicodeString(&UnicodeString, ClassName);
2073 }
2074 pCsw->lpszClass = UserHeapAddressToUser(pszClass);
2075 }
2076 if (WindowName->Length)
2077 {
2078 UNICODE_STRING Name;
2079 Name.Buffer = WindowName->Buffer;
2080 Name.Length = (USHORT)min(WindowName->Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2081 Name.MaximumLength = (USHORT)min(WindowName->MaximumLength, MAXUSHORT);
2082
2083 if (Window->state & WNDS_ANSICREATOR)
2084 {
2085 ANSI_STRING AnsiString;
2086 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(&Name) + sizeof(CHAR);
2087 pszName = UserHeapAlloc(AnsiString.MaximumLength);
2088 if (!pszName)
2089 {
2090 ERR("UserHeapAlloc() failed!\n");
2091 goto cleanup;
2092 }
2093 RtlZeroMemory(pszName, AnsiString.MaximumLength);
2094 AnsiString.Buffer = (PCHAR)pszName;
2095 RtlUnicodeStringToAnsiString(&AnsiString, &Name, FALSE);
2096 }
2097 else
2098 {
2099 UNICODE_STRING UnicodeString;
2100 UnicodeString.MaximumLength = Name.Length + sizeof(UNICODE_NULL);
2101 pszName = UserHeapAlloc(UnicodeString.MaximumLength);
2102 if (!pszName)
2103 {
2104 ERR("UserHeapAlloc() failed!\n");
2105 goto cleanup;
2106 }
2107 RtlZeroMemory(pszName, UnicodeString.MaximumLength);
2108 UnicodeString.Buffer = (PWSTR)pszName;
2109 RtlCopyUnicodeString(&UnicodeString, &Name);
2110 }
2111 pCsw->lpszName = UserHeapAddressToUser(pszName);
2112 }
2113
2114 pCbtCreate->lpcs = pCsw;
2115 pCbtCreate->hwndInsertAfter = hwndInsertAfter;
2116
2117 //// Call the WH_CBT hook ////
2118 Result = co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) pCbtCreate);
2119 if (Result != 0)
2120 {
2121 ERR("WH_CBT HCBT_CREATEWND hook failed! 0x%x\n", Result);
2122 goto cleanup;
2123 }
2124 // Write back changes.
2125 Cs->cx = pCsw->cx;
2126 Cs->cy = pCsw->cy;
2127 Cs->x = pCsw->x;
2128 Cs->y = pCsw->y;
2129 hwndInsertAfter = pCbtCreate->hwndInsertAfter;
2130 }
2131
2132 /* NCCREATE and WM_NCCALCSIZE need the original values */
2133 Cs->lpszName = (LPCWSTR) WindowName;
2134 Cs->lpszClass = (LPCWSTR) ClassName;
2135
2136 if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2137 {
2138 if (ParentWindow != co_GetDesktopWindow(Window))
2139 {
2140 Cs->x += ParentWindow->rcClient.left;
2141 Cs->y += ParentWindow->rcClient.top;
2142 }
2143 }
2144
2145 /* Send the WM_GETMINMAXINFO message */
2146 Size.cx = Cs->cx;
2147 Size.cy = Cs->cy;
2148
2149 if ((Cs->style & WS_THICKFRAME) || !(Cs->style & (WS_POPUP | WS_CHILD)))
2150 {
2151 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
2152 if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
2153 if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
2154 if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
2155 if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
2156 }
2157
2158 Window->rcWindow.left = Cs->x;
2159 Window->rcWindow.top = Cs->y;
2160 Window->rcWindow.right = Cs->x + Size.cx;
2161 Window->rcWindow.bottom = Cs->y + Size.cy;
2162 /*
2163 if (0 != (Window->style & WS_CHILD) && ParentWindow)
2164 {
2165 ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
2166 RECTL_vOffsetRect(&Window->rcWindow,
2167 ParentWindow->rcClient.left,
2168 ParentWindow->rcClient.top);
2169 }
2170 */
2171 /* correct child window coordinates if mirroring on parent is enabled */
2172 if (ParentWindow != NULL)
2173 {
2174 if ( ((Cs->style & WS_CHILD) == WS_CHILD) &&
2175 ((ParentWindow->ExStyle & WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL))
2176 {
2177 Window->rcWindow.right = ParentWindow->rcClient.right - (Window->rcWindow.left - ParentWindow->rcClient.left);
2178 Window->rcWindow.left = Window->rcWindow.right - Size.cx;
2179 }
2180 }
2181
2182 Window->rcClient = Window->rcWindow;
2183
2184 /* Link the window */
2185 if (NULL != ParentWindow)
2186 {
2187 /* Link the window into the siblings list */
2188 if ((Cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2189 IntLinkHwnd(Window, HWND_BOTTOM);
2190 else
2191 IntLinkHwnd(Window, hwndInsertAfter);
2192 }
2193
2194 if (!(Window->state2 & WNDS2_WIN31COMPAT))
2195 {
2196 if (Class->style & CS_PARENTDC && !(ParentWindow->style & WS_CLIPCHILDREN))
2197 Window->style &= ~(WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
2198 }
2199
2200 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2201 {
2202 if ( !IntIsTopLevelWindow(Window) )
2203 {
2204 if (pti != Window->spwndParent->head.pti)
2205 {
2206 //ERR("CreateWindow Parent in.\n");
2207 UserAttachThreadInput(pti, Window->spwndParent->head.pti, TRUE);
2208 }
2209 }
2210 }
2211
2212 /* Send the NCCREATE message */
2213 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_NCCREATE, 0, (LPARAM) Cs);
2214 if (!Result)
2215 {
2216 ERR("co_UserCreateWindowEx(): NCCREATE message failed\n");
2217 goto cleanup;
2218 }
2219
2220 /* Send the WM_NCCALCSIZE message */
2221 {
2222 // RECT rc;
2223 MaxPos.x = Window->rcWindow.left;
2224 MaxPos.y = Window->rcWindow.top;
2225
2226 Result = co_WinPosGetNonClientSize(Window, &Window->rcWindow, &Window->rcClient);
2227 //rc = Window->rcWindow;
2228 //Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM)&rc);
2229 //Window->rcClient = rc;
2230
2231 RECTL_vOffsetRect(&Window->rcWindow, MaxPos.x - Window->rcWindow.left,
2232 MaxPos.y - Window->rcWindow.top);
2233 }
2234
2235 /* Send the WM_CREATE message. */
2236 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_CREATE, 0, (LPARAM) Cs);
2237 if (Result == (LRESULT)-1)
2238 {
2239 ERR("co_UserCreateWindowEx(): WM_CREATE message failed\n");
2240 goto cleanup;
2241 }
2242
2243 /* Send the EVENT_OBJECT_CREATE event */
2244 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2245
2246 /* By setting the flag below it can be examined to determine if the window
2247 was created successfully and a valid pwnd was passed back to caller since
2248 from here the function has to succeed. */
2249 Window->state2 |= WNDS2_WMCREATEMSGPROCESSED;
2250
2251 /* Send the WM_SIZE and WM_MOVE messages. */
2252 if (!(Window->state & WNDS_SENDSIZEMOVEMSGS))
2253 {
2254 co_WinPosSendSizeMove(Window);
2255 }
2256
2257 /* Show or maybe minimize or maximize the window. */
2258
2259 style = IntSetStyle( Window, 0, WS_MAXIMIZE | WS_MINIMIZE );
2260 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2261 {
2262 RECTL NewPos;
2263 UINT SwFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
2264
2265 SwFlag = co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2266 SwFlag |= SWP_NOZORDER|SWP_FRAMECHANGED; /* Frame always gets changed */
2267 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || UserGetActiveWindow()) SwFlag |= SWP_NOACTIVATE;
2268 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2269 NewPos.right, NewPos.bottom, SwFlag);
2270 }
2271
2272 /* Send the WM_PARENTNOTIFY message */
2273 IntSendParentNotify(Window, WM_CREATE);
2274
2275 /* Notify the shell that a new window was created */
2276 if ((!hWndParent) && (!hWndOwner))
2277 {
2278 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0);
2279 }
2280
2281 /* Initialize and show the window's scrollbars */
2282 if (Window->style & WS_VSCROLL)
2283 {
2284 co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE);
2285 }
2286 if (Window->style & WS_HSCROLL)
2287 {
2288 co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE);
2289 }
2290
2291 /* Show the new window */
2292 if (Cs->style & WS_VISIBLE)
2293 {
2294 if (Window->style & WS_MAXIMIZE)
2295 dwShowMode = SW_SHOW;
2296 else if (Window->style & WS_MINIMIZE)
2297 dwShowMode = SW_SHOWMINIMIZED;
2298
2299 co_WinPosShowWindow(Window, dwShowMode);
2300
2301 if (Window->ExStyle & WS_EX_MDICHILD)
2302 {
2303 ASSERT(ParentWindow);
2304 if(!ParentWindow)
2305 goto cleanup;
2306 co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0);
2307 /* ShowWindow won't activate child windows */
2308 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2309 }
2310 }
2311
2312 TRACE("co_UserCreateWindowEx(): Created window %p\n", hWnd);
2313 ret = Window;
2314
2315 cleanup:
2316 if (!ret)
2317 {
2318 TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2319 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2320 if (Window)
2321 co_UserDestroyWindow(Window);
2322 else if (Class)
2323 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2324 }
2325
2326 if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
2327 if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
2328 if (pszName) UserHeapFree(pszName);
2329 if (pszClass) UserHeapFree(pszClass);
2330
2331 if (Window)
2332 {
2333 UserDerefObjectCo(Window);
2334 }
2335 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2336
2337 return ret;
2338 }
2339
2340 NTSTATUS
2341 NTAPI
2342 ProbeAndCaptureLargeString(
2343 OUT PLARGE_STRING plstrSafe,
2344 IN PLARGE_STRING plstrUnsafe)
2345 {
2346 LARGE_STRING lstrTemp;
2347 PVOID pvBuffer = NULL;
2348
2349 _SEH2_TRY
2350 {
2351 /* Probe and copy the string */
2352 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2353 lstrTemp = *plstrUnsafe;
2354 }
2355 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2356 {
2357 /* Fail */
2358 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2359 }
2360 _SEH2_END
2361
2362 if (lstrTemp.Length != 0)
2363 {
2364 /* Allocate a buffer from paged pool */
2365 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2366 if (!pvBuffer)
2367 {
2368 return STATUS_NO_MEMORY;
2369 }
2370
2371 _SEH2_TRY
2372 {
2373 /* Probe and copy the buffer */
2374 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2375 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2376 }
2377 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2378 {
2379 /* Cleanup and fail */
2380 ExFreePoolWithTag(pvBuffer, TAG_STRING);
2381 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2382 }
2383 _SEH2_END
2384 }
2385
2386 /* Set the output string */
2387 plstrSafe->Buffer = pvBuffer;
2388 plstrSafe->Length = lstrTemp.Length;
2389 plstrSafe->MaximumLength = lstrTemp.Length;
2390
2391 return STATUS_SUCCESS;
2392 }
2393
2394 /**
2395 * \todo Allow passing plstrClassName as ANSI.
2396 */
2397 HWND
2398 NTAPI
2399 NtUserCreateWindowEx(
2400 DWORD dwExStyle,
2401 PLARGE_STRING plstrClassName,
2402 PLARGE_STRING plstrClsVersion,
2403 PLARGE_STRING plstrWindowName,
2404 DWORD dwStyle,
2405 int x,
2406 int y,
2407 int nWidth,
2408 int nHeight,
2409 HWND hWndParent,
2410 HMENU hMenu,
2411 HINSTANCE hInstance,
2412 LPVOID lpParam,
2413 DWORD dwFlags,
2414 PVOID acbiBuffer)
2415 {
2416 NTSTATUS Status;
2417 LARGE_STRING lstrWindowName;
2418 LARGE_STRING lstrClassName;
2419 UNICODE_STRING ustrClassName;
2420 CREATESTRUCTW Cs;
2421 HWND hwnd = NULL;
2422 PWND pwnd;
2423
2424 lstrWindowName.Buffer = NULL;
2425 lstrClassName.Buffer = NULL;
2426
2427 ASSERT(plstrWindowName);
2428
2429 if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2430 {
2431 /* check hMenu is valid handle */
2432 if (hMenu && !UserGetMenuObject(hMenu))
2433 {
2434 ERR("NtUserCreateWindowEx: Got an invalid menu handle!\n");
2435 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
2436 return NULL;
2437 }
2438 }
2439
2440 /* Copy the window name to kernel mode */
2441 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2442 if (!NT_SUCCESS(Status))
2443 {
2444 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2445 SetLastNtError(Status);
2446 return NULL;
2447 }
2448
2449 plstrWindowName = &lstrWindowName;
2450
2451 /* Check if the class is an atom */
2452 if (IS_ATOM(plstrClassName))
2453 {
2454 /* It is, pass the atom in the UNICODE_STRING */
2455 ustrClassName.Buffer = (PVOID)plstrClassName;
2456 ustrClassName.Length = 0;
2457 ustrClassName.MaximumLength = 0;
2458 }
2459 else
2460 {
2461 /* It's not, capture the class name */
2462 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2463 if (!NT_SUCCESS(Status))
2464 {
2465 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2466 /* Set last error, cleanup and return */
2467 SetLastNtError(Status);
2468 goto cleanup;
2469 }
2470
2471 /* We pass it on as a UNICODE_STRING */
2472 ustrClassName.Buffer = lstrClassName.Buffer;
2473 ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2474 ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
2475 }
2476
2477 /* Fill the CREATESTRUCTW */
2478 /* we will keep here the original parameters */
2479 Cs.style = dwStyle;
2480 Cs.lpCreateParams = lpParam;
2481 Cs.hInstance = hInstance;
2482 Cs.hMenu = hMenu;
2483 Cs.hwndParent = hWndParent;
2484 Cs.cx = nWidth;
2485 Cs.cy = nHeight;
2486 Cs.x = x;
2487 Cs.y = y;
2488 Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
2489 if (IS_ATOM(plstrClassName))
2490 Cs.lpszClass = (LPCWSTR) plstrClassName;
2491 else
2492 Cs.lpszClass = (LPCWSTR) plstrClassName->Buffer;
2493 Cs.dwExStyle = dwExStyle;
2494
2495 UserEnterExclusive();
2496
2497 /* Call the internal function */
2498 pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName, acbiBuffer);
2499
2500 if(!pwnd)
2501 {
2502 ERR("co_UserCreateWindowEx failed!\n");
2503 }
2504 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2505
2506 UserLeave();
2507
2508 cleanup:
2509 if (lstrWindowName.Buffer)
2510 {
2511 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2512 }
2513 if (lstrClassName.Buffer)
2514 {
2515 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2516 }
2517
2518 return hwnd;
2519 }
2520
2521
2522 BOOLEAN co_UserDestroyWindow(PVOID Object)
2523 {
2524 HWND hWnd;
2525 PWND pwndTemp;
2526 PTHREADINFO ti;
2527 MSG msg;
2528 PWND Window = Object;
2529
2530 ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
2531
2532 hWnd = Window->head.h;
2533 ti = PsGetCurrentThreadWin32Thread();
2534
2535 TRACE("co_UserDestroyWindow \n");
2536
2537 /* Check for owner thread */
2538 if ( Window->head.pti != PsGetCurrentThreadWin32Thread())
2539 {
2540 /* Check if we are destroying the desktop window */
2541 if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
2542 {
2543 EngSetLastError(ERROR_ACCESS_DENIED);
2544 return FALSE;
2545 }
2546 }
2547
2548 /* If window was created successfully and it is hooked */
2549 if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
2550 {
2551 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0))
2552 {
2553 ERR("Destroy Window WH_CBT Call Hook return!\n");
2554 return FALSE;
2555 }
2556 }
2557
2558 if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
2559 {
2560 if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2561 {
2562 if (Window->spwndOwner)
2563 {
2564 //ERR("DestroyWindow Owner out.\n");
2565 UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2566 }
2567 }
2568 }
2569
2570 /* Inform the parent */
2571 if (Window->style & WS_CHILD)
2572 {
2573 IntSendParentNotify(Window, WM_DESTROY);
2574 }
2575
2576 /* Look whether the focus is within the tree of windows we will
2577 * be destroying.
2578 */
2579 if (!co_WinPosShowWindow(Window, SW_HIDE))
2580 { // Rule #1.
2581 if (ti->MessageQueue->spwndActive == Window && ti->MessageQueue == IntGetFocusMessageQueue())
2582 {
2583 co_WinPosActivateOtherWindow(Window);
2584 }
2585 }
2586
2587 // Adjust last active.
2588 if ((pwndTemp = Window->spwndOwner))
2589 {
2590 while (pwndTemp->spwndOwner)
2591 pwndTemp = pwndTemp->spwndOwner;
2592
2593 if (pwndTemp->spwndLastActive == Window)
2594 pwndTemp->spwndLastActive = Window->spwndOwner;
2595 }
2596
2597 if (Window->spwndParent && IntIsWindow(Window->head.h))
2598 {
2599 if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
2600 {
2601 if (!IntIsTopLevelWindow(Window))
2602 {
2603 //ERR("DestroyWindow Parent out.\n");
2604 UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2605 }
2606 }
2607 }
2608
2609 if (Window->head.pti->MessageQueue->spwndActive == Window)
2610 Window->head.pti->MessageQueue->spwndActive = NULL;
2611 if (Window->head.pti->MessageQueue->spwndFocus == Window)
2612 Window->head.pti->MessageQueue->spwndFocus = NULL;
2613 if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
2614 Window->head.pti->MessageQueue->spwndActivePrev = NULL;
2615 if (Window->head.pti->MessageQueue->spwndCapture == Window)
2616 Window->head.pti->MessageQueue->spwndCapture = NULL;
2617
2618 /*
2619 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2620 */
2621
2622 if ((ti != NULL) && (ti->pDeskInfo != NULL))
2623 {
2624 if (ti->pDeskInfo->hShellWindow == hWnd)
2625 {
2626 ERR("Destroying the ShellWindow!\n");
2627 ti->pDeskInfo->hShellWindow = NULL;
2628 }
2629 }
2630
2631 IntEngWindowChanged(Window, WOC_DELETE);
2632
2633 if (!IntIsWindow(Window->head.h))
2634 {
2635 return TRUE;
2636 }
2637
2638 /* Recursively destroy owned windows */
2639
2640 if (! (Window->style & WS_CHILD))
2641 {
2642 for (;;)
2643 {
2644 BOOL GotOne = FALSE;
2645 HWND *Children;
2646 HWND *ChildHandle;
2647 PWND Child, Desktop;
2648
2649 Desktop = IntIsDesktopWindow(Window) ? Window :
2650 UserGetWindowObject(IntGetDesktopWindow());
2651 Children = IntWinListChildren(Desktop);
2652
2653 if (Children)
2654 {
2655 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2656 {
2657 Child = UserGetWindowObject(*ChildHandle);
2658 if (Child == NULL)
2659 continue;
2660 if (Child->spwndOwner != Window)
2661 {
2662 continue;
2663 }
2664
2665 if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
2666 {
2667 USER_REFERENCE_ENTRY ChildRef;
2668 UserRefObjectCo(Child, &ChildRef); // Temp HACK?
2669 co_UserDestroyWindow(Child);
2670 UserDerefObjectCo(Child); // Temp HACK?
2671
2672 GotOne = TRUE;
2673 continue;
2674 }
2675
2676 if (Child->spwndOwner != NULL)
2677 {
2678 Child->spwndOwner = NULL;
2679 }
2680
2681 }
2682 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
2683 }
2684 if (! GotOne)
2685 {
2686 break;
2687 }
2688 }
2689 }
2690
2691 /* Generate mouse move message for the next window */
2692 msg.message = WM_MOUSEMOVE;
2693 msg.wParam = UserGetMouseButtonsState();
2694 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2695 msg.pt = gpsi->ptCursor;
2696 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2697
2698 if (!IntIsWindow(Window->head.h))
2699 {
2700 return TRUE;
2701 }
2702
2703 /* Destroy the window storage */
2704 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2705
2706 return TRUE;
2707 }
2708
2709
2710 /*
2711 * @implemented
2712 */
2713 BOOLEAN APIENTRY
2714 NtUserDestroyWindow(HWND Wnd)
2715 {
2716 PWND Window;
2717 DECLARE_RETURN(BOOLEAN);
2718 BOOLEAN ret;
2719 USER_REFERENCE_ENTRY Ref;
2720
2721 TRACE("Enter NtUserDestroyWindow\n");
2722 UserEnterExclusive();
2723
2724 if (!(Window = UserGetWindowObject(Wnd)))
2725 {
2726 RETURN(FALSE);
2727 }
2728
2729 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
2730 ret = co_UserDestroyWindow(Window);
2731 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
2732
2733 RETURN(ret);
2734
2735 CLEANUP:
2736 TRACE("Leave NtUserDestroyWindow, ret=%u\n", _ret_);
2737 UserLeave();
2738 END_CLEANUP;
2739 }
2740
2741
2742 static HWND FASTCALL
2743 IntFindWindow(PWND Parent,
2744 PWND ChildAfter,
2745 RTL_ATOM ClassAtom,
2746 PUNICODE_STRING WindowName)
2747 {
2748 BOOL CheckWindowName;
2749 HWND *List, *phWnd;
2750 HWND Ret = NULL;
2751 UNICODE_STRING CurrentWindowName;
2752
2753 ASSERT(Parent);
2754
2755 CheckWindowName = WindowName->Buffer != 0;
2756
2757 if((List = IntWinListChildren(Parent)))
2758 {
2759 phWnd = List;
2760 if(ChildAfter)
2761 {
2762 /* skip handles before and including ChildAfter */
2763 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2764 ;
2765 }
2766
2767 /* search children */
2768 while(*phWnd)
2769 {
2770 PWND Child;
2771 if(!(Child = UserGetWindowObject(*(phWnd++))))
2772 {
2773 continue;
2774 }
2775
2776 /* Do not send WM_GETTEXT messages in the kernel mode version!
2777 The user mode version however calls GetWindowText() which will
2778 send WM_GETTEXT messages to windows belonging to its processes */
2779 if (!ClassAtom || Child->pcls->atomClassName == ClassAtom)
2780 {
2781 // FIXME: LARGE_STRING truncated
2782 CurrentWindowName.Buffer = Child->strName.Buffer;
2783 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
2784 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
2785 if(!CheckWindowName ||
2786 (Child->strName.Length < 0xFFFF &&
2787 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
2788 {
2789 Ret = Child->head.h;
2790 break;
2791 }
2792 }
2793 }
2794 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2795 }
2796
2797 return Ret;
2798 }
2799
2800 /*
2801 * FUNCTION:
2802 * Searches a window's children for a window with the specified
2803 * class and name
2804 * ARGUMENTS:
2805 * hwndParent = The window whose childs are to be searched.
2806 * NULL = desktop
2807 * HWND_MESSAGE = message-only windows
2808 *
2809 * hwndChildAfter = Search starts after this child window.
2810 * NULL = start from beginning
2811 *
2812 * ucClassName = Class name to search for
2813 * Reguired parameter.
2814 *
2815 * ucWindowName = Window name
2816 * ->Buffer == NULL = don't care
2817 *
2818 * RETURNS:
2819 * The HWND of the window if it was found, otherwise NULL
2820 */
2821 /*
2822 * @implemented
2823 */
2824 HWND APIENTRY
2825 NtUserFindWindowEx(HWND hwndParent,
2826 HWND hwndChildAfter,
2827 PUNICODE_STRING ucClassName,
2828 PUNICODE_STRING ucWindowName,
2829 DWORD dwUnknown)
2830 {
2831 PWND Parent, ChildAfter;
2832 UNICODE_STRING ClassName = {0}, WindowName = {0};
2833 HWND Desktop, Ret = NULL;
2834 BOOL DoMessageWnd = FALSE;
2835 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2836 DECLARE_RETURN(HWND);
2837
2838 TRACE("Enter NtUserFindWindowEx\n");
2839 UserEnterShared();
2840
2841 if (ucClassName != NULL || ucWindowName != NULL)
2842 {
2843 _SEH2_TRY
2844 {
2845 if (ucClassName != NULL)
2846 {
2847 ClassName = ProbeForReadUnicodeString(ucClassName);
2848 if (ClassName.Length != 0)
2849 {
2850 ProbeForRead(ClassName.Buffer,
2851 ClassName.Length,
2852 sizeof(WCHAR));
2853 }
2854 else if (!IS_ATOM(ClassName.Buffer))
2855 {
2856 EngSetLastError(ERROR_INVALID_PARAMETER);
2857 _SEH2_LEAVE;
2858 }
2859
2860 if (!IntGetAtomFromStringOrAtom(&ClassName,
2861 &ClassAtom))
2862 {
2863 _SEH2_LEAVE;
2864 }
2865 }
2866
2867 if (ucWindowName != NULL)
2868 {
2869 WindowName = ProbeForReadUnicodeString(ucWindowName);
2870 if (WindowName.Length != 0)
2871 {
2872 ProbeForRead(WindowName.Buffer,
2873 WindowName.Length,
2874 sizeof(WCHAR));
2875 }
2876 }
2877 }
2878 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2879 {
2880 SetLastNtError(_SEH2_GetExceptionCode());
2881 _SEH2_YIELD(RETURN(NULL));
2882 }
2883 _SEH2_END;
2884
2885 if (ucClassName != NULL)
2886 {
2887 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
2888 !IS_ATOM(ClassName.Buffer))
2889 {
2890 EngSetLastError(ERROR_INVALID_PARAMETER);
2891 RETURN(NULL);
2892 }
2893 else if (ClassAtom == (RTL_ATOM)0)
2894 {
2895 /* LastError code was set by IntGetAtomFromStringOrAtom */
2896 RETURN(NULL);
2897 }
2898 }
2899 }
2900
2901 Desktop = IntGetCurrentThreadDesktopWindow();
2902
2903 if(hwndParent == NULL)
2904 {
2905 hwndParent = Desktop;
2906 DoMessageWnd = TRUE;
2907 }
2908 else if(hwndParent == HWND_MESSAGE)
2909 {
2910 hwndParent = IntGetMessageWindow();
2911 }
2912
2913 if(!(Parent = UserGetWindowObject(hwndParent)))
2914 {
2915 RETURN( NULL);
2916 }
2917
2918 ChildAfter = NULL;
2919 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
2920 {
2921 RETURN( NULL);
2922 }
2923
2924 _SEH2_TRY
2925 {
2926 if(Parent->head.h == Desktop)
2927 {
2928 HWND *List, *phWnd;
2929 PWND TopLevelWindow;
2930 BOOLEAN CheckWindowName;
2931 BOOLEAN WindowMatches;
2932 BOOLEAN ClassMatches;
2933
2934 /* windows searches through all top-level windows if the parent is the desktop
2935 window */
2936
2937 if((List = IntWinListChildren(Parent)))
2938 {
2939 phWnd = List;
2940
2941 if(ChildAfter)
2942 {
2943 /* skip handles before and including ChildAfter */
2944 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2945 ;
2946 }
2947
2948 CheckWindowName = WindowName.Buffer != 0;
2949
2950 /* search children */
2951 while(*phWnd)
2952 {
2953 UNICODE_STRING ustr;
2954
2955 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
2956 {
2957 continue;
2958 }
2959
2960 /* Do not send WM_GETTEXT messages in the kernel mode version!
2961 The user mode version however calls GetWindowText() which will
2962 send WM_GETTEXT messages to windows belonging to its processes */
2963 ustr.Buffer = TopLevelWindow->strName.Buffer;
2964 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
2965 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
2966 WindowMatches = !CheckWindowName ||
2967 (TopLevelWindow->strName.Length < 0xFFFF &&
2968 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
2969 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
2970 ClassAtom == TopLevelWindow->pcls->atomClassName;
2971
2972 if (WindowMatches && ClassMatches)
2973 {
2974 Ret = TopLevelWindow->head.h;
2975 break;
2976 }
2977
2978 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
2979 {
2980 /* window returns the handle of the top-level window, in case it found
2981 the child window */
2982 Ret = TopLevelWindow->head.h;
2983 break;
2984 }
2985
2986 }
2987 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2988 }
2989 }
2990 else
2991 {
2992 ERR("FindWindowEx: Not Desktop Parent!\n");
2993 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
2994 }
2995
2996 if (Ret == NULL && DoMessageWnd)
2997 {
2998 PWND MsgWindows;
2999
3000 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3001 {
3002 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3003 }
3004 }
3005 }
3006 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3007 {
3008 SetLastNtError(_SEH2_GetExceptionCode());
3009 Ret = NULL;
3010 }
3011 _SEH2_END;
3012
3013 RETURN( Ret);
3014
3015 CLEANUP:
3016 TRACE("Leave NtUserFindWindowEx, ret %p\n", _ret_);
3017 UserLeave();
3018 END_CLEANUP;
3019 }
3020
3021
3022 /*
3023 * @implemented
3024 */
3025 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
3026 {
3027 PWND WndAncestor, Parent;
3028
3029 if (Wnd->head.h == IntGetDesktopWindow())
3030 {
3031 return NULL;
3032 }
3033
3034 switch (Type)
3035 {
3036 case GA_PARENT:
3037 {
3038 WndAncestor = Wnd->spwndParent;
3039 break;
3040 }
3041
3042 case GA_ROOT:
3043 {
3044 WndAncestor = Wnd;
3045 Parent = NULL;
3046
3047 for(;;)
3048 {
3049 if(!(Parent = WndAncestor->spwndParent))
3050 {
3051 break;
3052 }
3053 if(IntIsDesktopWindow(Parent))
3054 {
3055 break;
3056 }
3057
3058 WndAncestor = Parent;
3059 }
3060 break;
3061 }
3062
3063 case GA_ROOTOWNER:
3064 {
3065 WndAncestor = Wnd;
3066
3067 for (;;)
3068 {
3069 Parent = IntGetParent(WndAncestor);
3070
3071 if (!Parent)
3072 {
3073 break;
3074 }
3075
3076 WndAncestor = Parent;
3077 }
3078 break;
3079 }
3080
3081 default:
3082 {
3083 return NULL;
3084 }
3085 }
3086
3087 return WndAncestor;
3088 }
3089
3090 /*
3091 * @implemented
3092 */
3093 HWND APIENTRY
3094 NtUserGetAncestor(HWND hWnd, UINT Type)
3095 {
3096 PWND Window, Ancestor;
3097 DECLARE_RETURN(HWND);
3098
3099 TRACE("Enter NtUserGetAncestor\n");
3100 UserEnterExclusive();
3101
3102 if (!(Window = UserGetWindowObject(hWnd)))
3103 {
3104 RETURN(NULL);
3105 }
3106
3107 Ancestor = UserGetAncestor(Window, Type);
3108 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3109
3110 RETURN(Ancestor ? Ancestor->head.h : NULL);
3111
3112 CLEANUP:
3113 TRACE("Leave NtUserGetAncestor, ret=%p\n", _ret_);
3114 UserLeave();
3115 END_CLEANUP;
3116 }
3117
3118 ////
3119 //// ReactOS work around! Keep it the sames as in Combo.c and Controls.h
3120 ////
3121 /* combo state struct */
3122 typedef struct
3123 {
3124 HWND self;
3125 HWND owner;
3126 UINT dwStyle;
3127 HWND hWndEdit;
3128 HWND hWndLBox;
3129 UINT wState;
3130 HFONT hFont;
3131 RECT textRect;
3132 RECT buttonRect;
3133 RECT droppedRect;
3134 INT droppedIndex;
3135 INT fixedOwnerDrawHeight;
3136 INT droppedWidth; /* last two are not used unless set */
3137 INT editHeight; /* explicitly */
3138 LONG UIState;
3139 } HEADCOMBO,*LPHEADCOMBO;
3140
3141 // Window Extra data container.
3142 typedef struct _WND2CBOX
3143 {
3144 WND;
3145 LPHEADCOMBO pCBox;
3146 } WND2CBOX, *PWND2CBOX;
3147
3148 #define CBF_BUTTONDOWN 0x0002
3149 ////
3150 ////
3151 ////
3152 BOOL
3153 APIENTRY
3154 NtUserGetComboBoxInfo(
3155 HWND hWnd,
3156 PCOMBOBOXINFO pcbi)
3157 {
3158 PWND Wnd;
3159 PPROCESSINFO ppi;
3160 BOOL NotSameppi = FALSE;
3161 BOOL Ret = TRUE;
3162 DECLARE_RETURN(BOOL);
3163
3164 TRACE("Enter NtUserGetComboBoxInfo\n");
3165 UserEnterShared();
3166
3167 if (!(Wnd = UserGetWindowObject(hWnd)))
3168 {
3169 RETURN( FALSE );
3170 }
3171 _SEH2_TRY
3172 {
3173 if(pcbi)
3174 {
3175 ProbeForWrite(pcbi,
3176 sizeof(COMBOBOXINFO),
3177 1);
3178 }
3179 }
3180 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3181 {
3182 SetLastNtError(_SEH2_GetExceptionCode());
3183 _SEH2_YIELD(RETURN(FALSE));
3184 }
3185 _SEH2_END;
3186
3187 if (pcbi->cbSize < sizeof(COMBOBOXINFO))
3188 {
3189 EngSetLastError(ERROR_INVALID_PARAMETER);
3190 RETURN(FALSE);
3191 }
3192
3193 // Pass the user pointer, it was already probed.
3194 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_COMBOBOX]) && Wnd->fnid != FNID_COMBOBOX)
3195 {
3196 RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3197 }
3198
3199 ppi = PsGetCurrentProcessWin32Process();
3200 NotSameppi = ppi != Wnd->head.pti->ppi;
3201 if (NotSameppi)
3202 {
3203 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3204 }
3205
3206 _SEH2_TRY
3207 {
3208 LPHEADCOMBO lphc = ((PWND2CBOX)Wnd)->pCBox;
3209 pcbi->rcItem = lphc->textRect;
3210 pcbi->rcButton = lphc->buttonRect;
3211 pcbi->stateButton = 0;
3212 if (lphc->wState & CBF_BUTTONDOWN)
3213 pcbi->stateButton |= STATE_SYSTEM_PRESSED;
3214 if (RECTL_bIsEmptyRect(&lphc->buttonRect))
3215 pcbi->stateButton |= STATE_SYSTEM_INVISIBLE;
3216 pcbi->hwndCombo = lphc->self;
3217 pcbi->hwndItem = lphc->hWndEdit;
3218 pcbi->hwndList = lphc->hWndLBox;
3219 }
3220 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3221 {
3222 Ret = FALSE;
3223 SetLastNtError(_SEH2_GetExceptionCode());
3224 }
3225 _SEH2_END;
3226
3227 RETURN( Ret);
3228
3229 CLEANUP:
3230 if (NotSameppi) KeDetachProcess();
3231 TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3232 UserLeave();
3233 END_CLEANUP;
3234 }
3235
3236 ////
3237 //// ReactOS work around! Keep it the sames as in Listbox.c
3238 ////
3239 /* Listbox structure */
3240 typedef struct
3241 {
3242 HWND self; /* Our own window handle */
3243 HWND owner; /* Owner window to send notifications to */
3244 UINT style; /* Window style */
3245 INT width; /* Window width */
3246 INT height; /* Window height */
3247 VOID *items; /* Array of items */
3248 INT nb_items; /* Number of items */
3249 INT top_item; /* Top visible item */
3250 INT selected_item; /* Selected item */
3251 INT focus_item; /* Item that has the focus */
3252 INT anchor_item; /* Anchor item for extended selection */
3253 INT item_height; /* Default item height */
3254 INT page_size; /* Items per listbox page */
3255 INT column_width; /* Column width for multi-column listboxes */
3256 } LB_DESCR;
3257
3258 // Window Extra data container.
3259 typedef struct _WND2LB
3260 {
3261 WND;
3262 LB_DESCR * pLBiv;
3263 } WND2LB, *PWND2LB;
3264 ////
3265 ////
3266 ////
3267 DWORD
3268 APIENTRY
3269 NtUserGetListBoxInfo(
3270 HWND hWnd)
3271 {
3272 PWND Wnd;
3273 PPROCESSINFO ppi;
3274 BOOL NotSameppi = FALSE;
3275 DWORD Ret = 0;
3276 DECLARE_RETURN(DWORD);
3277
3278 TRACE("Enter NtUserGetListBoxInfo\n");
3279 UserEnterShared();
3280
3281 if (!(Wnd = UserGetWindowObject(hWnd)))
3282 {
3283 RETURN( 0 );
3284 }
3285
3286 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && Wnd->fnid != FNID_LISTBOX)
3287 {
3288 RETURN( (DWORD) co_IntSendMessage( Wnd->head.h, LB_GETLISTBOXINFO, 0, 0 ));
3289 }
3290
3291 // wine lisbox:test_GetListBoxInfo lb_getlistboxinfo = 0, should not send a message!
3292 ppi = PsGetCurrentProcessWin32Process();
3293 NotSameppi = ppi != Wnd->head.pti->ppi;
3294 if (NotSameppi)
3295 {
3296 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3297 }
3298
3299 _SEH2_TRY
3300 {
3301 LB_DESCR *descr = ((PWND2LB)Wnd)->pLBiv;
3302 // See Controls ListBox.c:LB_GETLISTBOXINFO must match...
3303 if (descr->style & LBS_MULTICOLUMN) //// ReactOS
3304 Ret = descr->page_size * descr->column_width;
3305 else
3306 Ret = descr->page_size;
3307 }
3308 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3309 {
3310 Ret = 0;
3311 SetLastNtError(_SEH2_GetExceptionCode());
3312 }
3313 _SEH2_END;
3314
3315 RETURN( Ret);
3316
3317 CLEANUP:
3318 if (NotSameppi) KeDetachProcess();
3319 TRACE("Leave NtUserGetListBoxInfo, ret=%lu\n", _ret_);
3320 UserLeave();
3321 END_CLEANUP;
3322 }
3323
3324 /*
3325 * NtUserSetParent
3326 *
3327 * The NtUserSetParent function changes the parent window of the specified
3328 * child window.
3329 *
3330 * Remarks
3331 * The new parent window and the child window must belong to the same
3332 * application. If the window identified by the hWndChild parameter is
3333 * visible, the system performs the appropriate redrawing and repainting.
3334 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3335 * or WS_POPUP window styles of the window whose parent is being changed.
3336 *
3337 * Status
3338 * @implemented
3339 */
3340
3341 HWND APIENTRY
3342 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3343 {
3344 DECLARE_RETURN(HWND);
3345
3346 TRACE("Enter NtUserSetParent\n");
3347 UserEnterExclusive();
3348
3349 /*
3350 Check Parent first from user space, set it here.
3351 */
3352 if (!hWndNewParent)
3353 {
3354 hWndNewParent = IntGetDesktopWindow();
3355 }
3356 else if (hWndNewParent == HWND_MESSAGE)
3357 {
3358 hWndNewParent = IntGetMessageWindow();
3359 }
3360
3361 RETURN( co_UserSetParent(hWndChild, hWndNewParent));
3362
3363 CLEANUP:
3364 TRACE("Leave NtUserSetParent, ret=%p\n", _ret_);
3365 UserLeave();
3366 END_CLEANUP;
3367 }
3368
3369 /*
3370 * UserGetShellWindow
3371 *
3372 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3373 *
3374 * Status
3375 * @implemented
3376 */
3377 HWND FASTCALL UserGetShellWindow(VOID)
3378 {
3379 PWINSTATION_OBJECT WinStaObject;
3380 HWND Ret;
3381
3382 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3383 KernelMode,
3384 0,
3385 &WinStaObject);
3386
3387 if (!NT_SUCCESS(Status))
3388 {
3389 SetLastNtError(Status);
3390 return( (HWND)0);
3391 }
3392
3393 Ret = (HWND)WinStaObject->ShellWindow;
3394
3395 ObDereferenceObject(WinStaObject);
3396 return( Ret);
3397 }
3398
3399 /*
3400 * NtUserSetShellWindowEx
3401 *
3402 * This is undocumented function to set global shell window. The global
3403 * shell window has special handling of window position.
3404 *
3405 * Status
3406 * @implemented
3407 */
3408 BOOL APIENTRY
3409 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3410 {
3411 PWINSTATION_OBJECT WinStaObject;
3412 PWND WndShell, WndListView;
3413 DECLARE_RETURN(BOOL);
3414 USER_REFERENCE_ENTRY Ref;
3415 NTSTATUS Status;
3416 PTHREADINFO ti;
3417
3418 TRACE("Enter NtUserSetShellWindowEx\n");
3419 UserEnterExclusive();
3420
3421 if (!(WndShell = UserGetWindowObject(hwndShell)))
3422 {
3423 RETURN(FALSE);
3424 }
3425
3426 if(!(WndListView = UserGetWindowObject(hwndListView)))
3427 {
3428 RETURN(FALSE);
3429 }
3430
3431 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3432 KernelMode,
3433 0,
3434 &WinStaObject);
3435
3436 if (!NT_SUCCESS(Status))
3437 {
3438 SetLastNtError(Status);
3439 RETURN( FALSE);
3440 }
3441
3442 /*
3443 * Test if we are permitted to change the shell window.
3444 */
3445 if (WinStaObject->ShellWindow)
3446 {
3447 ObDereferenceObject(WinStaObject);
3448 RETURN( FALSE);
3449 }
3450
3451 /*
3452 * Move shell window into background.
3453 */
3454 if (hwndListView && hwndListView != hwndShell)
3455 {
3456 /*
3457 * Disabled for now to get Explorer working.
3458 * -- Filip, 01/nov/2003
3459 */
3460 #if 0
3461 co_WinPosSetWindowPos(WndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3462 #endif
3463
3464 if (WndListView->ExStyle & WS_EX_TOPMOST)
3465 {
3466 ObDereferenceObject(WinStaObject);
3467 RETURN( FALSE);
3468 }
3469 }
3470
3471 if (WndShell->ExStyle & WS_EX_TOPMOST)
3472 {
3473 ObDereferenceObject(WinStaObject);
3474 RETURN( FALSE);
3475 }
3476
3477 UserRefObjectCo(WndShell, &Ref);
3478 WndShell->state2 |= WNDS2_BOTTOMMOST;
3479 co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3480
3481 WinStaObject->ShellWindow = hwndShell;
3482 WinStaObject->ShellListView = hwndListView;
3483
3484 ti = GetW32ThreadInfo();
3485 if (ti->pDeskInfo)
3486 {
3487 ti->pDeskInfo->hShellWindow = hwndShell;
3488 ti->pDeskInfo->spwndShell = WndShell;
3489 ti->pDeskInfo->ppiShellProcess = ti->ppi;
3490 }
3491
3492 UserRegisterHotKey(WndShell, SC_TASKLIST, MOD_CONTROL, VK_ESCAPE);
3493
3494 UserDerefObjectCo(WndShell);
3495
3496 ObDereferenceObject(WinStaObject);
3497 RETURN( TRUE);
3498
3499 CLEANUP:
3500 TRACE("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_);
3501 UserLeave();
3502 END_CLEANUP;
3503 }
3504
3505 // Fixes wine Win test_window_styles and todo tests...
3506 static BOOL FASTCALL
3507 IntCheckFrameEdge(ULONG Style, ULONG ExStyle)
3508 {
3509 if (ExStyle & WS_EX_DLGMODALFRAME)
3510 return TRUE;
3511 else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME)))
3512 return TRUE;
3513 else
3514 return FALSE;
3515 }
3516
3517 LONG FASTCALL
3518 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3519 {
3520 PWND Window, Parent;
3521 PWINSTATION_OBJECT WindowStation;
3522 LONG OldValue;
3523 STYLESTRUCT Style;
3524
3525 if (!(Window = UserGetWindowObject(hWnd)))
3526 {
3527 return( 0);
3528 }
3529
3530 if ((INT)Index >= 0)
3531 {
3532 if ((Index + sizeof(LONG)) > Window->cbwndExtra)
3533 {
3534 EngSetLastError(ERROR_INVALID_INDEX);
3535 return( 0);
3536 }
3537
3538 OldValue = *((LONG *)((PCHAR)(Window + 1) + Index));
3539 /*
3540 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3541 {
3542 OldValue = (LONG)IntSetWindowProc( Wnd,
3543 (WNDPROC)NewValue,
3544 Ansi);
3545 if (!OldValue) return 0;
3546 }
3547 */
3548 *((LONG *)((PCHAR)(Window + 1) + Index)) = NewValue;
3549 }
3550 else
3551 {
3552 switch (Index)
3553 {
3554 case GWL_EXSTYLE:
3555 OldValue = (LONG) Window->ExStyle;
3556 Style.styleOld = OldValue;
3557 Style.styleNew = NewValue;
3558
3559 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3560
3561 /*
3562 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3563 */
3564 WindowStation = Window->head.pti->rpdesk->rpwinstaParent;
3565 if(WindowStation)
3566 {
3567 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3568 Style.styleNew &= ~WS_EX_TOPMOST;
3569 }
3570 /* WS_EX_WINDOWEDGE depends on some other styles */
3571 if (IntCheckFrameEdge(Window->style, NewValue))
3572 Style.styleNew |= WS_EX_WINDOWEDGE;
3573 else
3574 Style.styleNew &= ~WS_EX_WINDOWEDGE;
3575
3576 Window->ExStyle = (DWORD)Style.styleNew;
3577 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3578 break;
3579
3580 case GWL_STYLE:
3581 OldValue = (LONG) Window->style;
3582 Style.styleOld = OldValue;
3583 Style.styleNew = NewValue;
3584 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3585
3586 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
3587 if (Window->spwndParent == UserGetDesktopWindow()) Style.styleNew |= WS_CLIPSIBLINGS;
3588 /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */
3589 if (IntCheckFrameEdge(NewValue, Window->ExStyle))
3590 Window->ExStyle |= WS_EX_WINDOWEDGE;
3591 else
3592 Window->ExStyle &= ~WS_EX_WINDOWEDGE;
3593
3594 if ((Style.styleOld ^ Style.styleNew) & WS_VISIBLE)
3595 {
3596 if (Style.styleOld & WS_VISIBLE) Window->head.pti->cVisWindows--;
3597 if (Style.styleNew & WS_VISIBLE) Window->head.pti->cVisWindows++;
3598 DceResetActiveDCEs( Window );
3599 }
3600 Window->style = (DWORD)Style.styleNew;
3601 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3602 break;
3603
3604 case GWL_WNDPROC:
3605 {
3606 if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
3607 Window->fnid & FNID_FREED)
3608 {
3609 EngSetLastError(ERROR_ACCESS_DENIED);
3610 return( 0);
3611 }
3612 OldValue = (LONG)IntSetWindowProc(Window,
3613 (WNDPROC)NewValue,
3614 Ansi);
3615 break;
3616 }
3617
3618 case GWL_HINSTANCE:
3619 OldValue = (LONG) Window->hModule;
3620 Window->hModule = (HINSTANCE) NewValue;
3621 break;
3622
3623 case GWL_HWNDPARENT:
3624 Parent = Window->spwndParent;
3625 if (Parent && (Parent->head.h == IntGetDesktopWindow()))
3626 OldValue = (LONG) IntSetOwner(Window->head.h, (HWND) NewValue);
3627 else
3628 OldValue = (LONG) co_UserSetParent(Window->head.h, (HWND) NewValue);
3629 break;
3630
3631 case GWL_ID:
3632 OldValue = (LONG) Window->IDMenu;
3633 Window->IDMenu = (UINT) NewValue;
3634 break;
3635
3636 case GWL_USERDATA:
3637 OldValue = Window->dwUserData;
3638 Window->dwUserData = NewValue;
3639 break;
3640
3641 default:
3642 ERR("NtUserSetWindowLong(): Unsupported index %lu\n", Index);
3643 EngSetLastError(ERROR_INVALID_INDEX);
3644 OldValue = 0;
3645 break;
3646 }
3647 }
3648
3649 return( OldValue);
3650 }
3651
3652 /*
3653 * NtUserSetWindowLong
3654 *
3655 * The NtUserSetWindowLong function changes an attribute of the specified
3656 * window. The function also sets the 32-bit (long) value at the specified
3657 * offset into the extra window memory.
3658 *
3659 * Status
3660 * @implemented
3661 */
3662
3663 LONG APIENTRY
3664 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
3665 {
3666 DECLARE_RETURN(LONG);
3667
3668 TRACE("Enter NtUserSetWindowLong\n");
3669 UserEnterExclusive();
3670
3671 if (hWnd == IntGetDesktopWindow())
3672 {
3673 EngSetLastError(STATUS_ACCESS_DENIED);
3674 RETURN( 0);
3675 }
3676
3677 RETURN( co_UserSetWindowLong(hWnd, Index, NewValue, Ansi));
3678
3679 CLEANUP:
3680 TRACE("Leave NtUserSetWindowLong, ret=%i\n",_ret_);
3681 UserLeave();
3682 END_CLEANUP;
3683 }
3684
3685 /*
3686 * NtUserSetWindowWord
3687 *
3688 * Legacy function similar to NtUserSetWindowLong.
3689 *
3690 * Status
3691 * @implemented
3692 */
3693
3694 WORD APIENTRY
3695 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
3696 {
3697 PWND Window;
3698 WORD OldValue;
3699 DECLARE_RETURN(WORD);
3700
3701 TRACE("Enter NtUserSetWindowWord\n");
3702 UserEnterExclusive();
3703
3704 if (hWnd == IntGetDesktopWindow())
3705 {
3706 EngSetLastError(STATUS_ACCESS_DENIED);
3707 RETURN( 0);
3708 }
3709
3710 if (!(Window = UserGetWindowObject(hWnd)))
3711 {
3712 RETURN( 0);
3713 }
3714
3715 switch (Index)
3716 {
3717 case GWL_ID:
3718 case GWL_HINSTANCE:
3719 case GWL_HWNDPARENT:
3720 RETURN( (WORD)co_UserSetWindowLong(UserHMGetHandle(Window), Index, (UINT)NewValue, TRUE));
3721 default:
3722 if (Index < 0)
3723 {
3724 EngSetLastError(ERROR_INVALID_INDEX);
3725 RETURN( 0);
3726 }
3727 }
3728
3729 if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD)))
3730 {
3731 EngSetLastError(ERROR_INVALID_PARAMETER);
3732 RETURN( 0);
3733 }
3734
3735 OldValue = *((WORD *)((PCHAR)(Window + 1) + Index));
3736 *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue;
3737
3738 RETURN( OldValue);
3739
3740 CLEANUP:
3741 TRACE("Leave NtUserSetWindowWord, ret=%u\n", _ret_);
3742 UserLeave();
3743 END_CLEANUP;
3744 }
3745
3746 /*
3747 QueryWindow based on KJK::Hyperion and James Tabor.
3748
3749 0 = QWUniqueProcessId
3750 1 = QWUniqueThreadId
3751 2 = QWActiveWindow
3752 3 = QWFocusWindow
3753 4 = QWIsHung Implements IsHungAppWindow found
3754 by KJK::Hyperion.
3755
3756 9 = QWKillWindow When I called this with hWnd ==
3757 DesktopWindow, it shutdown the system
3758 and rebooted.
3759 */
3760 /*
3761 * @implemented
3762 */
3763 DWORD APIENTRY
3764 NtUserQueryWindow(HWND hWnd, DWORD Index)
3765 {
3766 /* Console Leader Process CID Window offsets */
3767 #define GWLP_CONSOLE_LEADER_PID 0
3768 #define GWLP_CONSOLE_LEADER_TID 4
3769
3770 PWND pWnd;
3771 DWORD Result;
3772 DECLARE_RETURN(UINT);
3773
3774 TRACE("Enter NtUserQueryWindow\n");
3775 UserEnterShared();
3776
3777 if (!(pWnd = UserGetWindowObject(hWnd)))
3778 {
3779 RETURN( 0);
3780 }
3781
3782 switch(Index)
3783 {
3784 case QUERY_WINDOW_UNIQUE_PROCESS_ID:
3785 {
3786 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
3787 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
3788 {
3789 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_PID)
3790 Result = (DWORD)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_PID)));
3791 }
3792 else
3793 {
3794 Result = (DWORD)IntGetWndProcessId(pWnd);
3795 }
3796 break;
3797 }
3798
3799 case QUERY_WINDOW_UNIQUE_THREAD_ID:
3800 {
3801 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
3802 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
3803 {
3804 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_TID)
3805 Result = (DWORD)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_TID)));
3806 }
3807 else
3808 {
3809 Result = (DWORD)IntGetWndThreadId(pWnd);
3810 }
3811 break;
3812 }
3813
3814 case QUERY_WINDOW_ACTIVE:
3815 Result = (DWORD)(pWnd->head.pti->MessageQueue->spwndActive ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndActive) : 0);
3816 break;
3817
3818 case QUERY_WINDOW_FOCUS:
3819 Result = (DWORD)(pWnd->head.pti->MessageQueue->spwndFocus ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndFocus) : 0);
3820 break;
3821
3822 case QUERY_WINDOW_ISHUNG:
3823 Result = (DWORD)MsqIsHung(pWnd->head.pti);
3824 break;
3825
3826 case QUERY_WINDOW_REAL_ID:
3827 Result = (DWORD)pWnd->head.pti->pEThread->Cid.UniqueProcess;
3828 break;
3829
3830 case QUERY_WINDOW_FOREGROUND:
3831 Result = (pWnd->head.pti->MessageQueue == gpqForeground);
3832 break;
3833
3834 default:
3835 Result = (DWORD)NULL;
3836 break;
3837 }
3838
3839 RETURN( Result);
3840
3841 CLEANUP:
3842 TRACE("Leave NtUserQueryWindow, ret=%u\n", _ret_);
3843 UserLeave();
3844 END_CLEANUP;
3845 }
3846
3847
3848 /*
3849 * @implemented
3850 */
3851 UINT APIENTRY
3852 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
3853 {
3854 UNICODE_STRING SafeMessageName;
3855 NTSTATUS Status;
3856 UINT Ret;
3857 DECLARE_RETURN(UINT);
3858
3859 TRACE("Enter NtUserRegisterWindowMessage\n");
3860 UserEnterExclusive();
3861
3862 if(MessageNameUnsafe == NULL)
3863 {
3864 EngSetLastError(ERROR_INVALID_PARAMETER);
3865 RETURN( 0);
3866 }
3867
3868 Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
3869 if(!NT_SUCCESS(Status))
3870 {
3871 SetLastNtError(Status);
3872 RETURN( 0);
3873 }
3874
3875 Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
3876 if (SafeMessageName.Buffer)
3877 ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING);
3878 RETURN( Ret);
3879
3880 CLEANUP:
3881 TRACE("Leave NtUserRegisterWindowMessage, ret=%u\n", _ret_);
3882 UserLeave();
3883 END_CLEANUP;
3884 }
3885
3886
3887 /*
3888 * @implemented
3889 */
3890 BOOL APIENTRY
3891 NtUserSetMenu(
3892 HWND hWnd,
3893 HMENU Menu,
3894 BOOL Repaint)
3895 {
3896 PWND Window;
3897 BOOL Changed;
3898 DECLARE_RETURN(BOOL);
3899
3900 TRACE("Enter NtUserSetMenu\n");
3901 UserEnterExclusive();
3902
3903 if (!(Window = UserGetWindowObject(hWnd)))
3904 {
3905 RETURN( FALSE);
3906 }
3907
3908 if (! IntSetMenu(Window, Menu, &Changed))
3909 {
3910 RETURN( FALSE);
3911 }
3912
3913 if (Changed && Repaint)
3914 {
3915 USER_REFERENCE_ENTRY Ref;
3916
3917 UserRefObjectCo(Window, &Ref);
3918 co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
3919 SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
3920
3921 UserDerefObjectCo(Window);
3922 }
3923
3924 RETURN( TRUE);
3925
3926 CLEANUP:
3927 TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_);
3928 UserLeave();
3929 END_CLEANUP;
3930 }
3931
3932 /*
3933 * @implemented
3934 */
3935 BOOL APIENTRY
3936 NtUserSetWindowFNID(HWND hWnd,
3937 WORD fnID)
3938 {
3939 PWND Wnd;
3940 DECLARE_RETURN(BOOL);
3941
3942 TRACE("Enter NtUserSetWindowFNID\n");
3943 UserEnterExclusive();
3944
3945 if (!(Wnd = UserGetWindowObject(hWnd)))
3946 {
3947 RETURN( FALSE);
3948 }
3949
3950 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
3951 {
3952 EngSetLastError(ERROR_ACCESS_DENIED);
3953 RETURN( FALSE);
3954 }
3955
3956 // From user land we only set these.
3957 if (fnID != FNID_DESTROY)
3958 { // Hacked so we can mark desktop~!
3959 if ( (/*(fnID < FNID_BUTTON)*/ (fnID < FNID_FIRST) && (fnID > FNID_GHOST)) ||
3960 Wnd->fnid != 0 )
3961 {
3962 EngSetLastError(ERROR_INVALID_PARAMETER);
3963 RETURN( FALSE);
3964 }
3965 }
3966
3967 Wnd->fnid |= fnID;
3968 RETURN( TRUE);
3969
3970 CLEANUP:
3971 TRACE("Leave NtUserSetWindowFNID\n");
3972 UserLeave();
3973 END_CLEANUP;
3974 }
3975
3976 /*
3977 * NtUserDefSetText
3978 *
3979 * Undocumented function that is called from DefWindowProc to set
3980 * window text.
3981 *
3982 * Status
3983 * @implemented
3984 */
3985 BOOL APIENTRY
3986 NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText)
3987 {
3988 PWND Wnd;
3989 LARGE_STRING SafeText;
3990 UNICODE_STRING UnicodeString;
3991 BOOL Ret = TRUE;
3992
3993 TRACE("Enter NtUserDefSetText\n");
3994
3995 if (WindowText != NULL)
3996 {
3997 _SEH2_TRY
3998 {
3999 SafeText = ProbeForReadLargeString(WindowText);
4000 }
4001 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4002 {
4003 Ret = FALSE;
4004 SetLastNtError(_SEH2_GetExceptionCode());
4005 }
4006 _SEH2_END;
4007
4008 if (!Ret)
4009 return FALSE;
4010 }
4011 else
4012 return TRUE;
4013
4014 UserEnterExclusive();
4015
4016 if(!(Wnd = UserGetWindowObject(hWnd)))
4017 {
4018 UserLeave();
4019 return FALSE;
4020 }
4021
4022 // ReactOS uses Unicode and not mixed. Up/Down converting will take time.
4023 // Brought to you by: The Wine Project! Dysfunctional Thought Processes!
4024 // Now we know what the bAnsi is for.
4025 RtlInitUnicodeString(&UnicodeString, NULL);
4026 if (SafeText.Buffer)
4027 {
4028 _SEH2_TRY
4029 {
4030 if (SafeText.bAnsi)
4031 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR));
4032 else
4033 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR));
4034 Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText);
4035 }
4036 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4037 {
4038 Ret = FALSE;
4039 SetLastNtError(_SEH2_GetExceptionCode());
4040 }
4041 _SEH2_END;
4042 if (!Ret) goto Exit;
4043 }
4044
4045 if (UnicodeString.Length != 0)
4046 {
4047 if (Wnd->strName.MaximumLength > 0 &&
4048 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4049 {
4050 ASSERT(Wnd->strName.Buffer != NULL);
4051
4052 Wnd->strName.Length = UnicodeString.Length;
4053 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4054 RtlCopyMemory(Wnd->strName.Buffer,
4055 UnicodeString.Buffer,
4056 UnicodeString.Length);
4057 }
4058 else
4059 {
4060 PWCHAR buf;
4061 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4062 buf = Wnd->strName.Buffer;
4063 Wnd->strName.Buffer = NULL;
4064 if (buf != NULL)
4065 {
4066 DesktopHeapFree(Wnd->head.rpdesk, buf);
4067 }
4068
4069 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4070 UnicodeString.Length + sizeof(UNICODE_NULL));
4071 if (Wnd->strName.Buffer != NULL)
4072 {
4073 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4074 RtlCopyMemory(Wnd->strName.Buffer,
4075 UnicodeString.Buffer,
4076 UnicodeString.Length);
4077 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4078 Wnd->strName.Length = UnicodeString.Length;
4079 }
4080 else
4081 {
4082 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4083 Ret = FALSE;
4084 goto Exit;
4085 }
4086 }
4087 }
4088 else
4089 {
4090 Wnd->strName.Length = 0;
4091 if (Wnd->strName.Buffer != NULL)
4092 Wnd->strName.Buffer[0] = L'\0';
4093 }
4094
4095 // FIXME: HAX! Windows does not do this in here!
4096 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4097 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4098 /* Send shell notifications */
4099 if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4100 {
4101 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) hWnd, FALSE); // FIXME Flashing?
4102 }
4103
4104 Ret = TRUE;
4105 Exit:
4106 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4107 TRACE("Leave NtUserDefSetText, ret=%i\n", Ret);
4108 UserLeave();
4109 return Ret;
4110 }
4111
4112 /*
4113 * NtUserInternalGetWindowText
4114 *
4115 * Status
4116 * @implemented
4117 */
4118
4119 INT APIENTRY
4120 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount)
4121 {
4122 PWND Wnd;
4123 NTSTATUS Status;
4124 INT Result;
4125 DECLARE_RETURN(INT);
4126
4127 TRACE("Enter NtUserInternalGetWindowText\n");
4128 UserEnterShared();
4129
4130 if(lpString && (nMaxCount <= 1))
4131 {
4132 EngSetLastError(ERROR_INVALID_PARAMETER);
4133 RETURN( 0);
4134 }
4135
4136 if(!(Wnd = UserGetWindowObject(hWnd)))
4137 {
4138 RETURN( 0);
4139 }
4140
4141 Result = Wnd->strName.Length / sizeof(WCHAR);
4142 if(lpString)
4143 {
4144 const WCHAR Terminator = L'\0';
4145 INT Copy;
4146 WCHAR *Buffer = (WCHAR*)lpString;
4147
4148 Copy = min(nMaxCount - 1, Result);
4149 if(Copy > 0)
4150 {
4151 Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR));
4152 if(!NT_SUCCESS(Status))
4153 {
4154 SetLastNtError(Status);
4155 RETURN( 0);
4156 }
4157 Buffer += Copy;
4158 }
4159
4160 Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
4161 if(!NT_SUCCESS(Status))
4162 {
4163 SetLastNtError(Status);
4164 RETURN( 0);
4165 }
4166
4167 Result = Copy;
4168 }
4169
4170 RETURN( Result);
4171
4172 CLEANUP:
4173 TRACE("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_);
4174 UserLeave();
4175 END_CLEANUP;
4176 }
4177
4178 /*
4179 API Call
4180 */
4181 BOOL
4182 FASTCALL
4183 IntShowOwnedPopups(PWND OwnerWnd, BOOL fShow )
4184 {
4185 int count = 0;
4186 PWND pWnd;
4187 HWND *win_array;
4188
4189 // ASSERT(OwnerWnd);
4190
4191 TRACE("Enter ShowOwnedPopups Show: %s\n", (fShow ? "TRUE" : "FALSE"));
4192 win_array = IntWinListChildren(OwnerWnd);
4193
4194 if (!win_array)
4195 return TRUE;
4196
4197 while (win_array[count])
4198 count++;
4199 while (--count >= 0)
4200 {
4201 if (!(pWnd = ValidateHwndNoErr( win_array[count] )))
4202 continue;
4203 if (pWnd->spwndOwner != OwnerWnd)
4204 continue;
4205
4206 if (fShow)
4207 {
4208 if (pWnd->state & WNDS_HIDDENPOPUP)
4209 {
4210 /* In Windows, ShowOwnedPopups(TRUE) generates
4211 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
4212 * regardless of the state of the owner
4213 */
4214 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
4215 continue;
4216 }
4217 }
4218 else
4219 {
4220 if (pWnd->style & WS_VISIBLE)
4221 {
4222 /* In Windows, ShowOwnedPopups(FALSE) generates
4223 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
4224 * regardless of the state of the owner
4225 */
4226 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
4227 continue;
4228 }
4229 }
4230
4231 }
4232 ExFreePoolWithTag(win_array, USERTAG_WINDOWLIST);
4233 TRACE("Leave ShowOwnedPopups\n");
4234 return TRUE;
4235 }
4236
4237 /* EOF */