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