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