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