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