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 if (descr->style & LBS_MULTICOLUMN) //// ReactOS 3353 Ret = descr->page_size * descr->column_width; 3354 else 3355 Ret = descr->page_size; 3356 } 3357 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3358 { 3359 Ret = 0; 3360 SetLastNtError(_SEH2_GetExceptionCode()); 3361 } 3362 _SEH2_END; 3363 3364 RETURN( Ret); 3365 3366 CLEANUP: 3367 if (NotSameppi) KeDetachProcess(); 3368 TRACE("Leave NtUserGetListBoxInfo, ret=%lu\n", _ret_); 3369 UserLeave(); 3370 END_CLEANUP; 3371 } 3372 3373 /* 3374 * NtUserSetParent 3375 * 3376 * The NtUserSetParent function changes the parent window of the specified 3377 * child window. 3378 * 3379 * Remarks 3380 * The new parent window and the child window must belong to the same 3381 * application. If the window identified by the hWndChild parameter is 3382 * visible, the system performs the appropriate redrawing and repainting. 3383 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD 3384 * or WS_POPUP window styles of the window whose parent is being changed. 3385 * 3386 * Status 3387 * @implemented 3388 */ 3389 3390 HWND APIENTRY 3391 NtUserSetParent(HWND hWndChild, HWND hWndNewParent) 3392 { 3393 DECLARE_RETURN(HWND); 3394 3395 TRACE("Enter NtUserSetParent\n"); 3396 UserEnterExclusive(); 3397 3398 /* 3399 Check Parent first from user space, set it here. 3400 */ 3401 if (!hWndNewParent) 3402 { 3403 hWndNewParent = IntGetDesktopWindow(); 3404 } 3405 else if (hWndNewParent == HWND_MESSAGE) 3406 { 3407 hWndNewParent = IntGetMessageWindow(); 3408 } 3409 3410 RETURN( co_UserSetParent(hWndChild, hWndNewParent)); 3411 3412 CLEANUP: 3413 TRACE("Leave NtUserSetParent, ret=%p\n", _ret_); 3414 UserLeave(); 3415 END_CLEANUP; 3416 } 3417 3418 /* 3419 * UserGetShellWindow 3420 * 3421 * Returns a handle to shell window that was set by NtUserSetShellWindowEx. 3422 * 3423 * Status 3424 * @implemented 3425 */ 3426 HWND FASTCALL UserGetShellWindow(VOID) 3427 { 3428 PWINSTATION_OBJECT WinStaObject; 3429 HWND Ret; 3430 3431 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation, 3432 UserMode, 3433 0, 3434 &WinStaObject, 3435 0); 3436 3437 if (!NT_SUCCESS(Status)) 3438 { 3439 SetLastNtError(Status); 3440 return( (HWND)0); 3441 } 3442 3443 Ret = (HWND)WinStaObject->ShellWindow; 3444 3445 ObDereferenceObject(WinStaObject); 3446 return( Ret); 3447 } 3448 3449 /* 3450 * NtUserSetShellWindowEx 3451 * 3452 * This is undocumented function to set global shell window. The global 3453 * shell window has special handling of window position. 3454 * 3455 * Status 3456 * @implemented 3457 */ 3458 BOOL APIENTRY 3459 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView) 3460 { 3461 PWINSTATION_OBJECT WinStaObject; 3462 PWND WndShell, WndListView; 3463 DECLARE_RETURN(BOOL); 3464 USER_REFERENCE_ENTRY Ref; 3465 NTSTATUS Status; 3466 PTHREADINFO ti; 3467 3468 TRACE("Enter NtUserSetShellWindowEx\n"); 3469 UserEnterExclusive(); 3470 3471 if (!(WndShell = UserGetWindowObject(hwndShell))) 3472 { 3473 RETURN(FALSE); 3474 } 3475 3476 if (!(WndListView = UserGetWindowObject(hwndListView))) 3477 { 3478 RETURN(FALSE); 3479 } 3480 3481 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation, 3482 UserMode, 3483 0, 3484 &WinStaObject, 3485 0); 3486 3487 if (!NT_SUCCESS(Status)) 3488 { 3489 SetLastNtError(Status); 3490 RETURN( FALSE); 3491 } 3492 3493 /* 3494 * Test if we are permitted to change the shell window. 3495 */ 3496 if (WinStaObject->ShellWindow) 3497 { 3498 ObDereferenceObject(WinStaObject); 3499 RETURN( FALSE); 3500 } 3501 3502 /* 3503 * Move shell window into background. 3504 */ 3505 if (hwndListView && hwndListView != hwndShell) 3506 { 3507 /* 3508 * Disabled for now to get Explorer working. 3509 * -- Filip, 01/nov/2003 3510 */ 3511 #if 0 3512 co_WinPosSetWindowPos(WndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE); 3513 #endif 3514 3515 if (WndListView->ExStyle & WS_EX_TOPMOST) 3516 { 3517 ObDereferenceObject(WinStaObject); 3518 RETURN( FALSE); 3519 } 3520 } 3521 3522 if (WndShell->ExStyle & WS_EX_TOPMOST) 3523 { 3524 ObDereferenceObject(WinStaObject); 3525 RETURN( FALSE); 3526 } 3527 3528 UserRefObjectCo(WndShell, &Ref); 3529 WndShell->state2 |= WNDS2_BOTTOMMOST; 3530 co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE); 3531 3532 WinStaObject->ShellWindow = hwndShell; 3533 WinStaObject->ShellListView = hwndListView; 3534 3535 ti = GetW32ThreadInfo(); 3536 if (ti->pDeskInfo) 3537 { 3538 ti->pDeskInfo->hShellWindow = hwndShell; 3539 ti->pDeskInfo->spwndShell = WndShell; 3540 ti->pDeskInfo->spwndBkGnd = WndListView; 3541 ti->pDeskInfo->ppiShellProcess = ti->ppi; 3542 } 3543 3544 UserRegisterHotKey(WndShell, SC_TASKLIST, MOD_CONTROL, VK_ESCAPE); 3545 3546 UserDerefObjectCo(WndShell); 3547 3548 ObDereferenceObject(WinStaObject); 3549 RETURN( TRUE); 3550 3551 CLEANUP: 3552 TRACE("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_); 3553 UserLeave(); 3554 END_CLEANUP; 3555 } 3556 3557 // Fixes wine Win test_window_styles and todo tests... 3558 static BOOL FASTCALL 3559 IntCheckFrameEdge(ULONG Style, ULONG ExStyle) 3560 { 3561 if (ExStyle & WS_EX_DLGMODALFRAME) 3562 return TRUE; 3563 else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME))) 3564 return TRUE; 3565 else 3566 return FALSE; 3567 } 3568 3569 static LONG_PTR 3570 co_IntSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi, ULONG Size, BOOL bAlter) 3571 { 3572 PWND Window, Parent; 3573 PWINSTATION_OBJECT WindowStation; 3574 LONG_PTR OldValue; 3575 STYLESTRUCT Style; 3576 3577 if (!(Window = UserGetWindowObject(hWnd))) 3578 { 3579 return( 0); 3580 } 3581 3582 if ((INT)Index >= 0) 3583 { 3584 if ((Index + Size) > Window->cbwndExtra) 3585 { 3586 EngSetLastError(ERROR_INVALID_INDEX); 3587 return( 0); 3588 } 3589 3590 #ifdef _WIN64 3591 if (Size == sizeof(LONG)) 3592 { 3593 OldValue = *((LONG *)((PCHAR)(Window + 1) + Index)); 3594 *((LONG*)((PCHAR)(Window + 1) + Index)) = (LONG)NewValue; 3595 } 3596 else 3597 #endif 3598 { 3599 OldValue = *((LONG_PTR *)((PCHAR)(Window + 1) + Index)); 3600 /* 3601 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW) 3602 { 3603 OldValue = (LONG_PTR)IntSetWindowProc( Wnd, (WNDPROC)NewValue, Ansi); 3604 if (!OldValue) return 0; 3605 } 3606 */ 3607 *((LONG_PTR*)((PCHAR)(Window + 1) + Index)) = NewValue; 3608 } 3609 3610 } 3611 else 3612 { 3613 #ifdef _WIN64 3614 if (Size == sizeof(LONG)) 3615 { 3616 if ((Index != GWL_STYLE) && 3617 (Index != GWL_EXSTYLE) && 3618 (Index != GWL_ID) && 3619 (Index != GWL_USERDATA)) 3620 { 3621 ERR("NtUserSetWindowLong(): Index requires pointer size: %lu\n", Index); 3622 EngSetLastError(ERROR_INVALID_INDEX); 3623 return 0; 3624 } 3625 } 3626 #endif 3627 3628 switch (Index) 3629 { 3630 case GWL_EXSTYLE: // LONG 3631 OldValue = (LONG) Window->ExStyle; 3632 Style.styleOld = OldValue; 3633 Style.styleNew = NewValue; 3634 3635 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style); 3636 3637 /* 3638 * Remove extended window style bit WS_EX_TOPMOST for shell windows. 3639 */ 3640 WindowStation = Window->head.pti->rpdesk->rpwinstaParent; 3641 if(WindowStation) 3642 { 3643 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView) 3644 Style.styleNew &= ~WS_EX_TOPMOST; 3645 } 3646 /* WS_EX_WINDOWEDGE depends on some other styles */ 3647 if (IntCheckFrameEdge(Window->style, NewValue)) 3648 Style.styleNew |= WS_EX_WINDOWEDGE; 3649 else 3650 Style.styleNew &= ~WS_EX_WINDOWEDGE; 3651 3652 if (!(Window->ExStyle & WS_EX_LAYERED)) 3653 { 3654 SetLayeredStatus(Window, 0); 3655 } 3656 3657 Window->ExStyle = (DWORD)Style.styleNew; 3658 3659 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style); 3660 break; 3661 3662 case GWL_STYLE: // LONG 3663 OldValue = (LONG) Window->style; 3664 Style.styleOld = OldValue; 3665 Style.styleNew = NewValue; 3666 3667 if (!bAlter) 3668 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style); 3669 3670 /* WS_CLIPSIBLINGS can't be reset on top-level windows */ 3671 if (UserIsDesktopWindow(Window->spwndParent)) Style.styleNew |= WS_CLIPSIBLINGS; 3672 /* WS_MINIMIZE can't be reset */ 3673 if (OldValue & WS_MINIMIZE) Style.styleNew |= WS_MINIMIZE; 3674 /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */ 3675 if (IntCheckFrameEdge(NewValue, Window->ExStyle)) 3676 Window->ExStyle |= WS_EX_WINDOWEDGE; 3677 else 3678 Window->ExStyle &= ~WS_EX_WINDOWEDGE; 3679 3680 if ((OldValue & (WS_CHILD | WS_POPUP)) == WS_CHILD) 3681 { 3682 if ((NewValue & (WS_CHILD | WS_POPUP)) != WS_CHILD) 3683 { 3684 //// From child to non-child it should be null already. 3685 ERR("IDMenu going null! %d\n",Window->IDMenu); 3686 Window->IDMenu = 0; // Window->spmenu = 0; 3687 } 3688 } 3689 else 3690 { 3691 if ((NewValue & (WS_CHILD | WS_POPUP)) == WS_CHILD) 3692 { 3693 PMENU pMenu = UserGetMenuObject(UlongToHandle(Window->IDMenu)); 3694 Window->state &= ~WNDS_HASMENU; 3695 if (pMenu) 3696 { 3697 ERR("IDMenu released 0x%p\n",pMenu); 3698 // ROS may not hold a lock after setting menu to window. But it should! 3699 //IntReleaseMenuObject(pMenu); 3700 } 3701 } 3702 } 3703 3704 if ((Style.styleOld ^ Style.styleNew) & WS_VISIBLE) 3705 { 3706 if (Style.styleOld & WS_VISIBLE) Window->head.pti->cVisWindows--; 3707 if (Style.styleNew & WS_VISIBLE) Window->head.pti->cVisWindows++; 3708 DceResetActiveDCEs( Window ); 3709 } 3710 Window->style = (DWORD)Style.styleNew; 3711 3712 if (!bAlter) 3713 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style); 3714 break; 3715 3716 case GWLP_WNDPROC: // LONG_PTR 3717 { 3718 if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() || 3719 Window->fnid & FNID_FREED) 3720 { 3721 EngSetLastError(ERROR_ACCESS_DENIED); 3722 return( 0); 3723 } 3724 OldValue = (LONG_PTR)IntSetWindowProc(Window, 3725 (WNDPROC)NewValue, 3726 Ansi); 3727 break; 3728 } 3729 3730 case GWLP_HINSTANCE: // LONG_PTR 3731 OldValue = (LONG_PTR) Window->hModule; 3732 Window->hModule = (HINSTANCE) NewValue; 3733 break; 3734 3735 case GWLP_HWNDPARENT: // LONG_PTR 3736 Parent = Window->spwndParent; 3737 if (Parent && (Parent->head.h == IntGetDesktopWindow())) 3738 OldValue = (LONG_PTR) IntSetOwner(Window->head.h, (HWND) NewValue); 3739 else 3740 OldValue = (LONG_PTR) co_UserSetParent(Window->head.h, (HWND) NewValue); 3741 break; 3742 3743 case GWLP_ID: // LONG 3744 OldValue = (LONG) Window->IDMenu; 3745 Window->IDMenu = (UINT) NewValue; 3746 break; 3747 3748 case GWLP_USERDATA: // LONG or LONG_PTR 3749 OldValue = Window->dwUserData; 3750 Window->dwUserData = NewValue; 3751 break; 3752 3753 default: 3754 ERR("NtUserSetWindowLong(): Unsupported index %lu\n", Index); 3755 EngSetLastError(ERROR_INVALID_INDEX); 3756 OldValue = 0; 3757 break; 3758 } 3759 } 3760 3761 return( OldValue); 3762 } 3763 3764 LONG FASTCALL 3765 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi) 3766 { 3767 return (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE); 3768 } 3769 3770 LONG_PTR FASTCALL 3771 co_UserSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi) 3772 { 3773 return co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE); 3774 } 3775 3776 /* 3777 * NtUserSetWindowLong 3778 * 3779 * The NtUserSetWindowLong function changes an attribute of the specified 3780 * window. The function also sets the 32-bit (long) value at the specified 3781 * offset into the extra window memory. 3782 * 3783 * Status 3784 * @implemented 3785 */ 3786 3787 LONG APIENTRY 3788 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi) 3789 { 3790 LONG ret; 3791 3792 UserEnterExclusive(); 3793 3794 if (hWnd == IntGetDesktopWindow()) 3795 { 3796 EngSetLastError(STATUS_ACCESS_DENIED); 3797 UserLeave(); 3798 return 0; 3799 } 3800 3801 ret = (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE); 3802 3803 UserLeave(); 3804 3805 return ret; 3806 } 3807 3808 #ifdef _WIN64 3809 LONG_PTR APIENTRY 3810 NtUserSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi) 3811 { 3812 LONG_PTR ret; 3813 3814 UserEnterExclusive(); 3815 3816 if (hWnd == IntGetDesktopWindow()) 3817 { 3818 EngSetLastError(STATUS_ACCESS_DENIED); 3819 UserLeave(); 3820 return 0; 3821 } 3822 3823 ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE); 3824 3825 UserLeave(); 3826 3827 return ret; 3828 } 3829 #endif // _WIN64 3830 3831 DWORD APIENTRY 3832 NtUserAlterWindowStyle(HWND hWnd, DWORD Index, LONG NewValue) 3833 { 3834 LONG ret; 3835 3836 UserEnterExclusive(); 3837 3838 if (hWnd == IntGetDesktopWindow()) 3839 { 3840 EngSetLastError(STATUS_ACCESS_DENIED); 3841 UserLeave(); 3842 return 0; 3843 } 3844 3845 ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, FALSE, sizeof(LONG), TRUE); 3846 3847 UserLeave(); 3848 3849 return ret; 3850 } 3851 3852 3853 /* 3854 * NtUserSetWindowWord 3855 * 3856 * Legacy function similar to NtUserSetWindowLong. 3857 * 3858 * Status 3859 * @implemented 3860 */ 3861 3862 WORD APIENTRY 3863 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue) 3864 { 3865 PWND Window; 3866 WORD OldValue; 3867 DECLARE_RETURN(WORD); 3868 3869 TRACE("Enter NtUserSetWindowWord\n"); 3870 UserEnterExclusive(); 3871 3872 if (hWnd == IntGetDesktopWindow()) 3873 { 3874 EngSetLastError(STATUS_ACCESS_DENIED); 3875 RETURN( 0); 3876 } 3877 3878 if (!(Window = UserGetWindowObject(hWnd))) 3879 { 3880 RETURN( 0); 3881 } 3882 3883 switch (Index) 3884 { 3885 case GWL_ID: 3886 case GWL_HINSTANCE: 3887 case GWL_HWNDPARENT: 3888 RETURN( (WORD)co_UserSetWindowLong(UserHMGetHandle(Window), Index, (UINT)NewValue, TRUE)); 3889 default: 3890 if (Index < 0) 3891 { 3892 EngSetLastError(ERROR_INVALID_INDEX); 3893 RETURN( 0); 3894 } 3895 } 3896 3897 if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD))) 3898 { 3899 EngSetLastError(ERROR_INVALID_PARAMETER); 3900 RETURN( 0); 3901 } 3902 3903 OldValue = *((WORD *)((PCHAR)(Window + 1) + Index)); 3904 *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue; 3905 3906 RETURN( OldValue); 3907 3908 CLEANUP: 3909 TRACE("Leave NtUserSetWindowWord, ret=%u\n", _ret_); 3910 UserLeave(); 3911 END_CLEANUP; 3912 } 3913 3914 /* 3915 QueryWindow based on KJK::Hyperion and James Tabor. 3916 3917 0 = QWUniqueProcessId 3918 1 = QWUniqueThreadId 3919 2 = QWActiveWindow 3920 3 = QWFocusWindow 3921 4 = QWIsHung Implements IsHungAppWindow found 3922 by KJK::Hyperion. 3923 3924 9 = QWKillWindow When I called this with hWnd == 3925 DesktopWindow, it shutdown the system 3926 and rebooted. 3927 */ 3928 /* 3929 * @implemented 3930 */ 3931 DWORD_PTR APIENTRY 3932 NtUserQueryWindow(HWND hWnd, DWORD Index) 3933 { 3934 /* Console Leader Process CID Window offsets */ 3935 #define GWLP_CONSOLE_LEADER_PID 0 3936 #define GWLP_CONSOLE_LEADER_TID 4 3937 3938 PWND pWnd; 3939 DWORD_PTR Result; 3940 DECLARE_RETURN(UINT); 3941 3942 TRACE("Enter NtUserQueryWindow\n"); 3943 UserEnterShared(); 3944 3945 if (!(pWnd = UserGetWindowObject(hWnd))) 3946 { 3947 RETURN( 0); 3948 } 3949 3950 switch(Index) 3951 { 3952 case QUERY_WINDOW_UNIQUE_PROCESS_ID: 3953 { 3954 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) && 3955 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) ) 3956 { 3957 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_PID) 3958 Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_PID))); 3959 } 3960 else 3961 { 3962 Result = (DWORD_PTR)IntGetWndProcessId(pWnd); 3963 } 3964 break; 3965 } 3966 3967 case QUERY_WINDOW_UNIQUE_THREAD_ID: 3968 { 3969 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) && 3970 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) ) 3971 { 3972 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_TID) 3973 Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_TID))); 3974 } 3975 else 3976 { 3977 Result = (DWORD_PTR)IntGetWndThreadId(pWnd); 3978 } 3979 break; 3980 } 3981 3982 case QUERY_WINDOW_ACTIVE: 3983 Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndActive ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndActive) : 0); 3984 break; 3985 3986 case QUERY_WINDOW_FOCUS: 3987 Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndFocus ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndFocus) : 0); 3988 break; 3989 3990 case QUERY_WINDOW_ISHUNG: 3991 Result = (DWORD_PTR)MsqIsHung(pWnd->head.pti, MSQ_HUNG); 3992 break; 3993 3994 case QUERY_WINDOW_REAL_ID: 3995 Result = (DWORD_PTR)pWnd->head.pti->pEThread->Cid.UniqueProcess; 3996 break; 3997 3998 case QUERY_WINDOW_FOREGROUND: 3999 Result = (pWnd->head.pti->MessageQueue == gpqForeground); 4000 break; 4001 4002 default: 4003 Result = 0; 4004 break; 4005 } 4006 4007 RETURN( Result); 4008 4009 CLEANUP: 4010 TRACE("Leave NtUserQueryWindow, ret=%u\n", _ret_); 4011 UserLeave(); 4012 END_CLEANUP; 4013 } 4014 4015 /* 4016 * @implemented 4017 */ 4018 UINT APIENTRY 4019 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe) 4020 { 4021 UNICODE_STRING SafeMessageName; 4022 NTSTATUS Status; 4023 UINT Ret; 4024 DECLARE_RETURN(UINT); 4025 4026 TRACE("Enter NtUserRegisterWindowMessage\n"); 4027 UserEnterExclusive(); 4028 4029 if(MessageNameUnsafe == NULL) 4030 { 4031 EngSetLastError(ERROR_INVALID_PARAMETER); 4032 RETURN( 0); 4033 } 4034 4035 Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe); 4036 if(!NT_SUCCESS(Status)) 4037 { 4038 SetLastNtError(Status); 4039 RETURN( 0); 4040 } 4041 4042 Ret = (UINT)IntAddAtom(SafeMessageName.Buffer); 4043 if (SafeMessageName.Buffer) 4044 ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING); 4045 RETURN( Ret); 4046 4047 CLEANUP: 4048 TRACE("Leave NtUserRegisterWindowMessage, ret=%u\n", _ret_); 4049 UserLeave(); 4050 END_CLEANUP; 4051 } 4052 4053 /* 4054 * @implemented 4055 */ 4056 BOOL APIENTRY 4057 NtUserSetWindowFNID(HWND hWnd, 4058 WORD fnID) 4059 { 4060 PWND Wnd; 4061 DECLARE_RETURN(BOOL); 4062 4063 TRACE("Enter NtUserSetWindowFNID\n"); 4064 UserEnterExclusive(); 4065 4066 if (!(Wnd = UserGetWindowObject(hWnd))) 4067 { 4068 RETURN( FALSE); 4069 } 4070 4071 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process()) 4072 { 4073 EngSetLastError(ERROR_ACCESS_DENIED); 4074 RETURN( FALSE); 4075 } 4076 4077 // From user land we only set these. 4078 if (fnID != FNID_DESTROY) 4079 { 4080 /* HACK: The minimum should be FNID_BUTTON, but menu code relies on this */ 4081 if (fnID < FNID_FIRST || fnID > FNID_GHOST || 4082 Wnd->fnid != 0) 4083 { 4084 EngSetLastError(ERROR_INVALID_PARAMETER); 4085 RETURN( FALSE); 4086 } 4087 } 4088 4089 Wnd->fnid |= fnID; 4090 RETURN( TRUE); 4091 4092 CLEANUP: 4093 TRACE("Leave NtUserSetWindowFNID\n"); 4094 UserLeave(); 4095 END_CLEANUP; 4096 } 4097 4098 BOOL APIENTRY 4099 DefSetText(PWND Wnd, PCWSTR WindowText) 4100 { 4101 UNICODE_STRING UnicodeString; 4102 BOOL Ret = FALSE; 4103 4104 RtlInitUnicodeString(&UnicodeString, WindowText); 4105 4106 if (UnicodeString.Length != 0) 4107 { 4108 if (Wnd->strName.MaximumLength > 0 && 4109 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL)) 4110 { 4111 ASSERT(Wnd->strName.Buffer != NULL); 4112 4113 Wnd->strName.Length = UnicodeString.Length; 4114 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0'; 4115 RtlCopyMemory(Wnd->strName.Buffer, 4116 UnicodeString.Buffer, 4117 UnicodeString.Length); 4118 } 4119 else 4120 { 4121 PWCHAR buf; 4122 Wnd->strName.MaximumLength = Wnd->strName.Length = 0; 4123 buf = Wnd->strName.Buffer; 4124 Wnd->strName.Buffer = NULL; 4125 if (buf != NULL) 4126 { 4127 DesktopHeapFree(Wnd->head.rpdesk, buf); 4128 } 4129 4130 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk, 4131 UnicodeString.Length + sizeof(UNICODE_NULL)); 4132 if (Wnd->strName.Buffer != NULL) 4133 { 4134 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0'; 4135 RtlCopyMemory(Wnd->strName.Buffer, 4136 UnicodeString.Buffer, 4137 UnicodeString.Length); 4138 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL); 4139 Wnd->strName.Length = UnicodeString.Length; 4140 } 4141 else 4142 { 4143 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 4144 goto Exit; 4145 } 4146 } 4147 } 4148 else 4149 { 4150 Wnd->strName.Length = 0; 4151 if (Wnd->strName.Buffer != NULL) 4152 Wnd->strName.Buffer[0] = L'\0'; 4153 } 4154 4155 // FIXME: HAX! Windows does not do this in here! 4156 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than 4157 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc. 4158 /* Send shell notifications */ 4159 if (!Wnd->spwndOwner && !IntGetParent(Wnd)) 4160 { 4161 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) UserHMGetHandle(Wnd), FALSE); // FIXME Flashing? 4162 } 4163 4164 Ret = TRUE; 4165 Exit: 4166 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString); 4167 return Ret; 4168 } 4169 4170 /* 4171 * NtUserDefSetText 4172 * 4173 * Undocumented function that is called from DefWindowProc to set 4174 * window text. 4175 * 4176 * Status 4177 * @implemented 4178 */ 4179 BOOL APIENTRY 4180 NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText) 4181 { 4182 PWND Wnd; 4183 LARGE_STRING SafeText; 4184 UNICODE_STRING UnicodeString; 4185 BOOL Ret = TRUE; 4186 4187 TRACE("Enter NtUserDefSetText\n"); 4188 4189 if (WindowText != NULL) 4190 { 4191 _SEH2_TRY 4192 { 4193 SafeText = ProbeForReadLargeString(WindowText); 4194 } 4195 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4196 { 4197 Ret = FALSE; 4198 SetLastNtError(_SEH2_GetExceptionCode()); 4199 } 4200 _SEH2_END; 4201 4202 if (!Ret) 4203 return FALSE; 4204 } 4205 else 4206 return TRUE; 4207 4208 UserEnterExclusive(); 4209 4210 if(!(Wnd = UserGetWindowObject(hWnd))) 4211 { 4212 UserLeave(); 4213 return FALSE; 4214 } 4215 4216 // ReactOS uses Unicode and not mixed. Up/Down converting will take time. 4217 // Brought to you by: The Wine Project! Dysfunctional Thought Processes! 4218 // Now we know what the bAnsi is for. 4219 RtlInitUnicodeString(&UnicodeString, NULL); 4220 if (SafeText.Buffer) 4221 { 4222 _SEH2_TRY 4223 { 4224 if (SafeText.bAnsi) 4225 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR)); 4226 else 4227 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR)); 4228 Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText); 4229 } 4230 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4231 { 4232 Ret = FALSE; 4233 SetLastNtError(_SEH2_GetExceptionCode()); 4234 } 4235 _SEH2_END; 4236 if (!Ret) goto Exit; 4237 } 4238 4239 if (UnicodeString.Length != 0) 4240 { 4241 if (Wnd->strName.MaximumLength > 0 && 4242 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL)) 4243 { 4244 ASSERT(Wnd->strName.Buffer != NULL); 4245 4246 Wnd->strName.Length = UnicodeString.Length; 4247 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0'; 4248 RtlCopyMemory(Wnd->strName.Buffer, 4249 UnicodeString.Buffer, 4250 UnicodeString.Length); 4251 } 4252 else 4253 { 4254 PWCHAR buf; 4255 Wnd->strName.MaximumLength = Wnd->strName.Length = 0; 4256 buf = Wnd->strName.Buffer; 4257 Wnd->strName.Buffer = NULL; 4258 if (buf != NULL) 4259 { 4260 DesktopHeapFree(Wnd->head.rpdesk, buf); 4261 } 4262 4263 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk, 4264 UnicodeString.Length + sizeof(UNICODE_NULL)); 4265 if (Wnd->strName.Buffer != NULL) 4266 { 4267 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0'; 4268 RtlCopyMemory(Wnd->strName.Buffer, 4269 UnicodeString.Buffer, 4270 UnicodeString.Length); 4271 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL); 4272 Wnd->strName.Length = UnicodeString.Length; 4273 } 4274 else 4275 { 4276 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 4277 Ret = FALSE; 4278 goto Exit; 4279 } 4280 } 4281 } 4282 else 4283 { 4284 Wnd->strName.Length = 0; 4285 if (Wnd->strName.Buffer != NULL) 4286 Wnd->strName.Buffer[0] = L'\0'; 4287 } 4288 4289 // FIXME: HAX! Windows does not do this in here! 4290 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than 4291 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc. 4292 /* Send shell notifications */ 4293 if (!Wnd->spwndOwner && !IntGetParent(Wnd)) 4294 { 4295 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) hWnd, FALSE); // FIXME Flashing? 4296 } 4297 4298 Ret = TRUE; 4299 Exit: 4300 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString); 4301 TRACE("Leave NtUserDefSetText, ret=%i\n", Ret); 4302 UserLeave(); 4303 return Ret; 4304 } 4305 4306 /* 4307 * NtUserInternalGetWindowText 4308 * 4309 * Status 4310 * @implemented 4311 */ 4312 4313 INT APIENTRY 4314 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount) 4315 { 4316 PWND Wnd; 4317 NTSTATUS Status; 4318 INT Result; 4319 DECLARE_RETURN(INT); 4320 4321 TRACE("Enter NtUserInternalGetWindowText\n"); 4322 UserEnterShared(); 4323 4324 if(lpString && (nMaxCount <= 1)) 4325 { 4326 EngSetLastError(ERROR_INVALID_PARAMETER); 4327 RETURN( 0); 4328 } 4329 4330 if(!(Wnd = UserGetWindowObject(hWnd))) 4331 { 4332 RETURN( 0); 4333 } 4334 4335 Result = Wnd->strName.Length / sizeof(WCHAR); 4336 if(lpString) 4337 { 4338 const WCHAR Terminator = L'\0'; 4339 INT Copy; 4340 WCHAR *Buffer = (WCHAR*)lpString; 4341 4342 Copy = min(nMaxCount - 1, Result); 4343 if(Copy > 0) 4344 { 4345 Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR)); 4346 if(!NT_SUCCESS(Status)) 4347 { 4348 SetLastNtError(Status); 4349 RETURN( 0); 4350 } 4351 Buffer += Copy; 4352 } 4353 4354 Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR)); 4355 if(!NT_SUCCESS(Status)) 4356 { 4357 SetLastNtError(Status); 4358 RETURN( 0); 4359 } 4360 4361 Result = Copy; 4362 } 4363 4364 RETURN( Result); 4365 4366 CLEANUP: 4367 TRACE("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_); 4368 UserLeave(); 4369 END_CLEANUP; 4370 } 4371 4372 /* 4373 API Call 4374 */ 4375 BOOL 4376 FASTCALL 4377 IntShowOwnedPopups(PWND OwnerWnd, BOOL fShow ) 4378 { 4379 int count = 0; 4380 PWND pWnd; 4381 HWND *win_array; 4382 4383 // ASSERT(OwnerWnd); 4384 4385 TRACE("Enter ShowOwnedPopups Show: %s\n", (fShow ? "TRUE" : "FALSE")); 4386 4387 /* NOTE: Popups are not children */ 4388 win_array = IntWinListOwnedPopups(OwnerWnd); 4389 4390 if (!win_array) 4391 return TRUE; 4392 4393 while (win_array[count]) 4394 count++; 4395 while (--count >= 0) 4396 { 4397 if (!(pWnd = ValidateHwndNoErr( win_array[count] ))) 4398 continue; 4399 if (pWnd->spwndOwner != OwnerWnd) 4400 continue; 4401 4402 if (fShow) 4403 { 4404 if (pWnd->state & WNDS_HIDDENPOPUP) 4405 { 4406 /* In Windows, ShowOwnedPopups(TRUE) generates 4407 * WM_SHOWWINDOW messages with SW_PARENTOPENING, 4408 * regardless of the state of the owner 4409 */ 4410 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING); 4411 pWnd->state &= ~WNDS_HIDDENPOPUP; 4412 continue; 4413 } 4414 } 4415 else 4416 { 4417 if (pWnd->style & WS_VISIBLE) 4418 { 4419 /* In Windows, ShowOwnedPopups(FALSE) generates 4420 * WM_SHOWWINDOW messages with SW_PARENTCLOSING, 4421 * regardless of the state of the owner 4422 */ 4423 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING); 4424 pWnd->state |= WNDS_HIDDENPOPUP; 4425 continue; 4426 } 4427 } 4428 } 4429 ExFreePoolWithTag(win_array, USERTAG_WINDOWLIST); 4430 TRACE("Leave ShowOwnedPopups\n"); 4431 return TRUE; 4432 } 4433 4434 /* EOF */ 4435