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