[WIN32K]
[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 BOOL FASTCALL
899 IntIsChildWindow(PWND Parent, PWND BaseWindow)
900 {
901 PWND Window;
902
903 Window = BaseWindow;
904 while (Window && ((Window->style & (WS_POPUP|WS_CHILD)) == WS_CHILD))
905 {
906 if (Window == Parent)
907 {
908 return(TRUE);
909 }
910
911 Window = Window->spwndParent;
912 }
913
914 return(FALSE);
915 }
916
917 /*
918 Link the window into siblings list
919 children and parent are kept in place.
920 */
921 VOID FASTCALL
922 IntLinkWindow(
923 PWND Wnd,
924 PWND WndInsertAfter /* set to NULL if top sibling */
925 )
926 {
927 if ((Wnd->spwndPrev = WndInsertAfter))
928 {
929 /* link after WndInsertAfter */
930 if ((Wnd->spwndNext = WndInsertAfter->spwndNext))
931 Wnd->spwndNext->spwndPrev = Wnd;
932
933 Wnd->spwndPrev->spwndNext = Wnd;
934 }
935 else
936 {
937 /* link at top */
938 if ((Wnd->spwndNext = Wnd->spwndParent->spwndChild))
939 Wnd->spwndNext->spwndPrev = Wnd;
940
941 Wnd->spwndParent->spwndChild = Wnd;
942 }
943 }
944
945 /*
946 Note: Wnd->spwndParent can be null if it is the desktop.
947 */
948 VOID FASTCALL IntLinkHwnd(PWND Wnd, HWND hWndPrev)
949 {
950 if (hWndPrev == HWND_NOTOPMOST)
951 {
952 if (!(Wnd->ExStyle & WS_EX_TOPMOST) &&
953 (Wnd->ExStyle2 & WS_EX2_LINKED)) return; /* nothing to do */
954 Wnd->ExStyle &= ~WS_EX_TOPMOST;
955 hWndPrev = HWND_TOP; /* fallback to the HWND_TOP case */
956 }
957
958 IntUnlinkWindow(Wnd); /* unlink it from the previous location */
959
960 if (hWndPrev == HWND_BOTTOM)
961 {
962 /* Link in the bottom of the list */
963 PWND WndInsertAfter;
964
965 WndInsertAfter = Wnd->spwndParent->spwndChild;
966 while( WndInsertAfter && WndInsertAfter->spwndNext)
967 WndInsertAfter = WndInsertAfter->spwndNext;
968
969 IntLinkWindow(Wnd, WndInsertAfter);
970 Wnd->ExStyle &= ~WS_EX_TOPMOST;
971 }
972 else if (hWndPrev == HWND_TOPMOST)
973 {
974 /* Link in the top of the list */
975 IntLinkWindow(Wnd, NULL);
976
977 Wnd->ExStyle |= WS_EX_TOPMOST;
978 }
979 else if (hWndPrev == HWND_TOP)
980 {
981 /* Link it after the last topmost window */
982 PWND WndInsertBefore;
983
984 WndInsertBefore = Wnd->spwndParent->spwndChild;
985
986 if (!(Wnd->ExStyle & WS_EX_TOPMOST)) /* put it above the first non-topmost window */
987 {
988 while (WndInsertBefore != NULL && WndInsertBefore->spwndNext != NULL)
989 {
990 if (!(WndInsertBefore->ExStyle & WS_EX_TOPMOST)) break;
991 if (WndInsertBefore == Wnd->spwndOwner) /* keep it above owner */
992 {
993 Wnd->ExStyle |= WS_EX_TOPMOST;
994 break;
995 }
996 WndInsertBefore = WndInsertBefore->spwndNext;
997 }
998 }
999
1000 IntLinkWindow(Wnd, WndInsertBefore ? WndInsertBefore->spwndPrev : NULL);
1001 }
1002 else
1003 {
1004 /* Link it after hWndPrev */
1005 PWND WndInsertAfter;
1006
1007 WndInsertAfter = UserGetWindowObject(hWndPrev);
1008 /* Are we called with an erroneous handle */
1009 if(WndInsertAfter == NULL)
1010 {
1011 /* Link in a default position */
1012 IntLinkHwnd(Wnd, HWND_TOP);
1013 return;
1014 }
1015
1016 IntLinkWindow(Wnd, WndInsertAfter);
1017
1018 /* Fix the WS_EX_TOPMOST flag */
1019 if (!(WndInsertAfter->ExStyle & WS_EX_TOPMOST))
1020 {
1021 Wnd->ExStyle &= ~WS_EX_TOPMOST;
1022 }
1023 else
1024 {
1025 if(WndInsertAfter->spwndNext &&
1026 WndInsertAfter->spwndNext->ExStyle & WS_EX_TOPMOST)
1027 {
1028 Wnd->ExStyle |= WS_EX_TOPMOST;
1029 }
1030 }
1031 }
1032 Wnd->ExStyle2 |= WS_EX2_LINKED;
1033 }
1034
1035 VOID FASTCALL
1036 IntProcessOwnerSwap(PWND Wnd, PWND WndNewOwner, PWND WndOldOwner)
1037 {
1038 if (WndOldOwner)
1039 {
1040 if (Wnd->head.pti != WndOldOwner->head.pti)
1041 {
1042 if (!WndNewOwner ||
1043 Wnd->head.pti == WndNewOwner->head.pti ||
1044 WndOldOwner->head.pti != WndNewOwner->head.pti )
1045 {
1046 //ERR("ProcessOwnerSwap Old out.\n");
1047 UserAttachThreadInput(Wnd->head.pti, WndOldOwner->head.pti, FALSE);
1048 }
1049 }
1050 }
1051 if (WndNewOwner)
1052 {
1053 if (Wnd->head.pti != WndNewOwner->head.pti)
1054 {
1055 if (!WndOldOwner ||
1056 WndOldOwner->head.pti != WndNewOwner->head.pti )
1057 {
1058 //ERR("ProcessOwnerSwap New in.\n");
1059 UserAttachThreadInput(Wnd->head.pti, WndNewOwner->head.pti, TRUE);
1060 }
1061 }
1062 }
1063 // FIXME: System Tray checks.
1064 }
1065
1066 HWND FASTCALL
1067 IntSetOwner(HWND hWnd, HWND hWndNewOwner)
1068 {
1069 PWND Wnd, WndOldOwner, WndNewOwner;
1070 HWND ret;
1071
1072 Wnd = IntGetWindowObject(hWnd);
1073 if(!Wnd)
1074 return NULL;
1075
1076 WndOldOwner = Wnd->spwndOwner;
1077
1078 ret = WndOldOwner ? UserHMGetHandle(WndOldOwner) : 0;
1079 WndNewOwner = UserGetWindowObject(hWndNewOwner);
1080
1081 if (!WndNewOwner && hWndNewOwner)
1082 {
1083 EngSetLastError(ERROR_INVALID_PARAMETER);
1084 ret = NULL;
1085 goto Error;
1086 }
1087
1088 /* if parent belongs to a different thread and the window isn't */
1089 /* top-level, attach the two threads */
1090 IntProcessOwnerSwap(Wnd, WndNewOwner, WndOldOwner);
1091
1092 if (IntValidateOwnerDepth(Wnd, WndNewOwner))
1093 {
1094 if (WndNewOwner)
1095 {
1096 Wnd->spwndOwner= WndNewOwner;
1097 }
1098 else
1099 {
1100 Wnd->spwndOwner = NULL;
1101 }
1102 }
1103 else
1104 {
1105 IntProcessOwnerSwap(Wnd, WndOldOwner, WndNewOwner);
1106 EngSetLastError(ERROR_INVALID_PARAMETER);
1107 ret = NULL;
1108 }
1109 Error:
1110 UserDereferenceObject(Wnd);
1111 return ret;
1112 }
1113
1114 PWND FASTCALL
1115 co_IntSetParent(PWND Wnd, PWND WndNewParent)
1116 {
1117 PWND WndOldParent, pWndExam;
1118 BOOL WasVisible;
1119 POINT pt;
1120 int swFlags = SWP_NOSIZE|SWP_NOZORDER;
1121
1122 ASSERT(Wnd);
1123 ASSERT(WndNewParent);
1124 ASSERT_REFS_CO(Wnd);
1125 ASSERT_REFS_CO(WndNewParent);
1126
1127 if (Wnd == Wnd->head.rpdesk->spwndMessage)
1128 {
1129 EngSetLastError(ERROR_ACCESS_DENIED);
1130 return( NULL);
1131 }
1132
1133 /* Some applications try to set a child as a parent */
1134 if (IntIsChildWindow(Wnd, WndNewParent))
1135 {
1136 TRACE("IntSetParent try to set a child as a parent.\n");
1137 EngSetLastError( ERROR_INVALID_PARAMETER );
1138 return NULL;
1139 }
1140
1141 pWndExam = WndNewParent; // Load parent Window to examine.
1142 // Now test for set parent to parent hit.
1143 while (pWndExam)
1144 {
1145 if (Wnd == pWndExam)
1146 {
1147 TRACE("IntSetParent Failed Test for set parent to parent!\n");
1148 EngSetLastError(ERROR_INVALID_PARAMETER);
1149 return NULL;
1150 }
1151 pWndExam = pWndExam->spwndParent;
1152 }
1153
1154 /*
1155 * Windows hides the window first, then shows it again
1156 * including the WM_SHOWWINDOW messages and all
1157 */
1158 WasVisible = co_WinPosShowWindow(Wnd, SW_HIDE);
1159
1160 /* Window must belong to current process */
1161 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
1162 {
1163 ERR("IntSetParent Window must belong to current process!\n");
1164 return NULL;
1165 }
1166
1167 WndOldParent = Wnd->spwndParent;
1168
1169 if ( WndOldParent &&
1170 WndOldParent->ExStyle & WS_EX_LAYOUTRTL)
1171 pt.x = Wnd->rcWindow.right;
1172 else
1173 pt.x = Wnd->rcWindow.left;
1174 pt.y = Wnd->rcWindow.top;
1175
1176 IntScreenToClient(WndOldParent, &pt);
1177
1178 if (WndOldParent) UserReferenceObject(WndOldParent); /* Caller must deref */
1179
1180 if (WndNewParent != WndOldParent)
1181 {
1182 /* Unlink the window from the siblings list */
1183 IntUnlinkWindow(Wnd);
1184 Wnd->ExStyle2 &= ~WS_EX2_LINKED;
1185
1186 /* Set the new parent */
1187 Wnd->spwndParent = WndNewParent;
1188
1189 if ( Wnd->style & WS_CHILD &&
1190 Wnd->spwndOwner &&
1191 Wnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1192 {
1193 ERR("SetParent Top Most from Pop up!\n");
1194 Wnd->ExStyle |= WS_EX_TOPMOST;
1195 }
1196
1197 /* Link the window with its new siblings */
1198 IntLinkHwnd( Wnd,
1199 ((0 == (Wnd->ExStyle & WS_EX_TOPMOST) &&
1200 WndNewParent == UserGetDesktopWindow() ) ? HWND_TOP : HWND_TOPMOST ) );
1201
1202 }
1203
1204 if ( WndNewParent == co_GetDesktopWindow(Wnd) &&
1205 !(Wnd->style & WS_CLIPSIBLINGS) )
1206 {
1207 Wnd->style |= WS_CLIPSIBLINGS;
1208 DceResetActiveDCEs(Wnd);
1209 }
1210
1211 /* if parent belongs to a different thread and the window isn't */
1212 /* top-level, attach the two threads */
1213 if ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1214 {
1215 if ( Wnd->spwndParent != co_GetDesktopWindow(Wnd))
1216 {
1217 if (Wnd->head.pti != WndOldParent->head.pti)
1218 {
1219 //ERR("SetParent Old out.\n");
1220 UserAttachThreadInput(Wnd->head.pti, WndOldParent->head.pti, FALSE);
1221 }
1222 }
1223 if ( WndNewParent != co_GetDesktopWindow(Wnd))
1224 {
1225 if (Wnd->head.pti != WndNewParent->head.pti)
1226 {
1227 //ERR("SetParent New in.\n");
1228 UserAttachThreadInput(Wnd->head.pti, WndNewParent->head.pti, TRUE);
1229 }
1230 }
1231 }
1232
1233 if (WndOldParent == UserGetMessageWindow() || WndNewParent == UserGetMessageWindow())
1234 swFlags |= SWP_NOACTIVATE;
1235
1236 IntNotifyWinEvent(EVENT_OBJECT_PARENTCHANGE, Wnd ,OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1237 /*
1238 * SetParent additionally needs to make hwnd the top window
1239 * in the z-order and send the expected WM_WINDOWPOSCHANGING and
1240 * WM_WINDOWPOSCHANGED notification messages.
1241 */
1242 //ERR("IntSetParent SetWindowPos 1\n");
1243 co_WinPosSetWindowPos( Wnd,
1244 (0 == (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
1245 pt.x, pt.y, 0, 0, swFlags);
1246 //ERR("IntSetParent SetWindowPos 2 X %d Y %d\n",pt.x, pt.y);
1247 if (WasVisible) co_WinPosShowWindow(Wnd, SW_SHOWNORMAL);
1248
1249 return WndOldParent;
1250 }
1251
1252 HWND FASTCALL
1253 co_UserSetParent(HWND hWndChild, HWND hWndNewParent)
1254 {
1255 PWND Wnd = NULL, WndParent = NULL, WndOldParent;
1256 HWND hWndOldParent = NULL;
1257 USER_REFERENCE_ENTRY Ref, ParentRef;
1258
1259 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
1260 {
1261 EngSetLastError(ERROR_INVALID_PARAMETER);
1262 return( NULL);
1263 }
1264
1265 if (hWndChild == IntGetDesktopWindow())
1266 {
1267 ERR("UserSetParent Access Denied!\n");
1268 EngSetLastError(ERROR_ACCESS_DENIED);
1269 return( NULL);
1270 }
1271
1272 if (hWndNewParent)
1273 {
1274 if (!(WndParent = UserGetWindowObject(hWndNewParent)))
1275 {
1276 ERR("UserSetParent Bad New Parent!\n");
1277 return( NULL);
1278 }
1279 }
1280 else
1281 {
1282 if (!(WndParent = UserGetWindowObject(IntGetDesktopWindow())))
1283 {
1284 return( NULL);
1285 }
1286 }
1287
1288 if (!(Wnd = UserGetWindowObject(hWndChild)))
1289 {
1290 ERR("UserSetParent Bad Child!\n");
1291 return( NULL);
1292 }
1293
1294 UserRefObjectCo(Wnd, &Ref);
1295 UserRefObjectCo(WndParent, &ParentRef);
1296 //ERR("Enter co_IntSetParent\n");
1297 WndOldParent = co_IntSetParent(Wnd, WndParent);
1298 //ERR("Leave co_IntSetParent\n");
1299 UserDerefObjectCo(WndParent);
1300 UserDerefObjectCo(Wnd);
1301
1302 if (WndOldParent)
1303 {
1304 hWndOldParent = WndOldParent->head.h;
1305 UserDereferenceObject(WndOldParent);
1306 }
1307
1308 return( hWndOldParent);
1309 }
1310
1311 /* Unlink the window from siblings. children and parent are kept in place. */
1312 VOID FASTCALL
1313 IntUnlinkWindow(PWND Wnd)
1314 {
1315 if (Wnd->spwndNext)
1316 Wnd->spwndNext->spwndPrev = Wnd->spwndPrev;
1317
1318 if (Wnd->spwndPrev)
1319 Wnd->spwndPrev->spwndNext = Wnd->spwndNext;
1320
1321 if (Wnd->spwndParent && Wnd->spwndParent->spwndChild == Wnd)
1322 Wnd->spwndParent->spwndChild = Wnd->spwndNext;
1323
1324 Wnd->spwndPrev = Wnd->spwndNext = NULL;
1325 }
1326
1327 /* FUNCTIONS *****************************************************************/
1328
1329 /*
1330 * As best as I can figure, this function is used by EnumWindows,
1331 * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
1332 *
1333 * It's supposed to build a list of HWNDs to return to the caller.
1334 * We can figure out what kind of list by what parameters are
1335 * passed to us.
1336 */
1337 /*
1338 * @implemented
1339 */
1340 NTSTATUS
1341 APIENTRY
1342 NtUserBuildHwndList(
1343 HDESK hDesktop,
1344 HWND hwndParent,
1345 BOOLEAN bChildren,
1346 ULONG dwThreadId,
1347 ULONG lParam,
1348 HWND* pWnd,
1349 ULONG* pBufSize)
1350 {
1351 NTSTATUS Status;
1352 ULONG dwCount = 0;
1353
1354 if (pBufSize == 0)
1355 return ERROR_INVALID_PARAMETER;
1356
1357 if (hwndParent || !dwThreadId)
1358 {
1359 PDESKTOP Desktop;
1360 PWND Parent, Window;
1361
1362 if(!hwndParent)
1363 {
1364 if(hDesktop == NULL && !(Desktop = IntGetActiveDesktop()))
1365 {
1366 return ERROR_INVALID_HANDLE;
1367 }
1368
1369 if(hDesktop)
1370 {
1371 Status = IntValidateDesktopHandle(hDesktop,
1372 UserMode,
1373 0,
1374 &Desktop);
1375 if(!NT_SUCCESS(Status))
1376 {
1377 return ERROR_INVALID_HANDLE;
1378 }
1379 }
1380 hwndParent = Desktop->DesktopWindow;
1381 }
1382 else
1383 {
1384 hDesktop = 0;
1385 }
1386
1387 if((Parent = UserGetWindowObject(hwndParent)) &&
1388 (Window = Parent->spwndChild))
1389 {
1390 BOOL bGoDown = TRUE;
1391
1392 Status = STATUS_SUCCESS;
1393 while(TRUE)
1394 {
1395 if (bGoDown)
1396 {
1397 if(dwCount++ < *pBufSize && pWnd)
1398 {
1399 _SEH2_TRY
1400 {
1401 ProbeForWrite(pWnd, sizeof(HWND), 1);
1402 *pWnd = Window->head.h;
1403 pWnd++;
1404 }
1405 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1406 {
1407 Status = _SEH2_GetExceptionCode();
1408 }
1409 _SEH2_END
1410 if(!NT_SUCCESS(Status))
1411 {
1412 SetLastNtError(Status);
1413 break;
1414 }
1415 }
1416 if (Window->spwndChild && bChildren)
1417 {
1418 Window = Window->spwndChild;
1419 continue;
1420 }
1421 bGoDown = FALSE;
1422 }
1423 if (Window->spwndNext)
1424 {
1425 Window = Window->spwndNext;
1426 bGoDown = TRUE;
1427 continue;
1428 }
1429 Window = Window->spwndParent;
1430 if (Window == Parent)
1431 {
1432 break;
1433 }
1434 }
1435 }
1436
1437 if(hDesktop)
1438 {
1439 ObDereferenceObject(Desktop);
1440 }
1441 }
1442 else // Build EnumThreadWindows list!
1443 {
1444 PETHREAD Thread;
1445 PTHREADINFO W32Thread;
1446 PLIST_ENTRY Current;
1447 PWND Window;
1448
1449 Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
1450 if (!NT_SUCCESS(Status))
1451 {
1452 ERR("Thread Id is not valid!\n");
1453 return ERROR_INVALID_PARAMETER;
1454 }
1455 if (!(W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread))
1456 {
1457 ObDereferenceObject(Thread);
1458 ERR("Thread is not initialized!\n");
1459 return ERROR_INVALID_PARAMETER;
1460 }
1461
1462 Current = W32Thread->WindowListHead.Flink;
1463 while (Current != &(W32Thread->WindowListHead))
1464 {
1465 Window = CONTAINING_RECORD(Current, WND, ThreadListEntry);
1466 ASSERT(Window);
1467
1468 if (dwCount < *pBufSize && pWnd)
1469 {
1470 _SEH2_TRY
1471 {
1472 ProbeForWrite(pWnd, sizeof(HWND), 1);
1473 *pWnd = Window->head.h;
1474 pWnd++;
1475 }
1476 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1477 {
1478 Status = _SEH2_GetExceptionCode();
1479 }
1480 _SEH2_END
1481 if (!NT_SUCCESS(Status))
1482 {
1483 ERR("Failure to build window list!\n");
1484 SetLastNtError(Status);
1485 break;
1486 }
1487 }
1488 dwCount++;
1489 Current = Window->ThreadListEntry.Flink;
1490 }
1491
1492 ObDereferenceObject(Thread);
1493 }
1494
1495 *pBufSize = dwCount;
1496 return STATUS_SUCCESS;
1497 }
1498
1499 static void IntSendParentNotify( PWND pWindow, UINT msg )
1500 {
1501 if ( (pWindow->style & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
1502 !(pWindow->style & WS_EX_NOPARENTNOTIFY))
1503 {
1504 if (pWindow->spwndParent && pWindow->spwndParent != UserGetDesktopWindow())
1505 {
1506 USER_REFERENCE_ENTRY Ref;
1507 UserRefObjectCo(pWindow->spwndParent, &Ref);
1508 co_IntSendMessage( pWindow->spwndParent->head.h,
1509 WM_PARENTNOTIFY,
1510 MAKEWPARAM( msg, pWindow->IDMenu),
1511 (LPARAM)pWindow->head.h );
1512 UserDerefObjectCo(pWindow->spwndParent);
1513 }
1514 }
1515 }
1516
1517 void FASTCALL
1518 IntFixWindowCoordinates(CREATESTRUCTW* Cs, PWND ParentWindow, DWORD* dwShowMode)
1519 {
1520 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1521
1522 /* default positioning for overlapped windows */
1523 if(!(Cs->style & (WS_POPUP | WS_CHILD)))
1524 {
1525 PMONITOR pMonitor;
1526 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
1527
1528 pMonitor = UserGetPrimaryMonitor();
1529
1530 /* Check if we don't have a monitor attached yet */
1531 if(pMonitor == NULL)
1532 {
1533 Cs->x = Cs->y = 0;
1534 Cs->cx = 800;
1535 Cs->cy = 600;
1536 return;
1537 }
1538
1539 ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
1540
1541 if (IS_DEFAULT(Cs->x))
1542 {
1543 if (!IS_DEFAULT(Cs->y)) *dwShowMode = Cs->y;
1544
1545 if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
1546 {
1547 Cs->x = ProcessParams->StartingX;
1548 Cs->y = ProcessParams->StartingY;
1549 }
1550 else
1551 {
1552 Cs->x = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CXSIZE) + UserGetSystemMetrics(SM_CXFRAME));
1553 Cs->y = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CYSIZE) + UserGetSystemMetrics(SM_CYFRAME));
1554 if (Cs->x > ((pMonitor->rcWork.right - pMonitor->rcWork.left) / 4) ||
1555 Cs->y > ((pMonitor->rcWork.bottom - pMonitor->rcWork.top) / 4))
1556 {
1557 /* reset counter and position */
1558 Cs->x = 0;
1559 Cs->y = 0;
1560 pMonitor->cWndStack = 0;
1561 }
1562 pMonitor->cWndStack++;
1563 }
1564 }
1565
1566 if (IS_DEFAULT(Cs->cx))
1567 {
1568 if (ProcessParams->WindowFlags & STARTF_USEPOSITION)
1569 {
1570 Cs->cx = ProcessParams->CountX;
1571 Cs->cy = ProcessParams->CountY;
1572 }
1573 else
1574 {
1575 Cs->cx = (pMonitor->rcWork.right - pMonitor->rcWork.left) * 3 / 4;
1576 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1577 }
1578 }
1579 /* neither x nor cx are default. Check the y values .
1580 * In the trace we see Outlook and Outlook Express using
1581 * cy set to CW_USEDEFAULT when opening the address book.
1582 */
1583 else if (IS_DEFAULT(Cs->cy))
1584 {
1585 TRACE("Strange use of CW_USEDEFAULT in nHeight\n");
1586 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1587 }
1588 }
1589 else
1590 {
1591 /* if CW_USEDEFAULT is set for non-overlapped windows, both values are set to zero */
1592 if(IS_DEFAULT(Cs->x))
1593 {
1594 Cs->x = 0;
1595 Cs->y = 0;
1596 }
1597 if(IS_DEFAULT(Cs->cx))
1598 {
1599 Cs->cx = 0;
1600 Cs->cy = 0;
1601 }
1602 }
1603
1604 #undef IS_DEFAULT
1605 }
1606
1607 /* Allocates and initializes a window */
1608 PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
1609 PLARGE_STRING WindowName,
1610 PCLS Class,
1611 PWND ParentWindow,
1612 PWND OwnerWindow,
1613 PVOID acbiBuffer,
1614 PDESKTOP pdeskCreated)
1615 {
1616 PWND pWnd = NULL;
1617 HWND hWnd;
1618 PTHREADINFO pti = NULL;
1619 BOOL MenuChanged;
1620 BOOL bUnicodeWindow;
1621
1622 pti = pdeskCreated ? gptiDesktopThread : GetW32ThreadInfo();
1623
1624 if (!(Cs->dwExStyle & WS_EX_LAYOUTRTL))
1625 { // Need both here for wine win.c test_CreateWindow.
1626 //if (Cs->hwndParent && ParentWindow)
1627 if (ParentWindow) // It breaks more tests..... WIP.
1628 {
1629 if ( (Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD &&
1630 ParentWindow->ExStyle & WS_EX_LAYOUTRTL &&
1631 !(ParentWindow->ExStyle & WS_EX_NOINHERITLAYOUT) )
1632 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1633 }
1634 else
1635 { /*
1636 * Note from MSDN <http://msdn.microsoft.com/en-us/library/aa913269.aspx>:
1637 *
1638 * Dialog boxes and message boxes do not inherit layout, so you must
1639 * set the layout explicitly.
1640 */
1641 if ( Class->fnid != FNID_DIALOG )
1642 {
1643 if (pti->ppi->dwLayout & LAYOUT_RTL)
1644 {
1645 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1646 }
1647 }
1648 }
1649 }
1650
1651 /* Automatically add WS_EX_WINDOWEDGE */
1652 if ((Cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1653 ((!(Cs->dwExStyle & WS_EX_STATICEDGE)) &&
1654 (Cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1655 Cs->dwExStyle |= WS_EX_WINDOWEDGE;
1656 else
1657 Cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1658
1659 /* Is it a unicode window? */
1660 bUnicodeWindow =!(Cs->dwExStyle & WS_EX_SETANSICREATOR);
1661 Cs->dwExStyle &= ~WS_EX_SETANSICREATOR;
1662
1663 /* Allocate the new window */
1664 pWnd = (PWND) UserCreateObject( gHandleTable,
1665 pdeskCreated ? pdeskCreated : pti->rpdesk,
1666 pti,
1667 (PHANDLE)&hWnd,
1668 TYPE_WINDOW,
1669 sizeof(WND) + Class->cbwndExtra);
1670
1671 if (!pWnd)
1672 {
1673 goto AllocError;
1674 }
1675
1676 TRACE("Created window object with handle %p\n", hWnd);
1677
1678 if (pdeskCreated && pdeskCreated->DesktopWindow == NULL )
1679 { /* HACK: Helper for win32csr/desktopbg.c */
1680 /* If there is no desktop window yet, we must be creating it */
1681 TRACE("CreateWindow setting desktop.\n");
1682 pdeskCreated->DesktopWindow = hWnd;
1683 pdeskCreated->pDeskInfo->spwnd = pWnd;
1684 }
1685
1686 /*
1687 * Fill out the structure describing it.
1688 */
1689 /* Remember, pWnd->head is setup in object.c ... */
1690 pWnd->spwndParent = ParentWindow;
1691 pWnd->spwndOwner = OwnerWindow;
1692 pWnd->fnid = 0;
1693 pWnd->spwndLastActive = pWnd;
1694 pWnd->state2 |= WNDS2_WIN40COMPAT; // FIXME!!!
1695 pWnd->pcls = Class;
1696 pWnd->hModule = Cs->hInstance;
1697 pWnd->style = Cs->style & ~WS_VISIBLE;
1698 pWnd->ExStyle = Cs->dwExStyle;
1699 pWnd->cbwndExtra = pWnd->pcls->cbwndExtra;
1700 pWnd->pActCtx = acbiBuffer;
1701 pWnd->InternalPos.MaxPos.x = pWnd->InternalPos.MaxPos.y = -1;
1702 pWnd->InternalPos.IconPos.x = pWnd->InternalPos.IconPos.y = -1;
1703
1704 if (pWnd->spwndParent != NULL && Cs->hwndParent != 0)
1705 {
1706 pWnd->HideFocus = pWnd->spwndParent->HideFocus;
1707 pWnd->HideAccel = pWnd->spwndParent->HideAccel;
1708 }
1709
1710 pWnd->head.pti->cWindows++;
1711
1712 if (Class->hIcon && !Class->hIconSm)
1713 {
1714 Class->hIconSmIntern = co_IntCopyImage( Class->hIcon, IMAGE_ICON,
1715 UserGetSystemMetrics( SM_CXSMICON ),
1716 UserGetSystemMetrics( SM_CYSMICON ), 0 );
1717 TRACE("IntCreateWindow hIconSmIntern %p\n",Class->hIconSmIntern);
1718 Class->CSF_flags |= CSF_CACHEDSMICON;
1719 }
1720
1721 if (pWnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
1722 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
1723
1724 /* BugBoy Comments: Comment below say that System classes are always created
1725 as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
1726 sets the window to ansi as verified by testing with IsUnicodeWindow API.
1727
1728 No where can I see in code or through testing does the window change back
1729 to ANSI after being created as UNICODE in ROS. I didnt do more testing to
1730 see what problems this would cause. */
1731
1732 // Set WndProc from Class.
1733 pWnd->lpfnWndProc = pWnd->pcls->lpfnWndProc;
1734
1735 // GetWindowProc, test for non server side default classes and set WndProc.
1736 if ( pWnd->pcls->fnid <= FNID_GHOST && pWnd->pcls->fnid >= FNID_BUTTON )
1737 {
1738 if (bUnicodeWindow)
1739 {
1740 if (GETPFNCLIENTA(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1741 pWnd->lpfnWndProc = GETPFNCLIENTW(pWnd->pcls->fnid);
1742 }
1743 else
1744 {
1745 if (GETPFNCLIENTW(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1746 pWnd->lpfnWndProc = GETPFNCLIENTA(pWnd->pcls->fnid);
1747 }
1748 }
1749
1750 // If not an Unicode caller, set Ansi creator bit.
1751 if (!bUnicodeWindow) pWnd->state |= WNDS_ANSICREATOR;
1752
1753 // Clone Class Ansi/Unicode proc type.
1754 if (pWnd->pcls->CSF_flags & CSF_ANSIPROC)
1755 {
1756 pWnd->state |= WNDS_ANSIWINDOWPROC;
1757 pWnd->Unicode = FALSE;
1758 }
1759 else
1760 { /*
1761 * It seems there can be both an Ansi creator and Unicode Class Window
1762 * WndProc, unless the following overriding conditions occur:
1763 */
1764 if ( !bUnicodeWindow &&
1765 ( Class->atomClassName == gpsi->atomSysClass[ICLS_BUTTON] ||
1766 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX] ||
1767 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOLBOX] ||
1768 Class->atomClassName == gpsi->atomSysClass[ICLS_DIALOG] ||
1769 Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT] ||
1770 Class->atomClassName == gpsi->atomSysClass[ICLS_IME] ||
1771 Class->atomClassName == gpsi->atomSysClass[ICLS_LISTBOX] ||
1772 Class->atomClassName == gpsi->atomSysClass[ICLS_MDICLIENT] ||
1773 Class->atomClassName == gpsi->atomSysClass[ICLS_STATIC] ) )
1774 { // Override Class and set the window Ansi WndProc.
1775 pWnd->state |= WNDS_ANSIWINDOWPROC;
1776 pWnd->Unicode = FALSE;
1777 }
1778 else
1779 { // Set the window Unicode WndProc.
1780 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
1781 pWnd->Unicode = TRUE;
1782 }
1783 }
1784
1785 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
1786 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
1787 Dont understand why it does this. */
1788 if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT])
1789 {
1790 PCALLPROCDATA CallProc;
1791 CallProc = CreateCallProc(NULL, pWnd->lpfnWndProc, pWnd->Unicode , pWnd->head.pti->ppi);
1792
1793 if (!CallProc)
1794 {
1795 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1796 ERR("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %p\n", hWnd);
1797 }
1798 else
1799 {
1800 UserAddCallProcToClass(pWnd->pcls, CallProc);
1801 }
1802 }
1803
1804 InitializeListHead(&pWnd->PropListHead);
1805 pWnd->PropListItems = 0;
1806
1807 if ( WindowName->Buffer != NULL && WindowName->Length > 0 )
1808 {
1809 pWnd->strName.Buffer = DesktopHeapAlloc(pWnd->head.rpdesk,
1810 WindowName->Length + sizeof(UNICODE_NULL));
1811 if (pWnd->strName.Buffer == NULL)
1812 {
1813 goto AllocError;
1814 }
1815
1816 RtlCopyMemory(pWnd->strName.Buffer, WindowName->Buffer, WindowName->Length);
1817 pWnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
1818 pWnd->strName.Length = WindowName->Length;
1819 pWnd->strName.MaximumLength = WindowName->Length + sizeof(UNICODE_NULL);
1820 }
1821
1822 /* Correct the window style. */
1823 if ((pWnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1824 {
1825 pWnd->style |= WS_CLIPSIBLINGS;
1826 if (!(pWnd->style & WS_POPUP))
1827 {
1828 pWnd->style |= WS_CAPTION;
1829 }
1830 }
1831
1832 /* WS_EX_WINDOWEDGE depends on some other styles */
1833 if (pWnd->ExStyle & WS_EX_DLGMODALFRAME)
1834 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1835 else if (pWnd->style & (WS_DLGFRAME | WS_THICKFRAME))
1836 {
1837 if (!((pWnd->ExStyle & WS_EX_STATICEDGE) &&
1838 (pWnd->style & (WS_CHILD | WS_POPUP))))
1839 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
1840 }
1841 else
1842 pWnd->ExStyle &= ~WS_EX_WINDOWEDGE;
1843
1844 if (!(pWnd->style & (WS_CHILD | WS_POPUP)))
1845 pWnd->state |= WNDS_SENDSIZEMOVEMSGS;
1846
1847 /* Set the window menu */
1848 if ((Cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1849 {
1850 if (Cs->hMenu)
1851 {
1852 IntSetMenu(pWnd, Cs->hMenu, &MenuChanged);
1853 }
1854 else if (pWnd->pcls->lpszMenuName) // Take it from the parent.
1855 {
1856 UNICODE_STRING MenuName;
1857 HMENU hMenu;
1858
1859 if (IS_INTRESOURCE(pWnd->pcls->lpszMenuName))
1860 {
1861 MenuName.Length = 0;
1862 MenuName.MaximumLength = 0;
1863 MenuName.Buffer = pWnd->pcls->lpszMenuName;
1864 }
1865 else
1866 {
1867 RtlInitUnicodeString( &MenuName, pWnd->pcls->lpszMenuName);
1868 }
1869 hMenu = co_IntCallLoadMenu( pWnd->pcls->hModule, &MenuName);
1870 if (hMenu) IntSetMenu(pWnd, hMenu, &MenuChanged);
1871 }
1872 }
1873 else // Not a child
1874 pWnd->IDMenu = (UINT) Cs->hMenu;
1875
1876
1877 if ( ParentWindow &&
1878 ParentWindow != ParentWindow->head.rpdesk->spwndMessage &&
1879 ParentWindow != ParentWindow->head.rpdesk->pDeskInfo->spwnd )
1880 {
1881 PWND Owner = IntGetNonChildAncestor(ParentWindow);
1882
1883 if (!IntValidateOwnerDepth(pWnd, Owner))
1884 {
1885 EngSetLastError(ERROR_INVALID_PARAMETER);
1886 goto Error;
1887 }
1888 if ( pWnd->spwndOwner &&
1889 pWnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
1890 {
1891 pWnd->ExStyle |= WS_EX_TOPMOST;
1892 }
1893 if ( pWnd->spwndOwner &&
1894 Class->atomClassName != gpsi->atomSysClass[ICLS_IME] &&
1895 pti != pWnd->spwndOwner->head.pti)
1896 {
1897 //ERR("CreateWindow Owner in.\n");
1898 UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE);
1899 }
1900 }
1901
1902 /* Insert the window into the thread's window list. */
1903 InsertTailList (&pti->WindowListHead, &pWnd->ThreadListEntry);
1904
1905 /* Handle "CS_CLASSDC", it is tested first. */
1906 if ( (pWnd->pcls->style & CS_CLASSDC) && !(pWnd->pcls->pdce) )
1907 { /* One DCE per class to have CLASS. */
1908 pWnd->pcls->pdce = DceAllocDCE( pWnd, DCE_CLASS_DC );
1909 }
1910 else if ( pWnd->pcls->style & CS_OWNDC)
1911 { /* Allocate a DCE for this window. */
1912 DceAllocDCE(pWnd, DCE_WINDOW_DC);
1913 }
1914
1915 return pWnd;
1916
1917 AllocError:
1918 ERR("IntCreateWindow Allocation Error.\n");
1919 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
1920 Error:
1921 if(pWnd)
1922 UserDereferenceObject(pWnd);
1923 return NULL;
1924 }
1925
1926 /*
1927 * @implemented
1928 */
1929 PWND FASTCALL
1930 co_UserCreateWindowEx(CREATESTRUCTW* Cs,
1931 PUNICODE_STRING ClassName,
1932 PLARGE_STRING WindowName,
1933 PVOID acbiBuffer)
1934 {
1935 ULONG style;
1936 PWND Window = NULL, ParentWindow = NULL, OwnerWindow;
1937 HWND hWnd, hWndParent, hWndOwner, hwndInsertAfter;
1938 PWINSTATION_OBJECT WinSta;
1939 PCLS Class = NULL;
1940 SIZE Size;
1941 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
1942 CBT_CREATEWNDW * pCbtCreate;
1943 LRESULT Result;
1944 USER_REFERENCE_ENTRY ParentRef, Ref;
1945 PTHREADINFO pti;
1946 DWORD dwShowMode = SW_SHOW;
1947 CREATESTRUCTW *pCsw = NULL;
1948 PVOID pszClass = NULL, pszName = NULL;
1949 PWND ret = NULL;
1950
1951 /* Get the current window station and reference it */
1952 pti = GetW32ThreadInfo();
1953 if (pti == NULL || pti->rpdesk == NULL)
1954 {
1955 ERR("Thread is not attached to a desktop! Cannot create window!\n");
1956 return NULL; // There is nothing to cleanup.
1957 }
1958 WinSta = pti->rpdesk->rpwinstaParent;
1959 ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
1960
1961 pCsw = NULL;
1962 pCbtCreate = NULL;
1963
1964 /* Get the class and reference it */
1965 Class = IntGetAndReferenceClass(ClassName, Cs->hInstance, FALSE);
1966 if(!Class)
1967 {
1968 ERR("Failed to find class %wZ\n", ClassName);
1969 goto cleanup;
1970 }
1971
1972 /* Now find the parent and the owner window */
1973 hWndParent = pti->rpdesk->pDeskInfo->spwnd->head.h;
1974 hWndOwner = NULL;
1975
1976 if (Cs->hwndParent == HWND_MESSAGE)
1977 {
1978 Cs->hwndParent = hWndParent = pti->rpdesk->spwndMessage->head.h;
1979 }
1980 else if (Cs->hwndParent)
1981 {
1982 if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
1983 hWndOwner = Cs->hwndParent;
1984 else
1985 hWndParent = Cs->hwndParent;
1986 }
1987 else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1988 {
1989 ERR("Cannot create a child window without a parrent!\n");
1990 EngSetLastError(ERROR_TLW_WITH_WSCHILD);
1991 goto cleanup; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1992 }
1993
1994 ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
1995 OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
1996
1997 /* FIXME: Is this correct? */
1998 if(OwnerWindow)
1999 OwnerWindow = UserGetAncestor(OwnerWindow, GA_ROOT);
2000
2001 /* Fix the position and the size of the window */
2002 if (ParentWindow)
2003 {
2004 UserRefObjectCo(ParentWindow, &ParentRef);
2005 IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode);
2006 }
2007
2008 /* Allocate and initialize the new window */
2009 Window = IntCreateWindow(Cs,
2010 WindowName,
2011 Class,
2012 ParentWindow,
2013 OwnerWindow,
2014 acbiBuffer,
2015 NULL);
2016 if(!Window)
2017 {
2018 ERR("IntCreateWindow failed!\n");
2019 goto cleanup;
2020 }
2021
2022 hWnd = UserHMGetHandle(Window);
2023 hwndInsertAfter = HWND_TOP;
2024
2025 UserRefObjectCo(Window, &Ref);
2026 UserDereferenceObject(Window);
2027 ObDereferenceObject(WinSta);
2028
2029 //// Check for a hook to eliminate overhead. ////
2030 if ( ISITHOOKED(WH_CBT) || (pti->rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)) )
2031 {
2032 // Allocate the calling structures Justin Case this goes Global.
2033 pCsw = ExAllocatePoolWithTag(NonPagedPool, sizeof(CREATESTRUCTW), TAG_HOOK);
2034 pCbtCreate = ExAllocatePoolWithTag(NonPagedPool, sizeof(CBT_CREATEWNDW), TAG_HOOK);
2035 if (!pCsw || !pCbtCreate)
2036 {
2037 ERR("UserHeapAlloc() failed!\n");
2038 goto cleanup;
2039 }
2040
2041 /* Fill the new CREATESTRUCTW */
2042 RtlCopyMemory(pCsw, Cs, sizeof(CREATESTRUCTW));
2043 pCsw->style = Window->style; /* HCBT_CREATEWND needs the real window style */
2044
2045 // Based on the assumption this is from "unicode source" user32, ReactOS, answer is yes.
2046 if (!IS_ATOM(ClassName->Buffer))
2047 {
2048 if (Window->state & WNDS_ANSICREATOR)
2049 {
2050 ANSI_STRING AnsiString;
2051 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(ClassName)+sizeof(CHAR);
2052 pszClass = UserHeapAlloc(AnsiString.MaximumLength);
2053 if (!pszClass)
2054 {
2055 ERR("UserHeapAlloc() failed!\n");
2056 goto cleanup;
2057 }
2058 RtlZeroMemory(pszClass, AnsiString.MaximumLength);
2059 AnsiString.Buffer = (PCHAR)pszClass;
2060 RtlUnicodeStringToAnsiString(&AnsiString, ClassName, FALSE);
2061 }
2062 else
2063 {
2064 UNICODE_STRING UnicodeString;
2065 UnicodeString.MaximumLength = ClassName->Length + sizeof(UNICODE_NULL);
2066 pszClass = UserHeapAlloc(UnicodeString.MaximumLength);
2067 if (!pszClass)
2068 {
2069 ERR("UserHeapAlloc() failed!\n");
2070 goto cleanup;
2071 }
2072 RtlZeroMemory(pszClass, UnicodeString.MaximumLength);
2073 UnicodeString.Buffer = (PWSTR)pszClass;
2074 RtlCopyUnicodeString(&UnicodeString, ClassName);
2075 }
2076 pCsw->lpszClass = UserHeapAddressToUser(pszClass);
2077 }
2078 if (WindowName->Length)
2079 {
2080 UNICODE_STRING Name;
2081 Name.Buffer = WindowName->Buffer;
2082 Name.Length = (USHORT)min(WindowName->Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2083 Name.MaximumLength = (USHORT)min(WindowName->MaximumLength, MAXUSHORT);
2084
2085 if (Window->state & WNDS_ANSICREATOR)
2086 {
2087 ANSI_STRING AnsiString;
2088 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(&Name) + sizeof(CHAR);
2089 pszName = UserHeapAlloc(AnsiString.MaximumLength);
2090 if (!pszName)
2091 {
2092 ERR("UserHeapAlloc() failed!\n");
2093 goto cleanup;
2094 }
2095 RtlZeroMemory(pszName, AnsiString.MaximumLength);
2096 AnsiString.Buffer = (PCHAR)pszName;
2097 RtlUnicodeStringToAnsiString(&AnsiString, &Name, FALSE);
2098 }
2099 else
2100 {
2101 UNICODE_STRING UnicodeString;
2102 UnicodeString.MaximumLength = Name.Length + sizeof(UNICODE_NULL);
2103 pszName = UserHeapAlloc(UnicodeString.MaximumLength);
2104 if (!pszName)
2105 {
2106 ERR("UserHeapAlloc() failed!\n");
2107 goto cleanup;
2108 }
2109 RtlZeroMemory(pszName, UnicodeString.MaximumLength);
2110 UnicodeString.Buffer = (PWSTR)pszName;
2111 RtlCopyUnicodeString(&UnicodeString, &Name);
2112 }
2113 pCsw->lpszName = UserHeapAddressToUser(pszName);
2114 }
2115
2116 pCbtCreate->lpcs = pCsw;
2117 pCbtCreate->hwndInsertAfter = hwndInsertAfter;
2118
2119 //// Call the WH_CBT hook ////
2120 Result = co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) pCbtCreate);
2121 if (Result != 0)
2122 {
2123 ERR("WH_CBT HCBT_CREATEWND hook failed! 0x%x\n", Result);
2124 goto cleanup;
2125 }
2126 // Write back changes.
2127 Cs->cx = pCsw->cx;
2128 Cs->cy = pCsw->cy;
2129 Cs->x = pCsw->x;
2130 Cs->y = pCsw->y;
2131 hwndInsertAfter = pCbtCreate->hwndInsertAfter;
2132 }
2133
2134 /* NCCREATE and WM_NCCALCSIZE need the original values */
2135 Cs->lpszName = (LPCWSTR) WindowName;
2136 Cs->lpszClass = (LPCWSTR) ClassName;
2137
2138 if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2139 {
2140 if (ParentWindow != co_GetDesktopWindow(Window))
2141 {
2142 Cs->x += ParentWindow->rcClient.left;
2143 Cs->y += ParentWindow->rcClient.top;
2144 }
2145 }
2146
2147 /* Send the WM_GETMINMAXINFO message */
2148 Size.cx = Cs->cx;
2149 Size.cy = Cs->cy;
2150
2151 if ((Cs->style & WS_THICKFRAME) || !(Cs->style & (WS_POPUP | WS_CHILD)))
2152 {
2153 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
2154 if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
2155 if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
2156 if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
2157 if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
2158 }
2159
2160 Window->rcWindow.left = Cs->x;
2161 Window->rcWindow.top = Cs->y;
2162 Window->rcWindow.right = Cs->x + Size.cx;
2163 Window->rcWindow.bottom = Cs->y + Size.cy;
2164 /*
2165 if (0 != (Window->style & WS_CHILD) && ParentWindow)
2166 {
2167 ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
2168 RECTL_vOffsetRect(&Window->rcWindow,
2169 ParentWindow->rcClient.left,
2170 ParentWindow->rcClient.top);
2171 }
2172 */
2173 /* correct child window coordinates if mirroring on parent is enabled */
2174 if (ParentWindow != NULL)
2175 {
2176 if ( ((Cs->style & WS_CHILD) == WS_CHILD) &&
2177 ((ParentWindow->ExStyle & WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL))
2178 {
2179 Window->rcWindow.right = ParentWindow->rcClient.right - (Window->rcWindow.left - ParentWindow->rcClient.left);
2180 Window->rcWindow.left = Window->rcWindow.right - Size.cx;
2181 }
2182 }
2183
2184 Window->rcClient = Window->rcWindow;
2185
2186 /* Link the window */
2187 if (NULL != ParentWindow)
2188 {
2189 /* Link the window into the siblings list */
2190 if ((Cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
2191 IntLinkHwnd(Window, HWND_BOTTOM);
2192 else
2193 IntLinkHwnd(Window, hwndInsertAfter);
2194 }
2195
2196 if (!(Window->state2 & WNDS2_WIN31COMPAT))
2197 {
2198 if (Class->style & CS_PARENTDC && !(ParentWindow->style & WS_CLIPCHILDREN))
2199 Window->style &= ~(WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
2200 }
2201
2202 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2203 {
2204 if ( !IntIsTopLevelWindow(Window) )
2205 {
2206 if (pti != Window->spwndParent->head.pti)
2207 {
2208 //ERR("CreateWindow Parent in.\n");
2209 UserAttachThreadInput(pti, Window->spwndParent->head.pti, TRUE);
2210 }
2211 }
2212 }
2213
2214 /* Send the NCCREATE message */
2215 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_NCCREATE, 0, (LPARAM) Cs);
2216 if (!Result)
2217 {
2218 ERR("co_UserCreateWindowEx(): NCCREATE message failed\n");
2219 goto cleanup;
2220 }
2221
2222 /* Send the WM_NCCALCSIZE message */
2223 {
2224 // RECT rc;
2225 MaxPos.x = Window->rcWindow.left;
2226 MaxPos.y = Window->rcWindow.top;
2227
2228 Result = co_WinPosGetNonClientSize(Window, &Window->rcWindow, &Window->rcClient);
2229 //rc = Window->rcWindow;
2230 //Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM)&rc);
2231 //Window->rcClient = rc;
2232
2233 RECTL_vOffsetRect(&Window->rcWindow, MaxPos.x - Window->rcWindow.left,
2234 MaxPos.y - Window->rcWindow.top);
2235 }
2236
2237 /* Send the WM_CREATE message. */
2238 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_CREATE, 0, (LPARAM) Cs);
2239 if (Result == (LRESULT)-1)
2240 {
2241 ERR("co_UserCreateWindowEx(): WM_CREATE message failed\n");
2242 goto cleanup;
2243 }
2244
2245 /* Send the EVENT_OBJECT_CREATE event */
2246 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2247
2248 /* By setting the flag below it can be examined to determine if the window
2249 was created successfully and a valid pwnd was passed back to caller since
2250 from here the function has to succeed. */
2251 Window->state2 |= WNDS2_WMCREATEMSGPROCESSED;
2252
2253 /* Send the WM_SIZE and WM_MOVE messages. */
2254 if (!(Window->state & WNDS_SENDSIZEMOVEMSGS))
2255 {
2256 co_WinPosSendSizeMove(Window);
2257 }
2258
2259 /* Show or maybe minimize or maximize the window. */
2260
2261 style = IntSetStyle( Window, 0, WS_MAXIMIZE | WS_MINIMIZE );
2262 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2263 {
2264 RECTL NewPos;
2265 UINT SwFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
2266
2267 SwFlag = co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2268 SwFlag |= SWP_NOZORDER|SWP_FRAMECHANGED; /* Frame always gets changed */
2269 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || UserGetActiveWindow()) SwFlag |= SWP_NOACTIVATE;
2270 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2271 NewPos.right, NewPos.bottom, SwFlag);
2272 }
2273
2274 /* Send the WM_PARENTNOTIFY message */
2275 IntSendParentNotify(Window, WM_CREATE);
2276
2277 /* Notify the shell that a new window was created */
2278 if ((!hWndParent) && (!hWndOwner))
2279 {
2280 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0);
2281 }
2282
2283 /* Initialize and show the window's scrollbars */
2284 if (Window->style & WS_VSCROLL)
2285 {
2286 co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE);
2287 }
2288 if (Window->style & WS_HSCROLL)
2289 {
2290 co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE);
2291 }
2292
2293 /* Show the new window */
2294 if (Cs->style & WS_VISIBLE)
2295 {
2296 if (Window->style & WS_MAXIMIZE)
2297 dwShowMode = SW_SHOW;
2298 else if (Window->style & WS_MINIMIZE)
2299 dwShowMode = SW_SHOWMINIMIZED;
2300
2301 co_WinPosShowWindow(Window, dwShowMode);
2302
2303 if (Window->ExStyle & WS_EX_MDICHILD)
2304 {
2305 ASSERT(ParentWindow);
2306 if(!ParentWindow)
2307 goto cleanup;
2308 co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0);
2309 /* ShowWindow won't activate child windows */
2310 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2311 }
2312 }
2313
2314 TRACE("co_UserCreateWindowEx(): Created window %p\n", hWnd);
2315 ret = Window;
2316
2317 cleanup:
2318 if (!ret)
2319 {
2320 TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2321 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2322 if (Window)
2323 co_UserDestroyWindow(Window);
2324 else if (Class)
2325 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2326 }
2327
2328 if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
2329 if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
2330 if (pszName) UserHeapFree(pszName);
2331 if (pszClass) UserHeapFree(pszClass);
2332
2333 if (Window)
2334 {
2335 UserDerefObjectCo(Window);
2336 }
2337 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2338
2339 return ret;
2340 }
2341
2342 NTSTATUS
2343 NTAPI
2344 ProbeAndCaptureLargeString(
2345 OUT PLARGE_STRING plstrSafe,
2346 IN PLARGE_STRING plstrUnsafe)
2347 {
2348 LARGE_STRING lstrTemp;
2349 PVOID pvBuffer = NULL;
2350
2351 _SEH2_TRY
2352 {
2353 /* Probe and copy the string */
2354 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2355 lstrTemp = *plstrUnsafe;
2356 }
2357 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2358 {
2359 /* Fail */
2360 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2361 }
2362 _SEH2_END
2363
2364 if (lstrTemp.Length != 0)
2365 {
2366 /* Allocate a buffer from paged pool */
2367 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2368 if (!pvBuffer)
2369 {
2370 return STATUS_NO_MEMORY;
2371 }
2372
2373 _SEH2_TRY
2374 {
2375 /* Probe and copy the buffer */
2376 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2377 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2378 }
2379 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2380 {
2381 /* Cleanup and fail */
2382 ExFreePoolWithTag(pvBuffer, TAG_STRING);
2383 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2384 }
2385 _SEH2_END
2386 }
2387
2388 /* Set the output string */
2389 plstrSafe->Buffer = pvBuffer;
2390 plstrSafe->Length = lstrTemp.Length;
2391 plstrSafe->MaximumLength = lstrTemp.Length;
2392
2393 return STATUS_SUCCESS;
2394 }
2395
2396 /**
2397 * \todo Allow passing plstrClassName as ANSI.
2398 */
2399 HWND
2400 NTAPI
2401 NtUserCreateWindowEx(
2402 DWORD dwExStyle,
2403 PLARGE_STRING plstrClassName,
2404 PLARGE_STRING plstrClsVersion,
2405 PLARGE_STRING plstrWindowName,
2406 DWORD dwStyle,
2407 int x,
2408 int y,
2409 int nWidth,
2410 int nHeight,
2411 HWND hWndParent,
2412 HMENU hMenu,
2413 HINSTANCE hInstance,
2414 LPVOID lpParam,
2415 DWORD dwFlags,
2416 PVOID acbiBuffer)
2417 {
2418 NTSTATUS Status;
2419 LARGE_STRING lstrWindowName;
2420 LARGE_STRING lstrClassName;
2421 UNICODE_STRING ustrClassName;
2422 CREATESTRUCTW Cs;
2423 HWND hwnd = NULL;
2424 PWND pwnd;
2425
2426 lstrWindowName.Buffer = NULL;
2427 lstrClassName.Buffer = NULL;
2428
2429 ASSERT(plstrWindowName);
2430
2431 if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2432 {
2433 /* check hMenu is valid handle */
2434 if (hMenu && !ValidateHandle(hMenu, TYPE_MENU))
2435 {
2436 /* error is set in ValidateHandle */
2437 return NULL;
2438 }
2439 }
2440
2441 /* Copy the window name to kernel mode */
2442 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2443 if (!NT_SUCCESS(Status))
2444 {
2445 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2446 SetLastNtError(Status);
2447 return NULL;
2448 }
2449
2450 plstrWindowName = &lstrWindowName;
2451
2452 /* Check if the class is an atom */
2453 if (IS_ATOM(plstrClassName))
2454 {
2455 /* It is, pass the atom in the UNICODE_STRING */
2456 ustrClassName.Buffer = (PVOID)plstrClassName;
2457 ustrClassName.Length = 0;
2458 ustrClassName.MaximumLength = 0;
2459 }
2460 else
2461 {
2462 /* It's not, capture the class name */
2463 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2464 if (!NT_SUCCESS(Status))
2465 {
2466 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2467 /* Set last error, cleanup and return */
2468 SetLastNtError(Status);
2469 goto cleanup;
2470 }
2471
2472 /* We pass it on as a UNICODE_STRING */
2473 ustrClassName.Buffer = lstrClassName.Buffer;
2474 ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2475 ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
2476 }
2477
2478 /* Fill the CREATESTRUCTW */
2479 /* we will keep here the original parameters */
2480 Cs.style = dwStyle;
2481 Cs.lpCreateParams = lpParam;
2482 Cs.hInstance = hInstance;
2483 Cs.hMenu = hMenu;
2484 Cs.hwndParent = hWndParent;
2485 Cs.cx = nWidth;
2486 Cs.cy = nHeight;
2487 Cs.x = x;
2488 Cs.y = y;
2489 Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
2490 if (IS_ATOM(plstrClassName))
2491 Cs.lpszClass = (LPCWSTR) plstrClassName;
2492 else
2493 Cs.lpszClass = (LPCWSTR) plstrClassName->Buffer;
2494 Cs.dwExStyle = dwExStyle;
2495
2496 UserEnterExclusive();
2497
2498 /* Call the internal function */
2499 pwnd = co_UserCreateWindowEx(&Cs, &ustrClassName, plstrWindowName, acbiBuffer);
2500
2501 if(!pwnd)
2502 {
2503 ERR("co_UserCreateWindowEx failed!\n");
2504 }
2505 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2506
2507 UserLeave();
2508
2509 cleanup:
2510 if (lstrWindowName.Buffer)
2511 {
2512 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2513 }
2514 if (lstrClassName.Buffer)
2515 {
2516 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2517 }
2518
2519 return hwnd;
2520 }
2521
2522
2523 BOOLEAN FASTCALL co_UserDestroyWindow(PWND Window)
2524 {
2525 HWND hWnd;
2526 PWND pwndTemp;
2527 PTHREADINFO ti;
2528 MSG msg;
2529
2530 ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
2531
2532 hWnd = Window->head.h;
2533 ti = PsGetCurrentThreadWin32Thread();
2534
2535 TRACE("co_UserDestroyWindow \n");
2536
2537 /* Check for owner thread */
2538 if ( Window->head.pti != PsGetCurrentThreadWin32Thread())
2539 {
2540 /* Check if we are destroying the desktop window */
2541 if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
2542 {
2543 EngSetLastError(ERROR_ACCESS_DENIED);
2544 return FALSE;
2545 }
2546 }
2547
2548 /* If window was created successfully and it is hooked */
2549 if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
2550 {
2551 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0))
2552 {
2553 ERR("Destroy Window WH_CBT Call Hook return!\n");
2554 return FALSE;
2555 }
2556 }
2557
2558 if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
2559 {
2560 if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2561 {
2562 if (Window->spwndOwner)
2563 {
2564 //ERR("DestroyWindow Owner out.\n");
2565 UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2566 }
2567 }
2568 }
2569
2570 /* Inform the parent */
2571 if (Window->style & WS_CHILD)
2572 {
2573 IntSendParentNotify(Window, WM_DESTROY);
2574 }
2575
2576 /* Look whether the focus is within the tree of windows we will
2577 * be destroying.
2578 */
2579 if (!co_WinPosShowWindow(Window, SW_HIDE))
2580 { // Rule #1.
2581 if (ti->MessageQueue->spwndActive == Window && ti->MessageQueue == IntGetFocusMessageQueue())
2582 {
2583 co_WinPosActivateOtherWindow(Window);
2584 }
2585 }
2586
2587 // Adjust last active.
2588 if ((pwndTemp = Window->spwndOwner))
2589 {
2590 while (pwndTemp->spwndOwner)
2591 pwndTemp = pwndTemp->spwndOwner;
2592
2593 if (pwndTemp->spwndLastActive == Window)
2594 pwndTemp->spwndLastActive = Window->spwndOwner;
2595 }
2596
2597 if (Window->spwndParent && IntIsWindow(Window->head.h))
2598 {
2599 if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
2600 {
2601 if (!IntIsTopLevelWindow(Window))
2602 {
2603 //ERR("DestroyWindow Parent out.\n");
2604 UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2605 }
2606 }
2607 }
2608
2609 if (Window->head.pti->MessageQueue->spwndActive == Window)
2610 Window->head.pti->MessageQueue->spwndActive = NULL;
2611 if (Window->head.pti->MessageQueue->spwndFocus == Window)
2612 Window->head.pti->MessageQueue->spwndFocus = NULL;
2613 if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
2614 Window->head.pti->MessageQueue->spwndActivePrev = NULL;
2615 if (Window->head.pti->MessageQueue->spwndCapture == Window)
2616 Window->head.pti->MessageQueue->spwndCapture = NULL;
2617
2618 /*
2619 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2620 */
2621
2622 if ((ti != NULL) && (ti->pDeskInfo != NULL))
2623 {
2624 if (ti->pDeskInfo->hShellWindow == hWnd)
2625 {
2626 ERR("Destroying the ShellWindow!\n");
2627 ti->pDeskInfo->hShellWindow = NULL;
2628 }
2629 }
2630
2631 IntEngWindowChanged(Window, WOC_DELETE);
2632
2633 if (!IntIsWindow(Window->head.h))
2634 {
2635 return TRUE;
2636 }
2637
2638 /* Recursively destroy owned windows */
2639
2640 if (! (Window->style & WS_CHILD))
2641 {
2642 for (;;)
2643 {
2644 BOOL GotOne = FALSE;
2645 HWND *Children;
2646 HWND *ChildHandle;
2647 PWND Child, Desktop;
2648
2649 Desktop = IntIsDesktopWindow(Window) ? Window :
2650 UserGetWindowObject(IntGetDesktopWindow());
2651 Children = IntWinListChildren(Desktop);
2652
2653 if (Children)
2654 {
2655 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
2656 {
2657 Child = UserGetWindowObject(*ChildHandle);
2658 if (Child == NULL)
2659 continue;
2660 if (Child->spwndOwner != Window)
2661 {
2662 continue;
2663 }
2664
2665 if (IntWndBelongsToThread(Child, PsGetCurrentThreadWin32Thread()))
2666 {
2667 USER_REFERENCE_ENTRY ChildRef;
2668 UserRefObjectCo(Child, &ChildRef); // Temp HACK?
2669 co_UserDestroyWindow(Child);
2670 UserDerefObjectCo(Child); // Temp HACK?
2671
2672 GotOne = TRUE;
2673 continue;
2674 }
2675
2676 if (Child->spwndOwner != NULL)
2677 {
2678 Child->spwndOwner = NULL;
2679 }
2680
2681 }
2682 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
2683 }
2684 if (! GotOne)
2685 {
2686 break;
2687 }
2688 }
2689 }
2690
2691 /* Generate mouse move message for the next window */
2692 msg.message = WM_MOUSEMOVE;
2693 msg.wParam = UserGetMouseButtonsState();
2694 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2695 msg.pt = gpsi->ptCursor;
2696 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
2697
2698 if (!IntIsWindow(Window->head.h))
2699 {
2700 return TRUE;
2701 }
2702
2703 /* Destroy the window storage */
2704 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
2705
2706 return TRUE;
2707 }
2708
2709
2710 /*
2711 * @implemented
2712 */
2713 BOOLEAN APIENTRY
2714 NtUserDestroyWindow(HWND Wnd)
2715 {
2716 PWND Window;
2717 DECLARE_RETURN(BOOLEAN);
2718 BOOLEAN ret;
2719 USER_REFERENCE_ENTRY Ref;
2720
2721 TRACE("Enter NtUserDestroyWindow\n");
2722 UserEnterExclusive();
2723
2724 if (!(Window = UserGetWindowObject(Wnd)))
2725 {
2726 RETURN(FALSE);
2727 }
2728
2729 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
2730 ret = co_UserDestroyWindow(Window);
2731 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
2732
2733 RETURN(ret);
2734
2735 CLEANUP:
2736 TRACE("Leave NtUserDestroyWindow, ret=%u\n", _ret_);
2737 UserLeave();
2738 END_CLEANUP;
2739 }
2740
2741
2742 static HWND FASTCALL
2743 IntFindWindow(PWND Parent,
2744 PWND ChildAfter,
2745 RTL_ATOM ClassAtom,
2746 PUNICODE_STRING WindowName)
2747 {
2748 BOOL CheckWindowName;
2749 HWND *List, *phWnd;
2750 HWND Ret = NULL;
2751 UNICODE_STRING CurrentWindowName;
2752
2753 ASSERT(Parent);
2754
2755 CheckWindowName = WindowName->Buffer != 0;
2756
2757 if((List = IntWinListChildren(Parent)))
2758 {
2759 phWnd = List;
2760 if(ChildAfter)
2761 {
2762 /* skip handles before and including ChildAfter */
2763 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2764 ;
2765 }
2766
2767 /* search children */
2768 while(*phWnd)
2769 {
2770 PWND Child;
2771 if(!(Child = UserGetWindowObject(*(phWnd++))))
2772 {
2773 continue;
2774 }
2775
2776 /* Do not send WM_GETTEXT messages in the kernel mode version!
2777 The user mode version however calls GetWindowText() which will
2778 send WM_GETTEXT messages to windows belonging to its processes */
2779 if (!ClassAtom || Child->pcls->atomClassName == ClassAtom)
2780 {
2781 // FIXME: LARGE_STRING truncated
2782 CurrentWindowName.Buffer = Child->strName.Buffer;
2783 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
2784 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
2785 if(!CheckWindowName ||
2786 (Child->strName.Length < 0xFFFF &&
2787 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
2788 {
2789 Ret = Child->head.h;
2790 break;
2791 }
2792 }
2793 }
2794 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2795 }
2796
2797 return Ret;
2798 }
2799
2800 /*
2801 * FUNCTION:
2802 * Searches a window's children for a window with the specified
2803 * class and name
2804 * ARGUMENTS:
2805 * hwndParent = The window whose childs are to be searched.
2806 * NULL = desktop
2807 * HWND_MESSAGE = message-only windows
2808 *
2809 * hwndChildAfter = Search starts after this child window.
2810 * NULL = start from beginning
2811 *
2812 * ucClassName = Class name to search for
2813 * Reguired parameter.
2814 *
2815 * ucWindowName = Window name
2816 * ->Buffer == NULL = don't care
2817 *
2818 * RETURNS:
2819 * The HWND of the window if it was found, otherwise NULL
2820 */
2821 /*
2822 * @implemented
2823 */
2824 HWND APIENTRY
2825 NtUserFindWindowEx(HWND hwndParent,
2826 HWND hwndChildAfter,
2827 PUNICODE_STRING ucClassName,
2828 PUNICODE_STRING ucWindowName,
2829 DWORD dwUnknown)
2830 {
2831 PWND Parent, ChildAfter;
2832 UNICODE_STRING ClassName = {0}, WindowName = {0};
2833 HWND Desktop, Ret = NULL;
2834 BOOL DoMessageWnd = FALSE;
2835 RTL_ATOM ClassAtom = (RTL_ATOM)0;
2836 DECLARE_RETURN(HWND);
2837
2838 TRACE("Enter NtUserFindWindowEx\n");
2839 UserEnterShared();
2840
2841 if (ucClassName != NULL || ucWindowName != NULL)
2842 {
2843 _SEH2_TRY
2844 {
2845 if (ucClassName != NULL)
2846 {
2847 ClassName = ProbeForReadUnicodeString(ucClassName);
2848 if (ClassName.Length != 0)
2849 {
2850 ProbeForRead(ClassName.Buffer,
2851 ClassName.Length,
2852 sizeof(WCHAR));
2853 }
2854 else if (!IS_ATOM(ClassName.Buffer))
2855 {
2856 EngSetLastError(ERROR_INVALID_PARAMETER);
2857 _SEH2_LEAVE;
2858 }
2859
2860 if (!IntGetAtomFromStringOrAtom(&ClassName,
2861 &ClassAtom))
2862 {
2863 _SEH2_LEAVE;
2864 }
2865 }
2866
2867 if (ucWindowName != NULL)
2868 {
2869 WindowName = ProbeForReadUnicodeString(ucWindowName);
2870 if (WindowName.Length != 0)
2871 {
2872 ProbeForRead(WindowName.Buffer,
2873 WindowName.Length,
2874 sizeof(WCHAR));
2875 }
2876 }
2877 }
2878 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2879 {
2880 SetLastNtError(_SEH2_GetExceptionCode());
2881 _SEH2_YIELD(RETURN(NULL));
2882 }
2883 _SEH2_END;
2884
2885 if (ucClassName != NULL)
2886 {
2887 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
2888 !IS_ATOM(ClassName.Buffer))
2889 {
2890 EngSetLastError(ERROR_INVALID_PARAMETER);
2891 RETURN(NULL);
2892 }
2893 else if (ClassAtom == (RTL_ATOM)0)
2894 {
2895 /* LastError code was set by IntGetAtomFromStringOrAtom */
2896 RETURN(NULL);
2897 }
2898 }
2899 }
2900
2901 Desktop = IntGetCurrentThreadDesktopWindow();
2902
2903 if(hwndParent == NULL)
2904 {
2905 hwndParent = Desktop;
2906 DoMessageWnd = TRUE;
2907 }
2908 else if(hwndParent == HWND_MESSAGE)
2909 {
2910 hwndParent = IntGetMessageWindow();
2911 }
2912
2913 if(!(Parent = UserGetWindowObject(hwndParent)))
2914 {
2915 RETURN( NULL);
2916 }
2917
2918 ChildAfter = NULL;
2919 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
2920 {
2921 RETURN( NULL);
2922 }
2923
2924 _SEH2_TRY
2925 {
2926 if(Parent->head.h == Desktop)
2927 {
2928 HWND *List, *phWnd;
2929 PWND TopLevelWindow;
2930 BOOLEAN CheckWindowName;
2931 BOOLEAN WindowMatches;
2932 BOOLEAN ClassMatches;
2933
2934 /* windows searches through all top-level windows if the parent is the desktop
2935 window */
2936
2937 if((List = IntWinListChildren(Parent)))
2938 {
2939 phWnd = List;
2940
2941 if(ChildAfter)
2942 {
2943 /* skip handles before and including ChildAfter */
2944 while(*phWnd && (*(phWnd++) != ChildAfter->head.h))
2945 ;
2946 }
2947
2948 CheckWindowName = WindowName.Buffer != 0;
2949
2950 /* search children */
2951 while(*phWnd)
2952 {
2953 UNICODE_STRING ustr;
2954
2955 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
2956 {
2957 continue;
2958 }
2959
2960 /* Do not send WM_GETTEXT messages in the kernel mode version!
2961 The user mode version however calls GetWindowText() which will
2962 send WM_GETTEXT messages to windows belonging to its processes */
2963 ustr.Buffer = TopLevelWindow->strName.Buffer;
2964 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
2965 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
2966 WindowMatches = !CheckWindowName ||
2967 (TopLevelWindow->strName.Length < 0xFFFF &&
2968 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
2969 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
2970 ClassAtom == TopLevelWindow->pcls->atomClassName;
2971
2972 if (WindowMatches && ClassMatches)
2973 {
2974 Ret = TopLevelWindow->head.h;
2975 break;
2976 }
2977
2978 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
2979 {
2980 /* window returns the handle of the top-level window, in case it found
2981 the child window */
2982 Ret = TopLevelWindow->head.h;
2983 break;
2984 }
2985
2986 }
2987 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2988 }
2989 }
2990 else
2991 {
2992 ERR("FindWindowEx: Not Desktop Parent!\n");
2993 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
2994 }
2995
2996 if (Ret == NULL && DoMessageWnd)
2997 {
2998 PWND MsgWindows;
2999
3000 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3001 {
3002 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3003 }
3004 }
3005 }
3006 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3007 {
3008 SetLastNtError(_SEH2_GetExceptionCode());
3009 Ret = NULL;
3010 }
3011 _SEH2_END;
3012
3013 RETURN( Ret);
3014
3015 CLEANUP:
3016 TRACE("Leave NtUserFindWindowEx, ret %p\n", _ret_);
3017 UserLeave();
3018 END_CLEANUP;
3019 }
3020
3021
3022 /*
3023 * @implemented
3024 */
3025 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
3026 {
3027 PWND WndAncestor, Parent;
3028
3029 if (Wnd->head.h == IntGetDesktopWindow())
3030 {
3031 return NULL;
3032 }
3033
3034 switch (Type)
3035 {
3036 case GA_PARENT:
3037 {
3038 WndAncestor = Wnd->spwndParent;
3039 break;
3040 }
3041
3042 case GA_ROOT:
3043 {
3044 WndAncestor = Wnd;
3045 Parent = NULL;
3046
3047 for(;;)
3048 {
3049 if(!(Parent = WndAncestor->spwndParent))
3050 {
3051 break;
3052 }
3053 if(IntIsDesktopWindow(Parent))
3054 {
3055 break;
3056 }
3057
3058 WndAncestor = Parent;
3059 }
3060 break;
3061 }
3062
3063 case GA_ROOTOWNER:
3064 {
3065 WndAncestor = Wnd;
3066
3067 for (;;)
3068 {
3069 Parent = IntGetParent(WndAncestor);
3070
3071 if (!Parent)
3072 {
3073 break;
3074 }
3075
3076 WndAncestor = Parent;
3077 }
3078 break;
3079 }
3080
3081 default:
3082 {
3083 return NULL;
3084 }
3085 }
3086
3087 return WndAncestor;
3088 }
3089
3090 /*
3091 * @implemented
3092 */
3093 HWND APIENTRY
3094 NtUserGetAncestor(HWND hWnd, UINT Type)
3095 {
3096 PWND Window, Ancestor;
3097 DECLARE_RETURN(HWND);
3098
3099 TRACE("Enter NtUserGetAncestor\n");
3100 UserEnterExclusive();
3101
3102 if (!(Window = UserGetWindowObject(hWnd)))
3103 {
3104 RETURN(NULL);
3105 }
3106
3107 Ancestor = UserGetAncestor(Window, Type);
3108 /* faxme: can UserGetAncestor ever return NULL for a valid window? */
3109
3110 RETURN(Ancestor ? Ancestor->head.h : NULL);
3111
3112 CLEANUP:
3113 TRACE("Leave NtUserGetAncestor, ret=%p\n", _ret_);
3114 UserLeave();
3115 END_CLEANUP;
3116 }
3117
3118 ////
3119 //// ReactOS work around! Keep it the sames as in Combo.c and Controls.h
3120 ////
3121 /* combo state struct */
3122 typedef struct
3123 {
3124 HWND self;
3125 HWND owner;
3126 UINT dwStyle;
3127 HWND hWndEdit;
3128 HWND hWndLBox;
3129 UINT wState;
3130 HFONT hFont;
3131 RECT textRect;
3132 RECT buttonRect;
3133 RECT droppedRect;
3134 INT droppedIndex;
3135 INT fixedOwnerDrawHeight;
3136 INT droppedWidth; /* last two are not used unless set */
3137 INT editHeight; /* explicitly */
3138 LONG UIState;
3139 } HEADCOMBO,*LPHEADCOMBO;
3140
3141 // Window Extra data container.
3142 typedef struct _WND2CBOX
3143 {
3144 WND;
3145 LPHEADCOMBO pCBox;
3146 } WND2CBOX, *PWND2CBOX;
3147
3148 #define CBF_BUTTONDOWN 0x0002
3149 ////
3150 ////
3151 ////
3152 BOOL
3153 APIENTRY
3154 NtUserGetComboBoxInfo(
3155 HWND hWnd,
3156 PCOMBOBOXINFO pcbi)
3157 {
3158 PWND Wnd;
3159 PPROCESSINFO ppi;
3160 BOOL NotSameppi = FALSE;
3161 BOOL Ret = TRUE;
3162 DECLARE_RETURN(BOOL);
3163
3164 TRACE("Enter NtUserGetComboBoxInfo\n");
3165 UserEnterShared();
3166
3167 if (!(Wnd = UserGetWindowObject(hWnd)))
3168 {
3169 RETURN( FALSE );
3170 }
3171 _SEH2_TRY
3172 {
3173 if(pcbi)
3174 {
3175 ProbeForWrite(pcbi,
3176 sizeof(COMBOBOXINFO),
3177 1);
3178 }
3179 }
3180 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3181 {
3182 SetLastNtError(_SEH2_GetExceptionCode());
3183 _SEH2_YIELD(RETURN(FALSE));
3184 }
3185 _SEH2_END;
3186
3187 if (pcbi->cbSize < sizeof(COMBOBOXINFO))
3188 {
3189 EngSetLastError(ERROR_INVALID_PARAMETER);
3190 RETURN(FALSE);
3191 }
3192
3193 // Pass the user pointer, it was already probed.
3194 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_COMBOBOX]) && Wnd->fnid != FNID_COMBOBOX)
3195 {
3196 RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi));
3197 }
3198
3199 ppi = PsGetCurrentProcessWin32Process();
3200 NotSameppi = ppi != Wnd->head.pti->ppi;
3201 if (NotSameppi)
3202 {
3203 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3204 }
3205
3206 _SEH2_TRY
3207 {
3208 LPHEADCOMBO lphc = ((PWND2CBOX)Wnd)->pCBox;
3209 pcbi->rcItem = lphc->textRect;
3210 pcbi->rcButton = lphc->buttonRect;
3211 pcbi->stateButton = 0;
3212 if (lphc->wState & CBF_BUTTONDOWN)
3213 pcbi->stateButton |= STATE_SYSTEM_PRESSED;
3214 if (RECTL_bIsEmptyRect(&lphc->buttonRect))
3215 pcbi->stateButton |= STATE_SYSTEM_INVISIBLE;
3216 pcbi->hwndCombo = lphc->self;
3217 pcbi->hwndItem = lphc->hWndEdit;
3218 pcbi->hwndList = lphc->hWndLBox;
3219 }
3220 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3221 {
3222 Ret = FALSE;
3223 SetLastNtError(_SEH2_GetExceptionCode());
3224 }
3225 _SEH2_END;
3226
3227 RETURN( Ret);
3228
3229 CLEANUP:
3230 if (NotSameppi) KeDetachProcess();
3231 TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_);
3232 UserLeave();
3233 END_CLEANUP;
3234 }
3235
3236 ////
3237 //// ReactOS work around! Keep it the sames as in Listbox.c
3238 ////
3239 /* Listbox structure */
3240 typedef struct
3241 {
3242 HWND self; /* Our own window handle */
3243 HWND owner; /* Owner window to send notifications to */
3244 UINT style; /* Window style */
3245 INT width; /* Window width */
3246 INT height; /* Window height */
3247 VOID *items; /* Array of items */
3248 INT nb_items; /* Number of items */
3249 INT top_item; /* Top visible item */
3250 INT selected_item; /* Selected item */
3251 INT focus_item; /* Item that has the focus */
3252 INT anchor_item; /* Anchor item for extended selection */
3253 INT item_height; /* Default item height */
3254 INT page_size; /* Items per listbox page */
3255 INT column_width; /* Column width for multi-column listboxes */
3256 } LB_DESCR;
3257
3258 // Window Extra data container.
3259 typedef struct _WND2LB
3260 {
3261 WND;
3262 LB_DESCR * pLBiv;
3263 } WND2LB, *PWND2LB;
3264 ////
3265 ////
3266 ////
3267 DWORD
3268 APIENTRY
3269 NtUserGetListBoxInfo(
3270 HWND hWnd)
3271 {
3272 PWND Wnd;
3273 PPROCESSINFO ppi;
3274 BOOL NotSameppi = FALSE;
3275 DWORD Ret = 0;
3276 DECLARE_RETURN(DWORD);
3277
3278 TRACE("Enter NtUserGetListBoxInfo\n");
3279 UserEnterShared();
3280
3281 if (!(Wnd = UserGetWindowObject(hWnd)))
3282 {
3283 RETURN( 0 );
3284 }
3285
3286 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && Wnd->fnid != FNID_LISTBOX)
3287 {
3288 RETURN( (DWORD) co_IntSendMessage( Wnd->head.h, LB_GETLISTBOXINFO, 0, 0 ));
3289 }
3290
3291 // wine lisbox:test_GetListBoxInfo lb_getlistboxinfo = 0, should not send a message!
3292 ppi = PsGetCurrentProcessWin32Process();
3293 NotSameppi = ppi != Wnd->head.pti->ppi;
3294 if (NotSameppi)
3295 {
3296 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb