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