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