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