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