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 { 1620 PWND pWnd = NULL; 1621 HWND hWnd; 1622 PTHREADINFO pti = NULL; 1623 BOOL MenuChanged; 1624 BOOL bUnicodeWindow; 1625 1626 pti = pdeskCreated ? gptiDesktopThread : GetW32ThreadInfo(); 1627 1628 if (!(Cs->dwExStyle & WS_EX_LAYOUTRTL)) 1629 { // Need both here for wine win.c test_CreateWindow. 1630 //if (Cs->hwndParent && ParentWindow) 1631 if (ParentWindow) // It breaks more tests..... WIP. 1632 { 1633 if ( (Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD && 1634 ParentWindow->ExStyle & WS_EX_LAYOUTRTL && 1635 !(ParentWindow->ExStyle & WS_EX_NOINHERITLAYOUT) ) 1636 Cs->dwExStyle |= WS_EX_LAYOUTRTL; 1637 } 1638 else 1639 { /* 1640 * Note from MSDN <http://msdn.microsoft.com/en-us/library/aa913269.aspx>: 1641 * 1642 * Dialog boxes and message boxes do not inherit layout, so you must 1643 * set the layout explicitly. 1644 */ 1645 if ( Class->fnid != FNID_DIALOG ) 1646 { 1647 if (pti->ppi->dwLayout & LAYOUT_RTL) 1648 { 1649 Cs->dwExStyle |= WS_EX_LAYOUTRTL; 1650 } 1651 } 1652 } 1653 } 1654 1655 /* Automatically add WS_EX_WINDOWEDGE */ 1656 if ((Cs->dwExStyle & WS_EX_DLGMODALFRAME) || 1657 ((!(Cs->dwExStyle & WS_EX_STATICEDGE)) && 1658 (Cs->style & (WS_DLGFRAME | WS_THICKFRAME)))) 1659 Cs->dwExStyle |= WS_EX_WINDOWEDGE; 1660 else 1661 Cs->dwExStyle &= ~WS_EX_WINDOWEDGE; 1662 1663 /* Is it a unicode window? */ 1664 bUnicodeWindow =!(Cs->dwExStyle & WS_EX_SETANSICREATOR); 1665 Cs->dwExStyle &= ~WS_EX_SETANSICREATOR; 1666 1667 /* Allocate the new window */ 1668 pWnd = (PWND) UserCreateObject( gHandleTable, 1669 pdeskCreated ? pdeskCreated : pti->rpdesk, 1670 pti, 1671 (PHANDLE)&hWnd, 1672 TYPE_WINDOW, 1673 sizeof(WND) + Class->cbwndExtra); 1674 1675 if (!pWnd) 1676 { 1677 goto AllocError; 1678 } 1679 1680 TRACE("Created window object with handle %p\n", hWnd); 1681 1682 if (pdeskCreated && pdeskCreated->DesktopWindow == NULL ) 1683 { /* HACK: Helper for win32csr/desktopbg.c */ 1684 /* If there is no desktop window yet, we must be creating it */ 1685 TRACE("CreateWindow setting desktop.\n"); 1686 pdeskCreated->DesktopWindow = hWnd; 1687 pdeskCreated->pDeskInfo->spwnd = pWnd; 1688 } 1689 1690 /* 1691 * Fill out the structure describing it. 1692 */ 1693 /* Remember, pWnd->head is setup in object.c ... */ 1694 pWnd->spwndParent = ParentWindow; 1695 pWnd->spwndOwner = OwnerWindow; 1696 pWnd->fnid = 0; 1697 pWnd->spwndLastActive = pWnd; 1698 pWnd->state2 |= WNDS2_WIN40COMPAT; // FIXME!!! 1699 pWnd->pcls = Class; 1700 pWnd->hModule = Cs->hInstance; 1701 pWnd->style = Cs->style & ~WS_VISIBLE; 1702 pWnd->ExStyle = Cs->dwExStyle; 1703 pWnd->cbwndExtra = pWnd->pcls->cbwndExtra; 1704 pWnd->pActCtx = acbiBuffer; 1705 pWnd->InternalPos.MaxPos.x = pWnd->InternalPos.MaxPos.y = -1; 1706 pWnd->InternalPos.IconPos.x = pWnd->InternalPos.IconPos.y = -1; 1707 1708 if (pWnd->spwndParent != NULL && Cs->hwndParent != 0) 1709 { 1710 pWnd->HideFocus = pWnd->spwndParent->HideFocus; 1711 pWnd->HideAccel = pWnd->spwndParent->HideAccel; 1712 } 1713 1714 pWnd->head.pti->cWindows++; 1715 1716 if (Class->spicn && !Class->spicnSm) 1717 { 1718 HICON IconSmHandle = NULL; 1719 if((Class->spicn->CURSORF_flags & (CURSORF_LRSHARED | CURSORF_FROMRESOURCE)) 1720 == (CURSORF_LRSHARED | CURSORF_FROMRESOURCE)) 1721 { 1722 IconSmHandle = co_IntCopyImage( 1723 UserHMGetHandle(Class->spicn), 1724 IMAGE_ICON, 1725 UserGetSystemMetrics( SM_CXSMICON ), 1726 UserGetSystemMetrics( SM_CYSMICON ), 1727 LR_COPYFROMRESOURCE); 1728 } 1729 if (!IconSmHandle) 1730 { 1731 /* Retry without copying from resource */ 1732 IconSmHandle = co_IntCopyImage( 1733 UserHMGetHandle(Class->spicn), 1734 IMAGE_ICON, 1735 UserGetSystemMetrics( SM_CXSMICON ), 1736 UserGetSystemMetrics( SM_CYSMICON ), 1737 0); 1738 } 1739 1740 if (IconSmHandle) 1741 { 1742 Class->spicnSm = UserGetCurIconObject(IconSmHandle); 1743 Class->CSF_flags |= CSF_CACHEDSMICON; 1744 } 1745 } 1746 1747 if (pWnd->pcls->CSF_flags & CSF_SERVERSIDEPROC) 1748 pWnd->state |= WNDS_SERVERSIDEWINDOWPROC; 1749 1750 /* BugBoy Comments: Comment below say that System classes are always created 1751 as UNICODE. In windows, creating a window with the ANSI version of CreateWindow 1752 sets the window to ansi as verified by testing with IsUnicodeWindow API. 1753 1754 No where can I see in code or through testing does the window change back 1755 to ANSI after being created as UNICODE in ROS. I didnt do more testing to 1756 see what problems this would cause. */ 1757 1758 // Set WndProc from Class. 1759 pWnd->lpfnWndProc = pWnd->pcls->lpfnWndProc; 1760 1761 // GetWindowProc, test for non server side default classes and set WndProc. 1762 if ( pWnd->pcls->fnid <= FNID_GHOST && pWnd->pcls->fnid >= FNID_BUTTON ) 1763 { 1764 if (bUnicodeWindow) 1765 { 1766 if (GETPFNCLIENTA(pWnd->pcls->fnid) == pWnd->lpfnWndProc) 1767 pWnd->lpfnWndProc = GETPFNCLIENTW(pWnd->pcls->fnid); 1768 } 1769 else 1770 { 1771 if (GETPFNCLIENTW(pWnd->pcls->fnid) == pWnd->lpfnWndProc) 1772 pWnd->lpfnWndProc = GETPFNCLIENTA(pWnd->pcls->fnid); 1773 } 1774 } 1775 1776 // If not an Unicode caller, set Ansi creator bit. 1777 if (!bUnicodeWindow) pWnd->state |= WNDS_ANSICREATOR; 1778 1779 // Clone Class Ansi/Unicode proc type. 1780 if (pWnd->pcls->CSF_flags & CSF_ANSIPROC) 1781 { 1782 pWnd->state |= WNDS_ANSIWINDOWPROC; 1783 pWnd->Unicode = FALSE; 1784 } 1785 else 1786 { /* 1787 * It seems there can be both an Ansi creator and Unicode Class Window 1788 * WndProc, unless the following overriding conditions occur: 1789 */ 1790 if ( !bUnicodeWindow && 1791 ( Class->atomClassName == gpsi->atomSysClass[ICLS_BUTTON] || 1792 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOBOX] || 1793 Class->atomClassName == gpsi->atomSysClass[ICLS_COMBOLBOX] || 1794 Class->atomClassName == gpsi->atomSysClass[ICLS_DIALOG] || 1795 Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT] || 1796 Class->atomClassName == gpsi->atomSysClass[ICLS_IME] || 1797 Class->atomClassName == gpsi->atomSysClass[ICLS_LISTBOX] || 1798 Class->atomClassName == gpsi->atomSysClass[ICLS_MDICLIENT] || 1799 Class->atomClassName == gpsi->atomSysClass[ICLS_STATIC] ) ) 1800 { // Override Class and set the window Ansi WndProc. 1801 pWnd->state |= WNDS_ANSIWINDOWPROC; 1802 pWnd->Unicode = FALSE; 1803 } 1804 else 1805 { // Set the window Unicode WndProc. 1806 pWnd->state &= ~WNDS_ANSIWINDOWPROC; 1807 pWnd->Unicode = TRUE; 1808 } 1809 } 1810 1811 /* BugBoy Comments: if the window being created is a edit control, ATOM 0xCxxx, 1812 then my testing shows that windows (2k and XP) creates a CallProc for it immediately 1813 Dont understand why it does this. */ 1814 if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT]) 1815 { 1816 PCALLPROCDATA CallProc; 1817 CallProc = CreateCallProc(pWnd->head.rpdesk, pWnd->lpfnWndProc, pWnd->Unicode , pWnd->head.pti->ppi); 1818 1819 if (!CallProc) 1820 { 1821 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 1822 ERR("Warning: Unable to create CallProc for edit control. Control may not operate correctly! hwnd %p\n", hWnd); 1823 } 1824 else 1825 { 1826 UserAddCallProcToClass(pWnd->pcls, CallProc); 1827 } 1828 } 1829 1830 InitializeListHead(&pWnd->PropListHead); 1831 pWnd->PropListItems = 0; 1832 1833 if ( WindowName->Buffer != NULL && WindowName->Length > 0 ) 1834 { 1835 pWnd->strName.Buffer = DesktopHeapAlloc(pWnd->head.rpdesk, 1836 WindowName->Length + sizeof(UNICODE_NULL)); 1837 if (pWnd->strName.Buffer == NULL) 1838 { 1839 goto AllocError; 1840 } 1841 1842 RtlCopyMemory(pWnd->strName.Buffer, WindowName->Buffer, WindowName->Length); 1843 pWnd->strName.Buffer[WindowName->Length / sizeof(WCHAR)] = L'\0'; 1844 pWnd->strName.Length = WindowName->Length; 1845 pWnd->strName.MaximumLength = WindowName->Length + sizeof(UNICODE_NULL); 1846 } 1847 1848 /* Correct the window style. */ 1849 if ((pWnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD) 1850 { 1851 pWnd->style |= WS_CLIPSIBLINGS; 1852 if (!(pWnd->style & WS_POPUP)) 1853 { 1854 pWnd->style |= WS_CAPTION; 1855 } 1856 } 1857 1858 /* WS_EX_WINDOWEDGE depends on some other styles */ 1859 if (pWnd->ExStyle & WS_EX_DLGMODALFRAME) 1860 pWnd->ExStyle |= WS_EX_WINDOWEDGE; 1861 else if (pWnd->style & (WS_DLGFRAME | WS_THICKFRAME)) 1862 { 1863 if (!((pWnd->ExStyle & WS_EX_STATICEDGE) && 1864 (pWnd->style & (WS_CHILD | WS_POPUP)))) 1865 pWnd->ExStyle |= WS_EX_WINDOWEDGE; 1866 } 1867 else 1868 pWnd->ExStyle &= ~WS_EX_WINDOWEDGE; 1869 1870 if (!(pWnd->style & (WS_CHILD | WS_POPUP))) 1871 pWnd->state |= WNDS_SENDSIZEMOVEMSGS; 1872 1873 /* Set the window menu */ 1874 if ((Cs->style & (WS_CHILD | WS_POPUP)) != WS_CHILD) 1875 { 1876 if (Cs->hMenu) 1877 { 1878 IntSetMenu(pWnd, Cs->hMenu, &MenuChanged); 1879 } 1880 else if (pWnd->pcls->lpszMenuName) // Take it from the parent. 1881 { 1882 UNICODE_STRING MenuName; 1883 HMENU hMenu; 1884 1885 if (IS_INTRESOURCE(pWnd->pcls->lpszMenuName)) 1886 { 1887 MenuName.Length = 0; 1888 MenuName.MaximumLength = 0; 1889 MenuName.Buffer = pWnd->pcls->lpszMenuName; 1890 } 1891 else 1892 { 1893 RtlInitUnicodeString( &MenuName, pWnd->pcls->lpszMenuName); 1894 } 1895 hMenu = co_IntCallLoadMenu( pWnd->pcls->hModule, &MenuName); 1896 if (hMenu) IntSetMenu(pWnd, hMenu, &MenuChanged); 1897 } 1898 } 1899 else // Not a child 1900 pWnd->IDMenu = (UINT_PTR)Cs->hMenu; 1901 1902 1903 if ( ParentWindow && 1904 ParentWindow != ParentWindow->head.rpdesk->spwndMessage && 1905 ParentWindow != ParentWindow->head.rpdesk->pDeskInfo->spwnd ) 1906 { 1907 PWND Owner = IntGetNonChildAncestor(ParentWindow); 1908 1909 if (!IntValidateOwnerDepth(pWnd, Owner)) 1910 { 1911 EngSetLastError(ERROR_INVALID_PARAMETER); 1912 goto Error; 1913 } 1914 if ( pWnd->spwndOwner && 1915 pWnd->spwndOwner->ExStyle & WS_EX_TOPMOST ) 1916 { 1917 pWnd->ExStyle |= WS_EX_TOPMOST; 1918 } 1919 if ( pWnd->spwndOwner && 1920 Class->atomClassName != gpsi->atomSysClass[ICLS_IME] && 1921 pti != pWnd->spwndOwner->head.pti) 1922 { 1923 //ERR("CreateWindow Owner in.\n"); 1924 UserAttachThreadInput(pti, pWnd->spwndOwner->head.pti, TRUE); 1925 } 1926 } 1927 1928 /* Insert the window into the thread's window list. */ 1929 InsertTailList (&pti->WindowListHead, &pWnd->ThreadListEntry); 1930 1931 /* Handle "CS_CLASSDC", it is tested first. */ 1932 if ( (pWnd->pcls->style & CS_CLASSDC) && !(pWnd->pcls->pdce) ) 1933 { /* One DCE per class to have CLASS. */ 1934 pWnd->pcls->pdce = DceAllocDCE( pWnd, DCE_CLASS_DC ); 1935 } 1936 else if ( pWnd->pcls->style & CS_OWNDC) 1937 { /* Allocate a DCE for this window. */ 1938 DceAllocDCE(pWnd, DCE_WINDOW_DC); 1939 } 1940 1941 return pWnd; 1942 1943 AllocError: 1944 ERR("IntCreateWindow Allocation Error.\n"); 1945 SetLastNtError(STATUS_INSUFFICIENT_RESOURCES); 1946 Error: 1947 if(pWnd) 1948 UserDereferenceObject(pWnd); 1949 return NULL; 1950 } 1951 1952 /* 1953 * @implemented 1954 */ 1955 PWND FASTCALL 1956 co_UserCreateWindowEx(CREATESTRUCTW* Cs, 1957 PUNICODE_STRING ClassName, 1958 PLARGE_STRING WindowName, 1959 PVOID acbiBuffer) 1960 { 1961 ULONG style; 1962 PWND Window = NULL, ParentWindow = NULL, OwnerWindow; 1963 HWND hWnd, hWndParent, hWndOwner, hwndInsertAfter; 1964 PWINSTATION_OBJECT WinSta; 1965 PCLS Class = NULL; 1966 SIZE Size; 1967 POINT MaxSize, MaxPos, MinTrack, MaxTrack; 1968 CBT_CREATEWNDW * pCbtCreate; 1969 LRESULT Result; 1970 USER_REFERENCE_ENTRY ParentRef, Ref; 1971 PTHREADINFO pti; 1972 DWORD dwShowMode = SW_SHOW; 1973 CREATESTRUCTW *pCsw = NULL; 1974 PVOID pszClass = NULL, pszName = NULL; 1975 PWND ret = NULL; 1976 1977 /* Get the current window station and reference it */ 1978 pti = GetW32ThreadInfo(); 1979 if (pti == NULL || pti->rpdesk == NULL) 1980 { 1981 ERR("Thread is not attached to a desktop! Cannot create window!\n"); 1982 return NULL; // There is nothing to cleanup. 1983 } 1984 WinSta = pti->rpdesk->rpwinstaParent; 1985 ObReferenceObjectByPointer(WinSta, KernelMode, ExWindowStationObjectType, 0); 1986 1987 pCsw = NULL; 1988 pCbtCreate = NULL; 1989 1990 /* Get the class and reference it */ 1991 Class = IntGetAndReferenceClass(ClassName, Cs->hInstance, FALSE); 1992 if(!Class) 1993 { 1994 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS); 1995 ERR("Failed to find class %wZ\n", ClassName); 1996 goto cleanup; 1997 } 1998 1999 /* Now find the parent and the owner window */ 2000 hWndParent = pti->rpdesk->pDeskInfo->spwnd->head.h; 2001 hWndOwner = NULL; 2002 2003 if (Cs->hwndParent == HWND_MESSAGE) 2004 { 2005 Cs->hwndParent = hWndParent = pti->rpdesk->spwndMessage->head.h; 2006 } 2007 else if (Cs->hwndParent) 2008 { 2009 if ((Cs->style & (WS_CHILD|WS_POPUP)) != WS_CHILD) 2010 hWndOwner = Cs->hwndParent; 2011 else 2012 hWndParent = Cs->hwndParent; 2013 } 2014 else if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD) 2015 { 2016 ERR("Cannot create a child window without a parent!\n"); 2017 EngSetLastError(ERROR_TLW_WITH_WSCHILD); 2018 goto cleanup; /* WS_CHILD needs a parent, but WS_POPUP doesn't */ 2019 } 2020 else if (Cs->lpszClass != (LPCWSTR)MAKEINTATOM(gpsi->atomSysClass[ICLS_DESKTOP]) && 2021 (IS_INTRESOURCE(Cs->lpszClass) || 2022 Cs->lpszClass != (LPCWSTR)MAKEINTATOM(gpsi->atomSysClass[ICLS_HWNDMESSAGE]) || 2023 _wcsicmp(Cs->lpszClass, L"Message") != 0)) 2024 { 2025 if (pti->ppi->dwLayout & LAYOUT_RTL) 2026 { 2027 Cs->dwExStyle |= WS_EX_LAYOUTRTL; 2028 } 2029 } 2030 2031 ParentWindow = hWndParent ? UserGetWindowObject(hWndParent): NULL; 2032 OwnerWindow = hWndOwner ? UserGetWindowObject(hWndOwner): NULL; 2033 2034 if (hWndParent && !ParentWindow) 2035 { 2036 ERR("Got invalid parent window handle\n"); 2037 goto cleanup; 2038 } 2039 else if (hWndOwner && !OwnerWindow) 2040 { 2041 ERR("Got invalid owner window handle\n"); 2042 ParentWindow = NULL; 2043 goto cleanup; 2044 } 2045 2046 if(OwnerWindow) 2047 { 2048 if (IntIsDesktopWindow(OwnerWindow)) OwnerWindow = NULL; 2049 else if (ParentWindow && !IntIsDesktopWindow(ParentWindow)) 2050 { 2051 ERR("an owned window must be created as top-level\n"); 2052 EngSetLastError( STATUS_ACCESS_DENIED ); 2053 goto cleanup; 2054 } 2055 else /* owner must be a top-level window */ 2056 { 2057 while ((OwnerWindow->style & (WS_POPUP|WS_CHILD)) == WS_CHILD && !IntIsDesktopWindow(OwnerWindow->spwndParent)) 2058 OwnerWindow = OwnerWindow->spwndParent; 2059 } 2060 } 2061 2062 /* Fix the position and the size of the window */ 2063 if (ParentWindow) 2064 { 2065 UserRefObjectCo(ParentWindow, &ParentRef); 2066 IntFixWindowCoordinates(Cs, ParentWindow, &dwShowMode); 2067 } 2068 2069 /* Allocate and initialize the new window */ 2070 Window = IntCreateWindow(Cs, 2071 WindowName, 2072 Class, 2073 ParentWindow, 2074 OwnerWindow, 2075 acbiBuffer, 2076 NULL); 2077 if(!Window) 2078 { 2079 ERR("IntCreateWindow failed!\n"); 2080 goto cleanup; 2081 } 2082 2083 hWnd = UserHMGetHandle(Window); 2084 hwndInsertAfter = HWND_TOP; 2085 2086 UserRefObjectCo(Window, &Ref); 2087 UserDereferenceObject(Window); 2088 ObDereferenceObject(WinSta); 2089 2090 //// Check for a hook to eliminate overhead. //// 2091 if ( ISITHOOKED(WH_CBT) || (pti->rpdesk->pDeskInfo->fsHooks & HOOKID_TO_FLAG(WH_CBT)) ) 2092 { 2093 // Allocate the calling structures Justin Case this goes Global. 2094 pCsw = ExAllocatePoolWithTag(NonPagedPool, sizeof(CREATESTRUCTW), TAG_HOOK); 2095 pCbtCreate = ExAllocatePoolWithTag(NonPagedPool, sizeof(CBT_CREATEWNDW), TAG_HOOK); 2096 if (!pCsw || !pCbtCreate) 2097 { 2098 ERR("UserHeapAlloc() failed!\n"); 2099 goto cleanup; 2100 } 2101 2102 /* Fill the new CREATESTRUCTW */ 2103 RtlCopyMemory(pCsw, Cs, sizeof(CREATESTRUCTW)); 2104 pCsw->style = Window->style; /* HCBT_CREATEWND needs the real window style */ 2105 2106 // Based on the assumption this is from "unicode source" user32, ReactOS, answer is yes. 2107 if (!IS_ATOM(ClassName->Buffer)) 2108 { 2109 if (Window->state & WNDS_ANSICREATOR) 2110 { 2111 ANSI_STRING AnsiString; 2112 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(ClassName)+sizeof(CHAR); 2113 pszClass = UserHeapAlloc(AnsiString.MaximumLength); 2114 if (!pszClass) 2115 { 2116 ERR("UserHeapAlloc() failed!\n"); 2117 goto cleanup; 2118 } 2119 RtlZeroMemory(pszClass, AnsiString.MaximumLength); 2120 AnsiString.Buffer = (PCHAR)pszClass; 2121 RtlUnicodeStringToAnsiString(&AnsiString, ClassName, FALSE); 2122 } 2123 else 2124 { 2125 UNICODE_STRING UnicodeString; 2126 UnicodeString.MaximumLength = ClassName->Length + sizeof(UNICODE_NULL); 2127 pszClass = UserHeapAlloc(UnicodeString.MaximumLength); 2128 if (!pszClass) 2129 { 2130 ERR("UserHeapAlloc() failed!\n"); 2131 goto cleanup; 2132 } 2133 RtlZeroMemory(pszClass, UnicodeString.MaximumLength); 2134 UnicodeString.Buffer = (PWSTR)pszClass; 2135 RtlCopyUnicodeString(&UnicodeString, ClassName); 2136 } 2137 pCsw->lpszClass = UserHeapAddressToUser(pszClass); 2138 } 2139 if (WindowName->Length) 2140 { 2141 UNICODE_STRING Name; 2142 Name.Buffer = WindowName->Buffer; 2143 Name.Length = (USHORT)min(WindowName->Length, MAXUSHORT); // FIXME: LARGE_STRING truncated 2144 Name.MaximumLength = (USHORT)min(WindowName->MaximumLength, MAXUSHORT); 2145 2146 if (Window->state & WNDS_ANSICREATOR) 2147 { 2148 ANSI_STRING AnsiString; 2149 AnsiString.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(&Name) + sizeof(CHAR); 2150 pszName = UserHeapAlloc(AnsiString.MaximumLength); 2151 if (!pszName) 2152 { 2153 ERR("UserHeapAlloc() failed!\n"); 2154 goto cleanup; 2155 } 2156 RtlZeroMemory(pszName, AnsiString.MaximumLength); 2157 AnsiString.Buffer = (PCHAR)pszName; 2158 RtlUnicodeStringToAnsiString(&AnsiString, &Name, FALSE); 2159 } 2160 else 2161 { 2162 UNICODE_STRING UnicodeString; 2163 UnicodeString.MaximumLength = Name.Length + sizeof(UNICODE_NULL); 2164 pszName = UserHeapAlloc(UnicodeString.MaximumLength); 2165 if (!pszName) 2166 { 2167 ERR("UserHeapAlloc() failed!\n"); 2168 goto cleanup; 2169 } 2170 RtlZeroMemory(pszName, UnicodeString.MaximumLength); 2171 UnicodeString.Buffer = (PWSTR)pszName; 2172 RtlCopyUnicodeString(&UnicodeString, &Name); 2173 } 2174 pCsw->lpszName = UserHeapAddressToUser(pszName); 2175 } 2176 2177 pCbtCreate->lpcs = pCsw; 2178 pCbtCreate->hwndInsertAfter = hwndInsertAfter; 2179 2180 //// Call the WH_CBT hook //// 2181 Result = co_HOOK_CallHooks(WH_CBT, HCBT_CREATEWND, (WPARAM) hWnd, (LPARAM) pCbtCreate); 2182 if (Result != 0) 2183 { 2184 ERR("WH_CBT HCBT_CREATEWND hook failed! 0x%x\n", Result); 2185 goto cleanup; 2186 } 2187 // Write back changes. 2188 Cs->cx = pCsw->cx; 2189 Cs->cy = pCsw->cy; 2190 Cs->x = pCsw->x; 2191 Cs->y = pCsw->y; 2192 hwndInsertAfter = pCbtCreate->hwndInsertAfter; 2193 } 2194 2195 /* NCCREATE and WM_NCCALCSIZE need the original values */ 2196 Cs->lpszName = (LPCWSTR) WindowName; 2197 Cs->lpszClass = (LPCWSTR) ClassName; 2198 2199 if ((Cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD) 2200 { 2201 if (ParentWindow != co_GetDesktopWindow(Window)) 2202 { 2203 Cs->x += ParentWindow->rcClient.left; 2204 Cs->y += ParentWindow->rcClient.top; 2205 } 2206 } 2207 2208 /* Send the WM_GETMINMAXINFO message */ 2209 Size.cx = Cs->cx; 2210 Size.cy = Cs->cy; 2211 2212 if ((Cs->style & WS_THICKFRAME) || !(Cs->style & (WS_POPUP | WS_CHILD))) 2213 { 2214 co_WinPosGetMinMaxInfo(Window, &MaxSize, &MaxPos, &MinTrack, &MaxTrack); 2215 if (Size.cx > MaxTrack.x) Size.cx = MaxTrack.x; 2216 if (Size.cy > MaxTrack.y) Size.cy = MaxTrack.y; 2217 if (Size.cx < MinTrack.x) Size.cx = MinTrack.x; 2218 if (Size.cy < MinTrack.y) Size.cy = MinTrack.y; 2219 } 2220 2221 Window->rcWindow.left = Cs->x; 2222 Window->rcWindow.top = Cs->y; 2223 Window->rcWindow.right = Cs->x + Size.cx; 2224 Window->rcWindow.bottom = Cs->y + Size.cy; 2225 /* 2226 if (0 != (Window->style & WS_CHILD) && ParentWindow) 2227 { 2228 ERR("co_UserCreateWindowEx(): Offset rcWindow\n"); 2229 RECTL_vOffsetRect(&Window->rcWindow, 2230 ParentWindow->rcClient.left, 2231 ParentWindow->rcClient.top); 2232 } 2233 */ 2234 /* correct child window coordinates if mirroring on parent is enabled */ 2235 if (ParentWindow != NULL) 2236 { 2237 if ( ((Cs->style & WS_CHILD) == WS_CHILD) && 2238 ((ParentWindow->ExStyle & WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL)) 2239 { 2240 Window->rcWindow.right = ParentWindow->rcClient.right - (Window->rcWindow.left - ParentWindow->rcClient.left); 2241 Window->rcWindow.left = Window->rcWindow.right - Size.cx; 2242 } 2243 } 2244 2245 Window->rcClient = Window->rcWindow; 2246 2247 /* Link the window */ 2248 if (NULL != ParentWindow) 2249 { 2250 /* Link the window into the siblings list */ 2251 if ((Cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD) 2252 IntLinkHwnd(Window, HWND_BOTTOM); 2253 else 2254 IntLinkHwnd(Window, hwndInsertAfter); 2255 } 2256 2257 if (!(Window->state2 & WNDS2_WIN31COMPAT)) 2258 { 2259 if (Class->style & CS_PARENTDC && !(ParentWindow->style & WS_CLIPCHILDREN)) 2260 Window->style &= ~(WS_CLIPSIBLINGS | WS_CLIPCHILDREN); 2261 } 2262 2263 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD) 2264 { 2265 if ( !IntIsTopLevelWindow(Window) ) 2266 { 2267 if (pti != Window->spwndParent->head.pti) 2268 { 2269 //ERR("CreateWindow Parent in.\n"); 2270 UserAttachThreadInput(pti, Window->spwndParent->head.pti, TRUE); 2271 } 2272 } 2273 } 2274 2275 /* Send the NCCREATE message */ 2276 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_NCCREATE, 0, (LPARAM) Cs); 2277 if (!Result) 2278 { 2279 ERR("co_UserCreateWindowEx(): NCCREATE message failed\n"); 2280 goto cleanup; 2281 } 2282 2283 /* Send the WM_NCCALCSIZE message */ 2284 { 2285 // RECT rc; 2286 MaxPos.x = Window->rcWindow.left; 2287 MaxPos.y = Window->rcWindow.top; 2288 2289 Result = co_WinPosGetNonClientSize(Window, &Window->rcWindow, &Window->rcClient); 2290 //rc = Window->rcWindow; 2291 //Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM)&rc); 2292 //Window->rcClient = rc; 2293 2294 RECTL_vOffsetRect(&Window->rcWindow, MaxPos.x - Window->rcWindow.left, 2295 MaxPos.y - Window->rcWindow.top); 2296 } 2297 2298 /* Send the WM_CREATE message. */ 2299 Result = co_IntSendMessage(UserHMGetHandle(Window), WM_CREATE, 0, (LPARAM) Cs); 2300 if (Result == (LRESULT)-1) 2301 { 2302 ERR("co_UserCreateWindowEx(): WM_CREATE message failed\n"); 2303 goto cleanup; 2304 } 2305 2306 /* Send the EVENT_OBJECT_CREATE event */ 2307 IntNotifyWinEvent(EVENT_OBJECT_CREATE, Window, OBJID_WINDOW, CHILDID_SELF, 0); 2308 2309 /* By setting the flag below it can be examined to determine if the window 2310 was created successfully and a valid pwnd was passed back to caller since 2311 from here the function has to succeed. */ 2312 Window->state2 |= WNDS2_WMCREATEMSGPROCESSED; 2313 2314 /* Send the WM_SIZE and WM_MOVE messages. */ 2315 if (!(Window->state & WNDS_SENDSIZEMOVEMSGS)) 2316 { 2317 co_WinPosSendSizeMove(Window); 2318 } 2319 2320 /* Show or maybe minimize or maximize the window. */ 2321 2322 style = IntSetStyle( Window, 0, WS_MAXIMIZE | WS_MINIMIZE ); 2323 if (style & (WS_MINIMIZE | WS_MAXIMIZE)) 2324 { 2325 RECTL NewPos; 2326 UINT SwFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE; 2327 2328 SwFlag = co_WinPosMinMaximize(Window, SwFlag, &NewPos); 2329 SwFlag |= SWP_NOZORDER|SWP_FRAMECHANGED; /* Frame always gets changed */ 2330 if (!(style & WS_VISIBLE) || (style & WS_CHILD) || UserGetActiveWindow()) SwFlag |= SWP_NOACTIVATE; 2331 co_WinPosSetWindowPos(Window, 0, NewPos.left, NewPos.top, 2332 NewPos.right, NewPos.bottom, SwFlag); 2333 } 2334 2335 /* Send the WM_PARENTNOTIFY message */ 2336 IntSendParentNotify(Window, WM_CREATE); 2337 2338 /* Notify the shell that a new window was created */ 2339 if (UserIsDesktopWindow(Window->spwndParent) && 2340 Window->spwndOwner == NULL && 2341 (Window->style & WS_VISIBLE) && 2342 (!(Window->ExStyle & WS_EX_TOOLWINDOW) || 2343 (Window->ExStyle & WS_EX_APPWINDOW))) 2344 { 2345 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)hWnd, 0); 2346 } 2347 2348 /* Initialize and show the window's scrollbars */ 2349 if (Window->style & WS_VSCROLL) 2350 { 2351 co_UserShowScrollBar(Window, SB_VERT, FALSE, TRUE); 2352 } 2353 if (Window->style & WS_HSCROLL) 2354 { 2355 co_UserShowScrollBar(Window, SB_HORZ, TRUE, FALSE); 2356 } 2357 2358 /* Show the new window */ 2359 if (Cs->style & WS_VISIBLE) 2360 { 2361 if (Window->style & WS_MAXIMIZE) 2362 dwShowMode = SW_SHOW; 2363 else if (Window->style & WS_MINIMIZE) 2364 dwShowMode = SW_SHOWMINIMIZED; 2365 2366 co_WinPosShowWindow(Window, dwShowMode); 2367 2368 if (Window->ExStyle & WS_EX_MDICHILD) 2369 { 2370 ASSERT(ParentWindow); 2371 if(!ParentWindow) 2372 goto cleanup; 2373 co_IntSendMessage(UserHMGetHandle(ParentWindow), WM_MDIREFRESHMENU, 0, 0); 2374 /* ShowWindow won't activate child windows */ 2375 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE); 2376 } 2377 } 2378 2379 if (Class->atomClassName == gaGuiConsoleWndClass) 2380 { 2381 /* Count only console windows manually */ 2382 co_IntUserManualGuiCheck(TRUE); 2383 } 2384 2385 TRACE("co_UserCreateWindowEx(): Created window %p\n", hWnd); 2386 ret = Window; 2387 2388 cleanup: 2389 if (!ret) 2390 { 2391 TRACE("co_UserCreateWindowEx(): Error Created window!\n"); 2392 /* If the window was created, the class will be dereferenced by co_UserDestroyWindow */ 2393 if (Window) 2394 co_UserDestroyWindow(Window); 2395 else if (Class) 2396 IntDereferenceClass(Class, pti->pDeskInfo, pti->ppi); 2397 } 2398 2399 if (pCsw) ExFreePoolWithTag(pCsw, TAG_HOOK); 2400 if (pCbtCreate) ExFreePoolWithTag(pCbtCreate, TAG_HOOK); 2401 if (pszName) UserHeapFree(pszName); 2402 if (pszClass) UserHeapFree(pszClass); 2403 2404 if (Window) 2405 { 2406 UserDerefObjectCo(Window); 2407 } 2408 if (ParentWindow) UserDerefObjectCo(ParentWindow); 2409 2410 // See CORE-13717, not setting error on success. 2411 if (ret) 2412 EngSetLastError(ERROR_SUCCESS); 2413 2414 return ret; 2415 } 2416 2417 NTSTATUS 2418 NTAPI 2419 ProbeAndCaptureLargeString( 2420 OUT PLARGE_STRING plstrSafe, 2421 IN PLARGE_STRING plstrUnsafe) 2422 { 2423 LARGE_STRING lstrTemp; 2424 PVOID pvBuffer = NULL; 2425 2426 _SEH2_TRY 2427 { 2428 /* Probe and copy the string */ 2429 ProbeForRead(plstrUnsafe, sizeof(LARGE_STRING), sizeof(ULONG)); 2430 lstrTemp = *plstrUnsafe; 2431 } 2432 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2433 { 2434 /* Fail */ 2435 _SEH2_YIELD(return _SEH2_GetExceptionCode();) 2436 } 2437 _SEH2_END 2438 2439 if (lstrTemp.Length != 0) 2440 { 2441 /* Allocate a buffer from paged pool */ 2442 pvBuffer = ExAllocatePoolWithTag(PagedPool, lstrTemp.Length, TAG_STRING); 2443 if (!pvBuffer) 2444 { 2445 return STATUS_NO_MEMORY; 2446 } 2447 2448 _SEH2_TRY 2449 { 2450 /* Probe and copy the buffer */ 2451 ProbeForRead(lstrTemp.Buffer, lstrTemp.Length, sizeof(WCHAR)); 2452 RtlCopyMemory(pvBuffer, lstrTemp.Buffer, lstrTemp.Length); 2453 } 2454 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2455 { 2456 /* Cleanup and fail */ 2457 ExFreePoolWithTag(pvBuffer, TAG_STRING); 2458 _SEH2_YIELD(return _SEH2_GetExceptionCode();) 2459 } 2460 _SEH2_END 2461 } 2462 2463 /* Set the output string */ 2464 plstrSafe->Buffer = pvBuffer; 2465 plstrSafe->Length = lstrTemp.Length; 2466 plstrSafe->MaximumLength = lstrTemp.Length; 2467 2468 return STATUS_SUCCESS; 2469 } 2470 2471 /** 2472 * \todo Allow passing plstrClassName as ANSI. 2473 */ 2474 HWND 2475 NTAPI 2476 NtUserCreateWindowEx( 2477 DWORD dwExStyle, 2478 PLARGE_STRING plstrClassName, 2479 PLARGE_STRING plstrClsVersion, 2480 PLARGE_STRING plstrWindowName, 2481 DWORD dwStyle, 2482 int x, 2483 int y, 2484 int nWidth, 2485 int nHeight, 2486 HWND hWndParent, 2487 HMENU hMenu, 2488 HINSTANCE hInstance, 2489 LPVOID lpParam, 2490 DWORD dwFlags, 2491 PVOID acbiBuffer) 2492 { 2493 NTSTATUS Status; 2494 LARGE_STRING lstrWindowName; 2495 LARGE_STRING lstrClassName; 2496 LARGE_STRING lstrClsVersion; 2497 UNICODE_STRING ustrClassName; 2498 UNICODE_STRING ustrClsVersion; 2499 CREATESTRUCTW Cs; 2500 HWND hwnd = NULL; 2501 PWND pwnd; 2502 2503 lstrWindowName.Buffer = NULL; 2504 lstrClassName.Buffer = NULL; 2505 lstrClsVersion.Buffer = NULL; 2506 2507 ASSERT(plstrWindowName); 2508 2509 if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD) 2510 { 2511 /* check hMenu is valid handle */ 2512 if (hMenu && !UserGetMenuObject(hMenu)) 2513 { 2514 ERR("NtUserCreateWindowEx: Got an invalid menu handle!\n"); 2515 EngSetLastError(ERROR_INVALID_MENU_HANDLE); 2516 return NULL; 2517 } 2518 } 2519 2520 /* Copy the window name to kernel mode */ 2521 Status = ProbeAndCaptureLargeString(&lstrWindowName, plstrWindowName); 2522 if (!NT_SUCCESS(Status)) 2523 { 2524 ERR("NtUserCreateWindowEx: failed to capture plstrWindowName\n"); 2525 SetLastNtError(Status); 2526 return NULL; 2527 } 2528 2529 plstrWindowName = &lstrWindowName; 2530 2531 /* Check if the class is an atom */ 2532 if (IS_ATOM(plstrClassName)) 2533 { 2534 /* It is, pass the atom in the UNICODE_STRING */ 2535 ustrClassName.Buffer = (PVOID)plstrClassName; 2536 ustrClassName.Length = 0; 2537 ustrClassName.MaximumLength = 0; 2538 } 2539 else 2540 { 2541 /* It's not, capture the class name */ 2542 Status = ProbeAndCaptureLargeString(&lstrClassName, plstrClassName); 2543 if (!NT_SUCCESS(Status)) 2544 { 2545 ERR("NtUserCreateWindowEx: failed to capture plstrClassName\n"); 2546 /* Set last error, cleanup and return */ 2547 SetLastNtError(Status); 2548 goto cleanup; 2549 } 2550 2551 /* We pass it on as a UNICODE_STRING */ 2552 ustrClassName.Buffer = lstrClassName.Buffer; 2553 ustrClassName.Length = (USHORT)min(lstrClassName.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated 2554 ustrClassName.MaximumLength = (USHORT)min(lstrClassName.MaximumLength, MAXUSHORT); 2555 } 2556 2557 /* Check if the class version is an atom */ 2558 if (IS_ATOM(plstrClsVersion)) 2559 { 2560 /* It is, pass the atom in the UNICODE_STRING */ 2561 ustrClsVersion.Buffer = (PVOID)plstrClsVersion; 2562 ustrClsVersion.Length = 0; 2563 ustrClsVersion.MaximumLength = 0; 2564 } 2565 else 2566 { 2567 /* It's not, capture the class name */ 2568 Status = ProbeAndCaptureLargeString(&lstrClsVersion, plstrClsVersion); 2569 if (!NT_SUCCESS(Status)) 2570 { 2571 ERR("NtUserCreateWindowEx: failed to capture plstrClsVersion\n"); 2572 /* Set last error, cleanup and return */ 2573 SetLastNtError(Status); 2574 goto cleanup; 2575 } 2576 2577 /* We pass it on as a UNICODE_STRING */ 2578 ustrClsVersion.Buffer = lstrClsVersion.Buffer; 2579 ustrClsVersion.Length = (USHORT)min(lstrClsVersion.Length, MAXUSHORT); // FIXME: LARGE_STRING truncated 2580 ustrClsVersion.MaximumLength = (USHORT)min(lstrClsVersion.MaximumLength, MAXUSHORT); 2581 } 2582 2583 /* Fill the CREATESTRUCTW */ 2584 /* we will keep here the original parameters */ 2585 Cs.style = dwStyle; 2586 Cs.lpCreateParams = lpParam; 2587 Cs.hInstance = hInstance; 2588 Cs.hMenu = hMenu; 2589 Cs.hwndParent = hWndParent; 2590 Cs.cx = nWidth; 2591 Cs.cy = nHeight; 2592 Cs.x = x; 2593 Cs.y = y; 2594 Cs.lpszName = (LPCWSTR) plstrWindowName->Buffer; 2595 Cs.lpszClass = ustrClassName.Buffer; 2596 Cs.dwExStyle = dwExStyle; 2597 2598 UserEnterExclusive(); 2599 2600 /* Call the internal function */ 2601 pwnd = co_UserCreateWindowEx(&Cs, &ustrClsVersion, plstrWindowName, acbiBuffer); 2602 2603 if(!pwnd) 2604 { 2605 ERR("co_UserCreateWindowEx failed!\n"); 2606 } 2607 hwnd = pwnd ? UserHMGetHandle(pwnd) : NULL; 2608 2609 UserLeave(); 2610 2611 cleanup: 2612 if (lstrWindowName.Buffer) 2613 { 2614 ExFreePoolWithTag(lstrWindowName.Buffer, TAG_STRING); 2615 } 2616 if (lstrClassName.Buffer) 2617 { 2618 ExFreePoolWithTag(lstrClassName.Buffer, TAG_STRING); 2619 } 2620 if (lstrClsVersion.Buffer) 2621 { 2622 ExFreePoolWithTag(lstrClsVersion.Buffer, TAG_STRING); 2623 } 2624 2625 return hwnd; 2626 } 2627 2628 2629 BOOLEAN co_UserDestroyWindow(PVOID Object) 2630 { 2631 HWND hWnd; 2632 PWND pwndTemp; 2633 PTHREADINFO ti; 2634 MSG msg; 2635 PWND Window = Object; 2636 2637 ASSERT_REFS_CO(Window); // FIXME: Temp HACK? 2638 2639 hWnd = Window->head.h; 2640 ti = PsGetCurrentThreadWin32Thread(); 2641 2642 TRACE("co_UserDestroyWindow(Window = 0x%p, hWnd = 0x%p)\n", Window, hWnd); 2643 2644 /* Check for owner thread */ 2645 if ( Window->head.pti != PsGetCurrentThreadWin32Thread()) 2646 { 2647 /* Check if we are destroying the desktop window */ 2648 if (! ((Window->head.rpdesk->dwDTFlags & DF_DESTROYED) && Window == Window->head.rpdesk->pDeskInfo->spwnd)) 2649 { 2650 EngSetLastError(ERROR_ACCESS_DENIED); 2651 return FALSE; 2652 } 2653 } 2654 2655 /* If window was created successfully and it is hooked */ 2656 if ((Window->state2 & WNDS2_WMCREATEMSGPROCESSED)) 2657 { 2658 if (co_HOOK_CallHooks(WH_CBT, HCBT_DESTROYWND, (WPARAM) hWnd, 0)) 2659 { 2660 ERR("Destroy Window WH_CBT Call Hook return!\n"); 2661 return FALSE; 2662 } 2663 } 2664 2665 if (Window->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME]) 2666 { 2667 if ((Window->style & (WS_POPUP|WS_CHILD)) != WS_CHILD) 2668 { 2669 if (Window->spwndOwner) 2670 { 2671 //ERR("DestroyWindow Owner out.\n"); 2672 UserAttachThreadInput(Window->head.pti, Window->spwndOwner->head.pti, FALSE); 2673 } 2674 } 2675 } 2676 2677 /* Inform the parent */ 2678 if (Window->style & WS_CHILD) 2679 { 2680 IntSendParentNotify(Window, WM_DESTROY); 2681 } 2682 2683 if (!Window->spwndOwner && !IntGetParent(Window)) 2684 { 2685 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM) hWnd, 0); 2686 } 2687 2688 /* Hide the window */ 2689 if (Window->style & WS_VISIBLE) 2690 { 2691 if (Window->style & WS_CHILD) 2692 { 2693 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */ 2694 co_WinPosShowWindow(Window, SW_HIDE); 2695 } 2696 else 2697 { 2698 co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_HIDEWINDOW ); 2699 } 2700 } 2701 2702 /* Adjust last active */ 2703 if ((pwndTemp = Window->spwndOwner)) 2704 { 2705 while (pwndTemp->spwndOwner) 2706 pwndTemp = pwndTemp->spwndOwner; 2707 2708 if (pwndTemp->spwndLastActive == Window) 2709 pwndTemp->spwndLastActive = Window->spwndOwner; 2710 } 2711 2712 if (Window->spwndParent && IntIsWindow(UserHMGetHandle(Window))) 2713 { 2714 if ((Window->style & (WS_POPUP | WS_CHILD)) == WS_CHILD) 2715 { 2716 if (!IntIsTopLevelWindow(Window)) 2717 { 2718 //ERR("DestroyWindow Parent out.\n"); 2719 UserAttachThreadInput(Window->head.pti, Window->spwndParent->head.pti, FALSE); 2720 } 2721 } 2722 } 2723 2724 if (Window->head.pti->MessageQueue->spwndActive == Window) 2725 Window->head.pti->MessageQueue->spwndActive = NULL; 2726 if (Window->head.pti->MessageQueue->spwndFocus == Window) 2727 Window->head.pti->MessageQueue->spwndFocus = NULL; 2728 if (Window->head.pti->MessageQueue->spwndActivePrev == Window) 2729 Window->head.pti->MessageQueue->spwndActivePrev = NULL; 2730 if (Window->head.pti->MessageQueue->spwndCapture == Window) 2731 Window->head.pti->MessageQueue->spwndCapture = NULL; 2732 2733 /* 2734 * Check if this window is the Shell's Desktop Window. If so set hShellWindow to NULL 2735 */ 2736 2737 if ((ti != NULL) && (ti->pDeskInfo != NULL)) 2738 { 2739 if (ti->pDeskInfo->hShellWindow == hWnd) 2740 { 2741 ERR("Destroying the ShellWindow!\n"); 2742 ti->pDeskInfo->hShellWindow = NULL; 2743 } 2744 } 2745 2746 IntEngWindowChanged(Window, WOC_DELETE); 2747 2748 if (!IntIsWindow(UserHMGetHandle(Window))) 2749 { 2750 return TRUE; 2751 } 2752 2753 /* Recursively destroy owned windows */ 2754 if (!(Window->style & WS_CHILD)) 2755 { 2756 HWND* List; 2757 HWND* phWnd; 2758 PWND pWnd; 2759 2760 List = IntWinListOwnedPopups(Window); 2761 if (List) 2762 { 2763 for (phWnd = List; *phWnd; ++phWnd) 2764 { 2765 pWnd = ValidateHwndNoErr(*phWnd); 2766 if (pWnd == NULL) 2767 continue; 2768 ASSERT(pWnd->spwndOwner == Window); 2769 ASSERT(pWnd != Window); 2770 2771 pWnd->spwndOwner = NULL; 2772 if (IntWndBelongsToThread(pWnd, PsGetCurrentThreadWin32Thread())) 2773 { 2774 USER_REFERENCE_ENTRY Ref; 2775 UserRefObjectCo(pWnd, &Ref); // Temp HACK? 2776 co_UserDestroyWindow(pWnd); 2777 UserDerefObjectCo(pWnd); // Temp HACK? 2778 } 2779 else 2780 { 2781 ERR("IntWndBelongsToThread(0x%p) is FALSE, ignoring.\n", pWnd); 2782 } 2783 } 2784 2785 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 2786 } 2787 } 2788 2789 /* Generate mouse move message for the next window */ 2790 msg.message = WM_MOUSEMOVE; 2791 msg.wParam = UserGetMouseButtonsState(); 2792 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y); 2793 msg.pt = gpsi->ptCursor; 2794 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE); 2795 2796 IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Window, OBJID_WINDOW, CHILDID_SELF, 0); 2797 2798 /* Send destroy messages */ 2799 IntSendDestroyMsg(UserHMGetHandle(Window)); 2800 2801 if (!IntIsWindow(UserHMGetHandle(Window))) 2802 { 2803 return TRUE; 2804 } 2805 2806 /* Destroy the window storage */ 2807 co_UserFreeWindow(Window, PsGetCurrentProcessWin32Process(), PsGetCurrentThreadWin32Thread(), TRUE); 2808 2809 return TRUE; 2810 } 2811 2812 2813 /* 2814 * @implemented 2815 */ 2816 BOOLEAN APIENTRY 2817 NtUserDestroyWindow(HWND Wnd) 2818 { 2819 PWND Window; 2820 DECLARE_RETURN(BOOLEAN); 2821 BOOLEAN ret; 2822 USER_REFERENCE_ENTRY Ref; 2823 2824 TRACE("Enter NtUserDestroyWindow\n"); 2825 UserEnterExclusive(); 2826 2827 if (!(Window = UserGetWindowObject(Wnd))) 2828 { 2829 RETURN(FALSE); 2830 } 2831 2832 UserRefObjectCo(Window, &Ref); // FIXME: Dunno if win should be reffed during destroy... 2833 ret = co_UserDestroyWindow(Window); 2834 UserDerefObjectCo(Window); // FIXME: Dunno if win should be reffed during destroy... 2835 2836 RETURN(ret); 2837 2838 CLEANUP: 2839 TRACE("Leave NtUserDestroyWindow, ret=%u\n", _ret_); 2840 UserLeave(); 2841 END_CLEANUP; 2842 } 2843 2844 2845 static HWND FASTCALL 2846 IntFindWindow(PWND Parent, 2847 PWND ChildAfter, 2848 RTL_ATOM ClassAtom, 2849 PUNICODE_STRING WindowName) 2850 { 2851 BOOL CheckWindowName; 2852 HWND *List, *phWnd; 2853 HWND Ret = NULL; 2854 UNICODE_STRING CurrentWindowName; 2855 2856 ASSERT(Parent); 2857 2858 CheckWindowName = WindowName->Buffer != 0; 2859 2860 if((List = IntWinListChildren(Parent))) 2861 { 2862 phWnd = List; 2863 if(ChildAfter) 2864 { 2865 /* skip handles before and including ChildAfter */ 2866 while(*phWnd && (*(phWnd++) != ChildAfter->head.h)) 2867 ; 2868 } 2869 2870 /* search children */ 2871 while(*phWnd) 2872 { 2873 PWND Child; 2874 if(!(Child = UserGetWindowObject(*(phWnd++)))) 2875 { 2876 continue; 2877 } 2878 2879 /* Do not send WM_GETTEXT messages in the kernel mode version! 2880 The user mode version however calls GetWindowText() which will 2881 send WM_GETTEXT messages to windows belonging to its processes */ 2882 if (!ClassAtom || Child->pcls->atomNVClassName == ClassAtom) 2883 { 2884 // FIXME: LARGE_STRING truncated 2885 CurrentWindowName.Buffer = Child->strName.Buffer; 2886 CurrentWindowName.Length = (USHORT)min(Child->strName.Length, MAXUSHORT); 2887 CurrentWindowName.MaximumLength = (USHORT)min(Child->strName.MaximumLength, MAXUSHORT); 2888 if(!CheckWindowName || 2889 (Child->strName.Length < 0xFFFF && 2890 !RtlCompareUnicodeString(WindowName, &CurrentWindowName, TRUE))) 2891 { 2892 Ret = Child->head.h; 2893 break; 2894 } 2895 } 2896 } 2897 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 2898 } 2899 2900 return Ret; 2901 } 2902 2903 /* 2904 * FUNCTION: 2905 * Searches a window's children for a window with the specified 2906 * class and name 2907 * ARGUMENTS: 2908 * hwndParent = The window whose childs are to be searched. 2909 * NULL = desktop 2910 * HWND_MESSAGE = message-only windows 2911 * 2912 * hwndChildAfter = Search starts after this child window. 2913 * NULL = start from beginning 2914 * 2915 * ucClassName = Class name to search for 2916 * Reguired parameter. 2917 * 2918 * ucWindowName = Window name 2919 * ->Buffer == NULL = don't care 2920 * 2921 * RETURNS: 2922 * The HWND of the window if it was found, otherwise NULL 2923 */ 2924 /* 2925 * @implemented 2926 */ 2927 HWND APIENTRY 2928 NtUserFindWindowEx(HWND hwndParent, 2929 HWND hwndChildAfter, 2930 PUNICODE_STRING ucClassName, 2931 PUNICODE_STRING ucWindowName, 2932 DWORD dwUnknown) 2933 { 2934 PWND Parent, ChildAfter; 2935 UNICODE_STRING ClassName = {0}, WindowName = {0}; 2936 HWND Desktop, Ret = NULL; 2937 BOOL DoMessageWnd = FALSE; 2938 RTL_ATOM ClassAtom = (RTL_ATOM)0; 2939 DECLARE_RETURN(HWND); 2940 2941 TRACE("Enter NtUserFindWindowEx\n"); 2942 UserEnterShared(); 2943 2944 if (ucClassName != NULL || ucWindowName != NULL) 2945 { 2946 _SEH2_TRY 2947 { 2948 if (ucClassName != NULL) 2949 { 2950 ClassName = ProbeForReadUnicodeString(ucClassName); 2951 if (ClassName.Length != 0) 2952 { 2953 ProbeForRead(ClassName.Buffer, 2954 ClassName.Length, 2955 sizeof(WCHAR)); 2956 } 2957 else if (!IS_ATOM(ClassName.Buffer)) 2958 { 2959 EngSetLastError(ERROR_INVALID_PARAMETER); 2960 _SEH2_LEAVE; 2961 } 2962 2963 if (!IntGetAtomFromStringOrAtom(&ClassName, 2964 &ClassAtom)) 2965 { 2966 EngSetLastError(ERROR_CANNOT_FIND_WND_CLASS); 2967 _SEH2_LEAVE; 2968 } 2969 } 2970 2971 if (ucWindowName != NULL) 2972 { 2973 WindowName = ProbeForReadUnicodeString(ucWindowName); 2974 if (WindowName.Length != 0) 2975 { 2976 ProbeForRead(WindowName.Buffer, 2977 WindowName.Length, 2978 sizeof(WCHAR)); 2979 } 2980 } 2981 } 2982 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2983 { 2984 SetLastNtError(_SEH2_GetExceptionCode()); 2985 _SEH2_YIELD(RETURN(NULL)); 2986 } 2987 _SEH2_END; 2988 2989 if (ucClassName != NULL) 2990 { 2991 if (ClassName.Length == 0 && ClassName.Buffer != NULL && 2992 !IS_ATOM(ClassName.Buffer)) 2993 { 2994 EngSetLastError(ERROR_INVALID_PARAMETER); 2995 RETURN(NULL); 2996 } 2997 else if (ClassAtom == (RTL_ATOM)0) 2998 { 2999 /* LastError code was set by IntGetAtomFromStringOrAtom */ 3000 RETURN(NULL); 3001 } 3002 } 3003 } 3004 3005 Desktop = IntGetCurrentThreadDesktopWindow(); 3006 3007 if(hwndParent == NULL) 3008 { 3009 hwndParent = Desktop; 3010 DoMessageWnd = TRUE; 3011 } 3012 else if(hwndParent == HWND_MESSAGE) 3013 { 3014 hwndParent = IntGetMessageWindow(); 3015 } 3016 3017 if(!(Parent = UserGetWindowObject(hwndParent))) 3018 { 3019 RETURN( NULL); 3020 } 3021 3022 ChildAfter = NULL; 3023 if(hwndChildAfter && !(ChildAfter = UserGetWindowObject(hwndChildAfter))) 3024 { 3025 RETURN( NULL); 3026 } 3027 3028 _SEH2_TRY 3029 { 3030 if(Parent->head.h == Desktop) 3031 { 3032 HWND *List, *phWnd; 3033 PWND TopLevelWindow; 3034 BOOLEAN CheckWindowName; 3035 BOOLEAN WindowMatches; 3036 BOOLEAN ClassMatches; 3037 3038 /* windows searches through all top-level windows if the parent is the desktop 3039 window */ 3040 3041 if((List = IntWinListChildren(Parent))) 3042 { 3043 phWnd = List; 3044 3045 if(ChildAfter) 3046 { 3047 /* skip handles before and including ChildAfter */ 3048 while(*phWnd && (*(phWnd++) != ChildAfter->head.h)) 3049 ; 3050 } 3051 3052 CheckWindowName = WindowName.Buffer != 0; 3053 3054 /* search children */ 3055 while(*phWnd) 3056 { 3057 UNICODE_STRING ustr; 3058 3059 if(!(TopLevelWindow = UserGetWindowObject(*(phWnd++)))) 3060 { 3061 continue; 3062 } 3063 3064 /* Do not send WM_GETTEXT messages in the kernel mode version! 3065 The user mode version however calls GetWindowText() which will 3066 send WM_GETTEXT messages to windows belonging to its processes */ 3067 ustr.Buffer = TopLevelWindow->strName.Buffer; 3068 ustr.Length = (USHORT)min(TopLevelWindow->strName.Length, MAXUSHORT); // FIXME:LARGE_STRING truncated 3069 ustr.MaximumLength = (USHORT)min(TopLevelWindow->strName.MaximumLength, MAXUSHORT); 3070 WindowMatches = !CheckWindowName || 3071 (TopLevelWindow->strName.Length < 0xFFFF && 3072 !RtlCompareUnicodeString(&WindowName, &ustr, TRUE)); 3073 ClassMatches = (ClassAtom == (RTL_ATOM)0) || 3074 ClassAtom == TopLevelWindow->pcls->atomNVClassName; 3075 3076 if (WindowMatches && ClassMatches) 3077 { 3078 Ret = TopLevelWindow->head.h; 3079 break; 3080 } 3081 3082 if (IntFindWindow(TopLevelWindow, NULL, ClassAtom, &WindowName)) 3083 { 3084 /* window returns the handle of the top-level window, in case it found 3085 the child window */ 3086 Ret = TopLevelWindow->head.h; 3087 break; 3088 } 3089 3090 } 3091 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 3092 } 3093 } 3094 else 3095 { 3096 TRACE("FindWindowEx: Not Desktop Parent!\n"); 3097 Ret = IntFindWindow(Parent, ChildAfter, ClassAtom, &WindowName); 3098 } 3099 3100 if (Ret == NULL && DoMessageWnd) 3101 { 3102 PWND MsgWindows; 3103 3104 if((MsgWindows = UserGetWindowObject(IntGetMessageWindow()))) 3105 { 3106 Ret = IntFindWindow(MsgWindows, ChildAfter, ClassAtom, &WindowName); 3107 } 3108 } 3109 } 3110 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3111 { 3112 SetLastNtError(_SEH2_GetExceptionCode()); 3113 Ret = NULL; 3114 } 3115 _SEH2_END; 3116 3117 RETURN( Ret); 3118 3119 CLEANUP: 3120 TRACE("Leave NtUserFindWindowEx, ret %p\n", _ret_); 3121 UserLeave(); 3122 END_CLEANUP; 3123 } 3124 3125 3126 /* 3127 * @implemented 3128 */ 3129 PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type) 3130 { 3131 PWND WndAncestor, Parent; 3132 3133 if (Wnd->head.h == IntGetDesktopWindow()) 3134 { 3135 return NULL; 3136 } 3137 3138 switch (Type) 3139 { 3140 case GA_PARENT: 3141 { 3142 WndAncestor = Wnd->spwndParent; 3143 break; 3144 } 3145 3146 case GA_ROOT: 3147 { 3148 WndAncestor = Wnd; 3149 Parent = NULL; 3150 3151 for(;;) 3152 { 3153 if(!(Parent = WndAncestor->spwndParent)) 3154 { 3155 break; 3156 } 3157 if(IntIsDesktopWindow(Parent)) 3158 { 3159 break; 3160 } 3161 3162 WndAncestor = Parent; 3163 } 3164 break; 3165 } 3166 3167 case GA_ROOTOWNER: 3168 { 3169 WndAncestor = Wnd; 3170 3171 for (;;) 3172 { 3173 Parent = IntGetParent(WndAncestor); 3174 3175 if (!Parent) 3176 { 3177 break; 3178 } 3179 3180 WndAncestor = Parent; 3181 } 3182 break; 3183 } 3184 3185 default: 3186 { 3187 return NULL; 3188 } 3189 } 3190 3191 return WndAncestor; 3192 } 3193 3194 /* 3195 * @implemented 3196 */ 3197 HWND APIENTRY 3198 NtUserGetAncestor(HWND hWnd, UINT Type) 3199 { 3200 PWND Window, Ancestor; 3201 DECLARE_RETURN(HWND); 3202 3203 TRACE("Enter NtUserGetAncestor\n"); 3204 UserEnterExclusive(); 3205 3206 if (!(Window = UserGetWindowObject(hWnd))) 3207 { 3208 RETURN(NULL); 3209 } 3210 3211 Ancestor = UserGetAncestor(Window, Type); 3212 /* faxme: can UserGetAncestor ever return NULL for a valid window? */ 3213 3214 RETURN(Ancestor ? Ancestor->head.h : NULL); 3215 3216 CLEANUP: 3217 TRACE("Leave NtUserGetAncestor, ret=%p\n", _ret_); 3218 UserLeave(); 3219 END_CLEANUP; 3220 } 3221 3222 //// 3223 //// ReactOS work around! Keep it the sames as in Combo.c and Controls.h 3224 //// 3225 /* combo state struct */ 3226 typedef struct 3227 { 3228 HWND self; 3229 HWND owner; 3230 UINT dwStyle; 3231 HWND hWndEdit; 3232 HWND hWndLBox; 3233 UINT wState; 3234 HFONT hFont; 3235 RECT textRect; 3236 RECT buttonRect; 3237 RECT droppedRect; 3238 INT droppedIndex; 3239 INT fixedOwnerDrawHeight; 3240 INT droppedWidth; /* last two are not used unless set */ 3241 INT editHeight; /* explicitly */ 3242 LONG UIState; 3243 } HEADCOMBO,*LPHEADCOMBO; 3244 3245 // Window Extra data container. 3246 typedef struct _WND2CBOX 3247 { 3248 WND; 3249 LPHEADCOMBO pCBox; 3250 } WND2CBOX, *PWND2CBOX; 3251 3252 #define CBF_BUTTONDOWN 0x0002 3253 //// 3254 //// 3255 //// 3256 BOOL 3257 APIENTRY 3258 NtUserGetComboBoxInfo( 3259 HWND hWnd, 3260 PCOMBOBOXINFO pcbi) 3261 { 3262 PWND Wnd; 3263 PPROCESSINFO ppi; 3264 BOOL NotSameppi = FALSE; 3265 BOOL Ret = TRUE; 3266 DECLARE_RETURN(BOOL); 3267 3268 TRACE("Enter NtUserGetComboBoxInfo\n"); 3269 UserEnterShared(); 3270 3271 if (!(Wnd = UserGetWindowObject(hWnd))) 3272 { 3273 RETURN( FALSE ); 3274 } 3275 _SEH2_TRY 3276 { 3277 ProbeForWrite(pcbi, sizeof(COMBOBOXINFO), 1); 3278 } 3279 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3280 { 3281 SetLastNtError(_SEH2_GetExceptionCode()); 3282 _SEH2_YIELD(RETURN(FALSE)); 3283 } 3284 _SEH2_END; 3285 3286 if (pcbi->cbSize < sizeof(COMBOBOXINFO)) 3287 { 3288 EngSetLastError(ERROR_INVALID_PARAMETER); 3289 RETURN(FALSE); 3290 } 3291 3292 // Pass the user pointer, it was already probed. 3293 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_COMBOBOX]) && Wnd->fnid != FNID_COMBOBOX) 3294 { 3295 RETURN( (BOOL) co_IntSendMessage( Wnd->head.h, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi)); 3296 } 3297 3298 ppi = PsGetCurrentProcessWin32Process(); 3299 NotSameppi = ppi != Wnd->head.pti->ppi; 3300 if (NotSameppi) 3301 { 3302 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb); 3303 } 3304 3305 _SEH2_TRY 3306 { 3307 LPHEADCOMBO lphc = ((PWND2CBOX)Wnd)->pCBox; 3308 pcbi->rcItem = lphc->textRect; 3309 pcbi->rcButton = lphc->buttonRect; 3310 pcbi->stateButton = 0; 3311 if (lphc->wState & CBF_BUTTONDOWN) 3312 pcbi->stateButton |= STATE_SYSTEM_PRESSED; 3313 if (RECTL_bIsEmptyRect(&lphc->buttonRect)) 3314 pcbi->stateButton |= STATE_SYSTEM_INVISIBLE; 3315 pcbi->hwndCombo = lphc->self; 3316 pcbi->hwndItem = lphc->hWndEdit; 3317 pcbi->hwndList = lphc->hWndLBox; 3318 } 3319 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3320 { 3321 Ret = FALSE; 3322 SetLastNtError(_SEH2_GetExceptionCode()); 3323 } 3324 _SEH2_END; 3325 3326 RETURN( Ret); 3327 3328 CLEANUP: 3329 if (NotSameppi) KeDetachProcess(); 3330 TRACE("Leave NtUserGetComboBoxInfo, ret=%i\n",_ret_); 3331 UserLeave(); 3332 END_CLEANUP; 3333 } 3334 3335 //// 3336 //// ReactOS work around! Keep it the sames as in Listbox.c 3337 //// 3338 /* Listbox structure */ 3339 typedef struct 3340 { 3341 HWND self; /* Our own window handle */ 3342 HWND owner; /* Owner window to send notifications to */ 3343 UINT style; /* Window style */ 3344 INT width; /* Window width */ 3345 INT height; /* Window height */ 3346 VOID *items; /* Array of items */ 3347 INT nb_items; /* Number of items */ 3348 INT top_item; /* Top visible item */ 3349 INT selected_item; /* Selected item */ 3350 INT focus_item; /* Item that has the focus */ 3351 INT anchor_item; /* Anchor item for extended selection */ 3352 INT item_height; /* Default item height */ 3353 INT page_size; /* Items per listbox page */ 3354 INT column_width; /* Column width for multi-column listboxes */ 3355 } LB_DESCR; 3356 3357 // Window Extra data container. 3358 typedef struct _WND2LB 3359 { 3360 WND; 3361 LB_DESCR * pLBiv; 3362 } WND2LB, *PWND2LB; 3363 //// 3364 //// 3365 //// 3366 DWORD 3367 APIENTRY 3368 NtUserGetListBoxInfo( 3369 HWND hWnd) 3370 { 3371 PWND Wnd; 3372 PPROCESSINFO ppi; 3373 BOOL NotSameppi = FALSE; 3374 DWORD Ret = 0; 3375 DECLARE_RETURN(DWORD); 3376 3377 TRACE("Enter NtUserGetListBoxInfo\n"); 3378 UserEnterShared(); 3379 3380 if (!(Wnd = UserGetWindowObject(hWnd))) 3381 { 3382 RETURN( 0 ); 3383 } 3384 3385 if ((Wnd->pcls->atomClassName != gpsi->atomSysClass[ICLS_LISTBOX]) && Wnd->fnid != FNID_LISTBOX) 3386 { 3387 RETURN( (DWORD) co_IntSendMessage( Wnd->head.h, LB_GETLISTBOXINFO, 0, 0 )); 3388 } 3389 3390 // wine lisbox:test_GetListBoxInfo lb_getlistboxinfo = 0, should not send a message! 3391 ppi = PsGetCurrentProcessWin32Process(); 3392 NotSameppi = ppi != Wnd->head.pti->ppi; 3393 if (NotSameppi) 3394 { 3395 KeAttachProcess(&Wnd->head.pti->ppi->peProcess->Pcb); 3396 } 3397 3398 _SEH2_TRY 3399 { 3400 LB_DESCR *descr = ((PWND2LB)Wnd)->pLBiv; 3401 // See Controls ListBox.c:LB_GETLISTBOXINFO must match... 3402 if (descr->style & LBS_MULTICOLUMN) //// ReactOS 3403 Ret = descr->page_size * descr->column_width; 3404 else 3405 Ret = descr->page_size; 3406 } 3407 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3408 { 3409 Ret = 0; 3410 SetLastNtError(_SEH2_GetExceptionCode()); 3411 } 3412 _SEH2_END; 3413 3414 RETURN( Ret); 3415 3416 CLEANUP: 3417 if (NotSameppi) KeDetachProcess(); 3418 TRACE("Leave NtUserGetListBoxInfo, ret=%lu\n", _ret_); 3419 UserLeave(); 3420 END_CLEANUP; 3421 } 3422 3423 /* 3424 * NtUserSetParent 3425 * 3426 * The NtUserSetParent function changes the parent window of the specified 3427 * child window. 3428 * 3429 * Remarks 3430 * The new parent window and the child window must belong to the same 3431 * application. If the window identified by the hWndChild parameter is 3432 * visible, the system performs the appropriate redrawing and repainting. 3433 * For compatibility reasons, NtUserSetParent does not modify the WS_CHILD 3434 * or WS_POPUP window styles of the window whose parent is being changed. 3435 * 3436 * Status 3437 * @implemented 3438 */ 3439 3440 HWND APIENTRY 3441 NtUserSetParent(HWND hWndChild, HWND hWndNewParent) 3442 { 3443 DECLARE_RETURN(HWND); 3444 3445 TRACE("Enter NtUserSetParent\n"); 3446 UserEnterExclusive(); 3447 3448 /* 3449 Check Parent first from user space, set it here. 3450 */ 3451 if (!hWndNewParent) 3452 { 3453 hWndNewParent = IntGetDesktopWindow(); 3454 } 3455 else if (hWndNewParent == HWND_MESSAGE) 3456 { 3457 hWndNewParent = IntGetMessageWindow(); 3458 } 3459 3460 RETURN( co_UserSetParent(hWndChild, hWndNewParent)); 3461 3462 CLEANUP: 3463 TRACE("Leave NtUserSetParent, ret=%p\n", _ret_); 3464 UserLeave(); 3465 END_CLEANUP; 3466 } 3467 3468 /* 3469 * UserGetShellWindow 3470 * 3471 * Returns a handle to shell window that was set by NtUserSetShellWindowEx. 3472 * 3473 * Status 3474 * @implemented 3475 */ 3476 HWND FASTCALL UserGetShellWindow(VOID) 3477 { 3478 PWINSTATION_OBJECT WinStaObject; 3479 HWND Ret; 3480 3481 NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation, 3482 UserMode, 3483 0, 3484 &WinStaObject, 3485 0); 3486 3487 if (!NT_SUCCESS(Status)) 3488 { 3489 SetLastNtError(Status); 3490 return( (HWND)0); 3491 } 3492 3493 Ret = (HWND)WinStaObject->ShellWindow; 3494 3495 ObDereferenceObject(WinStaObject); 3496 return( Ret); 3497 } 3498 3499 /* 3500 * NtUserSetShellWindowEx 3501 * 3502 * This is undocumented function to set global shell window. The global 3503 * shell window has special handling of window position. 3504 * 3505 * Status 3506 * @implemented 3507 */ 3508 BOOL APIENTRY 3509 NtUserSetShellWindowEx(HWND hwndShell, HWND hwndListView) 3510 { 3511 PWINSTATION_OBJECT WinStaObject; 3512 PWND WndShell, WndListView; 3513 DECLARE_RETURN(BOOL); 3514 USER_REFERENCE_ENTRY Ref; 3515 NTSTATUS Status; 3516 PTHREADINFO ti; 3517 3518 TRACE("Enter NtUserSetShellWindowEx\n"); 3519 UserEnterExclusive(); 3520 3521 if (!(WndShell = UserGetWindowObject(hwndShell))) 3522 { 3523 RETURN(FALSE); 3524 } 3525 3526 if (!(WndListView = UserGetWindowObject(hwndListView))) 3527 { 3528 RETURN(FALSE); 3529 } 3530 3531 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation, 3532 UserMode, 3533 0, 3534 &WinStaObject, 3535 0); 3536 3537 if (!NT_SUCCESS(Status)) 3538 { 3539 SetLastNtError(Status); 3540 RETURN( FALSE); 3541 } 3542 3543 /* 3544 * Test if we are permitted to change the shell window. 3545 */ 3546 if (WinStaObject->ShellWindow) 3547 { 3548 ObDereferenceObject(WinStaObject); 3549 RETURN( FALSE); 3550 } 3551 3552 /* 3553 * Move shell window into background. 3554 */ 3555 if (hwndListView && hwndListView != hwndShell) 3556 { 3557 /* 3558 * Disabled for now to get Explorer working. 3559 * -- Filip, 01/nov/2003 3560 */ 3561 #if 0 3562 co_WinPosSetWindowPos(WndListView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE); 3563 #endif 3564 3565 if (WndListView->ExStyle & WS_EX_TOPMOST) 3566 { 3567 ObDereferenceObject(WinStaObject); 3568 RETURN( FALSE); 3569 } 3570 } 3571 3572 if (WndShell->ExStyle & WS_EX_TOPMOST) 3573 { 3574 ObDereferenceObject(WinStaObject); 3575 RETURN( FALSE); 3576 } 3577 3578 UserRefObjectCo(WndShell, &Ref); 3579 WndShell->state2 |= WNDS2_BOTTOMMOST; 3580 co_WinPosSetWindowPos(WndShell, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE); 3581 3582 WinStaObject->ShellWindow = hwndShell; 3583 WinStaObject->ShellListView = hwndListView; 3584 3585 ti = GetW32ThreadInfo(); 3586 if (ti->pDeskInfo) 3587 { 3588 ti->pDeskInfo->hShellWindow = hwndShell; 3589 ti->pDeskInfo->spwndShell = WndShell; 3590 ti->pDeskInfo->spwndBkGnd = WndListView; 3591 ti->pDeskInfo->ppiShellProcess = ti->ppi; 3592 } 3593 3594 UserRegisterHotKey(WndShell, SC_TASKLIST, MOD_CONTROL, VK_ESCAPE); 3595 3596 UserDerefObjectCo(WndShell); 3597 3598 ObDereferenceObject(WinStaObject); 3599 RETURN( TRUE); 3600 3601 CLEANUP: 3602 TRACE("Leave NtUserSetShellWindowEx, ret=%i\n",_ret_); 3603 UserLeave(); 3604 END_CLEANUP; 3605 } 3606 3607 // Fixes wine Win test_window_styles and todo tests... 3608 static BOOL FASTCALL 3609 IntCheckFrameEdge(ULONG Style, ULONG ExStyle) 3610 { 3611 if (ExStyle & WS_EX_DLGMODALFRAME) 3612 return TRUE; 3613 else if (!(ExStyle & WS_EX_STATICEDGE) && (Style & (WS_DLGFRAME | WS_THICKFRAME))) 3614 return TRUE; 3615 else 3616 return FALSE; 3617 } 3618 3619 static LONG_PTR 3620 co_IntSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi, ULONG Size, BOOL bAlter) 3621 { 3622 PWND Window, Parent; 3623 PWINSTATION_OBJECT WindowStation; 3624 LONG_PTR OldValue; 3625 STYLESTRUCT Style; 3626 3627 if (!(Window = UserGetWindowObject(hWnd))) 3628 { 3629 return( 0); 3630 } 3631 3632 if ((INT)Index >= 0) 3633 { 3634 if ((Index + Size) > Window->cbwndExtra) 3635 { 3636 EngSetLastError(ERROR_INVALID_INDEX); 3637 return( 0); 3638 } 3639 3640 #ifdef _WIN64 3641 if (Size == sizeof(LONG)) 3642 { 3643 OldValue = *((LONG *)((PCHAR)(Window + 1) + Index)); 3644 *((LONG*)((PCHAR)(Window + 1) + Index)) = (LONG)NewValue; 3645 } 3646 else 3647 #endif 3648 { 3649 OldValue = *((LONG_PTR *)((PCHAR)(Window + 1) + Index)); 3650 /* 3651 if ( Index == DWLP_DLGPROC && Wnd->state & WNDS_DIALOGWINDOW) 3652 { 3653 OldValue = (LONG_PTR)IntSetWindowProc( Wnd, (WNDPROC)NewValue, Ansi); 3654 if (!OldValue) return 0; 3655 } 3656 */ 3657 *((LONG_PTR*)((PCHAR)(Window + 1) + Index)) = NewValue; 3658 } 3659 3660 } 3661 else 3662 { 3663 #ifdef _WIN64 3664 if (Size == sizeof(LONG)) 3665 { 3666 if ((Index != GWL_STYLE) && 3667 (Index != GWL_EXSTYLE) && 3668 (Index != GWL_ID) && 3669 (Index != GWL_USERDATA)) 3670 { 3671 ERR("NtUserSetWindowLong(): Index requires pointer size: %lu\n", Index); 3672 EngSetLastError(ERROR_INVALID_INDEX); 3673 return 0; 3674 } 3675 } 3676 #endif 3677 3678 switch (Index) 3679 { 3680 case GWL_EXSTYLE: // LONG 3681 OldValue = (LONG) Window->ExStyle; 3682 Style.styleOld = OldValue; 3683 Style.styleNew = NewValue; 3684 3685 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM) &Style); 3686 3687 /* 3688 * Remove extended window style bit WS_EX_TOPMOST for shell windows. 3689 */ 3690 WindowStation = Window->head.pti->rpdesk->rpwinstaParent; 3691 if(WindowStation) 3692 { 3693 if (hWnd == WindowStation->ShellWindow || hWnd == WindowStation->ShellListView) 3694 Style.styleNew &= ~WS_EX_TOPMOST; 3695 } 3696 /* WS_EX_WINDOWEDGE depends on some other styles */ 3697 if (IntCheckFrameEdge(Window->style, NewValue)) 3698 Style.styleNew |= WS_EX_WINDOWEDGE; 3699 else 3700 Style.styleNew &= ~WS_EX_WINDOWEDGE; 3701 3702 if (!(Window->ExStyle & WS_EX_LAYERED)) 3703 { 3704 SetLayeredStatus(Window, 0); 3705 } 3706 3707 Window->ExStyle = (DWORD)Style.styleNew; 3708 3709 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style); 3710 break; 3711 3712 case GWL_STYLE: // LONG 3713 OldValue = (LONG) Window->style; 3714 Style.styleOld = OldValue; 3715 Style.styleNew = NewValue; 3716 3717 if (!bAlter) 3718 co_IntSendMessage(hWnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM) &Style); 3719 3720 /* WS_CLIPSIBLINGS can't be reset on top-level windows */ 3721 if (UserIsDesktopWindow(Window->spwndParent)) Style.styleNew |= WS_CLIPSIBLINGS; 3722 /* WS_MINIMIZE can't be reset */ 3723 if (OldValue & WS_MINIMIZE) Style.styleNew |= WS_MINIMIZE; 3724 /* Fixes wine FIXME: changing WS_DLGFRAME | WS_THICKFRAME is supposed to change WS_EX_WINDOWEDGE too */ 3725 if (IntCheckFrameEdge(NewValue, Window->ExStyle)) 3726 Window->ExStyle |= WS_EX_WINDOWEDGE; 3727 else 3728 Window->ExStyle &= ~WS_EX_WINDOWEDGE; 3729 3730 if ((OldValue & (WS_CHILD | WS_POPUP)) == WS_CHILD) 3731 { 3732 if ((NewValue & (WS_CHILD | WS_POPUP)) != WS_CHILD) 3733 { 3734 //// From child to non-child it should be null already. 3735 ERR("IDMenu going null! %d\n",Window->IDMenu); 3736 Window->IDMenu = 0; // Window->spmenu = 0; 3737 } 3738 } 3739 else 3740 { 3741 if ((NewValue & (WS_CHILD | WS_POPUP)) == WS_CHILD) 3742 { 3743 PMENU pMenu = UserGetMenuObject(UlongToHandle(Window->IDMenu)); 3744 Window->state &= ~WNDS_HASMENU; 3745 if (pMenu) 3746 { 3747 ERR("IDMenu released 0x%p\n",pMenu); 3748 // ROS may not hold a lock after setting menu to window. But it should! 3749 //IntReleaseMenuObject(pMenu); 3750 } 3751 } 3752 } 3753 3754 if ((Style.styleOld ^ Style.styleNew) & WS_VISIBLE) 3755 { 3756 if (Style.styleOld & WS_VISIBLE) Window->head.pti->cVisWindows--; 3757 if (Style.styleNew & WS_VISIBLE) Window->head.pti->cVisWindows++; 3758 DceResetActiveDCEs( Window ); 3759 } 3760 Window->style = (DWORD)Style.styleNew; 3761 3762 if (!bAlter) 3763 co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_STYLE, (LPARAM) &Style); 3764 break; 3765 3766 case GWLP_WNDPROC: // LONG_PTR 3767 { 3768 if ( Window->head.pti->ppi != PsGetCurrentProcessWin32Process() || 3769 Window->fnid & FNID_FREED) 3770 { 3771 EngSetLastError(ERROR_ACCESS_DENIED); 3772 return( 0); 3773 } 3774 OldValue = (LONG_PTR)IntSetWindowProc(Window, 3775 (WNDPROC)NewValue, 3776 Ansi); 3777 break; 3778 } 3779 3780 case GWLP_HINSTANCE: // LONG_PTR 3781 OldValue = (LONG_PTR) Window->hModule; 3782 Window->hModule = (HINSTANCE) NewValue; 3783 break; 3784 3785 case GWLP_HWNDPARENT: // LONG_PTR 3786 Parent = Window->spwndParent; 3787 if (Parent && (Parent->head.h == IntGetDesktopWindow())) 3788 OldValue = (LONG_PTR) IntSetOwner(Window->head.h, (HWND) NewValue); 3789 else 3790 OldValue = (LONG_PTR) co_UserSetParent(Window->head.h, (HWND) NewValue); 3791 break; 3792 3793 case GWLP_ID: // LONG 3794 OldValue = (LONG) Window->IDMenu; 3795 Window->IDMenu = (UINT) NewValue; 3796 break; 3797 3798 case GWLP_USERDATA: // LONG or LONG_PTR 3799 OldValue = Window->dwUserData; 3800 Window->dwUserData = NewValue; 3801 break; 3802 3803 default: 3804 ERR("NtUserSetWindowLong(): Unsupported index %lu\n", Index); 3805 EngSetLastError(ERROR_INVALID_INDEX); 3806 OldValue = 0; 3807 break; 3808 } 3809 } 3810 3811 return( OldValue); 3812 } 3813 3814 LONG FASTCALL 3815 co_UserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi) 3816 { 3817 return (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE); 3818 } 3819 3820 LONG_PTR FASTCALL 3821 co_UserSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi) 3822 { 3823 return co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE); 3824 } 3825 3826 /* 3827 * NtUserSetWindowLong 3828 * 3829 * The NtUserSetWindowLong function changes an attribute of the specified 3830 * window. The function also sets the 32-bit (long) value at the specified 3831 * offset into the extra window memory. 3832 * 3833 * Status 3834 * @implemented 3835 */ 3836 3837 LONG APIENTRY 3838 NtUserSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi) 3839 { 3840 LONG ret; 3841 3842 UserEnterExclusive(); 3843 3844 if (hWnd == IntGetDesktopWindow()) 3845 { 3846 EngSetLastError(STATUS_ACCESS_DENIED); 3847 UserLeave(); 3848 return 0; 3849 } 3850 3851 ret = (LONG)co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG), FALSE); 3852 3853 UserLeave(); 3854 3855 return ret; 3856 } 3857 3858 #ifdef _WIN64 3859 LONG_PTR APIENTRY 3860 NtUserSetWindowLongPtr(HWND hWnd, DWORD Index, LONG_PTR NewValue, BOOL Ansi) 3861 { 3862 LONG_PTR ret; 3863 3864 UserEnterExclusive(); 3865 3866 if (hWnd == IntGetDesktopWindow()) 3867 { 3868 EngSetLastError(STATUS_ACCESS_DENIED); 3869 UserLeave(); 3870 return 0; 3871 } 3872 3873 ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, Ansi, sizeof(LONG_PTR), FALSE); 3874 3875 UserLeave(); 3876 3877 return ret; 3878 } 3879 #endif // _WIN64 3880 3881 DWORD APIENTRY 3882 NtUserAlterWindowStyle(HWND hWnd, DWORD Index, LONG NewValue) 3883 { 3884 LONG ret; 3885 3886 UserEnterExclusive(); 3887 3888 if (hWnd == IntGetDesktopWindow()) 3889 { 3890 EngSetLastError(STATUS_ACCESS_DENIED); 3891 UserLeave(); 3892 return 0; 3893 } 3894 3895 ret = co_IntSetWindowLongPtr(hWnd, Index, NewValue, FALSE, sizeof(LONG), TRUE); 3896 3897 UserLeave(); 3898 3899 return ret; 3900 } 3901 3902 3903 /* 3904 * NtUserSetWindowWord 3905 * 3906 * Legacy function similar to NtUserSetWindowLong. 3907 * 3908 * Status 3909 * @implemented 3910 */ 3911 3912 WORD APIENTRY 3913 NtUserSetWindowWord(HWND hWnd, INT Index, WORD NewValue) 3914 { 3915 PWND Window; 3916 WORD OldValue; 3917 DECLARE_RETURN(WORD); 3918 3919 TRACE("Enter NtUserSetWindowWord\n"); 3920 UserEnterExclusive(); 3921 3922 if (hWnd == IntGetDesktopWindow()) 3923 { 3924 EngSetLastError(STATUS_ACCESS_DENIED); 3925 RETURN( 0); 3926 } 3927 3928 if (!(Window = UserGetWindowObject(hWnd))) 3929 { 3930 RETURN( 0); 3931 } 3932 3933 switch (Index) 3934 { 3935 case GWL_ID: 3936 case GWL_HINSTANCE: 3937 case GWL_HWNDPARENT: 3938 RETURN( (WORD)co_UserSetWindowLong(UserHMGetHandle(Window), Index, (UINT)NewValue, TRUE)); 3939 default: 3940 if (Index < 0) 3941 { 3942 EngSetLastError(ERROR_INVALID_INDEX); 3943 RETURN( 0); 3944 } 3945 } 3946 3947 if ((ULONG)Index > (Window->cbwndExtra - sizeof(WORD))) 3948 { 3949 EngSetLastError(ERROR_INVALID_PARAMETER); 3950 RETURN( 0); 3951 } 3952 3953 OldValue = *((WORD *)((PCHAR)(Window + 1) + Index)); 3954 *((WORD *)((PCHAR)(Window + 1) + Index)) = NewValue; 3955 3956 RETURN( OldValue); 3957 3958 CLEANUP: 3959 TRACE("Leave NtUserSetWindowWord, ret=%u\n", _ret_); 3960 UserLeave(); 3961 END_CLEANUP; 3962 } 3963 3964 /* 3965 QueryWindow based on KJK::Hyperion and James Tabor. 3966 3967 0 = QWUniqueProcessId 3968 1 = QWUniqueThreadId 3969 2 = QWActiveWindow 3970 3 = QWFocusWindow 3971 4 = QWIsHung Implements IsHungAppWindow found 3972 by KJK::Hyperion. 3973 3974 9 = QWKillWindow When I called this with hWnd == 3975 DesktopWindow, it shutdown the system 3976 and rebooted. 3977 */ 3978 /* 3979 * @implemented 3980 */ 3981 DWORD_PTR APIENTRY 3982 NtUserQueryWindow(HWND hWnd, DWORD Index) 3983 { 3984 /* Console Leader Process CID Window offsets */ 3985 #define GWLP_CONSOLE_LEADER_PID 0 3986 #define GWLP_CONSOLE_LEADER_TID 4 3987 3988 PWND pWnd; 3989 DWORD_PTR Result; 3990 DECLARE_RETURN(UINT); 3991 3992 TRACE("Enter NtUserQueryWindow\n"); 3993 UserEnterShared(); 3994 3995 if (!(pWnd = UserGetWindowObject(hWnd))) 3996 { 3997 RETURN( 0); 3998 } 3999 4000 switch(Index) 4001 { 4002 case QUERY_WINDOW_UNIQUE_PROCESS_ID: 4003 { 4004 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) && 4005 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) ) 4006 { 4007 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_PID) 4008 Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_PID))); 4009 } 4010 else 4011 { 4012 Result = (DWORD_PTR)IntGetWndProcessId(pWnd); 4013 } 4014 break; 4015 } 4016 4017 case QUERY_WINDOW_UNIQUE_THREAD_ID: 4018 { 4019 if ( (pWnd->head.pti->TIF_flags & TIF_CSRSSTHREAD) && 4020 (pWnd->pcls->atomClassName == gaGuiConsoleWndClass) ) 4021 { 4022 // IntGetWindowLong(offset == GWLP_CONSOLE_LEADER_TID) 4023 Result = (DWORD_PTR)(*((LONG_PTR*)((PCHAR)(pWnd + 1) + GWLP_CONSOLE_LEADER_TID))); 4024 } 4025 else 4026 { 4027 Result = (DWORD_PTR)IntGetWndThreadId(pWnd); 4028 } 4029 break; 4030 } 4031 4032 case QUERY_WINDOW_ACTIVE: 4033 Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndActive ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndActive) : 0); 4034 break; 4035 4036 case QUERY_WINDOW_FOCUS: 4037 Result = (DWORD_PTR)(pWnd->head.pti->MessageQueue->spwndFocus ? UserHMGetHandle(pWnd->head.pti->MessageQueue->spwndFocus) : 0); 4038 break; 4039 4040 case QUERY_WINDOW_ISHUNG: 4041 Result = (DWORD_PTR)MsqIsHung(pWnd->head.pti); 4042 break; 4043 4044 case QUERY_WINDOW_REAL_ID: 4045 Result = (DWORD_PTR)pWnd->head.pti->pEThread->Cid.UniqueProcess; 4046 break; 4047 4048 case QUERY_WINDOW_FOREGROUND: 4049 Result = (pWnd->head.pti->MessageQueue == gpqForeground); 4050 break; 4051 4052 default: 4053 Result = 0; 4054 break; 4055 } 4056 4057 RETURN( Result); 4058 4059 CLEANUP: 4060 TRACE("Leave NtUserQueryWindow, ret=%u\n", _ret_); 4061 UserLeave(); 4062 END_CLEANUP; 4063 } 4064 4065 /* 4066 * @implemented 4067 */ 4068 UINT APIENTRY 4069 NtUserRegisterWindowMessage(PUNICODE_STRING MessageNameUnsafe) 4070 { 4071 UNICODE_STRING SafeMessageName; 4072 NTSTATUS Status; 4073 UINT Ret; 4074 DECLARE_RETURN(UINT); 4075 4076 TRACE("Enter NtUserRegisterWindowMessage\n"); 4077 UserEnterExclusive(); 4078 4079 if(MessageNameUnsafe == NULL) 4080 { 4081 EngSetLastError(ERROR_INVALID_PARAMETER); 4082 RETURN( 0); 4083 } 4084 4085 Status = IntSafeCopyUnicodeStringTerminateNULL(&SafeMessageName, MessageNameUnsafe); 4086 if(!NT_SUCCESS(Status)) 4087 { 4088 SetLastNtError(Status); 4089 RETURN( 0); 4090 } 4091 4092 Ret = (UINT)IntAddAtom(SafeMessageName.Buffer); 4093 if (SafeMessageName.Buffer) 4094 ExFreePoolWithTag(SafeMessageName.Buffer, TAG_STRING); 4095 RETURN( Ret); 4096 4097 CLEANUP: 4098 TRACE("Leave NtUserRegisterWindowMessage, ret=%u\n", _ret_); 4099 UserLeave(); 4100 END_CLEANUP; 4101 } 4102 4103 /* 4104 * @implemented 4105 */ 4106 BOOL APIENTRY 4107 NtUserSetWindowFNID(HWND hWnd, 4108 WORD fnID) 4109 { 4110 PWND Wnd; 4111 DECLARE_RETURN(BOOL); 4112 4113 TRACE("Enter NtUserSetWindowFNID\n"); 4114 UserEnterExclusive(); 4115 4116 if (!(Wnd = UserGetWindowObject(hWnd))) 4117 { 4118 RETURN( FALSE); 4119 } 4120 4121 if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process()) 4122 { 4123 EngSetLastError(ERROR_ACCESS_DENIED); 4124 RETURN( FALSE); 4125 } 4126 4127 // From user land we only set these. 4128 if (fnID != FNID_DESTROY) 4129 { 4130 /* HACK: The minimum should be FNID_BUTTON, but menu code relies on this */ 4131 if (fnID < FNID_FIRST || fnID > FNID_GHOST || 4132 Wnd->fnid != 0) 4133 { 4134 EngSetLastError(ERROR_INVALID_PARAMETER); 4135 RETURN( FALSE); 4136 } 4137 } 4138 4139 Wnd->fnid |= fnID; 4140 RETURN( TRUE); 4141 4142 CLEANUP: 4143 TRACE("Leave NtUserSetWindowFNID\n"); 4144 UserLeave(); 4145 END_CLEANUP; 4146 } 4147 4148 BOOL APIENTRY 4149 DefSetText(PWND Wnd, PCWSTR WindowText) 4150 { 4151 UNICODE_STRING UnicodeString; 4152 BOOL Ret = FALSE; 4153 4154 RtlInitUnicodeString(&UnicodeString, WindowText); 4155 4156 if (UnicodeString.Length != 0) 4157 { 4158 if (Wnd->strName.MaximumLength > 0 && 4159 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL)) 4160 { 4161 ASSERT(Wnd->strName.Buffer != NULL); 4162 4163 Wnd->strName.Length = UnicodeString.Length; 4164 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0'; 4165 RtlCopyMemory(Wnd->strName.Buffer, 4166 UnicodeString.Buffer, 4167 UnicodeString.Length); 4168 } 4169 else 4170 { 4171 PWCHAR buf; 4172 Wnd->strName.MaximumLength = Wnd->strName.Length = 0; 4173 buf = Wnd->strName.Buffer; 4174 Wnd->strName.Buffer = NULL; 4175 if (buf != NULL) 4176 { 4177 DesktopHeapFree(Wnd->head.rpdesk, buf); 4178 } 4179 4180 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk, 4181 UnicodeString.Length + sizeof(UNICODE_NULL)); 4182 if (Wnd->strName.Buffer != NULL) 4183 { 4184 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0'; 4185 RtlCopyMemory(Wnd->strName.Buffer, 4186 UnicodeString.Buffer, 4187 UnicodeString.Length); 4188 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL); 4189 Wnd->strName.Length = UnicodeString.Length; 4190 } 4191 else 4192 { 4193 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 4194 goto Exit; 4195 } 4196 } 4197 } 4198 else 4199 { 4200 Wnd->strName.Length = 0; 4201 if (Wnd->strName.Buffer != NULL) 4202 Wnd->strName.Buffer[0] = L'\0'; 4203 } 4204 4205 // FIXME: HAX! Windows does not do this in here! 4206 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than 4207 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc. 4208 /* Send shell notifications */ 4209 if (!Wnd->spwndOwner && !IntGetParent(Wnd)) 4210 { 4211 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) UserHMGetHandle(Wnd), FALSE); // FIXME Flashing? 4212 } 4213 4214 Ret = TRUE; 4215 Exit: 4216 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString); 4217 return Ret; 4218 } 4219 4220 /* 4221 * NtUserDefSetText 4222 * 4223 * Undocumented function that is called from DefWindowProc to set 4224 * window text. 4225 * 4226 * Status 4227 * @implemented 4228 */ 4229 BOOL APIENTRY 4230 NtUserDefSetText(HWND hWnd, PLARGE_STRING WindowText) 4231 { 4232 PWND Wnd; 4233 LARGE_STRING SafeText; 4234 UNICODE_STRING UnicodeString; 4235 BOOL Ret = TRUE; 4236 4237 TRACE("Enter NtUserDefSetText\n"); 4238 4239 if (WindowText != NULL) 4240 { 4241 _SEH2_TRY 4242 { 4243 SafeText = ProbeForReadLargeString(WindowText); 4244 } 4245 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4246 { 4247 Ret = FALSE; 4248 SetLastNtError(_SEH2_GetExceptionCode()); 4249 } 4250 _SEH2_END; 4251 4252 if (!Ret) 4253 return FALSE; 4254 } 4255 else 4256 return TRUE; 4257 4258 UserEnterExclusive(); 4259 4260 if(!(Wnd = UserGetWindowObject(hWnd))) 4261 { 4262 UserLeave(); 4263 return FALSE; 4264 } 4265 4266 // ReactOS uses Unicode and not mixed. Up/Down converting will take time. 4267 // Brought to you by: The Wine Project! Dysfunctional Thought Processes! 4268 // Now we know what the bAnsi is for. 4269 RtlInitUnicodeString(&UnicodeString, NULL); 4270 if (SafeText.Buffer) 4271 { 4272 _SEH2_TRY 4273 { 4274 if (SafeText.bAnsi) 4275 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(CHAR)); 4276 else 4277 ProbeForRead(SafeText.Buffer, SafeText.Length, sizeof(WCHAR)); 4278 Ret = RtlLargeStringToUnicodeString(&UnicodeString, &SafeText); 4279 } 4280 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4281 { 4282 Ret = FALSE; 4283 SetLastNtError(_SEH2_GetExceptionCode()); 4284 } 4285 _SEH2_END; 4286 if (!Ret) goto Exit; 4287 } 4288 4289 if (UnicodeString.Length != 0) 4290 { 4291 if (Wnd->strName.MaximumLength > 0 && 4292 UnicodeString.Length <= Wnd->strName.MaximumLength - sizeof(UNICODE_NULL)) 4293 { 4294 ASSERT(Wnd->strName.Buffer != NULL); 4295 4296 Wnd->strName.Length = UnicodeString.Length; 4297 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0'; 4298 RtlCopyMemory(Wnd->strName.Buffer, 4299 UnicodeString.Buffer, 4300 UnicodeString.Length); 4301 } 4302 else 4303 { 4304 PWCHAR buf; 4305 Wnd->strName.MaximumLength = Wnd->strName.Length = 0; 4306 buf = Wnd->strName.Buffer; 4307 Wnd->strName.Buffer = NULL; 4308 if (buf != NULL) 4309 { 4310 DesktopHeapFree(Wnd->head.rpdesk, buf); 4311 } 4312 4313 Wnd->strName.Buffer = DesktopHeapAlloc(Wnd->head.rpdesk, 4314 UnicodeString.Length + sizeof(UNICODE_NULL)); 4315 if (Wnd->strName.Buffer != NULL) 4316 { 4317 Wnd->strName.Buffer[UnicodeString.Length / sizeof(WCHAR)] = L'\0'; 4318 RtlCopyMemory(Wnd->strName.Buffer, 4319 UnicodeString.Buffer, 4320 UnicodeString.Length); 4321 Wnd->strName.MaximumLength = UnicodeString.Length + sizeof(UNICODE_NULL); 4322 Wnd->strName.Length = UnicodeString.Length; 4323 } 4324 else 4325 { 4326 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 4327 Ret = FALSE; 4328 goto Exit; 4329 } 4330 } 4331 } 4332 else 4333 { 4334 Wnd->strName.Length = 0; 4335 if (Wnd->strName.Buffer != NULL) 4336 Wnd->strName.Buffer[0] = L'\0'; 4337 } 4338 4339 // FIXME: HAX! Windows does not do this in here! 4340 // In User32, these are called after: NotifyWinEvent EVENT_OBJECT_NAMECHANGE than 4341 // RepaintButton, StaticRepaint, NtUserCallHwndLock HWNDLOCK_ROUTINE_REDRAWFRAMEANDHOOK, etc. 4342 /* Send shell notifications */ 4343 if (!Wnd->spwndOwner && !IntGetParent(Wnd)) 4344 { 4345 co_IntShellHookNotify(HSHELL_REDRAW, (WPARAM) hWnd, FALSE); // FIXME Flashing? 4346 } 4347 4348 Ret = TRUE; 4349 Exit: 4350 if (UnicodeString.Buffer) RtlFreeUnicodeString(&UnicodeString); 4351 TRACE("Leave NtUserDefSetText, ret=%i\n", Ret); 4352 UserLeave(); 4353 return Ret; 4354 } 4355 4356 /* 4357 * NtUserInternalGetWindowText 4358 * 4359 * Status 4360 * @implemented 4361 */ 4362 4363 INT APIENTRY 4364 NtUserInternalGetWindowText(HWND hWnd, LPWSTR lpString, INT nMaxCount) 4365 { 4366 PWND Wnd; 4367 NTSTATUS Status; 4368 INT Result; 4369 DECLARE_RETURN(INT); 4370 4371 TRACE("Enter NtUserInternalGetWindowText\n"); 4372 UserEnterShared(); 4373 4374 if(lpString && (nMaxCount <= 1)) 4375 { 4376 EngSetLastError(ERROR_INVALID_PARAMETER); 4377 RETURN( 0); 4378 } 4379 4380 if(!(Wnd = UserGetWindowObject(hWnd))) 4381 { 4382 RETURN( 0); 4383 } 4384 4385 Result = Wnd->strName.Length / sizeof(WCHAR); 4386 if(lpString) 4387 { 4388 const WCHAR Terminator = L'\0'; 4389 INT Copy; 4390 WCHAR *Buffer = (WCHAR*)lpString; 4391 4392 Copy = min(nMaxCount - 1, Result); 4393 if(Copy > 0) 4394 { 4395 Status = MmCopyToCaller(Buffer, Wnd->strName.Buffer, Copy * sizeof(WCHAR)); 4396 if(!NT_SUCCESS(Status)) 4397 { 4398 SetLastNtError(Status); 4399 RETURN( 0); 4400 } 4401 Buffer += Copy; 4402 } 4403 4404 Status = MmCopyToCaller(Buffer, &Terminator, sizeof(WCHAR)); 4405 if(!NT_SUCCESS(Status)) 4406 { 4407 SetLastNtError(Status); 4408 RETURN( 0); 4409 } 4410 4411 Result = Copy; 4412 } 4413 4414 RETURN( Result); 4415 4416 CLEANUP: 4417 TRACE("Leave NtUserInternalGetWindowText, ret=%i\n",_ret_); 4418 UserLeave(); 4419 END_CLEANUP; 4420 } 4421 4422 /* 4423 API Call 4424 */ 4425 BOOL 4426 FASTCALL 4427 IntShowOwnedPopups(PWND OwnerWnd, BOOL fShow ) 4428 { 4429 int count = 0; 4430 PWND pWnd; 4431 HWND *win_array; 4432 4433 // ASSERT(OwnerWnd); 4434 4435 TRACE("Enter ShowOwnedPopups Show: %s\n", (fShow ? "TRUE" : "FALSE")); 4436 4437 /* NOTE: Popups are not children */ 4438 win_array = IntWinListOwnedPopups(OwnerWnd); 4439 4440 if (!win_array) 4441 return TRUE; 4442 4443 while (win_array[count]) 4444 count++; 4445 while (--count >= 0) 4446 { 4447 if (!(pWnd = ValidateHwndNoErr( win_array[count] ))) 4448 continue; 4449 if (pWnd->spwndOwner != OwnerWnd) 4450 continue; 4451 4452 if (fShow) 4453 { 4454 if (pWnd->state & WNDS_HIDDENPOPUP) 4455 { 4456 /* In Windows, ShowOwnedPopups(TRUE) generates 4457 * WM_SHOWWINDOW messages with SW_PARENTOPENING, 4458 * regardless of the state of the owner 4459 */ 4460 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING); 4461 pWnd->state &= ~WNDS_HIDDENPOPUP; 4462 continue; 4463 } 4464 } 4465 else 4466 { 4467 if (pWnd->style & WS_VISIBLE) 4468 { 4469 /* In Windows, ShowOwnedPopups(FALSE) generates 4470 * WM_SHOWWINDOW messages with SW_PARENTCLOSING, 4471 * regardless of the state of the owner 4472 */ 4473 co_IntSendMessage(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING); 4474 pWnd->state |= WNDS_HIDDENPOPUP; 4475 continue; 4476 } 4477 } 4478 } 4479 ExFreePoolWithTag(win_array, USERTAG_WINDOWLIST); 4480 TRACE("Leave ShowOwnedPopups\n"); 4481 return TRUE; 4482 } 4483 4484 /* EOF */ 4485