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