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