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