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