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