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 * PROGRAMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
8 */
9
10 #include <win32k.h>
11 #include <immdev.h>
12 #include <unaligned.h>
13
14 DBG_DEFAULT_CHANNEL(UserWnd);
15
16 INT gNestedWindowLimit = 50;
17
18 PWINDOWLIST gpwlList = NULL;
19 PWINDOWLIST gpwlCache = NULL;
20
21 /* HELPER FUNCTIONS ***********************************************************/
22
23 PVOID FASTCALL
IntReAllocatePoolWithTag(POOL_TYPE PoolType,PVOID pOld,SIZE_T cbOld,SIZE_T cbNew,ULONG Tag)24 IntReAllocatePoolWithTag(
25 POOL_TYPE PoolType,
26 PVOID pOld,
27 SIZE_T cbOld,
28 SIZE_T cbNew,
29 ULONG Tag)
30 {
31 PVOID pNew = ExAllocatePoolWithTag(PoolType, cbNew, Tag);
32 if (!pNew)
33 return NULL;
34
35 RtlCopyMemory(pNew, pOld, min(cbOld, cbNew));
36 ExFreePoolWithTag(pOld, Tag);
37 return pNew;
38 }
39
UserUpdateUiState(PWND Wnd,WPARAM wParam)40 BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam)
41 {
42 WORD Action = LOWORD(wParam);
43 WORD Flags = HIWORD(wParam);
44
45 if (Flags & ~(UISF_HIDEFOCUS | UISF_HIDEACCEL | UISF_ACTIVE))
46 {
47 EngSetLastError(ERROR_INVALID_PARAMETER);
48 return FALSE;
49 }
50
51 switch (Action)
52 {
53 case UIS_INITIALIZE:
54 EngSetLastError(ERROR_INVALID_PARAMETER);
55 return FALSE;
56
57 case UIS_SET:
58 if (Flags & UISF_HIDEFOCUS)
59 Wnd->HideFocus = TRUE;
60 if (Flags & UISF_HIDEACCEL)
61 Wnd->HideAccel = TRUE;
62 break;
63
64 case UIS_CLEAR:
65 if (Flags & UISF_HIDEFOCUS)
66 Wnd->HideFocus = FALSE;
67 if (Flags & UISF_HIDEACCEL)
68 Wnd->HideAccel = FALSE;
69 break;
70 }
71
72 return TRUE;
73 }
74
IntGetWindowObject(HWND hWnd)75 PWND FASTCALL IntGetWindowObject(HWND hWnd)
76 {
77 PWND Window;
78
79 if (!hWnd) return NULL;
80
81 Window = UserGetWindowObject(hWnd);
82 if (Window)
83 Window->head.cLockObj++;
84
85 return Window;
86 }
87
VerifyWnd(PWND pWnd)88 PWND FASTCALL VerifyWnd(PWND pWnd)
89 {
90 ULONG Error;
91
92 if (!pWnd ||
93 (pWnd->state & WNDS_DESTROYED) ||
94 (pWnd->state2 & WNDS2_INDESTROY))
95 {
96 return NULL;
97 }
98
99 Error = EngGetLastError();
100
101 if (UserObjectInDestroy(UserHMGetHandle(pWnd)))
102 pWnd = NULL;
103
104 EngSetLastError(Error);
105 return pWnd;
106 }
107
ValidateHwndNoErr(HWND hWnd)108 PWND FASTCALL ValidateHwndNoErr(HWND hWnd)
109 {
110 PWND Window;
111
112 if (!hWnd)
113 return NULL;
114
115 Window = (PWND)UserGetObjectNoErr(gHandleTable, hWnd, TYPE_WINDOW);
116 if (!Window || (Window->state & WNDS_DESTROYED))
117 return NULL;
118
119 return Window;
120 }
121
122 /* Temp HACK */
123 // Win: ValidateHwnd
UserGetWindowObject(HWND hWnd)124 PWND FASTCALL UserGetWindowObject(HWND hWnd)
125 {
126 PWND Window;
127
128 if (!hWnd)
129 {
130 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
131 return NULL;
132 }
133
134 Window = (PWND)UserGetObject(gHandleTable, hWnd, TYPE_WINDOW);
135 if (!Window || 0 != (Window->state & WNDS_DESTROYED))
136 {
137 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
138 return NULL;
139 }
140
141 return Window;
142 }
143
144 ULONG FASTCALL
IntSetStyle(PWND pwnd,ULONG set_bits,ULONG clear_bits)145 IntSetStyle( PWND pwnd, ULONG set_bits, ULONG clear_bits )
146 {
147 ULONG styleOld, styleNew;
148 styleOld = pwnd->style;
149 styleNew = (pwnd->style | set_bits) & ~clear_bits;
150 if (styleNew == styleOld) return styleNew;
151 pwnd->style = styleNew;
152 if ((styleOld ^ styleNew) & WS_VISIBLE) // State Change.
153 {
154 if (styleOld & WS_VISIBLE) pwnd->head.pti->cVisWindows--;
155 if (styleNew & WS_VISIBLE) pwnd->head.pti->cVisWindows++;
156 DceResetActiveDCEs( pwnd );
157 }
158 return styleOld;
159 }
160
161 /*
162 * IntIsWindow
163 *
164 * The function determines whether the specified window handle identifies
165 * an existing window.
166 *
167 * Parameters
168 * hWnd
169 * Handle to the window to test.
170 *
171 * Return Value
172 * If the window handle identifies an existing window, the return value
173 * is TRUE. If the window handle does not identify an existing window,
174 * the return value is FALSE.
175 */
176
177 BOOL FASTCALL
IntIsWindow(HWND hWnd)178 IntIsWindow(HWND hWnd)
179 {
180 PWND Window;
181
182 if (!(Window = UserGetWindowObject(hWnd)))
183 {
184 return FALSE;
185 }
186
187 return TRUE;
188 }
189
190 BOOL FASTCALL
IntIsWindowVisible(PWND Wnd)191 IntIsWindowVisible(PWND Wnd)
192 {
193 PWND Temp = Wnd;
194 for (;;)
195 {
196 if (!Temp) return TRUE;
197 if (!(Temp->style & WS_VISIBLE)) break;
198 if (Temp->style & WS_MINIMIZE && Temp != Wnd) break;
199 if (Temp->fnid == FNID_DESKTOP) return TRUE;
200 Temp = Temp->spwndParent;
201 }
202 return FALSE;
203 }
204
205 PWND FASTCALL
IntGetParent(PWND Wnd)206 IntGetParent(PWND Wnd)
207 {
208 if (Wnd->style & WS_POPUP)
209 {
210 return Wnd->spwndOwner;
211 }
212 else if (Wnd->style & WS_CHILD)
213 {
214 return Wnd->spwndParent;
215 }
216
217 return NULL;
218 }
219
220 BOOL
221 FASTCALL
IntEnableWindow(HWND hWnd,BOOL bEnable)222 IntEnableWindow( HWND hWnd, BOOL bEnable )
223 {
224 BOOL Update;
225 PWND pWnd;
226 UINT bIsDisabled;
227
228 if(!(pWnd = UserGetWindowObject(hWnd)))
229 {
230 return FALSE;
231 }
232
233 /* check if updating is needed */
234 bIsDisabled = !!(pWnd->style & WS_DISABLED);
235 Update = bIsDisabled;
236
237 if (bEnable)
238 {
239 IntSetStyle( pWnd, 0, WS_DISABLED );
240 }
241 else
242 {
243 Update = !bIsDisabled;
244
245 co_IntSendMessage( hWnd, WM_CANCELMODE, 0, 0);
246
247 /* Remove keyboard focus from that window if it had focus */
248 if (hWnd == IntGetThreadFocusWindow())
249 {
250 TRACE("IntEnableWindow SF NULL\n");
251 co_UserSetFocus(NULL);
252 }
253 IntSetStyle( pWnd, WS_DISABLED, 0 );
254 }
255
256 if (Update)
257 {
258 IntNotifyWinEvent(EVENT_OBJECT_STATECHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, 0);
259 co_IntSendMessage(hWnd, WM_ENABLE, (LPARAM)bEnable, 0);
260 }
261 // Return nonzero if it was disabled, or zero if it wasn't:
262 return bIsDisabled;
263 }
264
265 /*
266 * IntWinListChildren
267 *
268 * Compile a list of all child window handles from given window.
269 *
270 * Remarks
271 * This function is similar to Wine WIN_ListChildren. The caller
272 * must free the returned list with ExFreePool.
273 */
274
275 HWND* FASTCALL
IntWinListChildren(PWND Window)276 IntWinListChildren(PWND Window)
277 {
278 PWND Child;
279 HWND *List;
280 UINT Index, NumChildren = 0;
281
282 if (!Window) return NULL;
283
284 for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
285 {
286 ++NumChildren;
287 }
288
289 List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), USERTAG_WINDOWLIST);
290 if(!List)
291 {
292 ERR("Failed to allocate memory for children array\n");
293 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
294 return NULL;
295 }
296
297 Index = 0;
298 for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
299 {
300 List[Index++] = UserHMGetHandle(Child);
301 }
302 List[Index] = NULL;
303
304 return List;
305 }
306
307 static BOOL
IntWndIsDefaultIme(_In_ PWND Window)308 IntWndIsDefaultIme(_In_ PWND Window)
309 {
310 PTHREADINFO pti = Window->head.pti;
311
312 return (IS_IMM_MODE() && !(pti->TIF_flags & TIF_INCLEANUP) &&
313 Window == pti->spwndDefaultIme);
314 }
315
316 HWND* FASTCALL
IntWinListOwnedPopups(PWND Window)317 IntWinListOwnedPopups(PWND Window)
318 {
319 PWND Child, Desktop;
320 HWND *List;
321 UINT Index, NumOwned = 0;
322
323 Desktop = co_GetDesktopWindow(Window);
324 if (!Desktop)
325 return NULL;
326
327 for (Child = Desktop->spwndChild; Child; Child = Child->spwndNext)
328 {
329 if (Child->spwndOwner == Window && !IntWndIsDefaultIme(Child))
330 ++NumOwned;
331 }
332
333 List = ExAllocatePoolWithTag(PagedPool, (NumOwned + 1) * sizeof(HWND), USERTAG_WINDOWLIST);
334 if (!List)
335 {
336 ERR("Failed to allocate memory for children array\n");
337 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
338 return NULL;
339 }
340
341 Index = 0;
342 for (Child = Desktop->spwndChild; Child; Child = Child->spwndNext)
343 {
344 if (Child->spwndOwner == Window && !IntWndIsDefaultIme(Child))
345 List[Index++] = UserHMGetHandle(Child);
346 }
347 List[Index] = NULL;
348
349 return List;
350 }
351
352 PWND FASTCALL
IntGetNonChildAncestor(PWND pWnd)353 IntGetNonChildAncestor(PWND pWnd)
354 {
355 while(pWnd && (pWnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
356 pWnd = pWnd->spwndParent;
357 return pWnd;
358 }
359
360 BOOL FASTCALL
IntIsTopLevelWindow(PWND pWnd)361 IntIsTopLevelWindow(PWND pWnd)
362 {
363 if ( pWnd->spwndParent &&
364 pWnd->spwndParent == co_GetDesktopWindow(pWnd) ) return TRUE;
365 return FALSE;
366 }
367
368 BOOL FASTCALL
IntValidateOwnerDepth(PWND Wnd,PWND Owner)369 IntValidateOwnerDepth(PWND Wnd, PWND Owner)
370 {
371 INT Depth = 1;
372 for (;;)
373 {
374 if ( !Owner ) return gNestedWindowLimit >= Depth;
375 if (Owner == Wnd) break;
376 Owner = Owner->spwndOwner;
377 Depth++;
378 }
379 return FALSE;
380 }
381
382 HWND FASTCALL
IntGetWindow(HWND hWnd,UINT uCmd)383 IntGetWindow(HWND hWnd,
384 UINT uCmd)
385 {
386 PWND Wnd, FoundWnd;
387 HWND Ret = NULL;
388
389 Wnd = ValidateHwndNoErr(hWnd);
390 if (!Wnd)
391 return NULL;
392
393 FoundWnd = NULL;
394 switch (uCmd)
395 {
396 case GW_OWNER:
397 if (Wnd->spwndOwner != NULL)
398 FoundWnd = Wnd->spwndOwner;
399 break;
400
401 case GW_HWNDFIRST:
402 if(Wnd->spwndParent != NULL)
403 {
404 FoundWnd = Wnd->spwndParent;
405 if (FoundWnd->spwndChild != NULL)
406 FoundWnd = FoundWnd->spwndChild;
407 }
408 break;
409 case GW_HWNDNEXT:
410 if (Wnd->spwndNext != NULL)
411 FoundWnd = Wnd->spwndNext;
412 break;
413
414 case GW_HWNDPREV:
415 if (Wnd->spwndPrev != NULL)
416 FoundWnd = Wnd->spwndPrev;
417 break;
418
419 case GW_CHILD:
420 if (Wnd->spwndChild != NULL)
421 FoundWnd = Wnd->spwndChild;
422 break;
423
424 case GW_HWNDLAST:
425 FoundWnd = Wnd;
426 while ( FoundWnd->spwndNext != NULL)
427 FoundWnd = FoundWnd->spwndNext;
428 break;
429
430 default:
431 Wnd = NULL;
432 break;
433 }
434
435 if (FoundWnd != NULL)
436 Ret = UserHMGetHandle(FoundWnd);
437 return Ret;
438 }
439
IntGetWindowContextHelpId(PWND pWnd)440 DWORD FASTCALL IntGetWindowContextHelpId( PWND pWnd )
441 {
442 DWORD HelpId;
443
444 do
445 {
446 HelpId = HandleToUlong(UserGetProp(pWnd, gpsi->atomContextHelpIdProp, TRUE));
447 if (!HelpId) break;
448 pWnd = IntGetParent(pWnd);
449 }
450 while (pWnd && pWnd->fnid != FNID_DESKTOP);
451 return HelpId;
452 }
453
454
455 VOID
456 FASTCALL
457 IntRemoveTrackMouseEvent(
458 PDESKTOP pDesk);
459
460 /***********************************************************************
461 * IntSendDestroyMsg
462 */
IntSendDestroyMsg(HWND hWnd)463 static void IntSendDestroyMsg(HWND hWnd)
464 {
465 PTHREADINFO ti;
466 PWND Window;
467
468 ti = PsGetCurrentThreadWin32Thread();
469 Window = UserGetWindowObject(hWnd);
470
471 if (Window)
472 {
473 /*
474 * Look whether the focus is within the tree of windows
475 * we will be destroying.
476 */
477 // Rule #1
478 if ( ti->MessageQueue->spwndActive == Window || // Fixes CORE-106 RegSvr32 exit and return focus to CMD.
479 (ti->MessageQueue->spwndActive == NULL && ti->MessageQueue == IntGetFocusMessageQueue()) )
480 {
481 co_WinPosActivateOtherWindow(Window);
482 }
483
484 /* Fixes CMD properties closing and returning focus to CMD */
485 if (ti->MessageQueue->spwndFocus == Window)
486 {
487 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
488 {
489 co_UserSetFocus(Window->spwndParent);
490 }
491 else
492 {
493 co_UserSetFocus(NULL);
494 }
495 }
496
497 if (ti->MessageQueue->CaretInfo.hWnd == UserHMGetHandle(Window))
498 {
499 co_IntDestroyCaret(ti);
500 }
501
502 /* If the window being destroyed is currently tracked... */
503 if (ti->rpdesk && ti->rpdesk->spwndTrack == Window)
504 {
505 IntRemoveTrackMouseEvent(ti->rpdesk);
506 }
507 }
508
509 /* If the window being destroyed is the current clipboard owner... */
510 if (ti->ppi->prpwinsta != NULL && Window == ti->ppi->prpwinsta->spwndClipOwner)
511 {
512 /* ... make it release the clipboard */
513 UserClipboardRelease(Window);
514 }
515
516 /* Send the WM_DESTROY to the window */
517 co_IntSendMessage(hWnd, WM_DESTROY, 0, 0);
518
519 /*
520 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
521 * make sure that the window still exists when we come back.
522 */
523 if (IntIsWindow(hWnd))
524 {
525 HWND* pWndArray;
526 int i;
527
528 if (!(pWndArray = IntWinListChildren( Window ))) return;
529
530 for (i = 0; pWndArray[i]; i++)
531 {
532 if (IntIsWindow( pWndArray[i] )) IntSendDestroyMsg( pWndArray[i] );
533 }
534 ExFreePoolWithTag(pWndArray, USERTAG_WINDOWLIST);
535 }
536 else
537 {
538 TRACE("destroyed itself while in WM_DESTROY!\n");
539 }
540 }
541
542 static VOID
UserFreeWindowInfo(PTHREADINFO ti,PWND Wnd)543 UserFreeWindowInfo(PTHREADINFO ti, PWND Wnd)
544 {
545 PCLIENTINFO ClientInfo = GetWin32ClientInfo();
546
547 if (!Wnd) return;
548
549 if (ClientInfo->CallbackWnd.pWnd == DesktopHeapAddressToUser(Wnd))
550 {
551 ClientInfo->CallbackWnd.hWnd = NULL;
552 ClientInfo->CallbackWnd.pWnd = NULL;
553 }
554
555 if (Wnd->strName.Buffer != NULL)
556 {
557 Wnd->strName.Length = 0;
558 Wnd->strName.MaximumLength = 0;
559 DesktopHeapFree(Wnd->head.rpdesk,
560 Wnd->strName.Buffer);
561 Wnd->strName.Buffer = NULL;
562 }
563
564 // DesktopHeapFree(Wnd->head.rpdesk, Wnd);
565 // WindowObject->hWnd = NULL;
566 }
567
568 /***********************************************************************
569 * co_UserFreeWindow
570 *
571 * Destroy storage associated to a window. "Internals" p.358
572 *
573 * This is the "functional" DestroyWindows function i.e. all stuff
574 * done in CreateWindow is undone here and not in DestroyWindow :-P
575 */
co_UserFreeWindow(PWND Window,PPROCESSINFO ProcessData,PTHREADINFO ThreadData,BOOLEAN SendMessages)576 LRESULT co_UserFreeWindow(PWND Window,
577 PPROCESSINFO ProcessData,
578 PTHREADINFO ThreadData,
579 BOOLEAN SendMessages)
580 {
581 HWND *Children;
582 HWND *ChildHandle;
583 PWND Child;
584 PMENU Menu;
585 BOOLEAN BelongsToThreadData;
586 USER_REFERENCE_ENTRY Ref;
587
588 ASSERT(Window);
589
590 if(Window->state2 & WNDS2_INDESTROY)
591 {
592 TRACE("Tried to call co_UserFreeWindow() twice\n");
593 return 0;
594 }
595 Window->state2 |= WNDS2_INDESTROY;
596 Window->style &= ~WS_VISIBLE;
597 Window->head.pti->cVisWindows--;
598
599 /* remove the window already at this point from the thread window list so we
600 don't get into trouble when destroying the thread windows while we're still
601 in co_UserFreeWindow() */
602 if (!IsListEmpty(&Window->ThreadListEntry))
603 RemoveEntryList(&Window->ThreadListEntry);
604
605 BelongsToThreadData = IntWndBelongsToThread(Window, ThreadData);
606
607 IntDeRegisterShellHookWindow(UserHMGetHandle(Window));
608
609 /* free child windows */
610 Children = IntWinListChildren(Window);
611 if (Children)
612 {
613 for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
614 {
615 if ((Child = IntGetWindowObject(*ChildHandle)))
616 {
617 if (!IntWndBelongsToThread(Child, ThreadData))
618 {
619 /* send WM_DESTROY messages to windows not belonging to the same thread */
620 co_IntSendMessage( UserHMGetHandle(Child), WM_ASYNC_DESTROYWINDOW, 0, 0 );
621 }
622 else
623 co_UserFreeWindow(Child, ProcessData, ThreadData, SendMessages);
624
625 UserDereferenceObject(Child);
626 }
627 }
628 ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
629 }
630
631 if (SendMessages)
632 {
633 /*
634 * Clear the update region to make sure no WM_PAINT messages will be
635 * generated for this window while processing the WM_NCDESTROY.
636 */
637 co_UserRedrawWindow(Window, NULL, 0,
638 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
639 RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
640 if (BelongsToThreadData)
641 co_IntSendMessage(UserHMGetHandle(Window), WM_NCDESTROY, 0, 0);
642 }
643
644 UserClipboardFreeWindow(Window);
645
646 DestroyTimersForWindow(ThreadData, Window);
647
648 /* Unregister hot keys */
649 UnregisterWindowHotKeys(Window);
650
651 /* flush the message queue */
652 MsqRemoveWindowMessagesFromQueue(Window);
653
654 /* from now on no messages can be sent to this window anymore */
655 Window->state |= WNDS_DESTROYED;
656 Window->fnid |= FNID_FREED;
657
658 /* don't remove the WINDOWSTATUS_DESTROYING bit */
659
660 /* reset shell window handles */
661 if (ThreadData->rpdesk)
662 {
663 if (UserHMGetHandle(Window) == ThreadData->rpdesk->rpwinstaParent->ShellWindow)
664 ThreadData->rpdesk->rpwinstaParent->ShellWindow = NULL;
665
666 if (UserHMGetHandle(Window) == ThreadData->rpdesk->rpwinstaParent->ShellListView)
667 ThreadData->rpdesk->rpwinstaParent->ShellListView = NULL;
668 }
669
670 if (ThreadData->spwndDefaultIme &&
671 ThreadData->spwndDefaultIme->spwndOwner == Window)
672 {
673 WndSetOwner(ThreadData->spwndDefaultIme, NULL);
674 }
675
676 if (IS_IMM_MODE() && Window == ThreadData->spwndDefaultIme)
677 {
678 UserAssignmentUnlock((PVOID*)&(ThreadData->spwndDefaultIme));
679 }
680
681 /* Fixes dialog test_focus breakage due to r66237. */
682 if (ThreadData->MessageQueue->spwndFocus == Window)
683 ThreadData->MessageQueue->spwndFocus = NULL;
684
685 if (ThreadData->MessageQueue->spwndActive == Window)
686 ThreadData->MessageQueue->spwndActive = NULL;
687
688 if (ThreadData->MessageQueue->spwndCapture == Window)
689 {
690 IntReleaseCapture();
691 }
692
693 //// Now kill those remaining "PAINTING BUG: Thread marked as containing dirty windows" spam!!!
694 if ( Window->hrgnUpdate != NULL || Window->state & WNDS_INTERNALPAINT )
695 {
696 MsqDecPaintCountQueue(Window->head.pti);
697 if (Window->hrgnUpdate > HRGN_WINDOW && GreIsHandleValid(Window->hrgnUpdate))
698 {
699 IntGdiSetRegionOwner(Window->hrgnUpdate, GDI_OBJ_HMGR_POWNED);
700 GreDeleteObject(Window->hrgnUpdate);
701 }
702 Window->hrgnUpdate = NULL;
703 Window->state &= ~WNDS_INTERNALPAINT;
704 }
705
706 if (Window->state & (WNDS_SENDERASEBACKGROUND|WNDS_SENDNCPAINT))
707 {
708 Window->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_SENDNCPAINT);
709 }
710
711 if ( ((Window->style & (WS_CHILD|WS_POPUP)) != WS_CHILD) &&
712 Window->IDMenu &&
713 (Menu = UserGetMenuObject((HMENU)Window->IDMenu)))
714 {
715 TRACE("UFW: IDMenu %p\n",Window->IDMenu);
716 IntDestroyMenuObject(Menu, TRUE);
717 Window->IDMenu = 0;
718 }
719
720 if (Window->SystemMenu
721 && (Menu = UserGetMenuObject(Window->SystemMenu)))
722 {
723 IntDestroyMenuObject(Menu, TRUE);
724 Window->SystemMenu = (HMENU)0;
725 }
726
727 DceFreeWindowDCE(Window); /* Always do this to catch orphaned DCs */
728
729 IntUnlinkWindow(Window);
730
731 if (Window->PropListItems)
732 {
733 UserRemoveWindowProps(Window);
734 TRACE("Window->PropListItems %lu\n",Window->PropListItems);
735 ASSERT(Window->PropListItems==0);
736 }
737
738 /* Kill any reference to linked windows. Prev & Next are taken care of in IntUnlinkWindow */
739 WndSetOwner(Window, NULL);
740 WndSetParent(Window, NULL);
741 WndSetChild(Window, NULL);
742 WndSetLastActive(Window, NULL);
743
744 UserRefObjectCo(Window, &Ref);
745 UserMarkObjectDestroy(Window);
746
747 IntDestroyScrollBars(Window);
748
749 if (Window->pcls->atomClassName == gaGuiConsoleWndClass)
750 {
751 /* Count only console windows manually */
752 co_IntUserManualGuiCheck(FALSE);
753 }
754
755 /* dereference the class */
756 NT_ASSERT(Window->head.pti != NULL);
757 IntDereferenceClass(Window->pcls,
758 Window->head.pti->pDeskInfo,
759 Window->head.pti->ppi);
760 Window->pcls = NULL;
761
762 if (Window->hrgnClip)
763 {
764 IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED);
765 GreDeleteObject(Window->hrgnClip);
766 Window->hrgnClip = NULL;
767 }
768 Window->head.pti->cWindows--;
769
770 // ASSERT(Window != NULL);
771 UserFreeWindowInfo(Window->head.pti, Window);
772
773 UserDerefObjectCo(Window);
774 UserDeleteObject(UserHMGetHandle(Window), TYPE_WINDOW);
775
776 return 0;
777 }
778
779 //
780 // Same as User32:IntGetWndProc.
781 //
782 WNDPROC FASTCALL
IntGetWindowProc(PWND pWnd,BOOL Ansi)783 IntGetWindowProc(PWND pWnd,
784 BOOL Ansi)
785 {
786 INT i;
787 PCLS Class;
788 WNDPROC gcpd, Ret = 0;
789
790 ASSERT(UserIsEnteredExclusive());
791
792 Class = pWnd->pcls;
793
794 if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
795 {
796 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
797 {
798 if (GETPFNSERVER(i) == pWnd->lpfnWndProc)
799 {
800 if (Ansi)
801 Ret = GETPFNCLIENTA(i);
802 else
803 Ret = GETPFNCLIENTW(i);
804 }
805 }
806 return Ret;
807 }
808
809 if (Class->fnid == FNID_EDIT)
810 Ret = pWnd->lpfnWndProc;
811 else
812 {
813 Ret = pWnd->lpfnWndProc;
814
815 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
816 {
817 if (Ansi)
818 {
819 if (GETPFNCLIENTW(Class->fnid) == pWnd->lpfnWndProc)
820 Ret = GETPFNCLIENTA(Class->fnid);
821 }
822 else
823 {
824 if (GETPFNCLIENTA(Class->fnid) == pWnd->lpfnWndProc)
825 Ret = GETPFNCLIENTW(Class->fnid);
826 }
827 }
828 if ( Ret != pWnd->lpfnWndProc)
829 return Ret;
830 }
831 if ( Ansi == !!(pWnd->state & WNDS_ANSIWINDOWPROC) )
832 return Ret;
833
834 gcpd = (WNDPROC)UserGetCPD(
835 pWnd,
836 (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWindow,
837 (ULONG_PTR)Ret);
838
839 return (gcpd ? gcpd : Ret);
840 }
841
842 static WNDPROC
IntSetWindowProc(PWND pWnd,WNDPROC NewWndProc,BOOL Ansi)843 IntSetWindowProc(PWND pWnd,
844 WNDPROC NewWndProc,
845 BOOL Ansi)
846 {
847 INT i;
848 PCALLPROCDATA CallProc;
849 PCLS Class;
850 WNDPROC Ret, chWndProc = NULL;
851
852 // Retrieve previous window proc.
853 Ret = IntGetWindowProc(pWnd, Ansi);
854
855 Class = pWnd->pcls;
856
857 if (IsCallProcHandle(NewWndProc))
858 {
859 CallProc = UserGetObject(gHandleTable, NewWndProc, TYPE_CALLPROC);
860 if (CallProc)
861 { // Reset new WndProc.
862 NewWndProc = CallProc->pfnClientPrevious;
863 // Reset Ansi from CallProc handle. This is expected with wine "deftest".
864 Ansi = !!(CallProc->wType & UserGetCPDU2A);
865 }
866 }
867 // Switch from Client Side call to Server Side call if match. Ref: "deftest".
868 for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
869 {
870 if (GETPFNCLIENTW(i) == NewWndProc)
871 {
872 chWndProc = GETPFNSERVER(i);
873 break;
874 }
875 if (GETPFNCLIENTA(i) == NewWndProc)
876 {
877 chWndProc = GETPFNSERVER(i);
878 break;
879 }
880 }
881 // If match, set/reset to Server Side and clear ansi.
882 if (chWndProc)
883 {
884 pWnd->lpfnWndProc = chWndProc;
885 pWnd->Unicode = TRUE;
886 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
887 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
888 }
889 else
890 {
891 pWnd->Unicode = !Ansi;
892 // Handle the state change in here.
893 if (Ansi)
894 pWnd->state |= WNDS_ANSIWINDOWPROC;
895 else
896 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
897
898 if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
899 pWnd->state &= ~WNDS_SERVERSIDEWINDOWPROC;
900
901 if (!NewWndProc) NewWndProc = pWnd->lpfnWndProc;
902
903 if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
904 {
905 if (Ansi)
906 {
907 if (GETPFNCLIENTW(Class->fnid) == NewWndProc)
908 chWndProc = GETPFNCLIENTA(Class->fnid);
909 }
910 else
911 {
912 if (GETPFNCLIENTA(Class->fnid) == NewWndProc)
913 chWndProc = GETPFNCLIENTW(Class->fnid);
914 }
915 }
916 // Now set the new window proc.
917 pWnd->lpfnWndProc = (chWndProc ? chWndProc : NewWndProc);
918 }
919 return Ret;
920 }
921
922
923 /* INTERNAL ******************************************************************/
924
925 ////
926 // This fixes a check for children messages that need paint while searching the parents messages!
927 // Fixes wine msg:test_paint_messages:WmParentErasePaint ..
928 ////
929 BOOL FASTCALL
IntIsChildWindow(PWND Parent,PWND BaseWindow)930 IntIsChildWindow(PWND Parent, PWND BaseWindow)
931 {
932 PWND Window = BaseWindow;
933 do
934 {
935 if ( Window == NULL || (Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD )
936 return FALSE;
937
938 Window = Window->spwndParent;
939 }
940 while(Parent != Window);
941 return TRUE;
942 }
943 ////
944
945 /* Link the window into siblings list. Children and parent are kept in place. */
946 VOID FASTCALL
IntLinkWindow(PWND Wnd,PWND WndInsertAfter)947 IntLinkWindow(
948 PWND Wnd,
949 PWND WndInsertAfter /* Set to NULL if top sibling */
950 )
951 {
952 if (Wnd == WndInsertAfter)
953 {
954 ERR("Trying to link window 0x%p to itself\n", Wnd);
955 ASSERT(WndInsertAfter != Wnd);
956 return;
957 }
958
959 WndSetPrev(Wnd, WndInsertAfter);
960 if (Wnd->spwndPrev)
961 {
962 /* Link after WndInsertAfter */
963 ASSERT(Wnd != WndInsertAfter->spwndNext);
964 WndSetNext(Wnd, WndInsertAfter->spwndNext);
965 if (Wnd->spwndNext)
966 WndSetPrev(Wnd->spwndNext, Wnd);
967
968 ASSERT(Wnd != Wnd->spwndPrev);
969 WndSetNext(Wnd->spwndPrev, Wnd);
970 }
971 else
972 {
973 /* Link at the top */
974 ASSERT(Wnd != Wnd->spwndParent->spwndChild);
975 WndSetNext(Wnd, Wnd->spwndParent->spwndChild);
976 if (Wnd->spwndNext)
977 WndSetPrev(Wnd->spwndNext, Wnd);
978
979 WndSetChild(Wnd->spwndParent, Wnd);
980 }
981 }
982
983 /*
984 Note: Wnd->spwndParent can be null if it is the desktop.
985 */
IntLinkHwnd(PWND Wnd,HWND hWndPrev)986 VOID FASTCALL IntLinkHwnd(PWND Wnd, HWND hWndPrev)
987 {
988 if (hWndPrev == HWND_NOTOPMOST)
989 {
990 if (!(Wnd->ExStyle & WS_EX_TOPMOST) && (Wnd->ExStyle2 & WS_EX2_LINKED))
991 return; /* nothing to do */
992 Wnd->ExStyle &= ~WS_EX_TOPMOST;
993 hWndPrev = HWND_TOP; /* fallback to the HWND_TOP case */
994 }
995
996 IntUnlinkWindow(Wnd); /* unlink it from the previous location */
997
998 if (hWndPrev == HWND_BOTTOM)
999 {
1000 /* Link in the bottom of the list */
1001 PWND WndInsertAfter;
1002
1003 WndInsertAfter = Wnd->spwndParent->spwndChild;
1004 while (WndInsertAfter && WndInsertAfter->spwndNext)
1005 {
1006 WndInsertAfter = WndInsertAfter->spwndNext;
1007 }
1008
1009 IntLinkWindow(Wnd, WndInsertAfter);
1010 Wnd->ExStyle &= ~WS_EX_TOPMOST;
1011 }
1012 else if (hWndPrev == HWND_TOPMOST)
1013 {
1014 /* Link in the top of the list */
1015 IntLinkWindow(Wnd, NULL);
1016 Wnd->ExStyle |= WS_EX_TOPMOST;
1017 }
1018 else if (hWndPrev == HWND_TOP)
1019 {
1020 /* Link it after the last topmost window */
1021 PWND WndInsertBefore;
1022
1023 WndInsertBefore = Wnd->spwndParent->spwndChild;
1024
1025 if (!(Wnd->ExStyle & WS_EX_TOPMOST)) /* put it above the first non-topmost window */
1026 {
1027 while (WndInsertBefore != NULL && WndInsertBefore->spwndNext != NULL)
1028 {
1029 if (!(WndInsertBefore->ExStyle & WS_EX_TOPMOST))
1030 break;
1031
1032 if (WndInsertBefore == Wnd->spwndOwner) /* keep it above owner */
1033 {
1034 Wnd->ExStyle |= WS_EX_TOPMOST;
1035 break;
1036 }
1037 WndInsertBefore = WndInsertBefore->spwndNext;
1038 }
1039 }
1040
1041 IntLinkWindow(Wnd, WndInsertBefore ? WndInsertBefore->spwndPrev : NULL);
1042 }
1043 else
1044 {
1045 /* Link it after hWndPrev */
1046 PWND WndInsertAfter;
1047
1048 WndInsertAfter = UserGetWindowObject(hWndPrev);
1049 /* Are we called with an erroneous handle */
1050 if (WndInsertAfter == NULL)
1051 {
1052 /* Link in a default position */
1053 IntLinkHwnd(Wnd, HWND_TOP);
1054 return;
1055 }
1056
1057 if (Wnd == WndInsertAfter)
1058 {
1059 ERR("Trying to link window 0x%p to itself\n", Wnd);
1060 ASSERT(WndInsertAfter != Wnd);
1061 // FIXME: IntUnlinkWindow(Wnd) was already called. Continuing as is seems wrong!
1062 }
1063 else
1064 {
1065 IntLinkWindow(Wnd, WndInsertAfter);
1066 }
1067
1068 /* Fix the WS_EX_TOPMOST flag */
1069 if (!(WndInsertAfter->ExStyle & WS_EX_TOPMOST))
1070 {
1071 Wnd->ExStyle &= ~WS_EX_TOPMOST;
1072 }
1073 else
1074 {
1075 if (WndInsertAfter->spwndNext &&
1076 (WndInsertAfter->spwndNext->ExStyle & WS_EX_TOPMOST))
1077 {
1078 Wnd->ExStyle |= WS_EX_TOPMOST;
1079 }
1080 }
1081 }
1082 Wnd->ExStyle2 |= WS_EX2_LINKED;
1083 }
1084
1085 VOID FASTCALL
IntProcessOwnerSwap(PWND Wnd,PWND WndNewOwner,PWND WndOldOwner)1086 IntProcessOwnerSwap(PWND Wnd, PWND WndNewOwner, PWND WndOldOwner)
1087 {
1088 if (WndOldOwner)
1089 {
1090 if (Wnd->head.pti != WndOldOwner->head.pti)
1091 {
1092 if (!WndNewOwner ||
1093 Wnd->head.pti == WndNewOwner->head.pti ||
1094 WndOldOwner->head.pti != WndNewOwner->head.pti )
1095 {
1096 //ERR("ProcessOwnerSwap Old out.\n");
1097 UserAttachThreadInput(Wnd->head.pti, WndOldOwner->head.pti, FALSE);
1098 }
1099 }
1100 }
1101 if (WndNewOwner)
1102 {
1103 if (Wnd->head.pti != WndNewOwner->head.pti)
1104 {
1105 if (!WndOldOwner ||
1106 WndOldOwner->head.pti != WndNewOwner->head.pti )
1107 {
1108 //ERR("ProcessOwnerSwap New in.\n");
1109 UserAttachThreadInput(Wnd->head.pti, WndNewOwner->head.pti, TRUE);
1110 }
1111 }
1112 }
1113 // FIXME: System Tray checks.
1114 }
1115
1116 static
1117 HWND FASTCALL
IntSetOwner(HWND hWnd,HWND hWndNewOwner)1118 IntSetOwner(HWND hWnd, HWND hWndNewOwner)
1119 {
1120 PWND Wnd, WndOldOwner, WndNewOwner;
1121 HWND ret;
1122
1123 Wnd = IntGetWindowObject(hWnd);
1124 if(!Wnd)
1125 return NULL;
1126
1127 WndOldOwner = Wnd->spwndOwner;
1128
1129 ret = WndOldOwner ? UserHMGetHandle(WndOldOwner) : 0;
1130 WndNewOwner = UserGetWindowObject(hWndNewOwner);
1131
1132 if (!WndNewOwner && hWndNewOwner)
1133 {
1134 EngSetLastError(ERROR_INVALID_PARAMETER);
1135 ret = NULL;
1136 goto Error;
1137 }
1138
1139 /* if parent belongs to a different thread and the window isn't */
1140 /* top-level, attach the two threads */
1141 IntProcessOwnerSwap(Wnd, WndNewOwner, WndOldOwner);
1142
1143 if (IntValidateOwnerDepth(Wnd, WndNewOwner))
1144 {
1145 WndSetOwner(Wnd, WndNewOwner);
1146 }
1147 else
1148 {
1149 IntProcessOwnerSwap(Wnd, WndOldOwner, WndNewOwner);
1150 EngSetLastError(ERROR_INVALID_PARAMETER);
1151 ret = NULL;
1152 }
1153 Error:
1154 UserDereferenceObject(Wnd);
1155 return ret;
1156 }
1157
1158 PWND FASTCALL
co_IntSetParent(PWND Wnd,PWND WndNewParent)1159 co_IntSetParent(PWND Wnd, PWND WndNewParent)
1160 {
1161 PWND WndOldParent, pWndExam;
1162 BOOL WasVisible;
1163 POINT pt;
1164 int swFlags = SWP_NOSIZE|SWP_NOZORDER;
1165
1166 ASSERT(Wnd);
1167 ASSERT(WndNewParent);
1168 ASSERT_REFS_CO(Wnd);
1169 ASSERT_REFS_CO(WndNewParent);
1170
1171 if (Wnd == Wnd->head.rpdesk->spwndMessage)
1172 {
1173 EngSetLastError(ERROR_ACCESS_DENIED);
1174 return NULL;
1175 }
1176
1177 /* Some applications try to set a child as a parent */
1178 if (IntIsChildWindow(Wnd, WndNewParent))
1179 {
1180 TRACE("IntSetParent try to set a child as a parent.\n");
1181 EngSetLastError( ERROR_INVALID_PARAMETER );
1182 return NULL;
1183 }
1184
1185 pWndExam = WndNewParent; // Load parent Window to examine.
1186 // Now test for set parent to parent hit.
1187 while (pWndExam)
1188 {
1189 if (Wnd == pWndExam)
1190 {
1191 TRACE("IntSetParent Failed Test for set parent to parent!\n");
1192 EngSetLastError(ERROR_INVALID_PARAMETER);
1193 return NULL;
1194 }
1195 pWndExam = pWndExam->spwndParent;
1196 }
1197
1198 /*
1199 * Windows hides the window first, then shows it again
1200 * including the WM_SHOWWINDOW messages and all
1201 */
1202 WasVisible = co_WinPosShowWindow(Wnd, SW_HIDE);
1203
1204 /* Window must belong to current process */
1205 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
1206 {
1207 ERR("IntSetParent Window must belong to current process!\n");
1208 return NULL;
1209 }
1210
1211 WndOldParent = Wnd->spwndParent;
1212
1213 if ( WndOldParent &&
1214 WndOldParent->ExStyle & WS_EX_LAYOUTRTL)
1215 pt.x = Wnd->rcWindow.right;
1216 else
1217 pt.x = Wnd->rcWindow.left;
1218 pt.y = Wnd->rcWindow.top;
1219
1220 IntScreenToClient(WndOldParent, &pt);
1221
1222 if (WndOldParent) UserReferenceObject(WndOldParent); /* Caller must deref */
1223
1224 /* Even if WndNewParent == WndOldParent continue because the
1225 * child window (Wnd) should be moved to the top of the z-order */
1226
1227 /* Unlink the window from the siblings list */
1228 IntUnlinkWindow(Wnd);
1229 Wnd->ExStyle2 &= ~WS_EX2_LINKED;
1230
1231 /* Set the new parent */
1232 WndSetParent(Wnd, WndNewParent);
1233
1234 if (Wnd->style & WS_CHILD &&
1235 Wnd->spwndOwner &&
1236 Wnd->spwndOwner->ExStyle & WS_EX_TOPMOST)
1237 {
1238 ERR("SetParent Top Most from Pop up\n");
1239 Wnd->ExStyle |= WS_EX_TOPMOST;
1240 }
1241
1242 /* Link the window with its new siblings */
1243 IntLinkHwnd(Wnd,
1244 ((0 == (Wnd->ExStyle & WS_EX_TOPMOST) &&
1245 UserIsDesktopWindow(WndNewParent)) ? HWND_TOP : HWND_TOPMOST));
1246
1247 if ( WndNewParent == co_GetDesktopWindow(Wnd) &&
1248 !(Wnd->style & WS_CLIPSIBLINGS) )
1249 {
1250 Wnd->style |= WS_CLIPSIBLINGS;
1251 DceResetActiveDCEs(Wnd);
1252 }
1253
1254 /* if parent belongs to a different thread and the window isn't */
1255 /* top-level, attach the two threads */
1256 if ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1257 {
1258 if ( Wnd->spwndParent != co_GetDesktopWindow(Wnd))
1259 {
1260 if (WndOldParent && (Wnd->head.pti != WndOldParent->head.pti))
1261 {
1262 //ERR("SetParent Old out.\n");
1263 UserAttachThreadInput(Wnd->head.pti, WndOldParent->head.pti, FALSE);
1264 }
1265 }
1266 if ( WndNewParent != co_GetDesktopWindow(Wnd))
1267 {
1268 if (Wnd->head.pti != WndNewParent->head.pti)
1269 {
1270 //ERR("SetParent New in.\n");
1271 UserAttachThreadInput(Wnd->head.pti, WndNewParent->head.pti, TRUE);
1272 }
1273 }
1274 }
1275
1276 if (UserIsMessageWindow(WndOldParent) || UserIsMessageWindow(WndNewParent))
1277 swFlags |= SWP_NOACTIVATE;
1278
1279 IntNotifyWinEvent(EVENT_OBJECT_PARENTCHANGE, Wnd ,OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1280 /*
1281 * SetParent additionally needs to make hwnd the top window
1282 * in the z-order and send the expected WM_WINDOWPOSCHANGING and
1283 * WM_WINDOWPOSCHANGED notification messages.
1284 */
1285 //ERR("IntSetParent SetWindowPos 1\n");
1286 co_WinPosSetWindowPos( Wnd,
1287 (0 == (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
1288 pt.x, pt.y, 0, 0, swFlags);
1289 //ERR("IntSetParent SetWindowPos 2 X %d Y %d\n",pt.x, pt.y);
1290 if (WasVisible) co_WinPosShowWindow(Wnd, SW_SHOWNORMAL);
1291
1292 return WndOldParent;
1293 }
1294
1295 // Win: xxxSetParent
1296 HWND FASTCALL
co_UserSetParent(HWND hWndChild,HWND hWndNewParent)1297 co_UserSetParent(HWND hWndChild, HWND hWndNewParent)
1298 {
1299 PWND Wnd = NULL, WndParent = NULL, WndOldParent;
1300 HWND hWndOldParent = NULL;
1301 USER_REFERENCE_ENTRY Ref, ParentRef;
1302
1303 if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
1304 {
1305 EngSetLastError(ERROR_INVALID_PARAMETER);
1306 return NULL;
1307 }
1308
1309 if (hWndChild == IntGetDesktopWindow())
1310 {
1311 ERR("UserSetParent Access Denied!\n");
1312 EngSetLastError(ERROR_ACCESS_DENIED);
1313 return NULL;
1314 }
1315
1316 if (hWndNewParent)
1317 {
1318 if (!(WndParent = UserGetWindowObject(hWndNewParent)))
1319 {
1320 ERR("UserSetParent Bad New Parent!\n");
1321 return NULL;
1322 }
1323 }
1324 else
1325 {
1326 if (!(WndParent = UserGetWindowObject(IntGetDesktopWindow())))
1327 {
1328 return NULL;
1329 }
1330 }
1331
1332 if (!(Wnd = UserGetWindowObject(hWndChild)))
1333 {
1334 ERR("UserSetParent Bad Child!\n");
1335 return NULL;
1336 }
1337
1338 UserRefObjectCo(Wnd, &Ref);
1339 UserRefObjectCo(WndParent, &ParentRef);
1340 //ERR("Enter co_IntSetParent\n");
1341 WndOldParent = co_IntSetParent(Wnd, WndParent);
1342 //ERR("Leave co_IntSetParent\n");
1343 UserDerefObjectCo(WndParent);
1344 UserDerefObjectCo(Wnd);
1345
1346 if (WndOldParent)
1347 {
1348 hWndOldParent = UserHMGetHandle(WndOldParent);
1349 UserDereferenceObject(WndOldParent);
1350 }
1351
1352 return hWndOldParent;
1353 }
1354
1355 /* Unlink the window from siblings. Children and parent are kept in place. */
1356 VOID FASTCALL
IntUnlinkWindow(PWND Wnd)1357 IntUnlinkWindow(PWND Wnd)
1358 {
1359 ASSERT(Wnd != Wnd->spwndNext);
1360 ASSERT(Wnd != Wnd->spwndPrev);
1361
1362 if (Wnd->spwndNext)
1363 WndSetPrev(Wnd->spwndNext, Wnd->spwndPrev);
1364
1365 if (Wnd->spwndPrev)
1366 WndSetNext(Wnd->spwndPrev, Wnd->spwndNext);
1367
1368 if (Wnd->spwndParent && Wnd->spwndParent->spwndChild == Wnd)
1369 WndSetChild(Wnd->spwndParent, Wnd->spwndNext);
1370
1371 WndSetPrev(Wnd, NULL);
1372 WndSetNext(Wnd, NULL);
1373 }
1374
1375 // Win: ExpandWindowList
IntGrowHwndList(PWINDOWLIST * ppwl)1376 BOOL FASTCALL IntGrowHwndList(PWINDOWLIST *ppwl)
1377 {
1378 PWINDOWLIST pwlOld, pwlNew;
1379 SIZE_T ibOld, ibNew;
1380
1381 #define GROW_COUNT 8
1382 pwlOld = *ppwl;
1383 ibOld = (LPBYTE)pwlOld->phwndLast - (LPBYTE)pwlOld;
1384 ibNew = ibOld + GROW_COUNT * sizeof(HWND);
1385 #undef GROW_COUNT
1386 pwlNew = IntReAllocatePoolWithTag(PagedPool, pwlOld, ibOld, ibNew, USERTAG_WINDOWLIST);
1387 if (!pwlNew)
1388 return FALSE;
1389
1390 pwlNew->phwndLast = (HWND *)((LPBYTE)pwlNew + ibOld);
1391 pwlNew->phwndEnd = (HWND *)((LPBYTE)pwlNew + ibNew);
1392 *ppwl = pwlNew;
1393 return TRUE;
1394 }
1395
1396 // Win: InternalBuildHwndList
IntPopulateHwndList(PWINDOWLIST pwl,PWND pwnd,DWORD dwFlags)1397 PWINDOWLIST FASTCALL IntPopulateHwndList(PWINDOWLIST pwl, PWND pwnd, DWORD dwFlags)
1398 {
1399 ASSERT(!WL_IS_BAD(pwl));
1400
1401 for (; pwnd; pwnd = pwnd->spwndNext)
1402 {
1403 if (!pwl->pti || pwl->pti == pwnd->head.pti)
1404 {
1405 *(pwl->phwndLast) = UserHMGetHandle(pwnd);
1406 ++(pwl->phwndLast);
1407
1408 if (pwl->phwndLast == pwl->phwndEnd && !IntGrowHwndList(&pwl))
1409 break;
1410 }
1411
1412 if ((dwFlags & IACE_CHILDREN) && pwnd->spwndChild)
1413 {
1414 pwl = IntPopulateHwndList(pwl, pwnd->spwndChild, IACE_CHILDREN | IACE_LIST);
1415 if (WL_IS_BAD(pwl))
1416 break;
1417 }
1418
1419 if (!(dwFlags & IACE_LIST))
1420 break;
1421 }
1422
1423 return pwl;
1424 }
1425
1426 // Win: BuildHwndList
IntBuildHwndList(PWND pwnd,DWORD dwFlags,PTHREADINFO pti)1427 PWINDOWLIST FASTCALL IntBuildHwndList(PWND pwnd, DWORD dwFlags, PTHREADINFO pti)
1428 {
1429 PWINDOWLIST pwl;
1430 DWORD cbWL;
1431
1432 if (gpwlCache)
1433 {
1434 pwl = gpwlCache;
1435 gpwlCache = NULL;
1436 }
1437 else
1438 {
1439 #define INITIAL_COUNT 32
1440 cbWL = sizeof(WINDOWLIST) + (INITIAL_COUNT - 1) * sizeof(HWND);
1441 pwl = ExAllocatePoolWithTag(PagedPool, cbWL, USERTAG_WINDOWLIST);
1442 if (!pwl)
1443 return NULL;
1444
1445 pwl->phwndEnd = &pwl->ahwnd[INITIAL_COUNT];
1446 #undef INITIAL_COUNT
1447 }
1448
1449 pwl->pti = pti;
1450 pwl->phwndLast = pwl->ahwnd;
1451 pwl = IntPopulateHwndList(pwl, pwnd, dwFlags);
1452 if (WL_IS_BAD(pwl))
1453 {
1454 ExFreePoolWithTag(pwl, USERTAG_WINDOWLIST);
1455 return NULL;
1456 }
1457
1458 *(pwl->phwndLast) = HWND_TERMINATOR;
1459
1460 if (dwFlags & 0x8)
1461 {
1462 // TODO:
1463 }
1464
1465 pwl->pti = GetW32ThreadInfo();
1466 pwl->pNextList = gpwlList;
1467 gpwlList = pwl;
1468
1469 return pwl;
1470 }
1471
1472 // Win: FreeHwndList
IntFreeHwndList(PWINDOWLIST pwlTarget)1473 VOID FASTCALL IntFreeHwndList(PWINDOWLIST pwlTarget)
1474 {
1475 PWINDOWLIST pwl, *ppwl;
1476
1477 for (ppwl = &gpwlList; *ppwl; ppwl = &(*ppwl)->pNextList)
1478 {
1479 if (*ppwl != pwlTarget)
1480 continue;
1481
1482 *ppwl = pwlTarget->pNextList;
1483
1484 if (gpwlCache)
1485 {
1486 if (WL_CAPACITY(pwlTarget) > WL_CAPACITY(gpwlCache))
1487 {
1488 pwl = gpwlCache;
1489 gpwlCache = pwlTarget;
1490 ExFreePoolWithTag(pwl, USERTAG_WINDOWLIST);
1491 }
1492 else
1493 {
1494 ExFreePoolWithTag(pwlTarget, USERTAG_WINDOWLIST);
1495 }
1496 }
1497 else
1498 {
1499 gpwlCache = pwlTarget;
1500 }
1501
1502 break;
1503 }
1504 }
1505
1506 /* FUNCTIONS *****************************************************************/
1507
1508 /*
1509 * As best as I can figure, this function is used by EnumWindows,
1510 * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
1511 *
1512 * It's supposed to build a list of HWNDs to return to the caller.
1513 * We can figure out what kind of list by what parameters are
1514 * passed to us.
1515 */
1516 /*
1517 * @implemented
1518 */
1519 NTSTATUS
1520 NTAPI
NtUserBuildHwndList(HDESK hDesktop,HWND hwndParent,BOOLEAN bChildren,ULONG dwThreadId,ULONG cHwnd,HWND * phwndList,ULONG * pcHwndNeeded)1521 NtUserBuildHwndList(
1522 HDESK hDesktop,
1523 HWND hwndParent,
1524 BOOLEAN bChildren,
1525 ULONG dwThreadId,
1526 ULONG cHwnd,
1527 HWND* phwndList,
1528 ULONG* pcHwndNeeded)
1529 {
1530 NTSTATUS Status;
1531 ULONG dwCount = 0;
1532
1533 if (pcHwndNeeded == NULL)
1534 return STATUS_INVALID_PARAMETER;
1535
1536 UserEnterExclusive();
1537
1538 if (hwndParent || !dwThreadId)
1539 {
1540 PDESKTOP Desktop;
1541 PWND Parent, Window;
1542
1543 if(!hwndParent)
1544 {
1545 if(hDesktop == NULL && !(Desktop = IntGetActiveDesktop()))
1546 {
1547 Status = STATUS_INVALID_HANDLE;
1548 goto Quit;
1549 }
1550
1551 if(hDesktop)
1552 {
1553 Status = IntValidateDesktopHandle(hDesktop,
1554 UserMode,
1555 0,
1556 &Desktop);
1557 if(!NT_SUCCESS(Status))
1558 {
1559 Status = STATUS_INVALID_HANDLE;
1560 goto Quit;
1561 }
1562 }
1563 hwndParent = Desktop->DesktopWindow;
1564 }
1565 else
1566 {
1567 hDesktop = 0;
1568 }
1569
1570 if((Parent = UserGetWindowObject(hwndParent)) &&
1571 (Window = Parent->spwndChild))
1572 {
1573 BOOL bGoDown = TRUE;
1574
1575 Status = STATUS_SUCCESS;
1576 while(TRUE)
1577 {
1578 if (bGoDown)
1579 {
1580 if (dwCount++ < cHwnd && phwndList)
1581 {
1582 _SEH2_TRY
1583 {
1584 ProbeForWrite(phwndList, sizeof(HWND), 1);
1585 *phwndList = UserHMGetHandle(Window);
1586 phwndList++;
1587 }
1588 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1589 {
1590 Status = _SEH2_GetExceptionCode();
1591 }
1592 _SEH2_END
1593 if(!NT_SUCCESS(Status))
1594 {
1595 break;
1596 }
1597 }
1598 if (Window->spwndChild && bChildren)
1599 {
1600 Window = Window->spwndChild;
1601 continue;
1602 }
1603 bGoDown = FALSE;
1604 }
1605 if (Window->spwndNext)
1606 {
1607 Window = Window->spwndNext;
1608 bGoDown = TRUE;
1609 continue;
1610 }
1611 Window = Window->spwndParent;
1612 if (Window == Parent)
1613 {
1614 break;
1615 }
1616 }
1617 }
1618
1619 if(hDesktop)
1620 {
1621 ObDereferenceObject(Desktop);
1622 }
1623 }
1624 else // Build EnumThreadWindows list!
1625 {
1626 PETHREAD Thread;
1627 PTHREADINFO W32Thread;
1628 PWND Window;
1629 HWND *List = NULL;
1630
1631 Status = PsLookupThreadByThreadId(UlongToHandle(dwThreadId), &Thread);
1632 if (!NT_SUCCESS(Status))
1633 {
1634 ERR("Thread Id is not valid!\n");
1635 Status = STATUS_INVALID_PARAMETER;
1636 goto Quit;
1637 }
1638 if (!(W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread))
1639 {
1640 ObDereferenceObject(Thread);
1641 TRACE("Tried to enumerate windows of a non gui thread\n");
1642 Status = STATUS_INVALID_PARAMETER;
1643 goto Quit;
1644 }
1645
1646 // Do not use Thread link list due to co_UserFreeWindow!!!
1647 // Current = W32Thread->WindowListHead.Flink;
1648 // Fixes Api:CreateWindowEx tests!!!
1649 List = IntWinListChildren(UserGetDesktopWindow());
1650 if (List)
1651 {
1652 int i;
1653 for (i = 0; List[i]; i++)
1654 {
1655 Window = ValidateHwndNoErr(List[i]);
1656 if (Window && Window->head.pti == W32Thread)
1657 {
1658 if (dwCount < cHwnd && phwndList)
1659 {
1660 _SEH2_TRY
1661 {
1662 ProbeForWrite(phwndList, sizeof(HWND), 1);
1663 *phwndList = UserHMGetHandle(Window);
1664 phwndList++;
1665 }
1666 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1667 {
1668 Status = _SEH2_GetExceptionCode();
1669 }
1670 _SEH2_END
1671 if (!NT_SUCCESS(Status))
1672 {
1673 ERR("Failure to build window list!\n");
1674 break;
1675 }
1676 }
1677 dwCount++;
1678 }
1679 }
1680 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
1681 }
1682
1683 ObDereferenceObject(Thread);
1684 }
1685
1686 *pcHwndNeeded = dwCount;
1687 Status = STATUS_SUCCESS;
1688
1689 Quit:
1690 SetLastNtError(Status);
1691 UserLeave();
1692 return Status;
1693 }
1694
IntSendParentNotify(PWND pWindow,UINT msg)1695 static void IntSendParentNotify( PWND pWindow, UINT msg )
1696 {
1697 if ( (pWindow->style & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
1698 !(pWindow->ExStyle & WS_EX_NOPARENTNOTIFY))
1699 {
1700 if (VerifyWnd(pWindow->spwndParent) && !UserIsDesktopWindow(pWindow->spwndParent))
1701 {
1702 USER_REFERENCE_ENTRY Ref;
1703 UserRefObjectCo(pWindow->spwndParent, &Ref);
1704 co_IntSendMessage( UserHMGetHandle(pWindow->spwndParent),
1705 WM_PARENTNOTIFY,
1706 MAKEWPARAM( msg, pWindow->IDMenu),
1707 (LPARAM)UserHMGetHandle(pWindow) );
1708 UserDerefObjectCo(pWindow->spwndParent);
1709 }
1710 }
1711 }
1712
1713 void FASTCALL
IntFixWindowCoordinates(CREATESTRUCTW * Cs,PWND ParentWindow,DWORD * dwShowMode)1714 IntFixWindowCoordinates(CREATESTRUCTW* Cs, PWND ParentWindow, DWORD* dwShowMode)
1715 {
1716 #define IS_DEFAULT(x) ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
1717
1718 /* default positioning for overlapped windows */
1719 if(!(Cs->style & (WS_POPUP | WS_CHILD)))
1720 {
1721 PMONITOR pMonitor;
1722 PRTL_USER_PROCESS_PARAMETERS ProcessParams;
1723
1724 pMonitor = UserGetPrimaryMonitor();
1725
1726 /* Check if we don't have a monitor attached yet */
1727 if(pMonitor == NULL)
1728 {
1729 Cs->x = Cs->y = 0;
1730 Cs->cx = 800;
1731 Cs->cy = 600;
1732 return;
1733 }
1734
1735 ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
1736
1737 if (IS_DEFAULT(Cs->x))
1738 {
1739 if (!IS_DEFAULT(Cs->y)) *dwShowMode = Cs->y;
1740
1741 if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
1742 {
1743 Cs->x = ProcessParams->StartingX;
1744 Cs->y = ProcessParams->StartingY;
1745 }
1746 else
1747 {
1748 Cs->x = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CXSIZE) + UserGetSystemMetrics(SM_CXFRAME));
1749 Cs->y = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CYSIZE) + UserGetSystemMetrics(SM_CYFRAME));
1750 if (Cs->x > ((pMonitor->rcWork.right - pMonitor->rcWork.left) / 4) ||
1751 Cs->y > ((pMonitor->rcWork.bottom - pMonitor->rcWork.top) / 4))
1752 {
1753 /* reset counter and position */
1754 Cs->x = 0;
1755 Cs->y = 0;
1756 pMonitor->cWndStack = 0;
1757 }
1758 pMonitor->cWndStack++;
1759 }
1760 }
1761
1762 if (IS_DEFAULT(Cs->cx))
1763 {
1764 if (ProcessParams->WindowFlags & STARTF_USEPOSITION)
1765 {
1766 Cs->cx = ProcessParams->CountX;
1767 Cs->cy = ProcessParams->CountY;
1768 }
1769 else
1770 {
1771 Cs->cx = (pMonitor->rcWork.right - pMonitor->rcWork.left) * 3 / 4;
1772 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1773 }
1774 }
1775 /* neither x nor cx are default. Check the y values .
1776 * In the trace we see Outlook and Outlook Express using
1777 * cy set to CW_USEDEFAULT when opening the address book.
1778 */
1779 else if (IS_DEFAULT(Cs->cy))
1780 {
1781 TRACE("Strange use of CW_USEDEFAULT in nHeight\n");
1782 Cs->cy = (pMonitor->rcWork.bottom - pMonitor->rcWork.top) * 3 / 4;
1783 }
1784 }
1785 else
1786 {
1787 /* if CW_USEDEFAULT is set for non-overlapped windows, both values are set to zero */
1788 if(IS_DEFAULT(Cs->x))
1789 {
1790 Cs->x = 0;
1791 Cs->y = 0;
1792 }
1793 if(IS_DEFAULT(Cs->cx))
1794 {
1795 Cs->cx = 0;
1796 Cs->cy = 0;
1797 }
1798 }
1799
1800 #undef IS_DEFAULT
1801 }
1802
1803 /* Allocates and initializes a window */
IntCreateWindow(CREATESTRUCTW * Cs,PLARGE_STRING WindowName,PCLS Class,PWND ParentWindow,PWND OwnerWindow,PVOID acbiBuffer,PDESKTOP pdeskCreated,DWORD dwVer)1804 PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
1805 PLARGE_STRING WindowName,
1806 PCLS Class,
1807 PWND ParentWindow,
1808 PWND OwnerWindow,
1809 PVOID acbiBuffer,
1810 PDESKTOP pdeskCreated,
1811 DWORD dwVer )
1812 {
1813 PWND pWnd = NULL;
1814 HWND hWnd;
1815 PTHREADINFO pti;
1816 BOOL MenuChanged;
1817 BOOL bUnicodeWindow;
1818 PCALLPROCDATA pcpd;
1819
1820 pti = pdeskCreated ? gptiDesktopThread : GetW32ThreadInfo();
1821
1822 if (!(Cs->dwExStyle & WS_EX_LAYOUTRTL))
1823 { // Need both here for wine win.c test_CreateWindow.
1824 //if (Cs->hwndParent && ParentWindow)
1825 if (ParentWindow) // It breaks more tests..... WIP.
1826 {
1827 if ( (Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD &&
1828 ParentWindow->ExStyle & WS_EX_LAYOUTRTL &&
1829 !(ParentWindow->ExStyle & WS_EX_NOINHERITLAYOUT) )
1830 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1831 }
1832 else
1833 { /*
1834 * Note from MSDN <http://msdn.microsoft.com/en-us/library/aa913269.aspx>:
1835 *
1836 * Dialog boxes and message boxes do not inherit layout, so you must
1837 * set the layout explicitly.
1838 */
1839 if ( Class->fnid != FNID_DIALOG )
1840 {
1841 if (pti->ppi->dwLayout & LAYOUT_RTL)
1842 {
1843 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
1844 }
1845 }
1846 }
1847 }
1848
1849 /* Automatically add WS_EX_WINDOWEDGE */
1850 if ((Cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1851 ((!(Cs->dwExStyle & WS_EX_STATICEDGE)) &&
1852 (Cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1853 Cs->dwExStyle |= WS_EX_WINDOWEDGE;
1854 else
1855 Cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1856
1857 /* Is it a unicode window? */
1858 bUnicodeWindow =!(Cs->dwExStyle & WS_EX_SETANSICREATOR);
1859 Cs->dwExStyle &= ~WS_EX_SETANSICREATOR;
1860
1861 /* Allocate the new window */
1862 pWnd = (PWND) UserCreateObject( gHandleTable,
1863 pdeskCreated ? pdeskCreated : pti->rpdesk,
1864 pti,
1865 (PHANDLE)&hWnd,
1866 TYPE_WINDOW,
1867 sizeof(WND) + Class->cbwndExtra);
1868
1869 if (!pWnd)
1870 {
1871 goto AllocError;
1872 }
1873
1874 TRACE("Created window object with handle %p\n", hWnd);
1875
1876 if (pdeskCreated && pdeskCreated->DesktopWindow == NULL )
1877 { /* HACK: Helper for win32csr/desktopbg.c */
1878 /* If there is no desktop window yet, we must be creating it */
1879 TRACE("CreateWindow setting desktop.\n");
1880 pdeskCreated->DesktopWindow = hWnd;
1881 pdeskCreated->pDeskInfo->spwnd = pWnd;
1882 }
1883
1884 /*
1885 * Fill out the structure describing it.
1886 */
1887 /* Remember, pWnd->head is setup in object.c ... */
1888 WndSetParent(pWnd, ParentWindow);
1889 WndSetOwner(pWnd, OwnerWindow);
1890 pWnd->fnid = 0;
1891 WndSetLastActive(pWnd, pWnd);
1892 // Ramp up compatible version sets.
1893 if ( dwVer >= WINVER_WIN31 )
1894 {
1895 pWnd->state2 |= WNDS2_WIN31COMPAT;
1896 if ( dwVer >= WINVER_WINNT4 )
1897 {
1898 pWnd->state2 |= WNDS2_WIN40COMPAT;
1899 if ( dwVer >= WINVER_WIN2K )
1900 {
1901 pWnd->state2 |= WNDS2_WIN50COMPAT;
1902 }
1903 }
1904 }
1905 pWnd->pcls = Class;
1906 pWnd->hModule = Cs->hInstance;
1907 pWnd->style = Cs->style & ~WS_VISIBLE;
1908 pWnd->ExStyle = Cs->dwExStyle;
1909 pWnd->cbwndExtra = pWnd->pcls->cbwndExtra;
1910 pWnd->pActCtx = acbiBuffer;
1911
1912 if (pti->spDefaultImc && Class->atomClassName != gpsi->atomSysClass[ICLS_BUTTON])
1913 pWnd->hImc = UserHMGetHandle(pti->spDefaultImc);
1914
1915 pWnd->InternalPos.MaxPos.x = pWnd->InternalPos.MaxPos.y = -1;
1916 pWnd->InternalPos.IconPos.x = pWnd->InternalPos.IconPos.y = -1;
1917
1918 if (pWnd->spwndParent != NULL && Cs->hwndParent != 0)
1919 {
1920 pWnd->HideFocus = pWnd->spwndParent->HideFocus;
1921 pWnd->HideAccel = pWnd->spwndParent->HideAccel;
1922 }
1923
1924 InitializeListHead(&pWnd->ThreadListEntry);
1925 pWnd->head.pti->cWindows++;
1926
1927 if (Class->spicn && !Class->spicnSm)
1928 {
1929 HICON IconSmHandle = NULL;
1930 if((Class->spicn->CURSORF_flags & (CURSORF_LRSHARED | CURSORF_FROMRESOURCE))
1931 == (CURSORF_LRSHARED | CURSORF_FROMRESOURCE))
1932 {
1933 IconSmHandle = co_IntCopyImage(
1934 UserHMGetHandle(Class->spicn),
1935 IMAGE_ICON,
1936 UserGetSystemMetrics( SM_CXSMICON ),
1937 UserGetSystemMetrics( SM_CYSMICON ),
1938 LR_COPYFROMRESOURCE);
1939 }
1940 if (!IconSmHandle)
1941 {
1942 /* Retry without copying from resource */
1943 IconSmHandle = co_IntCopyImage(
1944 UserHMGetHandle(Class->spicn),
1945 IMAGE_ICON,
1946 UserGetSystemMetrics( SM_CXSMICON ),
1947 UserGetSystemMetrics( SM_CYSMICON ),
1948 0);
1949 }
1950
1951 if (IconSmHandle)
1952 {
1953 Class->spicnSm = UserGetCurIconObject(IconSmHandle);
1954 Class->CSF_flags |= CSF_CACHEDSMICON;
1955 }
1956 }
1957
1958 if (pWnd->pcls->CSF_flags & CSF_SERVERSIDEPROC)
1959 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
1960
1961 /* BugBoy Comments: Comment below say that System classes are always created
1962 as UNICODE. In windows, creating a window with the ANSI version of CreateWindow
1963 sets the window to ansi as verified by testing with IsUnicodeWindow API.
1964
1965 No where can I see in code or through testing does the window change back
1966 to ANSI after being created as UNICODE in ROS. I didnt do more testing to
1967 see what problems this would cause. */
1968
1969 // Set WndProc from Class.
1970 if (IsCallProcHandle(pWnd->pcls->lpfnWndProc))
1971 {
1972 pcpd = UserGetObject(gHandleTable, pWnd->pcls->lpfnWndProc, TYPE_CALLPROC);
1973 if (pcpd)
1974 pWnd->lpfnWndProc = pcpd->pfnClientPrevious;
1975 }
1976 else
1977 {
1978 pWnd->lpfnWndProc = pWnd->pcls->lpfnWndProc;
1979 }
1980
1981 // GetWindowProc, test for non server side default classes and set WndProc.
1982 if ( pWnd->pcls->fnid <= FNID_GHOST && pWnd->pcls->fnid >= FNID_BUTTON )
1983 {
1984 if (bUnicodeWindow)
1985 {
1986 if (GETPFNCLIENTA(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1987 pWnd->lpfnWndProc = GETPFNCLIENTW(pWnd->pcls->fnid);
1988 }
1989 else
1990 {
1991 if (GETPFNCLIENTW(pWnd->pcls->fnid) == pWnd->lpfnWndProc)
1992 pWnd->lpfnWndProc = GETPFNCLIENTA(pWnd->pcls->fnid);
1993 }
1994 }
1995
1996 // If not an Unicode caller, set Ansi creator bit.
1997 if (!bUnicodeWindow) pWnd->state |= WNDS_ANSICREATOR;
1998
1999 // Clone Class Ansi/Unicode proc type.
2000 if (pWnd->pcls->CSF_flags & CSF_ANSIPROC)
2001 {
2002 pWnd->state |= WNDS_ANSIWINDOWPROC;
2003 pWnd->Unicode = FALSE;
2004 }
2005 else
2006 { /*
2007 * It seems there can be both an Ansi creator and Unicode Class Window
2008 * WndProc, unless the following overriding conditions occur:
2009 */
2010 if ( !bUnicodeWindow &&
2011 ( Class->atomClassName == gpsi->atomSysClass[ICLS_BUTTON] ||
2012 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX] ||
2013 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOLBOX] ||
2014 Class->atomClassName == gpsi->atomSysClass[ICLS_DIALOG] ||
2015 Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT] ||
2016 Class->atomClassName == gpsi->atomSysClass[ICLS_IME] ||
2017 Class->atomClassName == gpsi->atomSysClass[ICLS_LISTBOX] ||
2018 Class->atomClassName == gpsi->atomSysClass[ICLS_MDICLIENT] ||
2019 Class->atomClassName == gpsi->atomSysClass[ICLS_STATIC] ) )
2020 { // Override Class and set the window Ansi WndProc.
2021 pWnd->state |= WNDS_ANSIWINDOWPROC;
2022 pWnd->Unicode = FALSE;
2023 }
2024 else
2025 { // Set the window Unicode WndProc.
2026 pWnd->state &= ~WNDS_ANSIWINDOWPROC;
2027 pWnd->Unicode = TRUE;
2028 }
2029 }
2030
2031 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx,
2032 then my testing shows that windows (2k and XP) creates a CallProc for it immediately
2033 Dont understand why it does this. */
2034 if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT])
2035 {
2036 PCALLPROCDATA CallProc;
2037 CallProc = CreateCallProc(pWnd->head.rpdesk, pWnd->lpfnWndProc, pWnd->Unicode , pWnd->head.pti->ppi);
2038
2039 if (!CallProc)
2040 {
2041 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
2042 ERR("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %p\n", hWnd);
2043 }
2044 else
2045 {
2046 UserAddCallProcToClass(pWnd->pcls, CallProc);
2047 }
2048 }
2049
2050 InitializeListHead(&pWnd->PropListHead);
2051 pWnd->PropListItems = 0;
2052
2053 if ( WindowName->Buffer != NULL && WindowName->Length > 0 )
2054 {
2055 pWnd->strName.Buffer = DesktopHeapAlloc(pWnd->head.rpdesk,
2056 WindowName->Length + sizeof(UNICODE_NULL));
2057 if (pWnd->strName.Buffer == NULL)
2058 {
2059 goto AllocError;
2060 }
2061
2062 RtlCopyMemory(pWnd->strName.Buffer, WindowName->Buffer, WindowName->Length);
2063 pWnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0';
2064 pWnd->strName.Length = WindowName->Length;
2065 pWnd->strName.MaximumLength = WindowName->Length + sizeof(UNICODE_NULL);
2066 }
2067
2068 /* Correct the window style. */
2069 if ((pWnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
2070 {
2071 pWnd->style |= WS_CLIPSIBLINGS;
2072 if (!(pWnd->style & WS_POPUP))
2073 {
2074 pWnd->style |= WS_CAPTION;
2075 }
2076 }
2077
2078 /* WS_EX_WINDOWEDGE depends on some other styles */
2079 if (pWnd->ExStyle & WS_EX_DLGMODALFRAME)
2080 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
2081 else if (pWnd->style & (WS_DLGFRAME | WS_THICKFRAME))
2082 {
2083 if (!((pWnd->ExStyle & WS_EX_STATICEDGE) &&
2084 (pWnd->style & (WS_CHILD | WS_POPUP))))
2085 pWnd->ExStyle |= WS_EX_WINDOWEDGE;
2086 }
2087 else
2088 pWnd->ExStyle &= ~WS_EX_WINDOWEDGE;
2089
2090 if (!(pWnd->style & (WS_CHILD | WS_POPUP)))
2091 pWnd->state |= WNDS_SENDSIZEMOVEMSGS;
2092
2093 /* Set the window menu */
2094 if ((Cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
2095 {
2096 if (Cs->hMenu)
2097 {
2098 IntSetMenu(pWnd, Cs->hMenu, &MenuChanged);
2099 }
2100 else if (pWnd->pcls->lpszMenuName) // Take it from the parent.
2101 {
2102 UNICODE_STRING MenuName;
2103 HMENU hMenu;
2104
2105 if (IS_INTRESOURCE(pWnd->pcls->lpszMenuName))
2106 {
2107 MenuName.Length = 0;
2108 MenuName.MaximumLength = 0;
2109 MenuName.Buffer = pWnd->pcls->lpszMenuName;
2110 }
2111 else
2112 {
2113 RtlInitUnicodeString( &MenuName, pWnd->pcls->lpszMenuName);
2114 }
2115 hMenu = co_IntCallLoadMenu( pWnd->pcls->hModule, &MenuName);
2116 if (hMenu) IntSetMenu(pWnd, hMenu, &MenuChanged);
2117 }
2118 }
2119 else // Not a child
2120 pWnd->IDMenu = (UINT_PTR)Cs->hMenu;
2121
2122
2123 if ( ParentWindow &&
2124 ParentWindow != ParentWindow->head.rpdesk->spwndMessage &&
2125 ParentWindow != ParentWindow->head.rpdesk->pDeskInfo->spwnd )
2126 {
2127 PWND Owner = IntGetNonChildAncestor(ParentWindow);
2128
2129 if (!IntValidateOwnerDepth(pWnd, Owner))
2130 {
2131 EngSetLastError(ERROR_INVALID_PARAMETER);
2132 goto Error;
2133 }
2134 if ( pWnd->spwndOwner &&
2135 pWnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
2136 {
2137 pWnd->ExStyle |= WS_EX_TOPMOST;
2138 }
2139 if ( pWnd->spwndOwner &&
2140 Class->atomClassName != gpsi->atomSysClass[ICLS_IME] &&
2141 pti != pWnd->spwndOwner->head.pti)
2142 {
2143 //ERR("CreateWindow Owner in.\n");
2144 UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE);
2145 }
2146 }
2147
2148 /* Insert the window into the thread's window list. */
2149 InsertTailList (&pti->WindowListHead, &pWnd->ThreadListEntry);
2150
2151 /* Handle "CS_CLASSDC", it is tested first. */
2152 if ( (pWnd->pcls->style & CS_CLASSDC) && !(pWnd->pcls->pdce) )
2153 { /* One DCE per class to have CLASS. */
2154 pWnd->pcls->pdce = DceAllocDCE( pWnd, DCE_CLASS_DC );
2155 }
2156 else if ( pWnd->pcls->style & CS_OWNDC)
2157 { /* Allocate a DCE for this window. */
2158 DceAllocDCE(pWnd, DCE_WINDOW_DC);
2159 }
2160
2161 return pWnd;
2162
2163 AllocError:
2164 ERR("IntCreateWindow Allocation Error.\n");
2165 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES);
2166 Error:
2167 if(pWnd)
2168 UserDereferenceObject(pWnd);
2169 return NULL;
2170 }
2171
2172 /*
2173 * @implemented
2174 */
2175 PWND FASTCALL
co_UserCreateWindowEx(CREATESTRUCTW * Cs,PUNICODE_STRING ClassName,PLARGE_STRING WindowName,PVOID acbiBuffer,DWORD dwVer)2176 co_UserCreateWindowEx(CREATESTRUCTW* Cs,
2177 PUNICODE_STRING ClassName,
2178 PLARGE_STRING WindowName,
2179 PVOID acbiBuffer,
2180 DWORD dwVer )
2181 {
2182 ULONG style;
2183 PWND Window = NULL, ParentWindow = NULL, OwnerWindow;
2184 HWND hWnd, hWndParent, hWndOwner, hwndInsertAfter;
2185 PWINSTATION_OBJECT WinSta;
2186 PCLS Class = NULL;
2187 SIZE Size;
2188 POINT MaxSize, MaxPos, MinTrack, MaxTrack;
2189 CBT_CREATEWNDW * pCbtCreate;
2190 LRESULT Result;
2191 USER_REFERENCE_ENTRY ParentRef, Ref;
2192 PTHREADINFO pti;
2193 DWORD dwShowMode = SW_SHOW;
2194 CREATESTRUCTW *pCsw = NULL;
2195 PVOID pszClass = NULL, pszName = NULL;
2196 PWND ret = NULL;
2197
2198 /* Get the current window station and reference it */
2199 pti = GetW32ThreadInfo();
2200 if (pti == NULL || pti->rpdesk == NULL)
2201 {
2202 ERR("Thread is not attached to a desktop! Cannot create window (%wZ)\n", ClassName);
2203 return NULL; // There is nothing to cleanup.
2204 }
2205 WinSta = pti->rpdesk->rpwinstaParent;
2206 ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0);
2207
2208 pCsw = NULL;
2209 pCbtCreate = NULL;
2210
2211 /* Get the class and reference it */
2212 Class = IntGetAndReferenceClass(ClassName, Cs->hInstance, FALSE);
2213 if(!Class)
2214 {
2215 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS);
2216 ERR("Failed to find class %wZ\n", ClassName);
2217 goto cleanup;
2218 }
2219
2220 /* Now find the parent and the owner window */
2221 hWndParent = UserHMGetHandle(pti->rpdesk->pDeskInfo->spwnd);
2222 hWndOwner = NULL;
2223
2224 if (Cs->hwndParent == HWND_MESSAGE)
2225 {
2226 Cs->hwndParent = hWndParent = UserHMGetHandle(pti->rpdesk->spwndMessage);
2227 }
2228 else if (Cs->hwndParent)
2229 {
2230 if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD)
2231 hWndOwner = Cs->hwndParent;
2232 else
2233 hWndParent = Cs->hwndParent;
2234 }
2235 else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2236 {
2237 ERR("Cannot create a child window (%wZ) without a parent\n", ClassName);
2238 EngSetLastError(ERROR_TLW_WITH_WSCHILD);
2239 goto cleanup; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
2240 }
2241 else if (Cs->lpszClass != (LPCWSTR)MAKEINTATOM(gpsi->atomSysClass[ICLS_DESKTOP]) &&
2242 (IS_INTRESOURCE(Cs->lpszClass) ||
2243 Cs->lpszClass != (LPCWSTR)MAKEINTATOM(gpsi->atomSysClass[ICLS_HWNDMESSAGE]) ||
2244 _wcsicmp(Cs->lpszClass, L"Message") != 0))
2245 {
2246 if (pti->ppi->dwLayout & LAYOUT_RTL)
2247 {
2248 Cs->dwExStyle |= WS_EX_LAYOUTRTL;
2249 }
2250 }
2251
2252 ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL;
2253 OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL;
2254
2255 if (hWndParent && !ParentWindow)
2256 {
2257 ERR("Got invalid parent window handle for %wZ\n", ClassName);
2258 goto cleanup;
2259 }
2260 else if (hWndOwner && !OwnerWindow)
2261 {
2262 ERR("Got invalid owner window handle for %wZ\n", ClassName);
2263 ParentWindow = NULL;
2264 goto cleanup;
2265 }
2266
2267 if(OwnerWindow)
2268 {
2269 if (IntIsDesktopWindow(OwnerWindow)) OwnerWindow = NULL;
2270 else if (ParentWindow && !IntIsDesktopWindow(ParentWindow))
2271 {
2272 ERR("an owned window must be created as top-level\n");
2273 EngSetLastError( STATUS_ACCESS_DENIED );
2274 goto cleanup;
2275 }
2276 else /* owner must be a top-level window */
2277 {
2278 while ((OwnerWindow->style & (WS_POPUP|WS_CHILD)) == WS_CHILD && !IntIsDesktopWindow(OwnerWindow->spwndParent))
2279 OwnerWindow = OwnerWindow->spwndParent;
2280 }
2281 }
2282
2283 /* Fix the position and the size of the window */
2284 if (ParentWindow)
2285 {
2286 UserRefObjectCo(ParentWindow, &ParentRef);
2287 IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode);
2288 }
2289
2290 /* Allocate and initialize the new window */
2291 Window = IntCreateWindow(Cs,
2292 WindowName,
2293 Class,
2294 ParentWindow,
2295 OwnerWindow,
2296 acbiBuffer,
2297 NULL,
2298 dwVer );
2299 if(!Window)
2300 {
2301 ERR("IntCreateWindow(%wZ) failed\n", ClassName);
2302 goto cleanup;
2303 }
2304
2305 hWnd = UserHMGetHandle(Window);
2306 hwndInsertAfter = HWND_TOP;
2307
2308 UserRefObjectCo(Window, &Ref);
2309 UserDereferenceObject(Window);
2310 ObDereferenceObject(WinSta);
2311
2312 /* NCCREATE, WM_NCCALCSIZE and Hooks need the original values */
2313 Cs->lpszName = (LPCWSTR) WindowName;
2314 Cs->lpszClass = (LPCWSTR) ClassName;
2315
2316 //// Check for a hook to eliminate overhead. ////
2317 if ( ISITHOOKED(WH_CBT) || (pti->rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)) )
2318 {
2319 // Allocate the calling structures Justin Case this goes Global.
2320 pCsw = ExAllocatePoolWithTag(NonPagedPool, sizeof(CREATESTRUCTW), TAG_HOOK);
2321 pCbtCreate = ExAllocatePoolWithTag(NonPagedPool, sizeof(CBT_CREATEWNDW), TAG_HOOK);
2322 if (!pCsw || !pCbtCreate)
2323 {
2324 ERR("UserHeapAlloc() failed!\n");
2325 goto cleanup;
2326 }
2327
2328 if (!IntMsgCreateStructW( Window, pCsw, Cs, &pszClass, &pszName ) )
2329 {
2330 ERR("IntMsgCreateStructW() failed!\n");
2331 goto cleanup;
2332 }
2333
2334 pCbtCreate->lpcs = pCsw;
2335 pCbtCreate->hwndInsertAfter = hwndInsertAfter;
2336
2337 //// Call the WH_CBT hook ////
2338 Result = co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) pCbtCreate);
2339 if (Result != 0)
2340 {
2341 ERR("WH_CBT HCBT_CREATEWND hook failed! 0x%x\n", Result);
2342 goto cleanup;
2343 }
2344 // Write back changes.
2345 Cs->cx = pCsw->cx;
2346 Cs->cy = pCsw->cy;
2347 Cs->x = pCsw->x;
2348 Cs->y = pCsw->y;
2349 hwndInsertAfter = pCbtCreate->hwndInsertAfter;
2350 }
2351
2352 if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
2353 {
2354 if (ParentWindow != co_GetDesktopWindow(Window))
2355 {
2356 Cs->x += ParentWindow->rcClient.left;
2357 Cs->y += ParentWindow->rcClient.top;
2358 }
2359 }
2360
2361 /* Send the WM_GETMINMAXINFO message */
2362 Size.cx = Cs->cx;
2363 Size.cy = Cs->cy;
2364
2365 if ((Cs->style & WS_THICKFRAME) || !(Cs->style & (WS_POPUP | WS_CHILD)))
2366 {
2367 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack);
2368 if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x;
2369 if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y;
2370 if (Size.cx < MinTrack.x) Size.cx = MinTrack.x;
2371 if (Size.cy < MinTrack.y) Size.cy = MinTrack.y;
2372 }
2373
2374 Window->rcWindow.left = Cs->x;
2375 Window->rcWindow.top = Cs->y;
2376 Window->rcWindow.right = Cs->x + Size.cx;
2377 Window->rcWindow.bottom = Cs->y + Size.cy;
2378 /*
2379 if (0 != (Window->style & WS_CHILD) && ParentWindow)
2380 {
2381 ERR("co_UserCreateWindowEx(): Offset rcWindow\n");
2382 RECTL_vOffsetRect(&Window->rcWindow,
2383 ParentWindow->rcClient.left,
2384 ParentWindow->rcClient.top);
2385 }
2386 */
2387 /* correct child window coordinates if mirroring on parent is enabled */
2388 if (ParentWindow != NULL)
2389 {
2390 if ( ((Cs->style & WS_CHILD) == WS_CHILD) &&
2391 ((ParentWindow->ExStyle & WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL))
2392 {
2393 Window->rcWindow.right = ParentWindow->rcClient.right - (Window->rcWindow.left - ParentWindow->rcClient.left);
2394 Window->rcWindow.left = Window->rcWindow.right - Size.cx;
2395 }
2396 }
2397
2398 Window->rcClient = Window->rcWindow;
2399
2400 if (Window->spwndNext || Window->spwndPrev)
2401 {
2402 ERR("Window 0x%p has been linked too early!\n", Window);
2403 }
2404
2405 if (!(Window->state2 & WNDS2_WIN31COMPAT))
2406 {
2407 if (Class->style & CS_PARENTDC && !(ParentWindow->style & WS_CLIPCHILDREN))
2408 Window->style &= ~(WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
2409 }
2410
2411 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
2412 {
2413 if ( !IntIsTopLevelWindow(Window) )
2414 {
2415 if (pti != ParentWindow->head.pti)
2416 {
2417 //ERR("CreateWindow Parent in.\n");
2418 UserAttachThreadInput(pti, ParentWindow->head.pti, TRUE);
2419 }
2420 }
2421 }
2422
2423 /* Send the NCCREATE message */
2424 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_NCCREATE, 0, (LPARAM) Cs);
2425 if (!Result)
2426 {
2427 ERR("co_UserCreateWindowEx(%wZ): NCCREATE message failed\n", ClassName);
2428 goto cleanup;
2429 }
2430
2431 /* Link the window */
2432 if (ParentWindow != NULL)
2433 {
2434 /* Link the window into the siblings list */
2435 if ((Cs->style & (WS_CHILD | WS_MAXIMIZE)) == WS_CHILD)
2436 IntLinkHwnd(Window, HWND_BOTTOM);
2437 else
2438 IntLinkHwnd(Window, hwndInsertAfter);
2439 }
2440
2441 /* Create the IME window for pWnd */
2442 if (IS_IMM_MODE() && !pti->spwndDefaultIme && IntWantImeWindow(Window))
2443 {
2444 PWND pwndDefaultIme = co_IntCreateDefaultImeWindow(Window, Window->hModule);
2445 UserAssignmentLock((PVOID*)&pti->spwndDefaultIme, pwndDefaultIme);
2446
2447 if (pwndDefaultIme)
2448 {
2449 HWND hImeWnd;
2450 USER_REFERENCE_ENTRY Ref;
2451 UserRefObjectCo(pwndDefaultIme, &Ref);
2452
2453 hImeWnd = UserHMGetHandle(pwndDefaultIme);
2454
2455 co_IntSendMessage(hImeWnd, WM_IME_SYSTEM, IMS_LOADTHREADLAYOUT, 0);
2456
2457 if (pti->pClientInfo->CI_flags & CI_IMMACTIVATE)
2458 {
2459 HKL hKL = pti->KeyboardLayout->hkl;
2460 co_IntSendMessage(hImeWnd, WM_IME_SYSTEM, IMS_ACTIVATELAYOUT, (LPARAM)hKL);
2461 pti->pClientInfo->CI_flags &= ~CI_IMMACTIVATE;
2462 }
2463
2464 UserDerefObjectCo(pwndDefaultIme);
2465 }
2466 }
2467
2468 /* Send the WM_NCCALCSIZE message */
2469 {
2470 // RECT rc;
2471 MaxPos.x = Window->rcWindow.left;
2472 MaxPos.y = Window->rcWindow.top;
2473
2474 Result = co_WinPosGetNonClientSize(Window, &Window->rcWindow, &Window->rcClient);
2475 //rc = Window->rcWindow;
2476 //Result = co_IntSendMessageNoWait(UserHMGetHandle(Window), WM_NCCALCSIZE, FALSE, (LPARAM)&rc);
2477 //Window->rcClient = rc;
2478
2479 RECTL_vOffsetRect(&Window->rcWindow, MaxPos.x - Window->rcWindow.left,
2480 MaxPos.y - Window->rcWindow.top);
2481 }
2482
2483 /* Send the WM_CREATE message. */
2484 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_CREATE, 0, (LPARAM) Cs);
2485 if (Result == (LRESULT)-1)
2486 {
2487 ERR("co_UserCreateWindowEx(%wZ): WM_CREATE message failed\n", ClassName);
2488 goto cleanup;
2489 }
2490
2491 /* Send the EVENT_OBJECT_CREATE event */
2492 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, CHILDID_SELF, 0);
2493
2494 /* By setting the flag below it can be examined to determine if the window
2495 was created successfully and a valid pwnd was passed back to caller since
2496 from here the function has to succeed. */
2497 Window->state2 |= WNDS2_WMCREATEMSGPROCESSED;
2498
2499 /* Send the WM_SIZE and WM_MOVE messages. */
2500 if (!(Window->state & WNDS_SENDSIZEMOVEMSGS))
2501 {
2502 co_WinPosSendSizeMove(Window);
2503 }
2504
2505 /* Show or maybe minimize or maximize the window. */
2506
2507 style = IntSetStyle( Window, 0, WS_MAXIMIZE | WS_MINIMIZE );
2508 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
2509 {
2510 RECTL NewPos;
2511 UINT SwFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
2512
2513 SwFlag = co_WinPosMinMaximize(Window, SwFlag, &NewPos);
2514 SwFlag |= SWP_NOZORDER|SWP_FRAMECHANGED; /* Frame always gets changed */
2515 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || UserGetActiveWindow() ||
2516 (Window->ExStyle & WS_EX_NOACTIVATE))
2517 {
2518 SwFlag |= SWP_NOACTIVATE;
2519 }
2520 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top,
2521 NewPos.right, NewPos.bottom, SwFlag);
2522 }
2523
2524 /* Send the WM_PARENTNOTIFY message */
2525 IntSendParentNotify(Window, WM_CREATE);
2526
2527 /* Notify the shell that a new window was created */
2528 if (Window->spwndOwner == NULL ||
2529 !(Window->spwndOwner->style & WS_VISIBLE) ||
2530 (Window->spwndOwner->ExStyle & WS_EX_TOOLWINDOW))
2531 {
2532 if (UserIsDesktopWindow(Window->spwndParent) &&
2533 (Window->style & WS_VISIBLE) &&
2534 (!(Window->ExStyle & WS_EX_TOOLWINDOW) ||
2535 (Window->ExStyle & WS_EX_APPWINDOW)))
2536 {
2537 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0);
2538 }
2539 }
2540
2541 /* Initialize and show the window's scrollbars */
2542 if (Window->style & WS_VSCROLL)
2543 {
2544 co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE);
2545 }
2546 if (Window->style & WS_HSCROLL)
2547 {
2548 co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE);
2549 }
2550
2551 /* Show the new window */
2552 if (Cs->style & WS_VISIBLE)
2553 {
2554 if (Window->style & WS_MAXIMIZE)
2555 dwShowMode = SW_SHOW;
2556 else if (Window->style & WS_MINIMIZE)
2557 dwShowMode = SW_SHOWMINIMIZED;
2558
2559 co_WinPosShowWindow(Window, dwShowMode);
2560
2561 if (Window->ExStyle & WS_EX_MDICHILD)
2562 {
2563 ASSERT(ParentWindow);
2564 if(!ParentWindow)
2565 goto cleanup;
2566 co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0);
2567 /* ShowWindow won't activate child windows */
2568 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
2569 }
2570 }
2571
2572 if (Class->atomClassName == gaGuiConsoleWndClass)
2573 {
2574 /* Count only console windows manually */
2575 co_IntUserManualGuiCheck(TRUE);
2576 }
2577
2578 TRACE("co_UserCreateWindowEx(%wZ): Created window %p\n", ClassName, hWnd);
2579 ret = Window;
2580
2581 cleanup:
2582 if (!ret)
2583 {
2584 TRACE("co_UserCreateWindowEx(): Error Created window!\n");
2585 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */
2586 if (Window)
2587 co_UserDestroyWindow(Window);
2588 else if (Class)
2589 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi);
2590 }
2591
2592 if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK);
2593 if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK);
2594 if (pszName) UserHeapFree(pszName);
2595 if (pszClass) UserHeapFree(pszClass);
2596
2597 if (Window)
2598 {
2599 UserDerefObjectCo(Window);
2600 }
2601 if (ParentWindow) UserDerefObjectCo(ParentWindow);
2602
2603 // See CORE-13717, not setting error on success.
2604 if (ret)
2605 EngSetLastError(ERROR_SUCCESS);
2606
2607 return ret;
2608 }
2609
2610 NTSTATUS
2611 NTAPI
ProbeAndCaptureLargeString(OUT PLARGE_STRING plstrSafe,IN PLARGE_STRING plstrUnsafe)2612 ProbeAndCaptureLargeString(
2613 OUT PLARGE_STRING plstrSafe,
2614 IN PLARGE_STRING plstrUnsafe)
2615 {
2616 LARGE_STRING lstrTemp;
2617 PVOID pvBuffer = NULL;
2618
2619 _SEH2_TRY
2620 {
2621 /* Probe and copy the string */
2622 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG));
2623 lstrTemp = *plstrUnsafe;
2624 }
2625 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2626 {
2627 /* Fail */
2628 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2629 }
2630 _SEH2_END
2631
2632 if (lstrTemp.Length != 0)
2633 {
2634 /* Allocate a buffer from paged pool */
2635 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING);
2636 if (!pvBuffer)
2637 {
2638 return STATUS_NO_MEMORY;
2639 }
2640
2641 _SEH2_TRY
2642 {
2643 /* Probe and copy the buffer */
2644 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR));
2645 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length);
2646 }
2647 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2648 {
2649 /* Cleanup and fail */
2650 ExFreePoolWithTag(pvBuffer, TAG_STRING);
2651 _SEH2_YIELD(return _SEH2_GetExceptionCode();)
2652 }
2653 _SEH2_END
2654 }
2655
2656 /* Set the output string */
2657 plstrSafe->Buffer = pvBuffer;
2658 plstrSafe->Length = lstrTemp.Length;
2659 plstrSafe->MaximumLength = lstrTemp.Length;
2660
2661 return STATUS_SUCCESS;
2662 }
2663
2664 /**
2665 * \todo Allow passing plstrClassName as ANSI.
2666 */
2667 HWND
2668 NTAPI
NtUserCreateWindowEx(DWORD dwExStyle,PLARGE_STRING plstrClassName,PLARGE_STRING plstrClsVersion,PLARGE_STRING plstrWindowName,DWORD dwStyle,int x,int y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam,DWORD dwFlags,PVOID acbiBuffer)2669 NtUserCreateWindowEx(
2670 DWORD dwExStyle,
2671 PLARGE_STRING plstrClassName,
2672 PLARGE_STRING plstrClsVersion,
2673 PLARGE_STRING plstrWindowName,
2674 DWORD dwStyle,
2675 int x,
2676 int y,
2677 int nWidth,
2678 int nHeight,
2679 HWND hWndParent,
2680 HMENU hMenu,
2681 HINSTANCE hInstance,
2682 LPVOID lpParam,
2683 DWORD dwFlags,
2684 PVOID acbiBuffer)
2685 {
2686 NTSTATUS Status;
2687 LARGE_STRING lstrWindowName;
2688 LARGE_STRING lstrClassName;
2689 LARGE_STRING lstrClsVersion;
2690 UNICODE_STRING ustrClassName;
2691 UNICODE_STRING ustrClsVersion;
2692 CREATESTRUCTW Cs;
2693 HWND hwnd = NULL;
2694 PWND pwnd;
2695
2696 lstrWindowName.Buffer = NULL;
2697 lstrClassName.Buffer = NULL;
2698 lstrClsVersion.Buffer = NULL;
2699
2700 if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2701 {
2702 /* check hMenu is valid handle */
2703 if (hMenu && !UserGetMenuObject(hMenu))
2704 {
2705 ERR("NtUserCreateWindowEx: Got an invalid menu handle!\n");
2706 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
2707 return NULL;
2708 }
2709 }
2710
2711 /* Copy the window name to kernel mode */
2712 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName);
2713 if (!NT_SUCCESS(Status))
2714 {
2715 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n");
2716 SetLastNtError(Status);
2717 return NULL;
2718 }
2719
2720 plstrWindowName = &lstrWindowName;
2721
2722 /* Check if the class is an atom */
2723 if (IS_ATOM(plstrClassName))
2724 {
2725 /* It is, pass the atom in the UNICODE_STRING */
2726 ustrClassName.Buffer = (PVOID)plstrClassName;
2727 ustrClassName.Length = 0;
2728 ustrClassName.MaximumLength = 0;
2729 }
2730 else
2731 {
2732 /* It's not, capture the class name */
2733 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName);
2734 if (!NT_SUCCESS(Status))
2735 {
2736 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n");
2737 /* Set last error, cleanup and return */
2738 SetLastNtError(Status);
2739 goto cleanup;
2740 }
2741
2742 /* We pass it on as a UNICODE_STRING */
2743 ustrClassName.Buffer = lstrClassName.Buffer;
2744 ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2745 ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT);
2746 }
2747
2748 /* Check if the class version is an atom */
2749 if (IS_ATOM(plstrClsVersion))
2750 {
2751 /* It is, pass the atom in the UNICODE_STRING */
2752 ustrClsVersion.Buffer = (PVOID)plstrClsVersion;
2753 ustrClsVersion.Length = 0;
2754 ustrClsVersion.MaximumLength = 0;
2755 }
2756 else
2757 {
2758 /* It's not, capture the class name */
2759 Status = ProbeAndCaptureLargeString(&lstrClsVersion, plstrClsVersion);
2760 if (!NT_SUCCESS(Status))
2761 {
2762 ERR("NtUserCreateWindowEx: failed to capture plstrClsVersion\n");
2763 /* Set last error, cleanup and return */
2764 SetLastNtError(Status);
2765 goto cleanup;
2766 }
2767
2768 /* We pass it on as a UNICODE_STRING */
2769 ustrClsVersion.Buffer = lstrClsVersion.Buffer;
2770 ustrClsVersion.Length = (USHORT)min(lstrClsVersion.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated
2771 ustrClsVersion.MaximumLength = (USHORT)min(lstrClsVersion.MaximumLength, MAXUSHORT);
2772 }
2773
2774 /* Fill the CREATESTRUCTW */
2775 /* we will keep here the original parameters */
2776 Cs.style = dwStyle;
2777 Cs.lpCreateParams = lpParam;
2778 Cs.hInstance = hInstance;
2779 Cs.hMenu = hMenu;
2780 Cs.hwndParent = hWndParent;
2781 Cs.cx = nWidth;
2782 Cs.cy = nHeight;
2783 Cs.x = x;
2784 Cs.y = y;
2785 Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer;
2786 Cs.lpszClass = ustrClassName.Buffer;
2787 Cs.dwExStyle = dwExStyle;
2788
2789 UserEnterExclusive();
2790
2791 /* Call the internal function */
2792 pwnd = co_UserCreateWindowEx(&Cs, &ustrClsVersion, plstrWindowName, acbiBuffer, dwFlags);
2793
2794 if(!pwnd)
2795 {
2796 ERR("co_UserCreateWindowEx failed!\n");
2797 }
2798 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL;
2799
2800 UserLeave();
2801
2802 cleanup:
2803 if (lstrWindowName.Buffer)
2804 {
2805 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING);
2806 }
2807 if (lstrClassName.Buffer)
2808 {
2809 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING);
2810 }
2811 if (lstrClsVersion.Buffer)
2812 {
2813 ExFreePoolWithTag(lstrClsVersion.Buffer, TAG_STRING);
2814 }
2815
2816 return hwnd;
2817 }
2818
2819 // Win: xxxDW_DestroyOwnedWindows
IntDestroyOwnedWindows(PWND Window)2820 VOID FASTCALL IntDestroyOwnedWindows(PWND Window)
2821 {
2822 HWND* List;
2823 HWND* phWnd;
2824 PWND pWnd;
2825 USER_REFERENCE_ENTRY Ref;
2826
2827 List = IntWinListOwnedPopups(Window);
2828 if (!List)
2829 return;
2830
2831 for (phWnd = List; *phWnd; ++phWnd)
2832 {
2833 pWnd = ValidateHwndNoErr(*phWnd);
2834 if (pWnd == NULL)
2835 continue;
2836 ASSERT(pWnd->spwndOwner == Window);
2837 ASSERT(pWnd != Window);
2838
2839 WndSetOwner(pWnd, NULL);
2840 if (IntWndBelongsToThread(pWnd, PsGetCurrentThreadWin32Thread()))
2841 {
2842 UserRefObjectCo(pWnd, &Ref); // Temp HACK?
2843 co_UserDestroyWindow(pWnd);
2844 UserDerefObjectCo(pWnd); // Temp HACK?
2845 }
2846 else
2847 {
2848 ERR("IntWndBelongsToThread(0x%p) is FALSE, ignoring.\n", pWnd);
2849 }
2850 }
2851
2852 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
2853 }
2854
2855 // Win: xxxDestroyWindow
co_UserDestroyWindow(PVOID Object)2856 BOOLEAN co_UserDestroyWindow(PVOID Object)
2857 {
2858 HWND hWnd;
2859 PWND pwndTemp;
2860 PTHREADINFO ti;
2861 MSG msg;
2862 PWND Window = Object;
2863
2864 ASSERT_REFS_CO(Window); // FIXME: Temp HACK?
2865
2866 /* NtUserDestroyWindow does check if the window has already been destroyed
2867 but co_UserDestroyWindow can be called from more paths which means
2868 that it can also be called for a window that has already been destroyed. */
2869 if (!IntIsWindow(UserHMGetHandle(Window)))
2870 {
2871 TRACE("Tried to destroy a window twice\n");
2872 return TRUE;
2873 }
2874
2875 hWnd = UserHMGetHandle(Window);
2876 ti = PsGetCurrentThreadWin32Thread();
2877
2878 TRACE("co_UserDestroyWindow(Window = 0x%p, hWnd = 0x%p)\n", Window, hWnd);
2879
2880 /* Check for owner thread */
2881 if (Window->head.pti != ti)
2882 {
2883 /* Check if we are destroying the desktop window */
2884 if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd))
2885 {
2886 EngSetLastError(ERROR_ACCESS_DENIED);
2887 return FALSE;
2888 }
2889 }
2890
2891 /* If window was created successfully and it is hooked */
2892 if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED))
2893 {
2894 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0))
2895 {
2896 ERR("Destroy Window WH_CBT Call Hook return!\n");
2897 return FALSE;
2898 }
2899 }
2900
2901 if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME])
2902 {
2903 if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
2904 {
2905 if (Window->spwndOwner)
2906 {
2907 //ERR("DestroyWindow Owner out.\n");
2908 UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE);
2909 }
2910 }
2911 }
2912
2913 /* Inform the parent */
2914 if (Window->style & WS_CHILD)
2915 {
2916 IntSendParentNotify(Window, WM_DESTROY);
2917 }
2918
2919 if (!Window->spwndOwner && !IntGetParent(Window))
2920 {
2921 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM) hWnd, 0);
2922 }
2923
2924 /* Hide the window */
2925 if (Window->style & WS_VISIBLE)
2926 {
2927 if (Window->style & WS_CHILD)
2928 {
2929 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
2930 co_WinPosShowWindow(Window, SW_HIDE);
2931 }
2932 else
2933 {
2934 co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_HIDEWINDOW );
2935 }
2936 }
2937
2938 /* Adjust last active */
2939 if ((pwndTemp = Window->spwndOwner))
2940 {
2941 while (pwndTemp->spwndOwner)
2942 pwndTemp = pwndTemp->spwndOwner;
2943
2944 if (pwndTemp->spwndLastActive == Window)
2945 WndSetLastActive(pwndTemp, Window->spwndOwner);
2946 }
2947
2948 if (Window->spwndParent && IntIsWindow(UserHMGetHandle(Window)))
2949 {
2950 if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD)
2951 {
2952 if (!IntIsTopLevelWindow(Window))
2953 {
2954 //ERR("DestroyWindow Parent out.\n");
2955 UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE);
2956 }
2957 }
2958 }
2959
2960 if (Window->head.pti->MessageQueue->spwndActive == Window)
2961 Window->head.pti->MessageQueue->spwndActive = NULL;
2962 if (Window->head.pti->MessageQueue->spwndFocus == Window)
2963 Window->head.pti->MessageQueue->spwndFocus = NULL;
2964 if (Window->head.pti->MessageQueue->spwndActivePrev == Window)
2965 Window->head.pti->MessageQueue->spwndActivePrev = NULL;
2966 if (Window->head.pti->MessageQueue->spwndCapture == Window)
2967 Window->head.pti->MessageQueue->spwndCapture = NULL;
2968
2969 /*
2970 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL
2971 */
2972
2973 if (ti->pDeskInfo != NULL)
2974 {
2975 if (ti->pDeskInfo->hShellWindow == hWnd)
2976 {
2977 ERR("Destroying the ShellWindow!\n");
2978 ti->pDeskInfo->hShellWindow = NULL;
2979 }
2980 }
2981
2982 IntEngWindowChanged(Window, WOC_DELETE);
2983
2984 if (!IntIsWindow(UserHMGetHandle(Window)))
2985 {
2986 return TRUE;
2987 }
2988
2989 /* Recursively destroy owned windows */
2990 if (!(Window->style & WS_CHILD))
2991 {
2992 IntDestroyOwnedWindows(Window);
2993 }
2994
2995 /* Generate mouse move message for the next window */
2996 msg.message = WM_MOUSEMOVE;
2997 msg.wParam = UserGetMouseButtonsState();
2998 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
2999 msg.pt = gpsi->ptCursor;
3000 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
3001
3002 IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Window, OBJID_WINDOW, CHILDID_SELF, 0);
3003
3004 /* Send destroy messages */
3005 IntSendDestroyMsg(UserHMGetHandle(Window));
3006
3007 /* Destroy the default IME window if necessary */
3008 if (IS_IMM_MODE() && !(ti->TIF_flags & TIF_INCLEANUP) &&
3009 ti->spwndDefaultIme && (ti->spwndDefaultIme != Window) &&
3010 !(Window->state & WNDS_DESTROYED) && !IS_WND_IMELIKE(Window))
3011 {
3012 if (IS_WND_CHILD(Window))
3013 {
3014 if (IntImeCanDestroyDefIMEforChild(ti->spwndDefaultIme, Window))
3015 co_UserDestroyWindow(ti->spwndDefaultIme);
3016 }
3017 else
3018 {
3019 if (IntImeCanDestroyDefIME(ti->spwndDefaultIme, Window))
3020 co_UserDestroyWindow(ti->spwndDefaultIme);
3021 }
3022 }
3023
3024 if (!IntIsWindow(UserHMGetHandle(Window)))
3025 {
3026 return TRUE;
3027 }
3028
3029 /* Destroy the window storage */
3030 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE);
3031
3032 return TRUE;
3033 }
3034
3035
3036 /*
3037 * @implemented
3038 */
3039 BOOLEAN APIENTRY
NtUserDestroyWindow(HWND Wnd)3040 NtUserDestroyWindow(HWND Wnd)
3041 {
3042 PWND Window;
3043 BOOLEAN ret = FALSE;
3044 USER_REFERENCE_ENTRY Ref;
3045
3046 TRACE("Enter NtUserDestroyWindow\n");
3047 UserEnterExclusive();
3048
3049 Window = UserGetWindowObject(Wnd);
3050 if (Window)
3051 {
3052 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy...
3053 ret = co_UserDestroyWindow(Window);
3054 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy...
3055 }
3056
3057 TRACE("Leave NtUserDestroyWindow, ret=%u\n", ret);
3058 UserLeave();
3059 return ret;
3060 }
3061
3062
3063 HWND FASTCALL
IntFindWindow(PWND Parent,PWND ChildAfter,RTL_ATOM ClassAtom,PUNICODE_STRING WindowName)3064 IntFindWindow(PWND Parent,
3065 PWND ChildAfter,
3066 RTL_ATOM ClassAtom,
3067 PUNICODE_STRING WindowName)
3068 {
3069 BOOL CheckWindowName;
3070 HWND *List, *phWnd;
3071 HWND Ret = NULL;
3072 UNICODE_STRING CurrentWindowName;
3073
3074 ASSERT(Parent);
3075
3076 CheckWindowName = WindowName->Buffer != 0;
3077
3078 if((List = IntWinListChildren(Parent)))
3079 {
3080 phWnd = List;
3081 if(ChildAfter)
3082 {
3083 /* skip handles before and including ChildAfter */
3084 while(*phWnd && (*(phWnd++) != UserHMGetHandle(ChildAfter)))
3085 ;
3086 }
3087
3088 /* search children */
3089 while(*phWnd)
3090 {
3091 PWND Child;
3092 if(!(Child = UserGetWindowObject(*(phWnd++))))
3093 {
3094 continue;
3095 }
3096
3097 /* Do not send WM_GETTEXT messages in the kernel mode version!
3098 The user mode version however calls GetWindowText() which will
3099 send WM_GETTEXT messages to windows belonging to its processes */
3100 if (!ClassAtom || Child->pcls->atomNVClassName == ClassAtom)
3101 {
3102 // FIXME: LARGE_STRING truncated
3103 CurrentWindowName.Buffer = Child->strName.Buffer;
3104 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT);
3105 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT);
3106 if(!CheckWindowName ||
3107 (Child->strName.Length < 0xFFFF &&
3108 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE)))
3109 {
3110 Ret = UserHMGetHandle(Child);
3111 break;
3112 }
3113 }
3114 }
3115 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
3116 }
3117
3118 return Ret;
3119 }
3120
3121 /*
3122 * FUNCTION:
3123 * Searches a window's children for a window with the specified
3124 * class and name
3125 * ARGUMENTS:
3126 * hwndParent = The window whose childs are to be searched.
3127 * NULL = desktop
3128 * HWND_MESSAGE = message-only windows
3129 *
3130 * hwndChildAfter = Search starts after this child window.
3131 * NULL = start from beginning
3132 *
3133 * ucClassName = Class name to search for
3134 * Reguired parameter.
3135 *
3136 * ucWindowName = Window name
3137 * ->Buffer == NULL = don't care
3138 *
3139 * RETURNS:
3140 * The HWND of the window if it was found, otherwise NULL
3141 */
3142 /*
3143 * @implemented
3144 */
3145 HWND APIENTRY
NtUserFindWindowEx(HWND hwndParent,HWND hwndChildAfter,PUNICODE_STRING ucClassName,PUNICODE_STRING ucWindowName,DWORD dwUnknown)3146 NtUserFindWindowEx(HWND hwndParent,
3147 HWND hwndChildAfter,
3148 PUNICODE_STRING ucClassName,
3149 PUNICODE_STRING ucWindowName,
3150 DWORD dwUnknown)
3151 {
3152 PWND Parent, ChildAfter;
3153 UNICODE_STRING ClassName = {0}, WindowName = {0};
3154 HWND Desktop, Ret = NULL;
3155 BOOL DoMessageWnd = FALSE;
3156 RTL_ATOM ClassAtom = (RTL_ATOM)0;
3157
3158 TRACE("Enter NtUserFindWindowEx\n");
3159 UserEnterShared();
3160
3161 if (ucClassName != NULL || ucWindowName != NULL)
3162 {
3163 _SEH2_TRY
3164 {
3165 if (ucClassName != NULL)
3166 {
3167 ClassName = ProbeForReadUnicodeString(ucClassName);
3168 if (ClassName.Length != 0)
3169 {
3170 ProbeForRead(ClassName.Buffer,
3171 ClassName.Length,
3172 sizeof(WCHAR));
3173 }
3174 else if (!IS_ATOM(ClassName.Buffer))
3175 {
3176 EngSetLastError(ERROR_INVALID_PARAMETER);
3177 _SEH2_LEAVE;
3178 }
3179
3180 if (!IntGetAtomFromStringOrAtom(&ClassName,
3181 &ClassAtom))
3182 {
3183 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS);
3184 _SEH2_LEAVE;
3185 }
3186 }
3187
3188 if (ucWindowName != NULL)
3189 {
3190 WindowName = ProbeForReadUnicodeString(ucWindowName);
3191 if (WindowName.Length != 0)
3192 {
3193 ProbeForRead(WindowName.Buffer,
3194 WindowName.Length,
3195 sizeof(WCHAR));
3196 }
3197 }
3198 }
3199 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3200 {
3201 SetLastNtError(_SEH2_GetExceptionCode());
3202 _SEH2_YIELD(goto Exit); // Return NULL
3203 }
3204 _SEH2_END;
3205
3206 if (ucClassName != NULL)
3207 {
3208 if (ClassName.Length == 0 && ClassName.Buffer != NULL &&
3209 !IS_ATOM(ClassName.Buffer))
3210 {
3211 EngSetLastError(ERROR_INVALID_PARAMETER);
3212 goto Exit; // Return NULL
3213 }
3214 else if (ClassAtom == (RTL_ATOM)0)
3215 {
3216 /* LastError code was set by IntGetAtomFromStringOrAtom */
3217 goto Exit; // Return NULL
3218 }
3219 }
3220 }
3221
3222 Desktop = IntGetCurrentThreadDesktopWindow();
3223
3224 if(hwndParent == NULL)
3225 {
3226 hwndParent = Desktop;
3227 DoMessageWnd = TRUE;
3228 }
3229 else if(hwndParent == HWND_MESSAGE)
3230 {
3231 hwndParent = IntGetMessageWindow();
3232 }
3233
3234 if(!(Parent = UserGetWindowObject(hwndParent)))
3235 {
3236 goto Exit; // Return NULL
3237 }
3238
3239 ChildAfter = NULL;
3240 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter)))
3241 {
3242 goto Exit; // Return NULL
3243 }
3244
3245 _SEH2_TRY
3246 {
3247 if(UserHMGetHandle(Parent) == Desktop)
3248 {
3249 HWND *List, *phWnd;
3250 PWND TopLevelWindow;
3251 BOOLEAN CheckWindowName;
3252 BOOLEAN WindowMatches;
3253 BOOLEAN ClassMatches;
3254
3255 /* windows searches through all top-level windows if the parent is the desktop
3256 window */
3257
3258 if((List = IntWinListChildren(Parent)))
3259 {
3260 phWnd = List;
3261
3262 if(ChildAfter)
3263 {
3264 /* skip handles before and including ChildAfter */
3265 while(*phWnd && (*(phWnd++) != UserHMGetHandle(ChildAfter)))
3266 ;
3267 }
3268
3269 CheckWindowName = WindowName.Buffer != 0;
3270
3271 /* search children */
3272 while(*phWnd)
3273 {
3274 UNICODE_STRING ustr;
3275
3276 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++))))
3277 {
3278 continue;
3279 }
3280
3281 /* Do not send WM_GETTEXT messages in the kernel mode version!
3282 The user mode version however calls GetWindowText() which will
3283 send WM_GETTEXT messages to windows belonging to its processes */
3284 ustr.Buffer = TopLevelWindow->strName.Buffer;
3285 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated
3286 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT);
3287 WindowMatches = !CheckWindowName ||
3288 (TopLevelWindow->strName.Length < 0xFFFF &&
3289 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE));
3290 ClassMatches = (ClassAtom == (RTL_ATOM)0) ||
3291 ClassAtom == TopLevelWindow->pcls->atomNVClassName;
3292
3293 if (WindowMatches && ClassMatches)
3294 {
3295 Ret = UserHMGetHandle(TopLevelWindow);
3296 break;
3297 }
3298
3299 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName))
3300 {
3301 /* window returns the handle of the top-level window, in case it found
3302 the child window */
3303 Ret = UserHMGetHandle(TopLevelWindow);
3304 break;
3305 }
3306
3307 }
3308 ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
3309 }
3310 }
3311 else
3312 {
3313 TRACE("FindWindowEx: Not Desktop Parent!\n");
3314 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName);
3315 }
3316
3317 if (Ret == NULL && DoMessageWnd)
3318 {
3319 PWND MsgWindows;
3320
3321 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow())))
3322 {
3323 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName);
3324 }
3325 }
3326 }
3327 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3328 {
3329 SetLastNtError(_SEH2_GetExceptionCode());
3330 Ret = NULL;
3331 }
3332 _SEH2_END;
3333
3334 Exit:
3335 TRACE("Leave NtUserFindWindowEx, ret %p\n", Ret);
3336 UserLeave();
3337 return Ret;
3338 }
3339
3340
3341 /*
3342 * @implemented
3343 */
UserGetAncestor(PWND Wnd,UINT Type)3344 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type)
3345 {
3346 PWND WndAncestor, Parent;
3347
3348 if (UserHMGetHandle(Wnd) == IntGetDesktopWindow())
3349 {
3350 return NULL;
3351 }
3352
3353 switch (Type)
3354 {
3355 case GA_PARENT:
3356 {
3357 WndAncestor = Wnd->spwndParent;
3358 break;
3359 }
3360
3361 case GA_ROOT:
3362 {
3363 WndAncestor = Wnd;
3364 Parent = NULL;
3365
3366 for(;;)
3367 {
3368 if(!(Parent = WndAncestor->spwndParent))
3369 {
3370 break;
3371 }
3372 if(IntIsDesktopWindow(Parent))
3373 {
3374 break;
3375 }
3376
3377 WndAncestor = Parent;
3378 }
3379 break;
3380 }
3381
3382 case GA_ROOTOWNER:
3383 {
3384 WndAncestor = Wnd;
3385
3386 for (;;)
3387 {
3388 Parent = IntGetParent(WndAncestor);
3389
3390 if (!Parent)
3391 {
3392 break;
3393 }
3394
3395 WndAncestor = Parent;
3396 }
3397 break;
3398 }
3399
3400 default:
3401 {
3402 return NULL;
3403 }
3404 }
3405
3406 return WndAncestor;
3407 }
3408
3409 /*
3410 * @implemented
3411 */
3412 HWND APIENTRY
NtUserGetAncestor(HWND hWnd,UINT Type)3413 NtUserGetAncestor(HWND hWnd, UINT Type)
3414 {
3415 PWND Window, Ancestor;
3416 HWND Ret = NULL;
3417
3418 TRACE("Enter NtUserGetAncestor\n");
3419 UserEnterExclusive();
3420
3421 Window = UserGetWindowObject(hWnd);
3422 if (Window)
3423 {
3424 Ancestor = UserGetAncestor(Window, Type);
3425 /* fixme: can UserGetAncestor ever return NULL for a valid window? */
3426
3427 Ret = (Ancestor ? UserHMGetHandle(Ancestor) : NULL);
3428 }
3429
3430 TRACE("Leave NtUserGetAncestor, ret=%p\n", Ret);
3431 UserLeave();
3432 return Ret;
3433 }
3434
3435 ////
3436 //// ReactOS work around! Keep it the sames as in Combo.c and Controls.h
3437 ////
3438 /* combo state struct */
3439 typedef struct
3440 {
3441 HWND self;
3442 HWND owner;
3443 UINT dwStyle;
3444 HWND hWndEdit;
3445 HWND hWndLBox;
3446 UINT wState;
3447 HFONT hFont;
3448 RECT textRect;
3449 RECT buttonRect;
3450 RECT droppedRect;
3451 INT droppedIndex;
3452 INT fixedOwnerDrawHeight;
3453 INT droppedWidth; /* last two are not used unless set */
3454 INT editHeight; /* explicitly */
3455 LONG UIState;
3456 } HEADCOMBO,*LPHEADCOMBO;
3457
3458 // Window Extra data container.
3459 typedef struct _WND2CBOX
3460 {
3461 WND;
3462 LPHEADCOMBO pCBox;
3463 } WND2CBOX, *PWND2CBOX;
3464
3465 #define CBF_BUTTONDOWN 0x0002
3466 ////
3467 ////
3468 ////
3469 BOOL
3470 APIENTRY
NtUserGetComboBoxInfo(HWND hWnd,PCOMBOBOXINFO pcbi)3471 NtUserGetComboBoxInfo(
3472 HWND hWnd,
3473 PCOMBOBOXINFO pcbi)
3474 {
3475 PWND Wnd;
3476 PPROCESSINFO ppi;
3477 BOOL NotSameppi = FALSE;
3478 BOOL Ret = TRUE;
3479
3480 TRACE("Enter NtUserGetComboBoxInfo\n");
3481 UserEnterShared();
3482
3483 if (!(Wnd = UserGetWindowObject(hWnd)))
3484 {
3485 Ret = FALSE;
3486 goto Exit;
3487 }
3488 _SEH2_TRY
3489 {
3490 ProbeForWrite(pcbi, sizeof(COMBOBOXINFO), 1);
3491 }
3492 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3493 {
3494 SetLastNtError(_SEH2_GetExceptionCode());
3495 Ret = FALSE;
3496 _SEH2_YIELD(goto Exit);
3497 }
3498 _SEH2_END;
3499
3500 if (pcbi->cbSize < sizeof(COMBOBOXINFO))
3501 {
3502 EngSetLastError(ERROR_INVALID_PARAMETER);
3503 Ret = FALSE;
3504 goto Exit;
3505 }
3506
3507 // Pass the user pointer, it was already probed.
3508 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_COMBOBOX]) && Wnd->fnid != FNID_COMBOBOX)
3509 {
3510 Ret = (BOOL)co_IntSendMessage(UserHMGetHandle(Wnd), CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi);
3511 goto Exit;
3512 }
3513
3514 ppi = PsGetCurrentProcessWin32Process();
3515 NotSameppi = ppi != Wnd->head.pti->ppi;
3516 if (NotSameppi)
3517 {
3518 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3519 }
3520
3521 _SEH2_TRY
3522 {
3523 LPHEADCOMBO lphc = ((PWND2CBOX)Wnd)->pCBox;
3524 pcbi->rcItem = lphc->textRect;
3525 pcbi->rcButton = lphc->buttonRect;
3526 pcbi->stateButton = 0;
3527 if (lphc->wState & CBF_BUTTONDOWN)
3528 pcbi->stateButton |= STATE_SYSTEM_PRESSED;
3529 if (RECTL_bIsEmptyRect(&lphc->buttonRect))
3530 pcbi->stateButton |= STATE_SYSTEM_INVISIBLE;
3531 pcbi->hwndCombo = lphc->self;
3532 pcbi->hwndItem = lphc->hWndEdit;
3533 pcbi->hwndList = lphc->hWndLBox;
3534 }
3535 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3536 {
3537 Ret = FALSE;
3538 SetLastNtError(_SEH2_GetExceptionCode());
3539 }
3540 _SEH2_END;
3541
3542 Exit:
3543 if (NotSameppi) KeDetachProcess();
3544 TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n", Ret);
3545 UserLeave();
3546 return Ret;
3547 }
3548
3549 ////
3550 //// ReactOS work around! Keep it the sames as in Listbox.c
3551 ////
3552 /* Listbox structure */
3553 typedef struct
3554 {
3555 HWND self; /* Our own window handle */
3556 HWND owner; /* Owner window to send notifications to */
3557 UINT style; /* Window style */
3558 INT width; /* Window width */
3559 INT height; /* Window height */
3560 VOID *items; /* Array of items */
3561 INT nb_items; /* Number of items */
3562 INT top_item; /* Top visible item */
3563 INT selected_item; /* Selected item */
3564 INT focus_item; /* Item that has the focus */
3565 INT anchor_item; /* Anchor item for extended selection */
3566 INT item_height; /* Default item height */
3567 INT page_size; /* Items per listbox page */
3568 INT column_width; /* Column width for multi-column listboxes */
3569 } LB_DESCR;
3570
3571 // Window Extra data container.
3572 typedef struct _WND2LB
3573 {
3574 WND;
3575 LB_DESCR * pLBiv;
3576 } WND2LB, *PWND2LB;
3577 ////
3578 ////
3579 ////
3580 DWORD
3581 APIENTRY
NtUserGetListBoxInfo(HWND hWnd)3582 NtUserGetListBoxInfo(
3583 HWND hWnd)
3584 {
3585 PWND Wnd;
3586 PPROCESSINFO ppi;
3587 BOOL NotSameppi = FALSE;
3588 DWORD Ret = 0;
3589
3590 TRACE("Enter NtUserGetListBoxInfo\n");
3591 UserEnterShared();
3592
3593 if (!(Wnd = UserGetWindowObject(hWnd)))
3594 {
3595 goto Exit; // Return 0
3596 }
3597
3598 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && Wnd->fnid != FNID_LISTBOX)
3599 {
3600 Ret = (DWORD)co_IntSendMessage(UserHMGetHandle(Wnd), LB_GETLISTBOXINFO, 0, 0);
3601 goto Exit;
3602 }
3603
3604 // wine lisbox:test_GetListBoxInfo lb_getlistboxinfo = 0, should not send a message!
3605 ppi = PsGetCurrentProcessWin32Process();
3606 NotSameppi = ppi != Wnd->head.pti->ppi;
3607 if (NotSameppi)
3608 {
3609 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb);
3610 }
3611
3612 _SEH2_TRY
3613 {
3614 LB_DESCR *descr = ((PWND2LB)Wnd)->pLBiv;
3615 // See Controls ListBox.c:LB_GETLISTBOXINFO must match...
3616 Ret = descr->page_size;
3617 }
3618 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3619 {
3620 Ret = 0;
3621 SetLastNtError(_SEH2_GetExceptionCode());
3622 }
3623 _SEH2_END;
3624
3625 Exit:
3626 if (NotSameppi) KeDetachProcess();
3627 TRACE("Leave NtUserGetListBoxInfo, ret=%lu\n", Ret);
3628 UserLeave();
3629 return Ret;
3630 }
3631
3632 /*
3633 * NtUserSetParent
3634 *
3635 * The NtUserSetParent function changes the parent window of the specified
3636 * child window.
3637 *
3638 * Remarks
3639 * The new parent window and the child window must belong to the same
3640 * application. If the window identified by the hWndChild parameter is
3641 * visible, the system performs the appropriate redrawing and repainting.
3642 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD
3643 * or WS_POPUP window styles of the window whose parent is being changed.
3644 *
3645 * Status
3646 * @implemented
3647 */
3648
3649 HWND APIENTRY
NtUserSetParent(HWND hWndChild,HWND hWndNewParent)3650 NtUserSetParent(HWND hWndChild, HWND hWndNewParent)
3651 {
3652 HWND Ret;
3653
3654 TRACE("Enter NtUserSetParent\n");
3655 UserEnterExclusive();
3656
3657 /*
3658 Check Parent first from user space, set it here.
3659 */
3660 if (!hWndNewParent)
3661 {
3662 hWndNewParent = IntGetDesktopWindow();
3663 }
3664 else if (hWndNewParent == HWND_MESSAGE)
3665 {
3666 hWndNewParent = IntGetMessageWindow();
3667 }
3668
3669 Ret = co_UserSetParent(hWndChild, hWndNewParent);
3670
3671 TRACE("Leave NtUserSetParent, ret=%p\n", Ret);
3672 UserLeave();
3673 return Ret;
3674 }
3675
3676 /*
3677 * UserGetShellWindow
3678 *
3679 * Returns a handle to shell window that was set by NtUserSetShellWindowEx.
3680 *
3681 * Status
3682 * @implemented
3683 */
UserGetShellWindow(VOID)3684 HWND FASTCALL UserGetShellWindow(VOID)
3685 {
3686 PWINSTATION_OBJECT WinStaObject;
3687 HWND Ret;
3688
3689 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3690 UserMode,
3691 0,
3692 &WinStaObject,
3693 0);
3694
3695 if (!NT_SUCCESS(Status))
3696 {
3697 SetLastNtError(Status);
3698 return NULL;
3699 }
3700
3701 Ret = (HWND)WinStaObject->ShellWindow;
3702
3703 ObDereferenceObject(WinStaObject);
3704 return Ret;
3705 }
3706
3707 /*
3708 * NtUserSetShellWindowEx
3709 *
3710 * This is undocumented function to set global shell window. The global
3711 * shell window has special handling of window position.
3712 *
3713 * Status
3714 * @implemented
3715 */
3716 BOOL APIENTRY
NtUserSetShellWindowEx(HWND hwndShell,HWND hwndListView)3717 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView)
3718 {
3719 PWINSTATION_OBJECT WinStaObject;
3720 PWND WndShell, WndListView;
3721 BOOL Ret = FALSE;
3722 USER_REFERENCE_ENTRY Ref;
3723 NTSTATUS Status;
3724 PTHREADINFO ti;
3725
3726 TRACE("Enter NtUserSetShellWindowEx\n");
3727 UserEnterExclusive();
3728
3729 if (!(WndShell = UserGetWindowObject(hwndShell)))
3730 {
3731 goto Exit; // Return FALSE
3732 }
3733
3734 if (!(WndListView = UserGetWindowObject(hwndListView)))
3735 {
3736 goto Exit; // Return FALSE
3737 }
3738
3739 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
3740 UserMode,
3741 0,
3742 &WinStaObject,
3743 0);
3744
3745 if (!NT_SUCCESS(Status))
3746 {
3747 SetLastNtError(Status);
3748 goto Exit; // Return FALSE
3749 }
3750
3751 /*
3752 * Test if we are permitted to change the shell window.
3753 */
3754 if (WinStaObject->ShellWindow)
3755 {
3756 ObDereferenceObject(WinStaObject);
3757 goto Exit; // Return FALSE
3758 }
3759
3760 /*
3761 * Move shell window into background.
3762 */
3763 if (hwndListView && hwndListView != hwndShell)
3764 {
3765 /*
3766 * Disabled for now to get Explorer working.
3767 * -- Filip, 01/nov/2003
3768 */
3769 #if 0
3770 co_WinPosSetWindowPos(WndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3771 #endif
3772
3773 if (WndListView->ExStyle & WS_EX_TOPMOST)
3774 {
3775 ObDereferenceObject(WinStaObject);
3776 goto Exit; // Return FALSE
3777 }
3778 }
3779
3780 if (WndShell->ExStyle & WS_EX_TOPMOST)
3781 {
3782 ObDereferenceObject(WinStaObject);
3783 goto Exit; // Return FALSE
3784 }
3785
3786 UserRefObjectCo(WndShell, &Ref);
3787 WndShell->state2 |= WNDS2_BOTTOMMOST;
3788 co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
3789
3790 WinStaObject->ShellWindow = hwndShell;
3791 WinStaObject->ShellListView = hwndListView;
3792
3793 ti = GetW32ThreadInfo();
3794 if (ti->pDeskInfo)
3795 {
3796 ti->pDeskInfo->hShellWindow = hwndShell;
3797 ti->pDeskInfo->spwndShell = WndShell;
3798 ti->pDeskInfo->spwndBkGnd = WndListView;
3799 ti->pDeskInfo->ppiShellProcess = ti->ppi;
3800 }
3801
3802 UserRegisterHotKey(WndShell, SC_TASKLIST, MOD_CONTROL, VK_ESCAPE);
3803
3804 UserDerefObjectCo(WndShell);
3805
3806 ObDereferenceObject(WinStaObject);
3807 Ret = TRUE;
3808
3809 Exit:
3810 TRACE("Leave NtUserSetShellWindowEx, ret=%i\n", Ret);
3811 UserLeave();
3812 return Ret;
3813 }
3814
3815 // Fixes wine Win test_window_styles and todo tests...
3816 static BOOL FASTCALL
IntCheckFrameEdge(ULONG Style,ULONG ExStyle)3817 IntCheckFrameEdge(ULONG Style, ULONG ExStyle)
3818 {
3819 if (ExStyle & WS_EX_DLGMODALFRAME)
3820 return TRUE;
3821 else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME)))
3822 return TRUE;
3823 else
3824 return FALSE;
3825 }
3826
3827 static LONG_PTR
co_IntSetWindowLongPtr(HWND hWnd,DWORD Index,LONG_PTR NewValue,BOOL Ansi,ULONG Size,BOOL bAlter)3828 co_IntSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi, ULONG Size, BOOL bAlter)
3829 {
3830 PWND Window, Parent;
3831 PWINSTATION_OBJECT WindowStation;
3832 LONG_PTR OldValue;
3833 STYLESTRUCT Style;
3834
3835 if (!(Window = UserGetWindowObject(hWnd)))
3836 {
3837 return 0;
3838 }
3839
3840 if ((INT)Index >= 0)
3841 {
3842 if ((Index + Size) > Window->cbwndExtra)
3843 {
3844 EngSetLastError(ERROR_INVALID_INDEX);
3845 return 0;
3846 }
3847
3848 PVOID Address = (PUCHAR)(&Window[1]) + Index;
3849
3850 #ifdef _WIN64
3851 if (Size == sizeof(LONG))
3852 {
3853 OldValue = ReadUnalignedU32(Address);
3854 WriteUnalignedU32(Address, NewValue);
3855 }
3856 else
3857 #endif
3858 {
3859 OldValue = ReadUnalignedUlongPtr(Address);
3860 /*
3861 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW)
3862 {
3863 OldValue = (LONG_PTR)IntSetWindowProc( Wnd, (WNDPROC)NewValue, Ansi);
3864 if (!OldValue) return 0;
3865 }
3866 */
3867 WriteUnalignedUlongPtr(Address, NewValue);
3868 }
3869
3870 }
3871 else
3872 {
3873 #ifdef _WIN64
3874 if (Size == sizeof(LONG))
3875 {
3876 if ((Index != GWL_STYLE) &&
3877 (Index != GWL_EXSTYLE) &&
3878 (Index != GWL_ID) &&
3879 (Index != GWL_USERDATA))
3880 {
3881 ERR("NtUserSetWindowLong(): Index requires pointer size: %lu\n", Index);
3882 EngSetLastError(ERROR_INVALID_INDEX);
3883 return 0;
3884 }
3885 }
3886 #endif
3887
3888 switch (Index)
3889 {
3890 case GWL_EXSTYLE: // LONG
3891 OldValue = (LONG) Window->ExStyle;
3892 Style.styleOld = OldValue;
3893 Style.styleNew = NewValue;
3894
3895 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style);
3896
3897 /*
3898 * Remove extended window style bit WS_EX_TOPMOST for shell windows.
3899 */
3900 WindowStation = Window->head.pti->rpdesk->rpwinstaParent;
3901 if(WindowStation)
3902 {
3903 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView)
3904 Style.styleNew &= ~WS_EX_TOPMOST;
3905 }
3906 /* WS_EX_WINDOWEDGE depends on some other styles */
3907 if (IntCheckFrameEdge(Window->style, NewValue))
3908 Style.styleNew |= WS_EX_WINDOWEDGE;
3909 else
3910 Style.styleNew &= ~WS_EX_WINDOWEDGE;
3911
3912 if (!(Window->ExStyle & WS_EX_LAYERED))
3913 {
3914 SetLayeredStatus(Window, 0);
3915 }
3916
3917 Window->ExStyle = (DWORD)Style.styleNew;
3918
3919 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style);
3920 break;
3921
3922 case GWL_STYLE: // LONG
3923 OldValue = (LONG) Window->style;
3924 Style.styleOld = OldValue;
3925 Style.styleNew = NewValue;
3926
3927 if (!bAlter)
3928 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style);
3929
3930 /* WS_CLIPSIBLINGS can't be reset on top-level windows */
3931 if (UserIsDesktopWindow(Window->spwndParent)) Style.styleNew |= WS_CLIPSIBLINGS;
3932 /* WS_MINIMIZE can't be reset */
3933 if (OldValue & WS_MINIMIZE) Style.styleNew |= WS_MINIMIZE;
3934 /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */
3935 if (IntCheckFrameEdge(NewValue, Window->ExStyle))
3936 Window->ExStyle |= WS_EX_WINDOWEDGE;
3937 else
3938 Window->ExStyle &= ~WS_EX_WINDOWEDGE;
3939
3940 if ((OldValue & (WS_CHILD | WS_POPUP)) == WS_CHILD)
3941 {
3942 if ((NewValue & (WS_CHILD | WS_POPUP)) != WS_CHILD)
3943 {
3944 //// From child to non-child it should be null already.
3945 ERR("IDMenu going null! %d\n",Window->IDMenu);
3946 Window->IDMenu = 0; // Window->spmenu = 0;
3947 }
3948 }
3949 else
3950 {
3951 if ((NewValue & (WS_CHILD | WS_POPUP)) == WS_CHILD)
3952 {
3953 PMENU pMenu = UserGetMenuObject(UlongToHandle(Window->IDMenu));
3954 Window->state &= ~WNDS_HASMENU;
3955 if (pMenu)
3956 {
3957 ERR("IDMenu released 0x%p\n",pMenu);
3958 // ROS may not hold a lock after setting menu to window. But it should!
3959 //IntReleaseMenuObject(pMenu);
3960 }
3961 }
3962 }
3963
3964 if ((Style.styleOld ^ Style.styleNew) & WS_VISIBLE)
3965 {
3966 if (Style.styleOld & WS_VISIBLE) Window->head.pti->cVisWindows--;
3967 if (Style.styleNew & WS_VISIBLE) Window->head.pti->cVisWindows++;
3968 DceResetActiveDCEs( Window );
3969 }
3970 Window->style = (DWORD)Style.styleNew;
3971
3972 if (!bAlter)
3973 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style);
3974 break;
3975
3976 case GWLP_WNDPROC: // LONG_PTR
3977 {
3978 if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() ||
3979 Window->fnid & FNID_FREED)
3980 {
3981 EngSetLastError(ERROR_ACCESS_DENIED);
3982 return 0;
3983 }
3984 OldValue = (LONG_PTR)IntSetWindowProc(Window,
3985 (WNDPROC)NewValue,
3986 Ansi);
3987 break;
3988 }
3989
3990 case GWLP_HINSTANCE: // LONG_PTR
3991 OldValue = (LONG_PTR) Window->hModule;
3992 Window->hModule = (HINSTANCE) NewValue;
3993 break;
3994
3995 case GWLP_HWNDPARENT: // LONG_PTR
3996 Parent = Window->spwndParent;
3997 if (Parent && (UserHMGetHandle(Parent) == IntGetDesktopWindow()))
3998 OldValue = (LONG_PTR)IntSetOwner(UserHMGetHandle(Window), (HWND)NewValue);
3999 else
4000 OldValue = (LONG_PTR)co_UserSetParent(UserHMGetHandle(Window), (HWND)NewValue);
4001 break;
4002
4003 case GWLP_ID: // LONG
4004 OldValue = (LONG) Window->IDMenu;
4005 Window->IDMenu = (UINT) NewValue;
4006 break;
4007
4008 case GWLP_USERDATA: // LONG or LONG_PTR
4009 OldValue = Window->dwUserData;
4010 Window->dwUserData = NewValue;
4011 break;
4012
4013 default:
4014 ERR("NtUserSetWindowLong(): Unsupported index %lu\n", Index);
4015 EngSetLastError(ERROR_INVALID_INDEX);
4016 OldValue = 0;
4017 break;
4018 }
4019 }
4020
4021 return OldValue;
4022 }
4023
4024 LONG FASTCALL
co_UserSetWindowLong(HWND hWnd,DWORD Index,LONG NewValue,BOOL Ansi)4025 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
4026 {
4027 return (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE);
4028 }
4029
4030 LONG_PTR FASTCALL
co_UserSetWindowLongPtr(HWND hWnd,DWORD Index,LONG_PTR NewValue,BOOL Ansi)4031 co_UserSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi)
4032 {
4033 return co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE);
4034 }
4035
4036 /*
4037 * NtUserSetWindowLong
4038 *
4039 * The NtUserSetWindowLong function changes an attribute of the specified
4040 * window. The function also sets the 32-bit (long) value at the specified
4041 * offset into the extra window memory.
4042 *
4043 * Status
4044 * @implemented
4045 */
4046
4047 LONG APIENTRY
NtUserSetWindowLong(HWND hWnd,DWORD Index,LONG NewValue,BOOL Ansi)4048 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi)
4049 {
4050 LONG ret;
4051
4052 UserEnterExclusive();
4053
4054 if (hWnd == IntGetDesktopWindow())
4055 {
4056 EngSetLastError(STATUS_ACCESS_DENIED);
4057 UserLeave();
4058 return 0;
4059 }
4060
4061 ret = (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE);
4062
4063 UserLeave();
4064
4065 return ret;
4066 }
4067
4068 #ifdef _WIN64
4069 LONG_PTR APIENTRY
NtUserSetWindowLongPtr(HWND hWnd,DWORD Index,LONG_PTR NewValue,BOOL Ansi)4070 NtUserSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi)
4071 {
4072 LONG_PTR ret;
4073
4074 UserEnterExclusive();
4075
4076 if (hWnd == IntGetDesktopWindow())
4077 {
4078 EngSetLastError(STATUS_ACCESS_DENIED);
4079 UserLeave();
4080 return 0;
4081 }
4082
4083 ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE);
4084
4085 UserLeave();
4086
4087 return ret;
4088 }
4089 #endif // _WIN64
4090
4091 DWORD APIENTRY
NtUserAlterWindowStyle(HWND hWnd,DWORD Index,LONG NewValue)4092 NtUserAlterWindowStyle(HWND hWnd, DWORD Index, LONG NewValue)
4093 {
4094 LONG ret;
4095
4096 UserEnterExclusive();
4097
4098 if (hWnd == IntGetDesktopWindow())
4099 {
4100 EngSetLastError(STATUS_ACCESS_DENIED);
4101 UserLeave();
4102 return 0;
4103 }
4104
4105 ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, FALSE, sizeof(LONG), TRUE);
4106
4107 UserLeave();
4108
4109 return ret;
4110 }
4111
4112
4113 /*
4114 * NtUserSetWindowWord
4115 *
4116 * Legacy function similar to NtUserSetWindowLong.
4117 *
4118 * Status
4119 * @implemented
4120 */
4121
4122 WORD APIENTRY
NtUserSetWindowWord(HWND hWnd,INT Index,WORD NewValue)4123 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue)
4124 {
4125 PWND Window;
4126 WORD OldValue;
4127 WORD Ret = 0;
4128
4129 TRACE("Enter NtUserSetWindowWord\n");
4130 UserEnterExclusive();
4131
4132 if (hWnd == IntGetDesktopWindow())
4133 {
4134 EngSetLastError(STATUS_ACCESS_DENIED);
4135 goto Exit; // Return 0
4136 }
4137
4138 if (!(Window = UserGetWindowObject(hWnd)))
4139 {
4140 goto Exit; // Return 0
4141 }
4142
4143 switch (Index)
4144 {
4145 case GWL_ID:
4146 case GWL_HINSTANCE:
4147 case GWL_HWNDPARENT:
4148 Ret = (WORD)co_UserSetWindowLong(UserHMGetHandle(Window), Index, (UINT)NewValue, TRUE);
4149 goto Exit;
4150
4151 default:
4152 if (Index < 0)
4153 {
4154 EngSetLastError(ERROR_INVALID_INDEX);
4155 goto Exit; // Return 0
4156 }
4157 }
4158
4159 if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD)))
4160 {
4161 EngSetLastError(ERROR_INVALID_INDEX);
4162 goto Exit; // Return 0
4163 }
4164
4165 OldValue = *((WORD *)((PCHAR)(Window + 1) + Index));
4166 *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue;
4167
4168 Ret = OldValue;
4169
4170 Exit:
4171 TRACE("Leave NtUserSetWindowWord, ret=%u\n", Ret);
4172 UserLeave();
4173 return Ret;
4174 }
4175
4176 /*
4177 QueryWindow based on KJK::Hyperion and James Tabor.
4178
4179 0 = QWUniqueProcessId
4180 1 = QWUniqueThreadId
4181 2 = QWActiveWindow
4182 3 = QWFocusWindow
4183 4 = QWIsHung Implements IsHungAppWindow found
4184 by KJK::Hyperion.
4185
4186 9 = QWKillWindow When I called this with hWnd ==
4187 DesktopWindow, it shutdown the system
4188 and rebooted.
4189 */
4190 /*
4191 * @implemented
4192 */
4193 DWORD_PTR APIENTRY
NtUserQueryWindow(HWND hWnd,DWORD Index)4194 NtUserQueryWindow(HWND hWnd, DWORD Index)
4195 {
4196 /* Console Leader Process CID Window offsets */
4197 #define GWLP_CONSOLE_LEADER_PID 0
4198 #define GWLP_CONSOLE_LEADER_TID 4
4199
4200 DWORD_PTR Result = 0;
4201 PWND pWnd, pwndActive;
4202 PTHREADINFO pti, ptiActive;
4203
4204 TRACE("Enter NtUserQueryWindow\n");
4205 UserEnterShared();
4206
4207 if (!(pWnd = UserGetWindowObject(hWnd)))
4208 {
4209 goto Exit; // Return 0
4210 }
4211
4212 switch(Index)
4213 {
4214 case QUERY_WINDOW_UNIQUE_PROCESS_ID:
4215 {
4216 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
4217 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
4218 {
4219 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_PID)
4220 Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_PID)));
4221 }
4222 else
4223 {
4224 Result = (DWORD_PTR)IntGetWndProcessId(pWnd);
4225 }
4226 break;
4227 }
4228
4229 case QUERY_WINDOW_UNIQUE_THREAD_ID:
4230 {
4231 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) &&
4232 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) )
4233 {
4234 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_TID)
4235 Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_TID)));
4236 }
4237 else
4238 {
4239 Result = (DWORD_PTR)IntGetWndThreadId(pWnd);
4240 }
4241 break;
4242 }
4243
4244 case QUERY_WINDOW_ACTIVE:
4245 Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndActive ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndActive) : 0);
4246 break;
4247
4248 case QUERY_WINDOW_FOCUS:
4249 Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndFocus ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndFocus) : 0);
4250 break;
4251
4252 case QUERY_WINDOW_ISHUNG:
4253 Result = (pWnd->fnid == FNID_GHOST) || MsqIsHung(pWnd->head.pti, MSQ_HUNG);
4254 break;
4255
4256 case QUERY_WINDOW_REAL_ID:
4257 Result = (DWORD_PTR)pWnd->head.pti->pEThread->Cid.UniqueProcess;
4258 break;
4259
4260 case QUERY_WINDOW_FOREGROUND:
4261 Result = (pWnd->head.pti->MessageQueue == gpqForeground);
4262 break;
4263
4264 case QUERY_WINDOW_DEFAULT_IME: /* default IME window */
4265 if (pWnd->head.pti->spwndDefaultIme)
4266 Result = (DWORD_PTR)UserHMGetHandle(pWnd->head.pti->spwndDefaultIme);
4267 break;
4268
4269 case QUERY_WINDOW_DEFAULT_ICONTEXT: /* default input context handle */
4270 if (pWnd->head.pti->spDefaultImc)
4271 Result = (DWORD_PTR)UserHMGetHandle(pWnd->head.pti->spDefaultImc);
4272 break;
4273
4274 case QUERY_WINDOW_ACTIVE_IME:
4275 if (gpqForeground && gpqForeground->spwndActive)
4276 {
4277 pwndActive = gpqForeground->spwndActive;
4278 pti = PsGetCurrentThreadWin32Thread();
4279 if (pti->rpdesk == pwndActive->head.rpdesk)
4280 {
4281 ptiActive = pwndActive->head.pti;
4282 if (ptiActive->spwndDefaultIme)
4283 Result = (DWORD_PTR)UserHMGetHandle(ptiActive->spwndDefaultIme);
4284 }
4285 }
4286 break;
4287 }
4288
4289 Exit:
4290 TRACE("Leave NtUserQueryWindow, ret=%u\n", Result);
4291 UserLeave();
4292 return Result;
4293 }
4294
4295 /*
4296 * @implemented
4297 */
4298 UINT APIENTRY
NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)4299 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe)
4300 {
4301 UNICODE_STRING SafeMessageName;
4302 NTSTATUS Status;
4303 UINT Ret = 0;
4304
4305 TRACE("Enter NtUserRegisterWindowMessage\n");
4306 UserEnterExclusive();
4307
4308 if(MessageNameUnsafe == NULL)
4309 {
4310 EngSetLastError(ERROR_INVALID_PARAMETER);
4311 goto Exit; // Return 0
4312 }
4313
4314 Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe);
4315 if(!NT_SUCCESS(Status))
4316 {
4317 SetLastNtError(Status);
4318 goto Exit; // Return 0
4319 }
4320
4321 Ret = (UINT)IntAddAtom(SafeMessageName.Buffer);
4322 if (SafeMessageName.Buffer)
4323 ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING);
4324
4325 Exit:
4326 TRACE("Leave NtUserRegisterWindowMessage, ret=%u\n", Ret);
4327 UserLeave();
4328 return Ret;
4329 }
4330
4331 /*
4332 * @implemented
4333 */
4334 BOOL APIENTRY
NtUserSetWindowFNID(HWND hWnd,WORD fnID)4335 NtUserSetWindowFNID(HWND hWnd,
4336 WORD fnID)
4337 {
4338 PWND Wnd;
4339 BOOL Ret = FALSE;
4340
4341 TRACE("Enter NtUserSetWindowFNID\n");
4342 UserEnterExclusive();
4343
4344 if (!(Wnd = UserGetWindowObject(hWnd)))
4345 {
4346 goto Exit; // Return FALSE
4347 }
4348
4349 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
4350 {
4351 EngSetLastError(ERROR_ACCESS_DENIED);
4352 goto Exit; // Return FALSE
4353 }
4354
4355 // From user land we only set these.
4356 if (fnID != FNID_DESTROY)
4357 {
4358 /* HACK: The minimum should be FNID_BUTTON, but menu code relies on this */
4359 if (fnID < FNID_FIRST || fnID > FNID_GHOST ||
4360 Wnd->fnid != 0)
4361 {
4362 EngSetLastError(ERROR_INVALID_PARAMETER);
4363 goto Exit; // Return FALSE
4364 }
4365 }
4366
4367 Wnd->fnid |= fnID;
4368 Ret = TRUE;
4369
4370 Exit:
4371 TRACE("Leave NtUserSetWindowFNID\n");
4372 UserLeave();
4373 return Ret;
4374 }
4375
4376 BOOL APIENTRY
DefSetText(PWND Wnd,PCWSTR WindowText)4377 DefSetText(PWND Wnd, PCWSTR WindowText)
4378 {
4379 UNICODE_STRING UnicodeString;
4380 BOOL Ret = FALSE;
4381
4382 RtlInitUnicodeString(&UnicodeString, WindowText);
4383
4384 if (UnicodeString.Length != 0)
4385 {
4386 if (Wnd->strName.MaximumLength > 0 &&
4387 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4388 {
4389 ASSERT(Wnd->strName.Buffer != NULL);
4390
4391 Wnd->strName.Length = UnicodeString.Length;
4392 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4393 RtlCopyMemory(Wnd->strName.Buffer,
4394 UnicodeString.Buffer,
4395 UnicodeString.Length);
4396 }
4397 else
4398 {
4399 PWCHAR buf;
4400 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4401 buf = Wnd->strName.Buffer;
4402 Wnd->strName.Buffer = NULL;
4403 if (buf != NULL)
4404 {
4405 DesktopHeapFree(Wnd->head.rpdesk, buf);
4406 }
4407
4408 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4409 UnicodeString.Length + sizeof(UNICODE_NULL));
4410 if (Wnd->strName.Buffer != NULL)
4411 {
4412 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4413 RtlCopyMemory(Wnd->strName.Buffer,
4414 UnicodeString.Buffer,
4415 UnicodeString.Length);
4416 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4417 Wnd->strName.Length = UnicodeString.Length;
4418 }
4419 else
4420 {
4421 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4422 goto Exit;
4423 }
4424 }
4425 }
4426 else
4427 {
4428 Wnd->strName.Length = 0;
4429 if (Wnd->strName.Buffer != NULL)
4430 Wnd->strName.Buffer[0] = L'\0';
4431 }
4432
4433 // FIXME: HAX! Windows does not do this in here!
4434 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4435 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4436 /* Send shell notifications */
4437 if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4438 {
4439 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) UserHMGetHandle(Wnd), FALSE); // FIXME Flashing?
4440 }
4441
4442 Ret = TRUE;
4443 Exit:
4444 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4445 return Ret;
4446 }
4447
4448 /*
4449 * NtUserDefSetText
4450 *
4451 * Undocumented function that is called from DefWindowProc to set
4452 * window text.
4453 *
4454 * Status
4455 * @implemented
4456 */
4457 BOOL APIENTRY
NtUserDefSetText(HWND hWnd,PLARGE_STRING WindowText)4458 NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText)
4459 {
4460 PWND Wnd;
4461 LARGE_STRING SafeText;
4462 UNICODE_STRING UnicodeString;
4463 BOOL Ret = TRUE;
4464
4465 TRACE("Enter NtUserDefSetText\n");
4466
4467 if (WindowText != NULL)
4468 {
4469 _SEH2_TRY
4470 {
4471 SafeText = ProbeForReadLargeString(WindowText);
4472 }
4473 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4474 {
4475 Ret = FALSE;
4476 SetLastNtError(_SEH2_GetExceptionCode());
4477 }
4478 _SEH2_END;
4479
4480 if (!Ret)
4481 return FALSE;
4482 }
4483 else
4484 return TRUE;
4485
4486 UserEnterExclusive();
4487
4488 if(!(Wnd = UserGetWindowObject(hWnd)))
4489 {
4490 UserLeave();
4491 return FALSE;
4492 }
4493
4494 // ReactOS uses Unicode and not mixed. Up/Down converting will take time.
4495 // Brought to you by: The Wine Project! Dysfunctional Thought Processes!
4496 // Now we know what the bAnsi is for.
4497 RtlInitUnicodeString(&UnicodeString, NULL);
4498 if (SafeText.Buffer)
4499 {
4500 _SEH2_TRY
4501 {
4502 if (SafeText.bAnsi)
4503 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR));
4504 else
4505 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR));
4506 Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText);
4507 }
4508 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4509 {
4510 Ret = FALSE;
4511 SetLastNtError(_SEH2_GetExceptionCode());
4512 }
4513 _SEH2_END;
4514 if (!Ret) goto Exit;
4515 }
4516
4517 if (UnicodeString.Length != 0)
4518 {
4519 if (Wnd->strName.MaximumLength > 0 &&
4520 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL))
4521 {
4522 ASSERT(Wnd->strName.Buffer != NULL);
4523
4524 Wnd->strName.Length = UnicodeString.Length;
4525 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4526 RtlCopyMemory(Wnd->strName.Buffer,
4527 UnicodeString.Buffer,
4528 UnicodeString.Length);
4529 }
4530 else
4531 {
4532 PWCHAR buf;
4533 Wnd->strName.MaximumLength = Wnd->strName.Length = 0;
4534 buf = Wnd->strName.Buffer;
4535 Wnd->strName.Buffer = NULL;
4536 if (buf != NULL)
4537 {
4538 DesktopHeapFree(Wnd->head.rpdesk, buf);
4539 }
4540
4541 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk,
4542 UnicodeString.Length + sizeof(UNICODE_NULL));
4543 if (Wnd->strName.Buffer != NULL)
4544 {
4545 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0';
4546 RtlCopyMemory(Wnd->strName.Buffer,
4547 UnicodeString.Buffer,
4548 UnicodeString.Length);
4549 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL);
4550 Wnd->strName.Length = UnicodeString.Length;
4551 }
4552 else
4553 {
4554 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
4555 Ret = FALSE;
4556 goto Exit;
4557 }
4558 }
4559 }
4560 else
4561 {
4562 Wnd->strName.Length = 0;
4563 if (Wnd->strName.Buffer != NULL)
4564 Wnd->strName.Buffer[0] = L'\0';
4565 }
4566
4567 // FIXME: HAX! Windows does not do this in here!
4568 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than
4569 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc.
4570 /* Send shell notifications */
4571 if (!Wnd->spwndOwner && !IntGetParent(Wnd))
4572 {
4573 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) hWnd, FALSE); // FIXME Flashing?
4574 }
4575
4576 Ret = TRUE;
4577 Exit:
4578 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString);
4579 TRACE("Leave NtUserDefSetText, ret=%i\n", Ret);
4580 UserLeave();
4581 return Ret;
4582 }
4583
4584 /*
4585 * NtUserInternalGetWindowText
4586 *
4587 * Status
4588 * @implemented
4589 */
4590
4591 INT APIENTRY
NtUserInternalGetWindowText(HWND hWnd,LPWSTR lpString,INT nMaxCount)4592 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount)
4593 {
4594 PWND Wnd;
4595 NTSTATUS Status;
4596 INT Result = 0;
4597
4598 TRACE("Enter NtUserInternalGetWindowText\n");
4599 UserEnterShared();
4600
4601 if(lpString && (nMaxCount <= 1))
4602 {
4603 EngSetLastError(ERROR_INVALID_PARAMETER);
4604 goto Exit; // Return 0
4605 }
4606
4607 if(!(Wnd = UserGetWindowObject(hWnd)))
4608 {
4609 goto Exit; // Return 0
4610 }
4611
4612 Result = Wnd->strName.Length / sizeof(WCHAR);
4613 if(lpString)
4614 {
4615 const WCHAR Terminator = L'\0';
4616 INT Copy;
4617 WCHAR *Buffer = (WCHAR*)lpString;
4618
4619 Copy = min(nMaxCount - 1, Result);
4620 if(Copy > 0)
4621 {
4622 Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR));
4623 if(!NT_SUCCESS(Status))
4624 {
4625 SetLastNtError(Status);
4626 Result = 0;
4627 goto Exit;
4628 }
4629 Buffer += Copy;
4630 }
4631
4632 Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR));
4633 if(!NT_SUCCESS(Status))
4634 {
4635 SetLastNtError(Status);
4636 Result = 0;
4637 goto Exit;
4638 }
4639
4640 Result = Copy;
4641 }
4642
4643 Exit:
4644 TRACE("Leave NtUserInternalGetWindowText, ret=%i\n", Result);
4645 UserLeave();
4646 return Result;
4647 }
4648
4649 /*
4650 API Call
4651 */
4652 BOOL
4653 FASTCALL
IntShowOwnedPopups(PWND OwnerWnd,BOOL fShow)4654 IntShowOwnedPopups(PWND OwnerWnd, BOOL fShow )
4655 {
4656 int count = 0;
4657 PWND pWnd;
4658 HWND *win_array;
4659
4660 // ASSERT(OwnerWnd);
4661
4662 TRACE("Enter ShowOwnedPopups Show: %s\n", (fShow ? "TRUE" : "FALSE"));
4663
4664 /* NOTE: Popups are not children */
4665 win_array = IntWinListOwnedPopups(OwnerWnd);
4666
4667 if (!win_array)
4668 return TRUE;
4669
4670 while (win_array[count])
4671 count++;
4672 while (--count >= 0)
4673 {
4674 if (!(pWnd = ValidateHwndNoErr( win_array[count] )))
4675 continue;
4676 ASSERT(pWnd->spwndOwner == OwnerWnd);
4677
4678 if (fShow)
4679 {
4680 if (pWnd->state & WNDS_HIDDENPOPUP)
4681 {
4682 /* In Windows, ShowOwnedPopups(TRUE) generates
4683 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
4684 * regardless of the state of the owner
4685 */
4686 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
4687 pWnd->state &= ~WNDS_HIDDENPOPUP;
4688 continue;
4689 }
4690 }
4691 else
4692 {
4693 if (pWnd->style & WS_VISIBLE)
4694 {
4695 /* In Windows, ShowOwnedPopups(FALSE) generates
4696 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
4697 * regardless of the state of the owner
4698 */
4699 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
4700 pWnd->state |= WNDS_HIDDENPOPUP;
4701 continue;
4702 }
4703 }
4704 }
4705 ExFreePoolWithTag(win_array, USERTAG_WINDOWLIST);
4706 TRACE("Leave ShowOwnedPopups\n");
4707 return TRUE;
4708 }
4709
4710 /* EOF */
4711