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() || 2498 (Window->ExStyle & WS_EX_NOACTIVATE)) 2499 { 2500 SwFlag |= SWP_NOACTIVATE; 2501 } 2502 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top, 2503 NewPos.right, NewPos.bottom, SwFlag); 2504 } 2505 2506 /* Send the WM_PARENTNOTIFY message */ 2507 IntSendParentNotify(Window, WM_CREATE); 2508 2509 /* Notify the shell that a new window was created */ 2510 if (Window->spwndOwner == NULL || 2511 !(Window->spwndOwner->style & WS_VISIBLE) || 2512 (Window->spwndOwner->ExStyle & WS_EX_TOOLWINDOW)) 2513 { 2514 if (UserIsDesktopWindow(Window->spwndParent) && 2515 (Window->style & WS_VISIBLE) && 2516 (!(Window->ExStyle & WS_EX_TOOLWINDOW) || 2517 (Window->ExStyle & WS_EX_APPWINDOW))) 2518 { 2519 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0); 2520 } 2521 } 2522 2523 /* Initialize and show the window's scrollbars */ 2524 if (Window->style & WS_VSCROLL) 2525 { 2526 co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE); 2527 } 2528 if (Window->style & WS_HSCROLL) 2529 { 2530 co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE); 2531 } 2532 2533 /* Show the new window */ 2534 if (Cs->style & WS_VISIBLE) 2535 { 2536 if (Window->style & WS_MAXIMIZE) 2537 dwShowMode = SW_SHOW; 2538 else if (Window->style & WS_MINIMIZE) 2539 dwShowMode = SW_SHOWMINIMIZED; 2540 2541 co_WinPosShowWindow(Window, dwShowMode); 2542 2543 if (Window->ExStyle & WS_EX_MDICHILD) 2544 { 2545 ASSERT(ParentWindow); 2546 if(!ParentWindow) 2547 goto cleanup; 2548 co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0); 2549 /* ShowWindow won't activate child windows */ 2550 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); 2551 } 2552 } 2553 2554 if (Class->atomClassName == gaGuiConsoleWndClass) 2555 { 2556 /* Count only console windows manually */ 2557 co_IntUserManualGuiCheck(TRUE); 2558 } 2559 2560 TRACE("co_UserCreateWindowEx(): Created window %p\n", hWnd); 2561 ret = Window; 2562 2563 cleanup: 2564 if (!ret) 2565 { 2566 TRACE("co_UserCreateWindowEx(): Error Created window!\n"); 2567 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */ 2568 if (Window) 2569 co_UserDestroyWindow(Window); 2570 else if (Class) 2571 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi); 2572 } 2573 2574 if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK); 2575 if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK); 2576 if (pszName) UserHeapFree(pszName); 2577 if (pszClass) UserHeapFree(pszClass); 2578 2579 if (Window) 2580 { 2581 UserDerefObjectCo(Window); 2582 } 2583 if (ParentWindow) UserDerefObjectCo(ParentWindow); 2584 2585 // See CORE-13717, not setting error on success. 2586 if (ret) 2587 EngSetLastError(ERROR_SUCCESS); 2588 2589 return ret; 2590 } 2591 2592 NTSTATUS 2593 NTAPI 2594 ProbeAndCaptureLargeString( 2595 OUT PLARGE_STRING plstrSafe, 2596 IN PLARGE_STRING plstrUnsafe) 2597 { 2598 LARGE_STRING lstrTemp; 2599 PVOID pvBuffer = NULL; 2600 2601 _SEH2_TRY 2602 { 2603 /* Probe and copy the string */ 2604 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG)); 2605 lstrTemp = *plstrUnsafe; 2606 } 2607 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2608 { 2609 /* Fail */ 2610 _SEH2_YIELD(return _SEH2_GetExceptionCode();) 2611 } 2612 _SEH2_END 2613 2614 if (lstrTemp.Length != 0) 2615 { 2616 /* Allocate a buffer from paged pool */ 2617 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING); 2618 if (!pvBuffer) 2619 { 2620 return STATUS_NO_MEMORY; 2621 } 2622 2623 _SEH2_TRY 2624 { 2625 /* Probe and copy the buffer */ 2626 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR)); 2627 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length); 2628 } 2629 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2630 { 2631 /* Cleanup and fail */ 2632 ExFreePoolWithTag(pvBuffer, TAG_STRING); 2633 _SEH2_YIELD(return _SEH2_GetExceptionCode();) 2634 } 2635 _SEH2_END 2636 } 2637 2638 /* Set the output string */ 2639 plstrSafe->Buffer = pvBuffer; 2640 plstrSafe->Length = lstrTemp.Length; 2641 plstrSafe->MaximumLength = lstrTemp.Length; 2642 2643 return STATUS_SUCCESS; 2644 } 2645 2646 /** 2647 * \todo Allow passing plstrClassName as ANSI. 2648 */ 2649 HWND 2650 NTAPI 2651 NtUserCreateWindowEx( 2652 DWORD dwExStyle, 2653 PLARGE_STRING plstrClassName, 2654 PLARGE_STRING plstrClsVersion, 2655 PLARGE_STRING plstrWindowName, 2656 DWORD dwStyle, 2657 int x, 2658 int y, 2659 int nWidth, 2660 int nHeight, 2661 HWND hWndParent, 2662 HMENU hMenu, 2663 HINSTANCE hInstance, 2664 LPVOID lpParam, 2665 DWORD dwFlags, 2666 PVOID acbiBuffer) 2667 { 2668 NTSTATUS Status; 2669 LARGE_STRING lstrWindowName; 2670 LARGE_STRING lstrClassName; 2671 LARGE_STRING lstrClsVersion; 2672 UNICODE_STRING ustrClassName; 2673 UNICODE_STRING ustrClsVersion; 2674 CREATESTRUCTW Cs; 2675 HWND hwnd = NULL; 2676 PWND pwnd; 2677 2678 lstrWindowName.Buffer = NULL; 2679 lstrClassName.Buffer = NULL; 2680 lstrClsVersion.Buffer = NULL; 2681 2682 if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD) 2683 { 2684 /* check hMenu is valid handle */ 2685 if (hMenu && !UserGetMenuObject(hMenu)) 2686 { 2687 ERR("NtUserCreateWindowEx: Got an invalid menu handle!\n"); 2688 EngSetLastError(ERROR_INVALID_MENU_HANDLE); 2689 return NULL; 2690 } 2691 } 2692 2693 /* Copy the window name to kernel mode */ 2694 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName); 2695 if (!NT_SUCCESS(Status)) 2696 { 2697 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n"); 2698 SetLastNtError(Status); 2699 return NULL; 2700 } 2701 2702 plstrWindowName = &lstrWindowName; 2703 2704 /* Check if the class is an atom */ 2705 if (IS_ATOM(plstrClassName)) 2706 { 2707 /* It is, pass the atom in the UNICODE_STRING */ 2708 ustrClassName.Buffer = (PVOID)plstrClassName; 2709 ustrClassName.Length = 0; 2710 ustrClassName.MaximumLength = 0; 2711 } 2712 else 2713 { 2714 /* It's not, capture the class name */ 2715 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName); 2716 if (!NT_SUCCESS(Status)) 2717 { 2718 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n"); 2719 /* Set last error, cleanup and return */ 2720 SetLastNtError(Status); 2721 goto cleanup; 2722 } 2723 2724 /* We pass it on as a UNICODE_STRING */ 2725 ustrClassName.Buffer = lstrClassName.Buffer; 2726 ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated 2727 ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT); 2728 } 2729 2730 /* Check if the class version is an atom */ 2731 if (IS_ATOM(plstrClsVersion)) 2732 { 2733 /* It is, pass the atom in the UNICODE_STRING */ 2734 ustrClsVersion.Buffer = (PVOID)plstrClsVersion; 2735 ustrClsVersion.Length = 0; 2736 ustrClsVersion.MaximumLength = 0; 2737 } 2738 else 2739 { 2740 /* It's not, capture the class name */ 2741 Status = ProbeAndCaptureLargeString(&lstrClsVersion, plstrClsVersion); 2742 if (!NT_SUCCESS(Status)) 2743 { 2744 ERR("NtUserCreateWindowEx: failed to capture plstrClsVersion\n"); 2745 /* Set last error, cleanup and return */ 2746 SetLastNtError(Status); 2747 goto cleanup; 2748 } 2749 2750 /* We pass it on as a UNICODE_STRING */ 2751 ustrClsVersion.Buffer = lstrClsVersion.Buffer; 2752 ustrClsVersion.Length = (USHORT)min(lstrClsVersion.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated 2753 ustrClsVersion.MaximumLength = (USHORT)min(lstrClsVersion.MaximumLength, MAXUSHORT); 2754 } 2755 2756 /* Fill the CREATESTRUCTW */ 2757 /* we will keep here the original parameters */ 2758 Cs.style = dwStyle; 2759 Cs.lpCreateParams = lpParam; 2760 Cs.hInstance = hInstance; 2761 Cs.hMenu = hMenu; 2762 Cs.hwndParent = hWndParent; 2763 Cs.cx = nWidth; 2764 Cs.cy = nHeight; 2765 Cs.x = x; 2766 Cs.y = y; 2767 Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer; 2768 Cs.lpszClass = ustrClassName.Buffer; 2769 Cs.dwExStyle = dwExStyle; 2770 2771 UserEnterExclusive(); 2772 2773 /* Call the internal function */ 2774 pwnd = co_UserCreateWindowEx(&Cs, &ustrClsVersion, plstrWindowName, acbiBuffer, dwFlags); 2775 2776 if(!pwnd) 2777 { 2778 ERR("co_UserCreateWindowEx failed!\n"); 2779 } 2780 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL; 2781 2782 UserLeave(); 2783 2784 cleanup: 2785 if (lstrWindowName.Buffer) 2786 { 2787 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING); 2788 } 2789 if (lstrClassName.Buffer) 2790 { 2791 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING); 2792 } 2793 if (lstrClsVersion.Buffer) 2794 { 2795 ExFreePoolWithTag(lstrClsVersion.Buffer, TAG_STRING); 2796 } 2797 2798 return hwnd; 2799 } 2800 2801 // Win: xxxDW_DestroyOwnedWindows 2802 VOID FASTCALL IntDestroyOwnedWindows(PWND Window) 2803 { 2804 HWND* List; 2805 HWND* phWnd; 2806 PWND pWnd; 2807 PTHREADINFO pti = Window->head.pti; 2808 USER_REFERENCE_ENTRY Ref; 2809 2810 List = IntWinListOwnedPopups(Window); 2811 if (!List) 2812 return; 2813 2814 for (phWnd = List; *phWnd; ++phWnd) 2815 { 2816 pWnd = ValidateHwndNoErr(*phWnd); 2817 if (pWnd == NULL) 2818 continue; 2819 ASSERT(pWnd->spwndOwner == Window); 2820 ASSERT(pWnd != Window); 2821 2822 if (IS_IMM_MODE() && !(pti->TIF_flags & TIF_INCLEANUP) && 2823 pWnd == pti->spwndDefaultIme) 2824 { 2825 continue; 2826 } 2827 2828 pWnd->spwndOwner = NULL; 2829 if (IntWndBelongsToThread(pWnd, PsGetCurrentThreadWin32Thread())) 2830 { 2831 UserRefObjectCo(pWnd, &Ref); // Temp HACK? 2832 co_UserDestroyWindow(pWnd); 2833 UserDerefObjectCo(pWnd); // Temp HACK? 2834 } 2835 else 2836 { 2837 ERR("IntWndBelongsToThread(0x%p) is FALSE, ignoring.\n", pWnd); 2838 } 2839 } 2840 2841 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 2842 } 2843 2844 // Win: xxxDestroyWindow 2845 BOOLEAN co_UserDestroyWindow(PVOID Object) 2846 { 2847 HWND hWnd; 2848 PWND pwndTemp; 2849 PTHREADINFO ti; 2850 MSG msg; 2851 PWND Window = Object; 2852 2853 ASSERT_REFS_CO(Window); // FIXME: Temp HACK? 2854 2855 hWnd = Window->head.h; 2856 ti = PsGetCurrentThreadWin32Thread(); 2857 2858 TRACE("co_UserDestroyWindow(Window = 0x%p, hWnd = 0x%p)\n", Window, hWnd); 2859 2860 /* Check for owner thread */ 2861 if (Window->head.pti != ti) 2862 { 2863 /* Check if we are destroying the desktop window */ 2864 if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd)) 2865 { 2866 EngSetLastError(ERROR_ACCESS_DENIED); 2867 return FALSE; 2868 } 2869 } 2870 2871 /* If window was created successfully and it is hooked */ 2872 if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED)) 2873 { 2874 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0)) 2875 { 2876 ERR("Destroy Window WH_CBT Call Hook return!\n"); 2877 return FALSE; 2878 } 2879 } 2880 2881 if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME]) 2882 { 2883 if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD) 2884 { 2885 if (Window->spwndOwner) 2886 { 2887 //ERR("DestroyWindow Owner out.\n"); 2888 UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE); 2889 } 2890 } 2891 } 2892 2893 /* Inform the parent */ 2894 if (Window->style & WS_CHILD) 2895 { 2896 IntSendParentNotify(Window, WM_DESTROY); 2897 } 2898 2899 if (!Window->spwndOwner && !IntGetParent(Window)) 2900 { 2901 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM) hWnd, 0); 2902 } 2903 2904 /* Hide the window */ 2905 if (Window->style & WS_VISIBLE) 2906 { 2907 if (Window->style & WS_CHILD) 2908 { 2909 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */ 2910 co_WinPosShowWindow(Window, SW_HIDE); 2911 } 2912 else 2913 { 2914 co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_HIDEWINDOW ); 2915 } 2916 } 2917 2918 /* Adjust last active */ 2919 if ((pwndTemp = Window->spwndOwner)) 2920 { 2921 while (pwndTemp->spwndOwner) 2922 pwndTemp = pwndTemp->spwndOwner; 2923 2924 if (pwndTemp->spwndLastActive == Window) 2925 pwndTemp->spwndLastActive = Window->spwndOwner; 2926 } 2927 2928 if (Window->spwndParent && IntIsWindow(UserHMGetHandle(Window))) 2929 { 2930 if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD) 2931 { 2932 if (!IntIsTopLevelWindow(Window)) 2933 { 2934 //ERR("DestroyWindow Parent out.\n"); 2935 UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE); 2936 } 2937 } 2938 } 2939 2940 if (Window->head.pti->MessageQueue->spwndActive == Window) 2941 Window->head.pti->MessageQueue->spwndActive = NULL; 2942 if (Window->head.pti->MessageQueue->spwndFocus == Window) 2943 Window->head.pti->MessageQueue->spwndFocus = NULL; 2944 if (Window->head.pti->MessageQueue->spwndActivePrev == Window) 2945 Window->head.pti->MessageQueue->spwndActivePrev = NULL; 2946 if (Window->head.pti->MessageQueue->spwndCapture == Window) 2947 Window->head.pti->MessageQueue->spwndCapture = NULL; 2948 2949 /* 2950 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL 2951 */ 2952 2953 if ((ti != NULL) && (ti->pDeskInfo != NULL)) 2954 { 2955 if (ti->pDeskInfo->hShellWindow == hWnd) 2956 { 2957 ERR("Destroying the ShellWindow!\n"); 2958 ti->pDeskInfo->hShellWindow = NULL; 2959 } 2960 } 2961 2962 IntEngWindowChanged(Window, WOC_DELETE); 2963 2964 if (!IntIsWindow(UserHMGetHandle(Window))) 2965 { 2966 return TRUE; 2967 } 2968 2969 /* Recursively destroy owned windows */ 2970 if (!(Window->style & WS_CHILD)) 2971 { 2972 IntDestroyOwnedWindows(Window); 2973 } 2974 2975 /* Generate mouse move message for the next window */ 2976 msg.message = WM_MOUSEMOVE; 2977 msg.wParam = UserGetMouseButtonsState(); 2978 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y); 2979 msg.pt = gpsi->ptCursor; 2980 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE); 2981 2982 IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Window, OBJID_WINDOW, CHILDID_SELF, 0); 2983 2984 /* Send destroy messages */ 2985 IntSendDestroyMsg(UserHMGetHandle(Window)); 2986 2987 // Destroy the default IME window if necessary 2988 if (IS_IMM_MODE() && !(ti->TIF_flags & TIF_INCLEANUP) && 2989 ti->spwndDefaultIme && !IS_WND_IMELIKE(Window) && !(Window->state & WNDS_DESTROYED)) 2990 { 2991 if (IS_WND_CHILD(Window)) 2992 { 2993 if (IntImeCanDestroyDefIMEforChild(ti->spwndDefaultIme, Window)) 2994 co_UserDestroyWindow(ti->spwndDefaultIme); 2995 } 2996 else 2997 { 2998 if (IntImeCanDestroyDefIME(ti->spwndDefaultIme, Window)) 2999 co_UserDestroyWindow(ti->spwndDefaultIme); 3000 } 3001 } 3002 3003 if (!IntIsWindow(UserHMGetHandle(Window))) 3004 { 3005 return TRUE; 3006 } 3007 3008 /* Destroy the window storage */ 3009 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE); 3010 3011 return TRUE; 3012 } 3013 3014 3015 /* 3016 * @implemented 3017 */ 3018 BOOLEAN APIENTRY 3019 NtUserDestroyWindow(HWND Wnd) 3020 { 3021 PWND Window; 3022 DECLARE_RETURN(BOOLEAN); 3023 BOOLEAN ret; 3024 USER_REFERENCE_ENTRY Ref; 3025 3026 TRACE("Enter NtUserDestroyWindow\n"); 3027 UserEnterExclusive(); 3028 3029 if (!(Window = UserGetWindowObject(Wnd))) 3030 { 3031 RETURN(FALSE); 3032 } 3033 3034 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy... 3035 ret = co_UserDestroyWindow(Window); 3036 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy... 3037 3038 RETURN(ret); 3039 3040 CLEANUP: 3041 TRACE("Leave NtUserDestroyWindow, ret=%u\n", _ret_); 3042 UserLeave(); 3043 END_CLEANUP; 3044 } 3045 3046 3047 HWND FASTCALL 3048 IntFindWindow(PWND Parent, 3049 PWND ChildAfter, 3050 RTL_ATOM ClassAtom, 3051 PUNICODE_STRING WindowName) 3052 { 3053 BOOL CheckWindowName; 3054 HWND *List, *phWnd; 3055 HWND Ret = NULL; 3056 UNICODE_STRING CurrentWindowName; 3057 3058 ASSERT(Parent); 3059 3060 CheckWindowName = WindowName->Buffer != 0; 3061 3062 if((List = IntWinListChildren(Parent))) 3063 { 3064 phWnd = List; 3065 if(ChildAfter) 3066 { 3067 /* skip handles before and including ChildAfter */ 3068 while(*phWnd && (*(phWnd++) != ChildAfter->head.h)) 3069 ; 3070 } 3071 3072 /* search children */ 3073 while(*phWnd) 3074 { 3075 PWND Child; 3076 if(!(Child = UserGetWindowObject(*(phWnd++)))) 3077 { 3078 continue; 3079 } 3080 3081 /* Do not send WM_GETTEXT messages in the kernel mode version! 3082 The user mode version however calls GetWindowText() which will 3083 send WM_GETTEXT messages to windows belonging to its processes */ 3084 if (!ClassAtom || Child->pcls->atomNVClassName == ClassAtom) 3085 { 3086 // FIXME: LARGE_STRING truncated 3087 CurrentWindowName.Buffer = Child->strName.Buffer; 3088 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT); 3089 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT); 3090 if(!CheckWindowName || 3091 (Child->strName.Length < 0xFFFF && 3092 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE))) 3093 { 3094 Ret = Child->head.h; 3095 break; 3096 } 3097 } 3098 } 3099 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 3100 } 3101 3102 return Ret; 3103 } 3104 3105 /* 3106 * FUNCTION: 3107 * Searches a window's children for a window with the specified 3108 * class and name 3109 * ARGUMENTS: 3110 * hwndParent = The window whose childs are to be searched. 3111 * NULL = desktop 3112 * HWND_MESSAGE = message-only windows 3113 * 3114 * hwndChildAfter = Search starts after this child window. 3115 * NULL = start from beginning 3116 * 3117 * ucClassName = Class name to search for 3118 * Reguired parameter. 3119 * 3120 * ucWindowName = Window name 3121 * ->Buffer == NULL = don't care 3122 * 3123 * RETURNS: 3124 * The HWND of the window if it was found, otherwise NULL 3125 */ 3126 /* 3127 * @implemented 3128 */ 3129 HWND APIENTRY 3130 NtUserFindWindowEx(HWND hwndParent, 3131 HWND hwndChildAfter, 3132 PUNICODE_STRING ucClassName, 3133 PUNICODE_STRING ucWindowName, 3134 DWORD dwUnknown) 3135 { 3136 PWND Parent, ChildAfter; 3137 UNICODE_STRING ClassName = {0}, WindowName = {0}; 3138 HWND Desktop, Ret = NULL; 3139 BOOL DoMessageWnd = FALSE; 3140 RTL_ATOM ClassAtom = (RTL_ATOM)0; 3141 DECLARE_RETURN(HWND); 3142 3143 TRACE("Enter NtUserFindWindowEx\n"); 3144 UserEnterShared(); 3145 3146 if (ucClassName != NULL || ucWindowName != NULL) 3147 { 3148 _SEH2_TRY 3149 { 3150 if (ucClassName != NULL) 3151 { 3152 ClassName = ProbeForReadUnicodeString(ucClassName); 3153 if (ClassName.Length != 0) 3154 { 3155 ProbeForRead(ClassName.Buffer, 3156 ClassName.Length, 3157 sizeof(WCHAR)); 3158 } 3159 else if (!IS_ATOM(ClassName.Buffer)) 3160 { 3161 EngSetLastError(ERROR_INVALID_PARAMETER); 3162 _SEH2_LEAVE; 3163 } 3164 3165 if (!IntGetAtomFromStringOrAtom(&ClassName, 3166 &ClassAtom)) 3167 { 3168 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS); 3169 _SEH2_LEAVE; 3170 } 3171 } 3172 3173 if (ucWindowName != NULL) 3174 { 3175 WindowName = ProbeForReadUnicodeString(ucWindowName); 3176 if (WindowName.Length != 0) 3177 { 3178 ProbeForRead(WindowName.Buffer, 3179 WindowName.Length, 3180 sizeof(WCHAR)); 3181 } 3182 } 3183 } 3184 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3185 { 3186 SetLastNtError(_SEH2_GetExceptionCode()); 3187 _SEH2_YIELD(RETURN(NULL)); 3188 } 3189 _SEH2_END; 3190 3191 if (ucClassName != NULL) 3192 { 3193 if (ClassName.Length == 0 && ClassName.Buffer != NULL && 3194 !IS_ATOM(ClassName.Buffer)) 3195 { 3196 EngSetLastError(ERROR_INVALID_PARAMETER); 3197 RETURN(NULL); 3198 } 3199 else if (ClassAtom == (RTL_ATOM)0) 3200 { 3201 /* LastError code was set by IntGetAtomFromStringOrAtom */ 3202 RETURN(NULL); 3203 } 3204 } 3205 } 3206 3207 Desktop = IntGetCurrentThreadDesktopWindow(); 3208 3209 if(hwndParent == NULL) 3210 { 3211 hwndParent = Desktop; 3212 DoMessageWnd = TRUE; 3213 } 3214 else if(hwndParent == HWND_MESSAGE) 3215 { 3216 hwndParent = IntGetMessageWindow(); 3217 } 3218 3219 if(!(Parent = UserGetWindowObject(hwndParent))) 3220 { 3221 RETURN( NULL); 3222 } 3223 3224 ChildAfter = NULL; 3225 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter))) 3226 { 3227 RETURN( NULL); 3228 } 3229 3230 _SEH2_TRY 3231 { 3232 if(Parent->head.h == Desktop) 3233 { 3234 HWND *List, *phWnd; 3235 PWND TopLevelWindow; 3236 BOOLEAN CheckWindowName; 3237 BOOLEAN WindowMatches; 3238 BOOLEAN ClassMatches; 3239 3240 /* windows searches through all top-level windows if the parent is the desktop 3241 window */ 3242 3243 if((List = IntWinListChildren(Parent))) 3244 { 3245 phWnd = List; 3246 3247 if(ChildAfter) 3248 { 3249 /* skip handles before and including ChildAfter */ 3250 while(*phWnd && (*(phWnd++) != ChildAfter->head.h)) 3251 ; 3252 } 3253 3254 CheckWindowName = WindowName.Buffer != 0; 3255 3256 /* search children */ 3257 while(*phWnd) 3258 { 3259 UNICODE_STRING ustr; 3260 3261 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++)))) 3262 { 3263 continue; 3264 } 3265 3266 /* Do not send WM_GETTEXT messages in the kernel mode version! 3267 The user mode version however calls GetWindowText() which will 3268 send WM_GETTEXT messages to windows belonging to its processes */ 3269 ustr.Buffer = TopLevelWindow->strName.Buffer; 3270 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated 3271 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT); 3272 WindowMatches = !CheckWindowName || 3273 (TopLevelWindow->strName.Length < 0xFFFF && 3274 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE)); 3275 ClassMatches = (ClassAtom == (RTL_ATOM)0) || 3276 ClassAtom == TopLevelWindow->pcls->atomNVClassName; 3277 3278 if (WindowMatches && ClassMatches) 3279 { 3280 Ret = TopLevelWindow->head.h; 3281 break; 3282 } 3283 3284 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName)) 3285 { 3286 /* window returns the handle of the top-level window, in case it found 3287 the child window */ 3288 Ret = TopLevelWindow->head.h; 3289 break; 3290 } 3291 3292 } 3293 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 3294 } 3295 } 3296 else 3297 { 3298 TRACE("FindWindowEx: Not Desktop Parent!\n"); 3299 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName); 3300 } 3301 3302 if (Ret == NULL && DoMessageWnd) 3303 { 3304 PWND MsgWindows; 3305 3306 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow()))) 3307 { 3308 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName); 3309 } 3310 } 3311 } 3312 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3313 { 3314 SetLastNtError(_SEH2_GetExceptionCode()); 3315 Ret = NULL; 3316 } 3317 _SEH2_END; 3318 3319 RETURN( Ret); 3320 3321 CLEANUP: 3322 TRACE("Leave NtUserFindWindowEx, ret %p\n", _ret_); 3323 UserLeave(); 3324 END_CLEANUP; 3325 } 3326 3327 3328 /* 3329 * @implemented 3330 */ 3331 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type) 3332 { 3333 PWND WndAncestor, Parent; 3334 3335 if (Wnd->head.h == IntGetDesktopWindow()) 3336 { 3337 return NULL; 3338 } 3339 3340 switch (Type) 3341 { 3342 case GA_PARENT: 3343 { 3344 WndAncestor = Wnd->spwndParent; 3345 break; 3346 } 3347 3348 case GA_ROOT: 3349 { 3350 WndAncestor = Wnd; 3351 Parent = NULL; 3352 3353 for(;;) 3354 { 3355 if(!(Parent = WndAncestor->spwndParent)) 3356 { 3357 break; 3358 } 3359 if(IntIsDesktopWindow(Parent)) 3360 { 3361 break; 3362 } 3363 3364 WndAncestor = Parent; 3365 } 3366 break; 3367 } 3368 3369 case GA_ROOTOWNER: 3370 { 3371 WndAncestor = Wnd; 3372 3373 for (;;) 3374 { 3375 Parent = IntGetParent(WndAncestor); 3376 3377 if (!Parent) 3378 { 3379 break; 3380 } 3381 3382 WndAncestor = Parent; 3383 } 3384 break; 3385 } 3386 3387 default: 3388 { 3389 return NULL; 3390 } 3391 } 3392 3393 return WndAncestor; 3394 } 3395 3396 /* 3397 * @implemented 3398 */ 3399 HWND APIENTRY 3400 NtUserGetAncestor(HWND hWnd, UINT Type) 3401 { 3402 PWND Window, Ancestor; 3403 DECLARE_RETURN(HWND); 3404 3405 TRACE("Enter NtUserGetAncestor\n"); 3406 UserEnterExclusive(); 3407 3408 if (!(Window = UserGetWindowObject(hWnd))) 3409 { 3410 RETURN(NULL); 3411 } 3412 3413 Ancestor = UserGetAncestor(Window, Type); 3414 /* faxme: can UserGetAncestor ever return NULL for a valid window? */ 3415 3416 RETURN(Ancestor ? Ancestor->head.h : NULL); 3417 3418 CLEANUP: 3419 TRACE("Leave NtUserGetAncestor, ret=%p\n", _ret_); 3420 UserLeave(); 3421 END_CLEANUP; 3422 } 3423 3424 //// 3425 //// ReactOS work around! Keep it the sames as in Combo.c and Controls.h 3426 //// 3427 /* combo state struct */ 3428 typedef struct 3429 { 3430 HWND self; 3431 HWND owner; 3432 UINT dwStyle; 3433 HWND hWndEdit; 3434 HWND hWndLBox; 3435 UINT wState; 3436 HFONT hFont; 3437 RECT textRect; 3438 RECT buttonRect; 3439 RECT droppedRect; 3440 INT droppedIndex; 3441 INT fixedOwnerDrawHeight; 3442 INT droppedWidth; /* last two are not used unless set */ 3443 INT editHeight; /* explicitly */ 3444 LONG UIState; 3445 } HEADCOMBO,*LPHEADCOMBO; 3446 3447 // Window Extra data container. 3448 typedef struct _WND2CBOX 3449 { 3450 WND; 3451 LPHEADCOMBO pCBox; 3452 } WND2CBOX, *PWND2CBOX; 3453 3454 #define CBF_BUTTONDOWN 0x0002 3455 //// 3456 //// 3457 //// 3458 BOOL 3459 APIENTRY 3460 NtUserGetComboBoxInfo( 3461 HWND hWnd, 3462 PCOMBOBOXINFO pcbi) 3463 { 3464 PWND Wnd; 3465 PPROCESSINFO ppi; 3466 BOOL NotSameppi = FALSE; 3467 BOOL Ret = TRUE; 3468 DECLARE_RETURN(BOOL); 3469 3470 TRACE("Enter NtUserGetComboBoxInfo\n"); 3471 UserEnterShared(); 3472 3473 if (!(Wnd = UserGetWindowObject(hWnd))) 3474 { 3475 RETURN( FALSE ); 3476 } 3477 _SEH2_TRY 3478 { 3479 ProbeForWrite(pcbi, sizeof(COMBOBOXINFO), 1); 3480 } 3481 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3482 { 3483 SetLastNtError(_SEH2_GetExceptionCode()); 3484 _SEH2_YIELD(RETURN(FALSE)); 3485 } 3486 _SEH2_END; 3487 3488 if (pcbi->cbSize < sizeof(COMBOBOXINFO)) 3489 { 3490 EngSetLastError(ERROR_INVALID_PARAMETER); 3491 RETURN(FALSE); 3492 } 3493 3494 // Pass the user pointer, it was already probed. 3495 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_COMBOBOX]) && Wnd->fnid != FNID_COMBOBOX) 3496 { 3497 RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi)); 3498 } 3499 3500 ppi = PsGetCurrentProcessWin32Process(); 3501 NotSameppi = ppi != Wnd->head.pti->ppi; 3502 if (NotSameppi) 3503 { 3504 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb); 3505 } 3506 3507 _SEH2_TRY 3508 { 3509 LPHEADCOMBO lphc = ((PWND2CBOX)Wnd)->pCBox; 3510 pcbi->rcItem = lphc->textRect; 3511 pcbi->rcButton = lphc->buttonRect; 3512 pcbi->stateButton = 0; 3513 if (lphc->wState & CBF_BUTTONDOWN) 3514 pcbi->stateButton |= STATE_SYSTEM_PRESSED; 3515 if (RECTL_bIsEmptyRect(&lphc->buttonRect)) 3516 pcbi->stateButton |= STATE_SYSTEM_INVISIBLE; 3517 pcbi->hwndCombo = lphc->self; 3518 pcbi->hwndItem = lphc->hWndEdit; 3519 pcbi->hwndList = lphc->hWndLBox; 3520 } 3521 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3522 { 3523 Ret = FALSE; 3524 SetLastNtError(_SEH2_GetExceptionCode()); 3525 } 3526 _SEH2_END; 3527 3528 RETURN( Ret); 3529 3530 CLEANUP: 3531 if (NotSameppi) KeDetachProcess(); 3532 TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_); 3533 UserLeave(); 3534 END_CLEANUP; 3535 } 3536 3537 //// 3538 //// ReactOS work around! Keep it the sames as in Listbox.c 3539 //// 3540 /* Listbox structure */ 3541 typedef struct 3542 { 3543 HWND self; /* Our own window handle */ 3544 HWND owner; /* Owner window to send notifications to */ 3545 UINT style; /* Window style */ 3546 INT width; /* Window width */ 3547 INT height; /* Window height */ 3548 VOID *items; /* Array of items */ 3549 INT nb_items; /* Number of items */ 3550 INT top_item; /* Top visible item */ 3551 INT selected_item; /* Selected item */ 3552 INT focus_item; /* Item that has the focus */ 3553 INT anchor_item; /* Anchor item for extended selection */ 3554 INT item_height; /* Default item height */ 3555 INT page_size; /* Items per listbox page */ 3556 INT column_width; /* Column width for multi-column listboxes */ 3557 } LB_DESCR; 3558 3559 // Window Extra data container. 3560 typedef struct _WND2LB 3561 { 3562 WND; 3563 LB_DESCR * pLBiv; 3564 } WND2LB, *PWND2LB; 3565 //// 3566 //// 3567 //// 3568 DWORD 3569 APIENTRY 3570 NtUserGetListBoxInfo( 3571 HWND hWnd) 3572 { 3573 PWND Wnd; 3574 PPROCESSINFO ppi; 3575 BOOL NotSameppi = FALSE; 3576 DWORD Ret = 0; 3577 DECLARE_RETURN(DWORD); 3578 3579 TRACE("Enter NtUserGetListBoxInfo\n"); 3580 UserEnterShared(); 3581 3582 if (!(Wnd = UserGetWindowObject(hWnd))) 3583 { 3584 RETURN( 0 ); 3585 } 3586 3587 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && Wnd->fnid != FNID_LISTBOX) 3588 { 3589 RETURN( (DWORD) co_IntSendMessage( Wnd->head.h, LB_GETLISTBOXINFO, 0, 0 )); 3590 } 3591 3592 // wine lisbox:test_GetListBoxInfo lb_getlistboxinfo = 0, should not send a message! 3593 ppi = PsGetCurrentProcessWin32Process(); 3594 NotSameppi = ppi != Wnd->head.pti->ppi; 3595 if (NotSameppi) 3596 { 3597 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb); 3598 } 3599 3600 _SEH2_TRY 3601 { 3602 LB_DESCR *descr = ((PWND2LB)Wnd)->pLBiv; 3603 // See Controls ListBox.c:LB_GETLISTBOXINFO must match... 3604 Ret = descr->page_size; 3605 } 3606 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3607 { 3608 Ret = 0; 3609 SetLastNtError(_SEH2_GetExceptionCode()); 3610 } 3611 _SEH2_END; 3612 3613 RETURN( Ret); 3614 3615 CLEANUP: 3616 if (NotSameppi) KeDetachProcess(); 3617 TRACE("Leave NtUserGetListBoxInfo, ret=%lu\n", _ret_); 3618 UserLeave(); 3619 END_CLEANUP; 3620 } 3621 3622 /* 3623 * NtUserSetParent 3624 * 3625 * The NtUserSetParent function changes the parent window of the specified 3626 * child window. 3627 * 3628 * Remarks 3629 * The new parent window and the child window must belong to the same 3630 * application. If the window identified by the hWndChild parameter is 3631 * visible, the system performs the appropriate redrawing and repainting. 3632 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD 3633 * or WS_POPUP window styles of the window whose parent is being changed. 3634 * 3635 * Status 3636 * @implemented 3637 */ 3638 3639 HWND APIENTRY 3640 NtUserSetParent(HWND hWndChild, HWND hWndNewParent) 3641 { 3642 DECLARE_RETURN(HWND); 3643 3644 TRACE("Enter NtUserSetParent\n"); 3645 UserEnterExclusive(); 3646 3647 /* 3648 Check Parent first from user space, set it here. 3649 */ 3650 if (!hWndNewParent) 3651 { 3652 hWndNewParent = IntGetDesktopWindow(); 3653 } 3654 else if (hWndNewParent == HWND_MESSAGE) 3655 { 3656 hWndNewParent = IntGetMessageWindow(); 3657 } 3658 3659 RETURN( co_UserSetParent(hWndChild, hWndNewParent)); 3660 3661 CLEANUP: 3662 TRACE("Leave NtUserSetParent, ret=%p\n", _ret_); 3663 UserLeave(); 3664 END_CLEANUP; 3665 } 3666 3667 /* 3668 * UserGetShellWindow 3669 * 3670 * Returns a handle to shell window that was set by NtUserSetShellWindowEx. 3671 * 3672 * Status 3673 * @implemented 3674 */ 3675 HWND FASTCALL UserGetShellWindow(VOID) 3676 { 3677 PWINSTATION_OBJECT WinStaObject; 3678 HWND Ret; 3679 3680 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation, 3681 UserMode, 3682 0, 3683 &WinStaObject, 3684 0); 3685 3686 if (!NT_SUCCESS(Status)) 3687 { 3688 SetLastNtError(Status); 3689 return( (HWND)0); 3690 } 3691 3692 Ret = (HWND)WinStaObject->ShellWindow; 3693 3694 ObDereferenceObject(WinStaObject); 3695 return( Ret); 3696 } 3697 3698 /* 3699 * NtUserSetShellWindowEx 3700 * 3701 * This is undocumented function to set global shell window. The global 3702 * shell window has special handling of window position. 3703 * 3704 * Status 3705 * @implemented 3706 */ 3707 BOOL APIENTRY 3708 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView) 3709 { 3710 PWINSTATION_OBJECT WinStaObject; 3711 PWND WndShell, WndListView; 3712 DECLARE_RETURN(BOOL); 3713 USER_REFERENCE_ENTRY Ref; 3714 NTSTATUS Status; 3715 PTHREADINFO ti; 3716 3717 TRACE("Enter NtUserSetShellWindowEx\n"); 3718 UserEnterExclusive(); 3719 3720 if (!(WndShell = UserGetWindowObject(hwndShell))) 3721 { 3722 RETURN(FALSE); 3723 } 3724 3725 if (!(WndListView = UserGetWindowObject(hwndListView))) 3726 { 3727 RETURN(FALSE); 3728 } 3729 3730 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation, 3731 UserMode, 3732 0, 3733 &WinStaObject, 3734 0); 3735 3736 if (!NT_SUCCESS(Status)) 3737 { 3738 SetLastNtError(Status); 3739 RETURN( FALSE); 3740 } 3741 3742 /* 3743 * Test if we are permitted to change the shell window. 3744 */ 3745 if (WinStaObject->ShellWindow) 3746 { 3747 ObDereferenceObject(WinStaObject); 3748 RETURN( FALSE); 3749 } 3750 3751 /* 3752 * Move shell window into background. 3753 */ 3754 if (hwndListView && hwndListView != hwndShell) 3755 { 3756 /* 3757 * Disabled for now to get Explorer working. 3758 * -- Filip, 01/nov/2003 3759 */ 3760 #if 0 3761 co_WinPosSetWindowPos(WndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE); 3762 #endif 3763 3764 if (WndListView->ExStyle & WS_EX_TOPMOST) 3765 { 3766 ObDereferenceObject(WinStaObject); 3767 RETURN( FALSE); 3768 } 3769 } 3770 3771 if (WndShell->ExStyle & WS_EX_TOPMOST) 3772 { 3773 ObDereferenceObject(WinStaObject); 3774 RETURN( FALSE); 3775 } 3776 3777 UserRefObjectCo(WndShell, &Ref); 3778 WndShell->state2 |= WNDS2_BOTTOMMOST; 3779 co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE); 3780 3781 WinStaObject->ShellWindow = hwndShell; 3782 WinStaObject->ShellListView = hwndListView; 3783 3784 ti = GetW32ThreadInfo(); 3785 if (ti->pDeskInfo) 3786 { 3787 ti->pDeskInfo->hShellWindow = hwndShell; 3788 ti->pDeskInfo->spwndShell = WndShell; 3789 ti->pDeskInfo->spwndBkGnd = WndListView; 3790 ti->pDeskInfo->ppiShellProcess = ti->ppi; 3791 } 3792 3793 UserRegisterHotKey(WndShell, SC_TASKLIST, MOD_CONTROL, VK_ESCAPE); 3794 3795 UserDerefObjectCo(WndShell); 3796 3797 ObDereferenceObject(WinStaObject); 3798 RETURN( TRUE); 3799 3800 CLEANUP: 3801 TRACE("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_); 3802 UserLeave(); 3803 END_CLEANUP; 3804 } 3805 3806 // Fixes wine Win test_window_styles and todo tests... 3807 static BOOL FASTCALL 3808 IntCheckFrameEdge(ULONG Style, ULONG ExStyle) 3809 { 3810 if (ExStyle & WS_EX_DLGMODALFRAME) 3811 return TRUE; 3812 else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME))) 3813 return TRUE; 3814 else 3815 return FALSE; 3816 } 3817 3818 static LONG_PTR 3819 co_IntSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi, ULONG Size, BOOL bAlter) 3820 { 3821 PWND Window, Parent; 3822 PWINSTATION_OBJECT WindowStation; 3823 LONG_PTR OldValue; 3824 STYLESTRUCT Style; 3825 3826 if (!(Window = UserGetWindowObject(hWnd))) 3827 { 3828 return( 0); 3829 } 3830 3831 if ((INT)Index >= 0) 3832 { 3833 if ((Index + Size) > Window->cbwndExtra) 3834 { 3835 EngSetLastError(ERROR_INVALID_INDEX); 3836 return( 0); 3837 } 3838 3839 #ifdef _WIN64 3840 if (Size == sizeof(LONG)) 3841 { 3842 OldValue = *((LONG *)((PCHAR)(Window + 1) + Index)); 3843 *((LONG*)((PCHAR)(Window + 1) + Index)) = (LONG)NewValue; 3844 } 3845 else 3846 #endif 3847 { 3848 OldValue = *((LONG_PTR *)((PCHAR)(Window + 1) + Index)); 3849 /* 3850 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW) 3851 { 3852 OldValue = (LONG_PTR)IntSetWindowProc( Wnd, (WNDPROC)NewValue, Ansi); 3853 if (!OldValue) return 0; 3854 } 3855 */ 3856 *((LONG_PTR*)((PCHAR)(Window + 1) + Index)) = NewValue; 3857 } 3858 3859 } 3860 else 3861 { 3862 #ifdef _WIN64 3863 if (Size == sizeof(LONG)) 3864 { 3865 if ((Index != GWL_STYLE) && 3866 (Index != GWL_EXSTYLE) && 3867 (Index != GWL_ID) && 3868 (Index != GWL_USERDATA)) 3869 { 3870 ERR("NtUserSetWindowLong(): Index requires pointer size: %lu\n", Index); 3871 EngSetLastError(ERROR_INVALID_INDEX); 3872 return 0; 3873 } 3874 } 3875 #endif 3876 3877 switch (Index) 3878 { 3879 case GWL_EXSTYLE: // LONG 3880 OldValue = (LONG) Window->ExStyle; 3881 Style.styleOld = OldValue; 3882 Style.styleNew = NewValue; 3883 3884 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style); 3885 3886 /* 3887 * Remove extended window style bit WS_EX_TOPMOST for shell windows. 3888 */ 3889 WindowStation = Window->head.pti->rpdesk->rpwinstaParent; 3890 if(WindowStation) 3891 { 3892 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView) 3893 Style.styleNew &= ~WS_EX_TOPMOST; 3894 } 3895 /* WS_EX_WINDOWEDGE depends on some other styles */ 3896 if (IntCheckFrameEdge(Window->style, NewValue)) 3897 Style.styleNew |= WS_EX_WINDOWEDGE; 3898 else 3899 Style.styleNew &= ~WS_EX_WINDOWEDGE; 3900 3901 if (!(Window->ExStyle & WS_EX_LAYERED)) 3902 { 3903 SetLayeredStatus(Window, 0); 3904 } 3905 3906 Window->ExStyle = (DWORD)Style.styleNew; 3907 3908 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style); 3909 break; 3910 3911 case GWL_STYLE: // LONG 3912 OldValue = (LONG) Window->style; 3913 Style.styleOld = OldValue; 3914 Style.styleNew = NewValue; 3915 3916 if (!bAlter) 3917 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style); 3918 3919 /* WS_CLIPSIBLINGS can't be reset on top-level windows */ 3920 if (UserIsDesktopWindow(Window->spwndParent)) Style.styleNew |= WS_CLIPSIBLINGS; 3921 /* WS_MINIMIZE can't be reset */ 3922 if (OldValue & WS_MINIMIZE) Style.styleNew |= WS_MINIMIZE; 3923 /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */ 3924 if (IntCheckFrameEdge(NewValue, Window->ExStyle)) 3925 Window->ExStyle |= WS_EX_WINDOWEDGE; 3926 else 3927 Window->ExStyle &= ~WS_EX_WINDOWEDGE; 3928 3929 if ((OldValue & (WS_CHILD | WS_POPUP)) == WS_CHILD) 3930 { 3931 if ((NewValue & (WS_CHILD | WS_POPUP)) != WS_CHILD) 3932 { 3933 //// From child to non-child it should be null already. 3934 ERR("IDMenu going null! %d\n",Window->IDMenu); 3935 Window->IDMenu = 0; // Window->spmenu = 0; 3936 } 3937 } 3938 else 3939 { 3940 if ((NewValue & (WS_CHILD | WS_POPUP)) == WS_CHILD) 3941 { 3942 PMENU pMenu = UserGetMenuObject(UlongToHandle(Window->IDMenu)); 3943 Window->state &= ~WNDS_HASMENU; 3944 if (pMenu) 3945 { 3946 ERR("IDMenu released 0x%p\n",pMenu); 3947 // ROS may not hold a lock after setting menu to window. But it should! 3948 //IntReleaseMenuObject(pMenu); 3949 } 3950 } 3951 } 3952 3953 if ((Style.styleOld ^ Style.styleNew) & WS_VISIBLE) 3954 { 3955 if (Style.styleOld & WS_VISIBLE) Window->head.pti->cVisWindows--; 3956 if (Style.styleNew & WS_VISIBLE) Window->head.pti->cVisWindows++; 3957 DceResetActiveDCEs( Window ); 3958 } 3959 Window->style = (DWORD)Style.styleNew; 3960 3961 if (!bAlter) 3962 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style); 3963 break; 3964 3965 case GWLP_WNDPROC: // LONG_PTR 3966 { 3967 if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() || 3968 Window->fnid & FNID_FREED) 3969 { 3970 EngSetLastError(ERROR_ACCESS_DENIED); 3971 return( 0); 3972 } 3973 OldValue = (LONG_PTR)IntSetWindowProc(Window, 3974 (WNDPROC)NewValue, 3975 Ansi); 3976 break; 3977 } 3978 3979 case GWLP_HINSTANCE: // LONG_PTR 3980 OldValue = (LONG_PTR) Window->hModule; 3981 Window->hModule = (HINSTANCE) NewValue; 3982 break; 3983 3984 case GWLP_HWNDPARENT: // LONG_PTR 3985 Parent = Window->spwndParent; 3986 if (Parent && (Parent->head.h == IntGetDesktopWindow())) 3987 OldValue = (LONG_PTR) IntSetOwner(Window->head.h, (HWND) NewValue); 3988 else 3989 OldValue = (LONG_PTR) co_UserSetParent(Window->head.h, (HWND) NewValue); 3990 break; 3991 3992 case GWLP_ID: // LONG 3993 OldValue = (LONG) Window->IDMenu; 3994 Window->IDMenu = (UINT) NewValue; 3995 break; 3996 3997 case GWLP_USERDATA: // LONG or LONG_PTR 3998 OldValue = Window->dwUserData; 3999 Window->dwUserData = NewValue; 4000 break; 4001 4002 default: 4003 ERR("NtUserSetWindowLong(): Unsupported index %lu\n", Index); 4004 EngSetLastError(ERROR_INVALID_INDEX); 4005 OldValue = 0; 4006 break; 4007 } 4008 } 4009 4010 return( OldValue); 4011 } 4012 4013 LONG FASTCALL 4014 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi) 4015 { 4016 return (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE); 4017 } 4018 4019 LONG_PTR FASTCALL 4020 co_UserSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi) 4021 { 4022 return co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE); 4023 } 4024 4025 /* 4026 * NtUserSetWindowLong 4027 * 4028 * The NtUserSetWindowLong function changes an attribute of the specified 4029 * window. The function also sets the 32-bit (long) value at the specified 4030 * offset into the extra window memory. 4031 * 4032 * Status 4033 * @implemented 4034 */ 4035 4036 LONG APIENTRY 4037 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi) 4038 { 4039 LONG ret; 4040 4041 UserEnterExclusive(); 4042 4043 if (hWnd == IntGetDesktopWindow()) 4044 { 4045 EngSetLastError(STATUS_ACCESS_DENIED); 4046 UserLeave(); 4047 return 0; 4048 } 4049 4050 ret = (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE); 4051 4052 UserLeave(); 4053 4054 return ret; 4055 } 4056 4057 #ifdef _WIN64 4058 LONG_PTR APIENTRY 4059 NtUserSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi) 4060 { 4061 LONG_PTR ret; 4062 4063 UserEnterExclusive(); 4064 4065 if (hWnd == IntGetDesktopWindow()) 4066 { 4067 EngSetLastError(STATUS_ACCESS_DENIED); 4068 UserLeave(); 4069 return 0; 4070 } 4071 4072 ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE); 4073 4074 UserLeave(); 4075 4076 return ret; 4077 } 4078 #endif // _WIN64 4079 4080 DWORD APIENTRY 4081 NtUserAlterWindowStyle(HWND hWnd, DWORD Index, LONG NewValue) 4082 { 4083 LONG ret; 4084 4085 UserEnterExclusive(); 4086 4087 if (hWnd == IntGetDesktopWindow()) 4088 { 4089 EngSetLastError(STATUS_ACCESS_DENIED); 4090 UserLeave(); 4091 return 0; 4092 } 4093 4094 ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, FALSE, sizeof(LONG), TRUE); 4095 4096 UserLeave(); 4097 4098 return ret; 4099 } 4100 4101 4102 /* 4103 * NtUserSetWindowWord 4104 * 4105 * Legacy function similar to NtUserSetWindowLong. 4106 * 4107 * Status 4108 * @implemented 4109 */ 4110 4111 WORD APIENTRY 4112 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue) 4113 { 4114 PWND Window; 4115 WORD OldValue; 4116 DECLARE_RETURN(WORD); 4117 4118 TRACE("Enter NtUserSetWindowWord\n"); 4119 UserEnterExclusive(); 4120 4121 if (hWnd == IntGetDesktopWindow()) 4122 { 4123 EngSetLastError(STATUS_ACCESS_DENIED); 4124 RETURN( 0); 4125 } 4126 4127 if (!(Window = UserGetWindowObject(hWnd))) 4128 { 4129 RETURN( 0); 4130 } 4131 4132 switch (Index) 4133 { 4134 case GWL_ID: 4135 case GWL_HINSTANCE: 4136 case GWL_HWNDPARENT: 4137 RETURN( (WORD)co_UserSetWindowLong(UserHMGetHandle(Window), Index, (UINT)NewValue, TRUE)); 4138 default: 4139 if (Index < 0) 4140 { 4141 EngSetLastError(ERROR_INVALID_INDEX); 4142 RETURN( 0); 4143 } 4144 } 4145 4146 if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD))) 4147 { 4148 EngSetLastError(ERROR_INVALID_PARAMETER); 4149 RETURN( 0); 4150 } 4151 4152 OldValue = *((WORD *)((PCHAR)(Window + 1) + Index)); 4153 *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue; 4154 4155 RETURN( OldValue); 4156 4157 CLEANUP: 4158 TRACE("Leave NtUserSetWindowWord, ret=%u\n", _ret_); 4159 UserLeave(); 4160 END_CLEANUP; 4161 } 4162 4163 /* 4164 QueryWindow based on KJK::Hyperion and James Tabor. 4165 4166 0 = QWUniqueProcessId 4167 1 = QWUniqueThreadId 4168 2 = QWActiveWindow 4169 3 = QWFocusWindow 4170 4 = QWIsHung Implements IsHungAppWindow found 4171 by KJK::Hyperion. 4172 4173 9 = QWKillWindow When I called this with hWnd == 4174 DesktopWindow, it shutdown the system 4175 and rebooted. 4176 */ 4177 /* 4178 * @implemented 4179 */ 4180 DWORD_PTR APIENTRY 4181 NtUserQueryWindow(HWND hWnd, DWORD Index) 4182 { 4183 /* Console Leader Process CID Window offsets */ 4184 #define GWLP_CONSOLE_LEADER_PID 0 4185 #define GWLP_CONSOLE_LEADER_TID 4 4186 4187 DWORD_PTR Result; 4188 PWND pWnd, pwndActive; 4189 PTHREADINFO pti, ptiActive; 4190 DECLARE_RETURN(UINT); 4191 4192 TRACE("Enter NtUserQueryWindow\n"); 4193 UserEnterShared(); 4194 4195 if (!(pWnd = UserGetWindowObject(hWnd))) 4196 { 4197 RETURN( 0); 4198 } 4199 4200 switch(Index) 4201 { 4202 case QUERY_WINDOW_UNIQUE_PROCESS_ID: 4203 { 4204 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) && 4205 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) ) 4206 { 4207 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_PID) 4208 Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_PID))); 4209 } 4210 else 4211 { 4212 Result = (DWORD_PTR)IntGetWndProcessId(pWnd); 4213 } 4214 break; 4215 } 4216 4217 case QUERY_WINDOW_UNIQUE_THREAD_ID: 4218 { 4219 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) && 4220 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) ) 4221 { 4222 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_TID) 4223 Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_TID))); 4224 } 4225 else 4226 { 4227 Result = (DWORD_PTR)IntGetWndThreadId(pWnd); 4228 } 4229 break; 4230 } 4231 4232 case QUERY_WINDOW_ACTIVE: 4233 Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndActive ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndActive) : 0); 4234 break; 4235 4236 case QUERY_WINDOW_FOCUS: 4237 Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndFocus ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndFocus) : 0); 4238 break; 4239 4240 case QUERY_WINDOW_ISHUNG: 4241 Result = (pWnd->fnid == FNID_GHOST) || MsqIsHung(pWnd->head.pti, MSQ_HUNG); 4242 break; 4243 4244 case QUERY_WINDOW_REAL_ID: 4245 Result = (DWORD_PTR)pWnd->head.pti->pEThread->Cid.UniqueProcess; 4246 break; 4247 4248 case QUERY_WINDOW_FOREGROUND: 4249 Result = (pWnd->head.pti->MessageQueue == gpqForeground); 4250 break; 4251 4252 case QUERY_WINDOW_DEFAULT_IME: /* default IME window */ 4253 if (pWnd->head.pti->spwndDefaultIme) 4254 Result = (DWORD_PTR)UserHMGetHandle(pWnd->head.pti->spwndDefaultIme); 4255 else 4256 Result = 0; 4257 break; 4258 4259 case QUERY_WINDOW_DEFAULT_ICONTEXT: /* default input context handle */ 4260 if (pWnd->head.pti->spDefaultImc) 4261 Result = (DWORD_PTR)UserHMGetHandle(pWnd->head.pti->spDefaultImc); 4262 else 4263 Result = 0; 4264 break; 4265 4266 case QUERY_WINDOW_ACTIVE_IME: 4267 Result = 0; 4268 if (gpqForeground && gpqForeground->spwndActive) 4269 { 4270 pwndActive = gpqForeground->spwndActive; 4271 pti = PsGetCurrentThreadWin32Thread(); 4272 if (pti->rpdesk == pwndActive->head.rpdesk) 4273 { 4274 ptiActive = pwndActive->head.pti; 4275 if (ptiActive->spwndDefaultIme) 4276 Result = (DWORD_PTR)UserHMGetHandle(ptiActive->spwndDefaultIme); 4277 } 4278 } 4279 break; 4280 4281 default: 4282 Result = 0; 4283 break; 4284 } 4285 4286 RETURN( Result); 4287 4288 CLEANUP: 4289 TRACE("Leave NtUserQueryWindow, ret=%u\n", _ret_); 4290 UserLeave(); 4291 END_CLEANUP; 4292 } 4293 4294 /* 4295 * @implemented 4296 */ 4297 UINT APIENTRY 4298 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe) 4299 { 4300 UNICODE_STRING SafeMessageName; 4301 NTSTATUS Status; 4302 UINT Ret; 4303 DECLARE_RETURN(UINT); 4304 4305 TRACE("Enter NtUserRegisterWindowMessage\n"); 4306 UserEnterExclusive(); 4307 4308 if(MessageNameUnsafe == NULL) 4309 { 4310 EngSetLastError(ERROR_INVALID_PARAMETER); 4311 RETURN( 0); 4312 } 4313 4314 Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe); 4315 if(!NT_SUCCESS(Status)) 4316 { 4317 SetLastNtError(Status); 4318 RETURN( 0); 4319 } 4320 4321 Ret = (UINT)IntAddAtom(SafeMessageName.Buffer); 4322 if (SafeMessageName.Buffer) 4323 ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING); 4324 RETURN( Ret); 4325 4326 CLEANUP: 4327 TRACE("Leave NtUserRegisterWindowMessage, ret=%u\n", _ret_); 4328 UserLeave(); 4329 END_CLEANUP; 4330 } 4331 4332 /* 4333 * @implemented 4334 */ 4335 BOOL APIENTRY 4336 NtUserSetWindowFNID(HWND hWnd, 4337 WORD fnID) 4338 { 4339 PWND Wnd; 4340 DECLARE_RETURN(BOOL); 4341 4342 TRACE("Enter NtUserSetWindowFNID\n"); 4343 UserEnterExclusive(); 4344 4345 if (!(Wnd = UserGetWindowObject(hWnd))) 4346 { 4347 RETURN( FALSE); 4348 } 4349 4350 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process()) 4351 { 4352 EngSetLastError(ERROR_ACCESS_DENIED); 4353 RETURN( FALSE); 4354 } 4355 4356 // From user land we only set these. 4357 if (fnID != FNID_DESTROY) 4358 { 4359 /* HACK: The minimum should be FNID_BUTTON, but menu code relies on this */ 4360 if (fnID < FNID_FIRST || fnID > FNID_GHOST || 4361 Wnd->fnid != 0) 4362 { 4363 EngSetLastError(ERROR_INVALID_PARAMETER); 4364 RETURN( FALSE); 4365 } 4366 } 4367 4368 Wnd->fnid |= fnID; 4369 RETURN( TRUE); 4370 4371 CLEANUP: 4372 TRACE("Leave NtUserSetWindowFNID\n"); 4373 UserLeave(); 4374 END_CLEANUP; 4375 } 4376 4377 BOOL APIENTRY 4378 DefSetText(PWND Wnd, PCWSTR WindowText) 4379 { 4380 UNICODE_STRING UnicodeString; 4381 BOOL Ret = FALSE; 4382 4383 RtlInitUnicodeString(&UnicodeString, WindowText); 4384 4385 if (UnicodeString.Length != 0) 4386 { 4387 if (Wnd->strName.MaximumLength > 0 && 4388 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL)) 4389 { 4390 ASSERT(Wnd->strName.Buffer != NULL); 4391 4392 Wnd->strName.Length = UnicodeString.Length; 4393 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0'; 4394 RtlCopyMemory(Wnd->strName.Buffer, 4395 UnicodeString.Buffer, 4396 UnicodeString.Length); 4397 } 4398 else 4399 { 4400 PWCHAR buf; 4401 Wnd->strName.MaximumLength = Wnd->strName.Length = 0; 4402 buf = Wnd->strName.Buffer; 4403 Wnd->strName.Buffer = NULL; 4404 if (buf != NULL) 4405 { 4406 DesktopHeapFree(Wnd->head.rpdesk, buf); 4407 } 4408 4409 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk, 4410 UnicodeString.Length + sizeof(UNICODE_NULL)); 4411 if (Wnd->strName.Buffer != NULL) 4412 { 4413 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0'; 4414 RtlCopyMemory(Wnd->strName.Buffer, 4415 UnicodeString.Buffer, 4416 UnicodeString.Length); 4417 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL); 4418 Wnd->strName.Length = UnicodeString.Length; 4419 } 4420 else 4421 { 4422 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 4423 goto Exit; 4424 } 4425 } 4426 } 4427 else 4428 { 4429 Wnd->strName.Length = 0; 4430 if (Wnd->strName.Buffer != NULL) 4431 Wnd->strName.Buffer[0] = L'\0'; 4432 } 4433 4434 // FIXME: HAX! Windows does not do this in here! 4435 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than 4436 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc. 4437 /* Send shell notifications */ 4438 if (!Wnd->spwndOwner && !IntGetParent(Wnd)) 4439 { 4440 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) UserHMGetHandle(Wnd), FALSE); // FIXME Flashing? 4441 } 4442 4443 Ret = TRUE; 4444 Exit: 4445 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString); 4446 return Ret; 4447 } 4448 4449 /* 4450 * NtUserDefSetText 4451 * 4452 * Undocumented function that is called from DefWindowProc to set 4453 * window text. 4454 * 4455 * Status 4456 * @implemented 4457 */ 4458 BOOL APIENTRY 4459 NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText) 4460 { 4461 PWND Wnd; 4462 LARGE_STRING SafeText; 4463 UNICODE_STRING UnicodeString; 4464 BOOL Ret = TRUE; 4465 4466 TRACE("Enter NtUserDefSetText\n"); 4467 4468 if (WindowText != NULL) 4469 { 4470 _SEH2_TRY 4471 { 4472 SafeText = ProbeForReadLargeString(WindowText); 4473 } 4474 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4475 { 4476 Ret = FALSE; 4477 SetLastNtError(_SEH2_GetExceptionCode()); 4478 } 4479 _SEH2_END; 4480 4481 if (!Ret) 4482 return FALSE; 4483 } 4484 else 4485 return TRUE; 4486 4487 UserEnterExclusive(); 4488 4489 if(!(Wnd = UserGetWindowObject(hWnd))) 4490 { 4491 UserLeave(); 4492 return FALSE; 4493 } 4494 4495 // ReactOS uses Unicode and not mixed. Up/Down converting will take time. 4496 // Brought to you by: The Wine Project! Dysfunctional Thought Processes! 4497 // Now we know what the bAnsi is for. 4498 RtlInitUnicodeString(&UnicodeString, NULL); 4499 if (SafeText.Buffer) 4500 { 4501 _SEH2_TRY 4502 { 4503 if (SafeText.bAnsi) 4504 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR)); 4505 else 4506 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR)); 4507 Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText); 4508 } 4509 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4510 { 4511 Ret = FALSE; 4512 SetLastNtError(_SEH2_GetExceptionCode()); 4513 } 4514 _SEH2_END; 4515 if (!Ret) goto Exit; 4516 } 4517 4518 if (UnicodeString.Length != 0) 4519 { 4520 if (Wnd->strName.MaximumLength > 0 && 4521 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL)) 4522 { 4523 ASSERT(Wnd->strName.Buffer != NULL); 4524 4525 Wnd->strName.Length = UnicodeString.Length; 4526 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0'; 4527 RtlCopyMemory(Wnd->strName.Buffer, 4528 UnicodeString.Buffer, 4529 UnicodeString.Length); 4530 } 4531 else 4532 { 4533 PWCHAR buf; 4534 Wnd->strName.MaximumLength = Wnd->strName.Length = 0; 4535 buf = Wnd->strName.Buffer; 4536 Wnd->strName.Buffer = NULL; 4537 if (buf != NULL) 4538 { 4539 DesktopHeapFree(Wnd->head.rpdesk, buf); 4540 } 4541 4542 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk, 4543 UnicodeString.Length + sizeof(UNICODE_NULL)); 4544 if (Wnd->strName.Buffer != NULL) 4545 { 4546 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0'; 4547 RtlCopyMemory(Wnd->strName.Buffer, 4548 UnicodeString.Buffer, 4549 UnicodeString.Length); 4550 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL); 4551 Wnd->strName.Length = UnicodeString.Length; 4552 } 4553 else 4554 { 4555 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 4556 Ret = FALSE; 4557 goto Exit; 4558 } 4559 } 4560 } 4561 else 4562 { 4563 Wnd->strName.Length = 0; 4564 if (Wnd->strName.Buffer != NULL) 4565 Wnd->strName.Buffer[0] = L'\0'; 4566 } 4567 4568 // FIXME: HAX! Windows does not do this in here! 4569 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than 4570 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc. 4571 /* Send shell notifications */ 4572 if (!Wnd->spwndOwner && !IntGetParent(Wnd)) 4573 { 4574 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) hWnd, FALSE); // FIXME Flashing? 4575 } 4576 4577 Ret = TRUE; 4578 Exit: 4579 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString); 4580 TRACE("Leave NtUserDefSetText, ret=%i\n", Ret); 4581 UserLeave(); 4582 return Ret; 4583 } 4584 4585 /* 4586 * NtUserInternalGetWindowText 4587 * 4588 * Status 4589 * @implemented 4590 */ 4591 4592 INT APIENTRY 4593 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount) 4594 { 4595 PWND Wnd; 4596 NTSTATUS Status; 4597 INT Result; 4598 DECLARE_RETURN(INT); 4599 4600 TRACE("Enter NtUserInternalGetWindowText\n"); 4601 UserEnterShared(); 4602 4603 if(lpString && (nMaxCount <= 1)) 4604 { 4605 EngSetLastError(ERROR_INVALID_PARAMETER); 4606 RETURN( 0); 4607 } 4608 4609 if(!(Wnd = UserGetWindowObject(hWnd))) 4610 { 4611 RETURN( 0); 4612 } 4613 4614 Result = Wnd->strName.Length / sizeof(WCHAR); 4615 if(lpString) 4616 { 4617 const WCHAR Terminator = L'\0'; 4618 INT Copy; 4619 WCHAR *Buffer = (WCHAR*)lpString; 4620 4621 Copy = min(nMaxCount - 1, Result); 4622 if(Copy > 0) 4623 { 4624 Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR)); 4625 if(!NT_SUCCESS(Status)) 4626 { 4627 SetLastNtError(Status); 4628 RETURN( 0); 4629 } 4630 Buffer += Copy; 4631 } 4632 4633 Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR)); 4634 if(!NT_SUCCESS(Status)) 4635 { 4636 SetLastNtError(Status); 4637 RETURN( 0); 4638 } 4639 4640 Result = Copy; 4641 } 4642 4643 RETURN( Result); 4644 4645 CLEANUP: 4646 TRACE("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_); 4647 UserLeave(); 4648 END_CLEANUP; 4649 } 4650 4651 /* 4652 API Call 4653 */ 4654 BOOL 4655 FASTCALL 4656 IntShowOwnedPopups(PWND OwnerWnd, BOOL fShow ) 4657 { 4658 int count = 0; 4659 PWND pWnd; 4660 HWND *win_array; 4661 4662 // ASSERT(OwnerWnd); 4663 4664 TRACE("Enter ShowOwnedPopups Show: %s\n", (fShow ? "TRUE" : "FALSE")); 4665 4666 /* NOTE: Popups are not children */ 4667 win_array = IntWinListOwnedPopups(OwnerWnd); 4668 4669 if (!win_array) 4670 return TRUE; 4671 4672 while (win_array[count]) 4673 count++; 4674 while (--count >= 0) 4675 { 4676 if (!(pWnd = ValidateHwndNoErr( win_array[count] ))) 4677 continue; 4678 if (pWnd->spwndOwner != OwnerWnd) 4679 continue; 4680 4681 if (fShow) 4682 { 4683 if (pWnd->state & WNDS_HIDDENPOPUP) 4684 { 4685 /* In Windows, ShowOwnedPopups(TRUE) generates 4686 * WM_SHOWWINDOW messages with SW_PARENTOPENING, 4687 * regardless of the state of the owner 4688 */ 4689 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING); 4690 pWnd->state &= ~WNDS_HIDDENPOPUP; 4691 continue; 4692 } 4693 } 4694 else 4695 { 4696 if (pWnd->style & WS_VISIBLE) 4697 { 4698 /* In Windows, ShowOwnedPopups(FALSE) generates 4699 * WM_SHOWWINDOW messages with SW_PARENTCLOSING, 4700 * regardless of the state of the owner 4701 */ 4702 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING); 4703 pWnd->state |= WNDS_HIDDENPOPUP; 4704 continue; 4705 } 4706 } 4707 } 4708 ExFreePoolWithTag(win_array, USERTAG_WINDOWLIST); 4709 TRACE("Leave ShowOwnedPopups\n"); 4710 return TRUE; 4711 } 4712 4713 /* EOF */ 4714