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