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