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