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