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