Changeset 50101 in vbox
- Timestamp:
- Jan 17, 2014 11:33:40 PM (11 years ago)
- Location:
- trunk/src/VBox/Additions/WINNT/VBoxTray
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk
r49891 r50101 5 5 6 6 # 7 # Copyright (C) 2006-201 2Oracle Corporation7 # Copyright (C) 2006-2014 Oracle Corporation 8 8 # 9 9 # This file is part of VirtualBox Open Source Edition (OSE), as … … 49 49 VBoxDnDDataObject.cpp \ 50 50 VBoxDnDEnumFormat.cpp \ 51 VBoxDnDDropSource.cpp 51 VBoxDnDDropSource.cpp \ 52 VBoxDnDDropTarget.cpp 52 53 endif 53 54 ifdef VBOX_WITH_GUEST_PROPS -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp
r49947 r50101 5 5 6 6 /* 7 * Copyright (C) 2013 Oracle Corporation7 * Copyright (C) 2013-2014 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 25 25 #include <iprt/asm.h> 26 26 #include <iprt/assert.h> 27 #include <iprt/critsect.h>28 27 #include <iprt/err.h> 29 28 #include <iprt/ldr.h> … … 44 43 #endif 45 44 45 /** @todo Merge this with messages from VBoxTray.h. */ 46 46 #define WM_VBOXTRAY_DND_MESSAGE WM_APP + 401 47 47 48 48 static LRESULT CALLBACK vboxDnDWndProcInstance(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 49 49 static LRESULT CALLBACK vboxDnDWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 50 51 struct VBOXDNDCONTEXT;52 class VBoxDnDWnd;53 54 /*55 * A drag'n drop event from the host.56 */57 typedef struct VBOXDNDEVENT58 {59 /** The actual event data. */60 VBGLR3DNDHGCMEVENT Event;61 62 } VBOXDNDEVENT, *PVBOXDNDEVENT;63 64 /**65 * DnD context data.66 */67 typedef struct VBOXDNDCONTEXT68 {69 /** Pointer to the service environment. */70 const VBOXSERVICEENV *pEnv;71 /** Shutdown indicator. */72 bool fShutdown;73 /** Thread handle for main event queue74 * processing. */75 RTTHREAD hEvtQueue;76 /** The DnD main event queue. */77 RTCMTList<VBOXDNDEVENT> lstEvtQueue;78 /** Semaphore for waiting on main event queue79 * events. */80 RTSEMEVENT hEvtQueueSem;81 /** List of drag'n drop windows. At82 * the moment only one source is supported. */83 RTCMTList<VBoxDnDWnd*> lstWnd;84 85 } VBOXDNDCONTEXT, *PVBOXDNDCONTEXT;86 static VBOXDNDCONTEXT gCtx = {0};87 88 /**89 * Everything which is required to successfully start90 * a drag'n drop operation via DoDragDrop().91 */92 typedef struct VBOXDNDSTARTUPINFO93 {94 /** Our DnD data object, holding95 * the raw DnD data. */96 VBoxDnDDataObject *pDataObject;97 /** The drop source for sending the98 * DnD request to a IDropTarget. */99 VBoxDnDDropSource *pDropSource;100 /** The DnD effects which are wanted / allowed. */101 DWORD dwOKEffects;102 103 } VBOXDNDSTARTUPINFO, *PVBOXDNDSTARTUPINFO;104 105 /**106 * Class for handling a DnD proxy window.107 ** @todo Unify this and VBoxClient's DragInstance!108 */109 class VBoxDnDWnd110 {111 enum State112 {113 Uninitialized,114 Initialized,115 Dragging,116 Dropped,117 Canceled118 };119 120 enum Mode121 {122 Unknown,123 HG,124 GH125 };126 127 public:128 129 VBoxDnDWnd(void);130 virtual ~VBoxDnDWnd(void);131 132 public:133 134 int Initialize(PVBOXDNDCONTEXT pContext);135 136 public:137 138 /** The window's thread for the native message pump and139 * OLE context. */140 static int Thread(RTTHREAD hThread, void *pvUser);141 142 public:143 144 static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM lParam);145 /** The per-instance wndproc routine. */146 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);147 148 public:149 150 int DragRelease(void);151 152 int OnCreate(void);153 void OnDestroy(void);154 155 /* H->G */156 int OnHgEnter(const RTCList<RTCString> &formats, uint32_t uAllActions);157 int OnHgMove(uint32_t u32xPos, uint32_t u32yPos, uint32_t uAllActions);158 int OnHgDrop(void);159 int OnHgLeave(void);160 int OnHgDataReceived(const void *pvData, uint32_t cData);161 int OnHgCancel(void);162 163 #ifdef VBOX_WITH_DRAG_AND_DROP_GH164 /* G->H */165 int OnGhIsDnDPending(void);166 int OnGhDropped(const RTCString &strFormat, uint32_t action);167 #endif168 169 int ProcessEvent(PVBOXDNDEVENT pEvent);170 171 protected:172 173 void reset(void);174 175 public: /** @todo Make protected! */176 177 /** Pointer to DnD context. */178 PVBOXDNDCONTEXT pContext;179 RTCRITSECT mCritSect;180 RTSEMEVENT mEventSem;181 #ifdef RT_OS_WINDOWS182 /** The window's handle. */183 HWND hWnd;184 /** List of allowed MIME types this185 * client can handle. Make this a per-instance186 * property so that we can selectively allow/forbid187 * certain types later on runtime. */188 RTCList<RTCString> lstAllowedFormats;189 /** List of formats for the current190 * drag'n drop operation. */191 RTCList<RTCString> lstFormats;192 /** Flags of all current drag'n drop193 * actions allowed. */194 uint32_t uAllActions;195 /** The startup information required196 * for the actual DoDragDrop() call. */197 VBOXDNDSTARTUPINFO startupInfo;198 bool mfMouseButtonDown;199 #else200 /** @todo */201 #endif202 203 /** The window's own HGCM client ID. */204 uint32_t mClientID;205 Mode mMode;206 State mState;207 RTCString mFormatRequested;208 RTCList<RTCString> mLstFormats;209 RTCList<RTCString> mLstActions;210 };211 50 212 51 VBoxDnDWnd::VBoxDnDWnd(void) 213 52 : hWnd(NULL), 214 53 mfMouseButtonDown(false), 54 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 55 pDropTarget(NULL), 56 #endif 215 57 mClientID(UINT32_MAX), 216 58 mMode(Unknown), … … 218 60 { 219 61 RT_ZERO(startupInfo); 62 63 reset(); 220 64 } 221 65 … … 225 69 226 70 reset(); 227 }228 229 int VBoxDnDWnd::DragRelease(void)230 {231 /* Release mouse button in the guest to start the "drop"232 * action at the current mouse cursor position. */233 INPUT Input[1] = { 0 };234 Input[0].type = INPUT_MOUSE;235 Input[0].mi.dwFlags = MOUSEEVENTF_LEFTUP;236 SendInput(1, Input, sizeof(INPUT));237 238 return VINF_SUCCESS;239 71 } 240 72 … … 345 177 LogFlowFunc(("Debug proxy window created, hWnd=0x%x\n", pThis->hWnd)); 346 178 #endif 347 348 179 } 349 180 } … … 444 275 case WM_MOUSEMOVE: 445 276 { 446 LogFlowThisFunc(("WM_MOUSEMOVE: mfMouseButtonDown=%RTbool, mState=%ld\n", 447 mfMouseButtonDown, mState)); 448 449 /* Dragging not started yet? Kick it off ... */ 450 if ( mfMouseButtonDown 451 && (mState != Dragging)) 277 LogFlowThisFunc(("WM_MOUSEMOVE: mfMouseButtonDown=%RTbool, mMode=%ld, mState=%ld\n", 278 mfMouseButtonDown, mMode, mState)); 279 #ifdef DEBUG_andy 280 POINT p; 281 GetCursorPos(&p); 282 LogFlowThisFunc(("WM_MOUSEMOVE: curX=%ld, curY=%ld\n", p.x, p.y)); 283 #endif 284 int rc = VINF_SUCCESS; 285 if (mMode == HG) /* Host to guest. */ 452 286 { 453 mState = Dragging; 454 455 #ifdef VBOX_DND_DEBUG_WND 456 /* Delay hinding the proxy window a bit when debugging, to see 457 * whether the desired range is covered correctly. */ 458 RTThreadSleep(5000); 459 #endif 460 ShowWindow(hWnd, SW_HIDE); 461 462 int rc = VINF_SUCCESS; 463 464 LogFlowThisFunc(("Starting drag'n drop: uAllActions=0x%x, dwOKEffects=0x%x ...\n", 465 uAllActions, startupInfo.dwOKEffects)); 466 467 AssertPtr(startupInfo.pDataObject); 468 AssertPtr(startupInfo.pDropSource); 469 DWORD dwEffect; 470 HRESULT hr = DoDragDrop(startupInfo.pDataObject, startupInfo.pDropSource, 471 startupInfo.dwOKEffects, &dwEffect); 472 LogFlowThisFunc(("rc=%Rhrc, dwEffect=%RI32\n", hr, dwEffect)); 473 switch (hr) 287 /* Dragging not started yet? Kick it off ... */ 288 if ( mfMouseButtonDown 289 && (mState != Dragging)) 474 290 { 475 case DRAGDROP_S_DROP: 476 mState = Dropped; 477 break; 478 479 case DRAGDROP_S_CANCEL: 480 mState = Canceled; 481 break; 482 483 default: 484 LogFlowThisFunc(("Drag'n drop failed with %Rhrc\n", hr)); 485 mState = Canceled; 486 rc = VERR_GENERAL_FAILURE; /** @todo Find a better status code. */ 487 break; 291 mState = Dragging; 292 #if 0 293 /* Delay hiding the proxy window a bit when debugging, to see 294 * whether the desired range is covered correctly. */ 295 RTThreadSleep(5000); 296 #endif 297 hide(); 298 299 LogFlowThisFunc(("Starting drag'n drop: uAllActions=0x%x, dwOKEffects=0x%x ...\n", 300 uAllActions, startupInfo.dwOKEffects)); 301 302 AssertPtr(startupInfo.pDataObject); 303 AssertPtr(startupInfo.pDropSource); 304 DWORD dwEffect; 305 HRESULT hr = DoDragDrop(startupInfo.pDataObject, startupInfo.pDropSource, 306 startupInfo.dwOKEffects, &dwEffect); 307 LogFlowThisFunc(("rc=%Rhrc, dwEffect=%RI32\n", hr, dwEffect)); 308 switch (hr) 309 { 310 case DRAGDROP_S_DROP: 311 mState = Dropped; 312 break; 313 314 case DRAGDROP_S_CANCEL: 315 mState = Canceled; 316 break; 317 318 default: 319 LogFlowThisFunc(("Drag'n drop failed with %Rhrc\n", hr)); 320 mState = Canceled; 321 rc = VERR_GENERAL_FAILURE; /** @todo Find a better status code. */ 322 break; 323 } 324 325 int rc2 = RTCritSectEnter(&mCritSect); 326 if (RT_SUCCESS(rc2)) 327 { 328 startupInfo.pDropSource->Release(); 329 startupInfo.pDataObject->Release(); 330 331 RT_ZERO(startupInfo); 332 333 rc2 = RTCritSectLeave(&mCritSect); 334 if (RT_SUCCESS(rc)) 335 rc = rc2; 336 } 337 338 mMode = Unknown; 488 339 } 489 490 int rc2 = RTCritSectEnter(&mCritSect);491 if (RT_SUCCESS(rc2))492 {493 startupInfo.pDropSource->Release();494 startupInfo.pDataObject->Release();495 496 RT_ZERO(startupInfo);497 498 RTCritSectLeave(&mCritSect);499 }500 501 LogFlowThisFunc(("Drag'n drop resulted in mState=%ld, rc=%Rrc\n",502 mState, rc));503 340 } 504 341 else if (mMode == GH) /* Guest to host. */ 342 { 343 hide(); 344 } 345 else 346 rc = VERR_NOT_SUPPORTED; 347 348 LogFlowThisFunc(("WM_MOUSEMOVE: mMode=%ld, mState=%ld, rc=%Rrc\n", 349 mMode, mState, rc)); 505 350 return 0; 506 351 } … … 520 365 { 521 366 LogFlowThisFunc(("HOST_DND_HG_EVT_ENTER\n")); 367 368 reset(); 369 370 Assert(mMode == Unknown); 371 mMode = HG; 522 372 523 373 if (pEvent->Event.cbFormats) … … 540 390 { 541 391 LogFlowThisFunc(("HOST_DND_HG_EVT_MOVE: %d,%d\n", 542 pEvent->Event.u.a.uXpos, pEvent->Event.u.a.uYpos)); 543 544 rc = OnHgMove(pEvent->Event.u.a.uXpos, pEvent->Event.u.a.uYpos, pEvent->Event.u.a.uDefAction); 392 pEvent->Event.u.a.uXpos, pEvent->Event.u.a.uYpos)); 393 394 rc = OnHgMove(pEvent->Event.u.a.uXpos, pEvent->Event.u.a.uYpos, 395 pEvent->Event.u.a.uDefAction); 545 396 break; 546 397 } … … 566 417 LogFlowThisFunc(("HOST_DND_HG_SND_DATA\n")); 567 418 568 rc = OnHgDataReceived(pEvent->Event.u.b.pvData, pEvent->Event.u.b.cbData); 419 rc = OnHgDataReceived(pEvent->Event.u.b.pvData, 420 pEvent->Event.u.b.cbData); 569 421 break; 570 422 } … … 575 427 576 428 rc = OnHgCancel(); 429 430 reset(); 577 431 break; 578 432 } 579 433 580 #ifdef VBOX_WITH_DRAG_AND_DROP_GH581 434 case DragAndDropSvc::HOST_DND_GH_REQ_PENDING: 582 435 { 583 436 LogFlowThisFunc(("HOST_DND_GH_REQ_PENDING\n")); 584 437 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 438 Assert( mMode == Unknown 439 || mMode == GH); 440 mMode = GH; 441 rc = OnGhIsDnDPending(pEvent->Event.uScreenId); 442 #else 443 rc = VERR_NOT_SUPPORTED; 444 #endif 585 445 break; 586 446 } … … 589 449 { 590 450 LogFlowThisFunc(("HOST_DND_GH_EVT_DROPPED\n")); 591 451 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 452 Assert(mMode == GH); 453 rc = OnGhDropped(pEvent->Event.pszFormats, 454 pEvent->Event.cbFormats, 455 pEvent->Event.u.a.uDefAction); 456 mMode = Unknown; 457 #else 458 rc = VERR_NOT_SUPPORTED; 459 #endif 592 460 break; 593 461 } … … 596 464 { 597 465 LogFlowThisFunc(("GUEST_DND_GH_EVT_ERROR\n")); 598 466 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 467 reset(); 468 rc = VINF_SUCCESS; /** @todo GUEST_DND_GH_EVT_ERROR */ 469 #else 470 rc = VERR_NOT_SUPPORTED; 471 #endif 599 472 break; 600 473 } 601 #endif 474 602 475 default: 603 476 rc = VERR_NOT_SUPPORTED; … … 635 508 636 509 LogFlowThisFunc(("Processing event %RU32 resulted in rc=%Rrc\n", 637 pEvent->Event.uType, rc));510 pEvent->Event.uType, rc)); 638 511 if (pEvent) 639 512 RTMemFree(pEvent); … … 648 521 } 649 522 523 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 524 /** 525 * Registers this proxy window as a local drop target. 526 * 527 * @return IPRT status code. 528 */ 529 int VBoxDnDWnd::RegisterAsDropTarget(void) 530 { 531 if (pDropTarget) /* Already registered as drop target? */ 532 return VINF_SUCCESS; 533 534 int rc = VBoxDnDDropTarget::CreateDropTarget(this /* pParent */, 535 &pDropTarget); 536 if (RT_SUCCESS(rc)) 537 { 538 AssertPtr(pDropTarget); 539 HRESULT hr = CoLockObjectExternal(pDropTarget, TRUE /* fLock */, 540 FALSE /* fLastUnlockReleases */); 541 if (SUCCEEDED(hr)) 542 hr = RegisterDragDrop(hWnd, pDropTarget); 543 544 if (FAILED(hr)) 545 { 546 LogRel(("DnD: Creating drop target failed with hr=0x%x\n", hr)); 547 rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */ 548 } 549 } 550 551 LogFlowFuncLeaveRC(rc); 552 return rc; 553 } 554 555 int VBoxDnDWnd::UnregisterAsDropTarget(void) 556 { 557 if (!pDropTarget) /* No drop target? Bail out. */ 558 return VINF_SUCCESS; 559 560 HRESULT hr = RevokeDragDrop(hWnd); 561 if (SUCCEEDED(hr)) 562 hr = CoLockObjectExternal(pDropTarget, FALSE /* fLock */, 563 TRUE /* fLastUnlockReleases */); 564 if (SUCCEEDED(hr)) 565 pDropTarget->Release(); 566 567 int rc = SUCCEEDED(hr) 568 ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Fix this. */ 569 570 LogFlowFuncLeaveRC(rc); 571 return rc; 572 } 573 #endif /* VBOX_WITH_DRAG_AND_DROP_GH */ 574 650 575 int VBoxDnDWnd::OnCreate(void) 651 576 { … … 657 582 } 658 583 659 LogFlowThisFunc(("Client ID=%RU32 \n", mClientID));584 LogFlowThisFunc(("Client ID=%RU32, rc=%Rrc\n", mClientID, rc)); 660 585 return rc; 661 586 } … … 664 589 { 665 590 VbglR3DnDDisconnect(mClientID); 591 LogFlowThisFuncLeave(); 666 592 } 667 593 668 594 int VBoxDnDWnd::OnHgEnter(const RTCList<RTCString> &lstFormats, uint32_t uAllActions) 669 595 { 670 reset();671 672 mState = Initialized;673 674 596 #ifdef DEBUG 675 597 LogFlowThisFunc(("uActions=0x%x, lstFormats=%zu: ", uAllActions, lstFormats.size())); … … 740 662 } 741 663 742 /* 743 * Prepare the proxy window. 744 */ 664 if (RT_SUCCESS(rc)) 665 rc = makeFullscreen(); 666 667 LogFlowFuncLeaveRC(rc); 668 return rc; 669 } 670 671 int VBoxDnDWnd::OnHgMove(uint32_t u32xPos, uint32_t u32yPos, uint32_t uAction) 672 { 673 LogFlowThisFunc(("u32xPos=%RU32, u32yPos=%RU32, uAction=0x%x\n", 674 u32xPos, u32yPos, uAction)); 675 676 /** @todo Put this block into a function! */ 677 /** @todo Multi-monitor setups? */ 678 int iScreenX = GetSystemMetrics(SM_CXSCREEN) - 1; 679 int iScreenY = GetSystemMetrics(SM_CYSCREEN) - 1; 680 681 INPUT Input[1] = { 0 }; 682 Input[0].type = INPUT_MOUSE; 683 Input[0].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE; 684 Input[0].mi.dx = u32xPos * (65535 / iScreenX); 685 Input[0].mi.dy = u32yPos * (65535 / iScreenY); 686 SendInput(1, Input, sizeof(INPUT)); 687 688 #ifdef DEBUG_andy 689 POINT p; 690 GetCursorPos(&p); 691 LogFlowThisFunc(("curX=%d, curY=%d\n", p.x, p.y)); 692 #endif 693 694 uint32_t uActionNotify = DND_IGNORE_ACTION; 695 int rc = RTCritSectEnter(&mCritSect); 696 if (RT_SUCCESS(rc)) 697 { 698 if ( (Dragging == mState) 699 && startupInfo.pDropSource) 700 uActionNotify = startupInfo.pDropSource->GetCurrentAction(); 701 702 RTCritSectLeave(&mCritSect); 703 } 704 705 if (RT_SUCCESS(rc)) 706 { 707 rc = VbglR3DnDHGAcknowledgeOperation(mClientID, uActionNotify); 708 if (RT_FAILURE(rc)) 709 LogFlowThisFunc(("Acknowleding operation failed with rc=%Rrc\n", rc)); 710 } 711 712 LogFlowThisFunc(("Returning uActionNotify=0x%x, rc=%Rrc\n", uActionNotify, rc)); 713 return rc; 714 } 715 716 int VBoxDnDWnd::OnHgLeave(void) 717 { 718 LogFlowThisFunc(("mMode=%ld, mState=%RU32\n", mMode, mState)); 719 LogRel(("DnD: Drag'n drop operation aborted\n")); 720 721 reset(); 722 723 int rc = VINF_SUCCESS; 724 725 /* Post ESC to our window to officially abort the 726 * drag'n drop operation. */ 727 PostMessage(hWnd, WM_KEYDOWN, VK_ESCAPE, 0 /* lParam */); 728 729 LogFlowFuncLeaveRC(rc); 730 return rc; 731 } 732 733 int VBoxDnDWnd::OnHgDrop(void) 734 { 735 LogFlowThisFunc(("mMode=%ld, mState=%RU32\n", mMode, mState)); 736 737 int rc = VINF_SUCCESS; 738 if (mState == Dragging) 739 { 740 Assert(lstFormats.size() >= 1); 741 742 /** @todo What to do when multiple formats are available? */ 743 mFormatRequested = lstFormats.at(0); 744 745 rc = RTCritSectEnter(&mCritSect); 746 if (RT_SUCCESS(rc)) 747 { 748 if (startupInfo.pDataObject) 749 startupInfo.pDataObject->SetStatus(VBoxDnDDataObject::Dropping); 750 else 751 rc = VERR_NOT_FOUND; 752 753 RTCritSectLeave(&mCritSect); 754 } 755 756 if (RT_SUCCESS(rc)) 757 { 758 LogRel(("DnD: Requesting data as '%s' ...\n", mFormatRequested.c_str())); 759 rc = VbglR3DnDHGRequestData(mClientID, mFormatRequested.c_str()); 760 if (RT_FAILURE(rc)) 761 LogFlowThisFunc(("Requesting data failed with rc=%Rrc\n", rc)); 762 } 763 } 764 765 LogFlowFuncLeaveRC(rc); 766 return rc; 767 } 768 769 int VBoxDnDWnd::OnHgDataReceived(const void *pvData, uint32_t cbData) 770 { 771 LogFlowThisFunc(("mState=%ld, pvData=%p, cbData=%RU32\n", 772 mState, pvData, cbData)); 773 774 mState = Dropped; 775 776 int rc = VINF_SUCCESS; 777 if (pvData) 778 { 779 Assert(cbData); 780 rc = RTCritSectEnter(&mCritSect); 781 if (RT_SUCCESS(rc)) 782 { 783 if (startupInfo.pDataObject) 784 rc = startupInfo.pDataObject->Signal(mFormatRequested, pvData, cbData); 785 else 786 rc = VERR_NOT_FOUND; 787 788 RTCritSectLeave(&mCritSect); 789 } 790 } 791 792 int rc2 = dragRelease(); 793 if (RT_SUCCESS(rc)) 794 rc = rc2; 795 796 LogFlowFuncLeaveRC(rc); 797 return rc; 798 } 799 800 int VBoxDnDWnd::OnHgCancel(void) 801 { 802 int rc = RTCritSectEnter(&mCritSect); 803 if (RT_SUCCESS(rc)) 804 { 805 if (startupInfo.pDataObject) 806 startupInfo.pDataObject->Abort(); 807 808 RTCritSectLeave(&mCritSect); 809 } 810 811 int rc2 = dragRelease(); 812 if (RT_SUCCESS(rc)) 813 rc = rc2; 814 815 return rc; 816 } 817 818 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 819 int VBoxDnDWnd::OnGhIsDnDPending(uint32_t uScreenID) 820 { 821 LogFlowThisFunc(("mMode=%ld, mState=%ld, uScreenID=%RU32\n", 822 mMode, mState, uScreenID)); 823 824 if (mState == Uninitialized) 825 reset(); 826 827 int rc; 828 if (mState == Initialized) 829 { 830 //rc = makeFullscreen(); 831 rc = VINF_SUCCESS; 832 if (RT_SUCCESS(rc)) 833 rc = RegisterAsDropTarget(); 834 835 if (RT_SUCCESS(rc)) 836 mState = Dragging; 837 } 838 else 839 rc = VINF_SUCCESS; 840 841 if ( RT_SUCCESS(rc) 842 && (mState == Dragging)) 843 { 844 /** @todo Put this block into a function! */ 845 POINT p; 846 GetCursorPos(&p); 847 848 #ifdef DEBUG_andy 849 LogFlowThisFunc(("Setting cursor to curX=%d, curY=%d\n", p.x, p.y)); 850 #endif 851 /** @todo Multi-monitor setups? */ 852 int iScreenX = GetSystemMetrics(SM_CXSCREEN) - 1; 853 int iScreenY = GetSystemMetrics(SM_CYSCREEN) - 1; 854 855 static int pos = 100; 856 pos++; 857 858 INPUT Input[1] = { 0 }; 859 Input[0].type = INPUT_MOUSE; 860 Input[0].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE; 861 Input[0].mi.dx = pos * (65535 / iScreenX); //p.x * (65535 / iScreenX); 862 Input[0].mi.dy = 100 * (65535 / iScreenY); //p.y * (65535 / iScreenY); 863 SendInput(1, Input, sizeof(INPUT)); 864 865 #ifdef DEBUG_andy 866 CURSORINFO ci; 867 RT_ZERO(ci); 868 ci.cbSize = sizeof(ci); 869 BOOL fRc = GetCursorInfo(&ci); 870 if (fRc) 871 LogFlowThisFunc(("Cursor shown=%RTbool, cursor=0x%p, x=%d, y=%d\n", 872 (ci.flags & CURSOR_SHOWING) ? true : false, 873 ci.hCursor, ci.ptScreenPos.x, ci.ptScreenPos.y)); 874 #endif 875 } 876 877 int rc2= VbglR3DnDGHAcknowledgePending(mClientID, 878 DND_COPY_ACTION, DND_COPY_ACTION, "text/plain;charset=utf-8"); 879 LogFlowThisFunc(("sent=%Rrc\n", rc2)); 880 881 LogFlowFuncLeaveRC(rc); 882 return rc; 883 } 884 885 int VBoxDnDWnd::OnGhDropped(const char *pszFormats, uint32_t cbFormats, 886 uint32_t uDefAction) 887 { 888 LogFlowThisFunc(("mMode=%ld, mState=%ld, cbFormats=%RU32, uDefAction=0x%x\n", 889 mMode, mState, cbFormats, uDefAction)); 890 891 int rc; 892 if (mState == Dragging) 893 { 894 } 895 else 896 rc = VERR_WRONG_ORDER; 897 898 LogFlowFuncLeaveRC(rc); 899 return rc; 900 } 901 #endif /* VBOX_WITH_DRAG_AND_DROP_GH */ 902 903 int VBoxDnDWnd::ProcessEvent(PVBOXDNDEVENT pEvent) 904 { 905 AssertPtrReturn(pEvent, VERR_INVALID_POINTER); 906 907 PostMessage(hWnd, WM_VBOXTRAY_DND_MESSAGE, 908 0 /* wParm */, (LPARAM)pEvent /* lParm */); 909 910 return VINF_SUCCESS; 911 } 912 913 int VBoxDnDWnd::dragRelease(void) 914 { 915 /* Release mouse button in the guest to start the "drop" 916 * action at the current mouse cursor position. */ 917 INPUT Input[1] = { 0 }; 918 Input[0].type = INPUT_MOUSE; 919 Input[0].mi.dwFlags = MOUSEEVENTF_LEFTUP; 920 SendInput(1, Input, sizeof(INPUT)); 921 922 return VINF_SUCCESS; 923 } 924 925 int VBoxDnDWnd::hide(void) 926 { 927 ShowWindow(hWnd, SW_HIDE); 928 929 return VINF_SUCCESS; 930 } 931 932 int VBoxDnDWnd::makeFullscreen(void) 933 { 934 int rc = VINF_SUCCESS; 935 745 936 RECT r; 746 937 RT_ZERO(r); 747 938 748 if (RT_SUCCESS(rc)) 749 { 750 HDC hDC = GetDC(NULL); 751 BOOL fRc = EnumDisplayMonitors(hDC, NULL, VBoxDnDWnd::MonitorEnumProc, (LPARAM)&r); 939 BOOL fRc; 940 HDC hDC = GetDC(NULL /* Entire screen */); 941 if (hDC) 942 { 943 fRc = EnumDisplayMonitors(hDC, NULL, VBoxDnDWnd::MonitorEnumProc, 944 (LPARAM)&r); 752 945 if (!fRc) 753 946 rc = VERR_NOT_FOUND; 754 947 ReleaseDC(NULL, hDC); 755 948 } 949 else 950 rc = VERR_ACCESS_DENIED; 756 951 757 952 if (RT_FAILURE(rc)) … … 772 967 if (RT_SUCCESS(rc)) 773 968 { 774 SetWindowPos(hWnd, HWND_TOPMOST,775 r.left,776 r.top,777 r.right- r.left,778 r.bottom - r.top,969 fRc = SetWindowPos(hWnd, HWND_TOPMOST, 970 r.left, 971 r.top, 972 r.right - r.left, 973 r.bottom - r.top, 779 974 #ifdef VBOX_DND_DEBUG_WND 780 SWP_SHOWWINDOW);975 SWP_SHOWWINDOW); 781 976 #else 782 SWP_SHOWWINDOW | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); 783 #endif 784 LogFlowFunc(("Virtual screen is %ld,%ld,%ld,%ld (%ld x %ld)\n", 785 r.left, r.top, r.right, r.bottom, 786 r.right - r.left, r.bottom - r.top)); 977 SWP_SHOWWINDOW | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOACTIVATE); 978 #endif 979 if (fRc) 980 LogFlowFunc(("Virtual screen is %ld,%ld,%ld,%ld (%ld x %ld)\n", 981 r.left, r.top, r.right, r.bottom, 982 r.right - r.left, r.bottom - r.top)); 983 else 984 { 985 DWORD dwErr = GetLastError(); 986 LogRel(("DnD: Failed to set proxy window position, rc=%Rrc\n", 987 RTErrConvertFromWin32(dwErr))); 988 } 787 989 } 788 990 else … … 793 995 } 794 996 795 int VBoxDnDWnd::OnHgMove(uint32_t u32xPos, uint32_t u32yPos, uint32_t uAction)796 {797 LogFlowThisFunc(("u32xPos=%RU32, u32yPos=%RU32, uAction=0x%x\n",798 u32xPos, u32yPos, uAction));799 800 /** @todo Multi-monitor setups? */801 int iScreenX = GetSystemMetrics(SM_CXSCREEN) - 1;802 int iScreenY = GetSystemMetrics(SM_CYSCREEN) - 1;803 804 INPUT Input[1] = { 0 };805 Input[0].type = INPUT_MOUSE;806 Input[0].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE;807 Input[0].mi.dx = u32xPos * (65535 / iScreenX);808 Input[0].mi.dy = u32yPos * (65535 / iScreenY);809 SendInput(1, Input, sizeof(INPUT));810 811 #ifdef DEBUG812 POINT p;813 GetCursorPos(&p);814 LogFlowThisFunc(("curX=%d, cury=%d\n", p.x, p.y));815 #endif816 817 uint32_t uActionNotify = DND_IGNORE_ACTION;818 int rc = RTCritSectEnter(&mCritSect);819 if (RT_SUCCESS(rc))820 {821 if ( (Dragging == mState)822 && startupInfo.pDropSource)823 uActionNotify = startupInfo.pDropSource->GetCurrentAction();824 825 RTCritSectLeave(&mCritSect);826 }827 828 if (RT_SUCCESS(rc))829 {830 rc = VbglR3DnDHGAcknowledgeOperation(mClientID, uActionNotify);831 if (RT_FAILURE(rc))832 LogFlowThisFunc(("Acknowleding operation failed with rc=%Rrc\n", rc));833 }834 835 LogFlowThisFunc(("Returning uActionNotify=0x%x, rc=%Rrc\n", uActionNotify, rc));836 return rc;837 }838 839 int VBoxDnDWnd::OnHgLeave(void)840 {841 LogFlowThisFunc(("mMode=%RU32, mState=%RU32\n", mMode, mState));842 LogRel(("DnD: Drag'n drop operation aborted\n"));843 844 reset();845 846 int rc = VINF_SUCCESS;847 848 /* Post ESC to our window to officially abort the849 * drag'n drop operation. */850 PostMessage(hWnd, WM_KEYDOWN, VK_ESCAPE, 0 /* lParam */);851 852 LogFlowFuncLeaveRC(rc);853 return rc;854 }855 856 int VBoxDnDWnd::OnHgDrop(void)857 {858 LogFlowThisFunc(("mMode=%RU32, mState=%RU32\n", mMode, mState));859 860 int rc = VINF_SUCCESS;861 if (mState == Dragging)862 {863 Assert(lstFormats.size() >= 1);864 865 /** @todo What to do when multiple formats are available? */866 mFormatRequested = lstFormats.at(0);867 868 rc = RTCritSectEnter(&mCritSect);869 if (RT_SUCCESS(rc))870 {871 if (startupInfo.pDataObject)872 startupInfo.pDataObject->SetStatus(VBoxDnDDataObject::Dropping);873 else874 rc = VERR_NOT_FOUND;875 876 RTCritSectLeave(&mCritSect);877 }878 879 if (RT_SUCCESS(rc))880 {881 LogRel(("DnD: Requesting data as '%s' ...\n", mFormatRequested.c_str()));882 rc = VbglR3DnDHGRequestData(mClientID, mFormatRequested.c_str());883 if (RT_FAILURE(rc))884 LogFlowThisFunc(("Requesting data failed with rc=%Rrc\n", rc));885 }886 }887 888 LogFlowFuncLeaveRC(rc);889 return rc;890 }891 892 int VBoxDnDWnd::OnHgDataReceived(const void *pvData, uint32_t cbData)893 {894 LogFlowThisFunc(("mState=%ld, pvData=%p, cbData=%RU32\n",895 mState, pvData, cbData));896 897 mState = Dropped;898 899 int rc = VINF_SUCCESS;900 if (pvData)901 {902 Assert(cbData);903 rc = RTCritSectEnter(&mCritSect);904 if (RT_SUCCESS(rc))905 {906 if (startupInfo.pDataObject)907 rc = startupInfo.pDataObject->Signal(mFormatRequested, pvData, cbData);908 else909 rc = VERR_NOT_FOUND;910 911 RTCritSectLeave(&mCritSect);912 }913 }914 915 int rc2 = DragRelease();916 if (RT_SUCCESS(rc))917 rc = rc2;918 919 LogFlowFuncLeaveRC(rc);920 return rc;921 }922 923 int VBoxDnDWnd::OnHgCancel(void)924 {925 int rc = RTCritSectEnter(&mCritSect);926 if (RT_SUCCESS(rc))927 {928 if (startupInfo.pDataObject)929 startupInfo.pDataObject->Abort();930 931 RTCritSectLeave(&mCritSect);932 }933 934 int rc2 = DragRelease();935 if (RT_SUCCESS(rc))936 rc = rc2;937 938 return rc;939 }940 941 #ifdef VBOX_WITH_DRAG_AND_DROP_GH942 int VBoxDnDWnd::OnGhIsDnDPending(void)943 {944 return 0;945 }946 947 int VBoxDnDWnd::OnGhDropped(const RTCString &strFormat, uint32_t action)948 {949 return 0;950 }951 #endif /* VBOX_WITH_DRAG_AND_DROP_GH */952 953 int VBoxDnDWnd::ProcessEvent(PVBOXDNDEVENT pEvent)954 {955 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);956 957 PostMessage(hWnd, WM_VBOXTRAY_DND_MESSAGE,958 0 /* wParm */, (LPARAM)pEvent /* lParm */);959 960 return VINF_SUCCESS;961 }962 963 997 void VBoxDnDWnd::reset(void) 964 998 { 965 LogFlowThisFunc((" mState=%ld\n", mState));999 LogFlowThisFunc(("Old mState=%ld\n", mState)); 966 1000 967 1001 lstAllowedFormats.clear(); 968 1002 lstFormats.clear(); 969 1003 uAllActions = DND_IGNORE_ACTION; 1004 1005 mMode = Unknown; 1006 mState = Initialized; 970 1007 } 971 1008 … … 1109 1146 AssertPtr(pWnd); 1110 1147 1148 /* Number of invalid messages skipped in a row. */ 1149 int cMsgSkippedInvalid = 0; 1150 1111 1151 do 1112 1152 { … … 1127 1167 if (RT_SUCCESS(rc)) 1128 1168 { 1169 cMsgSkippedInvalid = 0; /* Reset skipped messages count. */ 1170 1129 1171 LogFlowFunc(("Received new event, type=%RU32\n", pEvent->Event.uType)); 1130 1172 … … 1140 1182 } 1141 1183 else 1184 { 1142 1185 LogFlowFunc(("Processing next message failed with rc=%Rrc\n", rc)); 1186 1187 /* Old(er) hosts either are broken regarding DnD support or otherwise 1188 * don't support the stuff we do on the guest side, so make sure we 1189 * don't process invalid messages forever. */ 1190 if (rc == VERR_INVALID_PARAMETER) 1191 cMsgSkippedInvalid++; 1192 if (cMsgSkippedInvalid > 3) 1193 { 1194 LogFlowFunc(("Too many invalid/skipped messages from host, exiting ...\n")); 1195 break; 1196 } 1197 } 1143 1198 1144 1199 if (ASMAtomicReadBool(&pCtx->fShutdown)) -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.h
r49947 r50101 5 5 6 6 /* 7 * Copyright (C) 2013 Oracle Corporation7 * Copyright (C) 2013-2014 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 18 18 #ifndef __VBOXTRAYDND__H 19 19 #define __VBOXTRAYDND__H 20 21 #include <iprt/critsect.h> 20 22 21 23 #include <iprt/cpp/mtlist.h> … … 130 132 }; 131 133 134 class VBoxDnDDropTarget : public IDropTarget 135 { 136 public: 137 138 VBoxDnDDropTarget(VBoxDnDWnd *pThis); 139 virtual ~VBoxDnDDropTarget(void); 140 141 public: 142 143 static int CreateDropTarget(VBoxDnDWnd *pParent, IDropTarget **ppDropTarget); 144 145 public: /* IUnknown methods. */ 146 147 STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject); 148 STDMETHOD_(ULONG, AddRef)(void); 149 STDMETHOD_(ULONG, Release)(void); 150 151 public: /* IDropTarget methods. */ 152 153 STDMETHOD(DragEnter)(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect); 154 STDMETHOD(DragOver)(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect); 155 STDMETHOD(DragLeave)(void); 156 STDMETHOD(Drop)(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect); 157 158 protected: 159 160 static DWORD GetDropEffect(DWORD grfKeyState, DWORD dwAllowedEffects); 161 162 protected: 163 164 LONG mRefCount; 165 VBoxDnDWnd *mpWndParent; 166 uint32_t mClientID; 167 DWORD mdwCurEffect; 168 IDataObject *mpDataObject; 169 bool mfHasDropData; 170 }; 171 132 172 class VBoxDnDEnumFormatEtc : public IEnumFORMATETC 133 173 { … … 160 200 FORMATETC * m_pFormatEtc; 161 201 }; 202 203 struct VBOXDNDCONTEXT; 204 class VBoxDnDWnd; 205 206 /* 207 * A drag'n drop event from the host. 208 */ 209 typedef struct VBOXDNDEVENT 210 { 211 /** The actual event data. */ 212 VBGLR3DNDHGCMEVENT Event; 213 214 } VBOXDNDEVENT, *PVBOXDNDEVENT; 215 216 /** 217 * DnD context data. 218 */ 219 typedef struct VBOXDNDCONTEXT 220 { 221 /** Pointer to the service environment. */ 222 const VBOXSERVICEENV *pEnv; 223 /** Shutdown indicator. */ 224 bool fShutdown; 225 /** Thread handle for main event queue 226 * processing. */ 227 RTTHREAD hEvtQueue; 228 /** The DnD main event queue. */ 229 RTCMTList<VBOXDNDEVENT> lstEvtQueue; 230 /** Semaphore for waiting on main event queue 231 * events. */ 232 RTSEMEVENT hEvtQueueSem; 233 /** List of drag'n drop windows. At 234 * the moment only one source is supported. */ 235 RTCMTList<VBoxDnDWnd*> lstWnd; 236 237 } VBOXDNDCONTEXT, *PVBOXDNDCONTEXT; 238 static VBOXDNDCONTEXT gCtx = {0}; 239 240 /** 241 * Everything which is required to successfully start 242 * a drag'n drop operation via DoDragDrop(). 243 */ 244 typedef struct VBOXDNDSTARTUPINFO 245 { 246 /** Our DnD data object, holding 247 * the raw DnD data. */ 248 VBoxDnDDataObject *pDataObject; 249 /** The drop source for sending the 250 * DnD request to a IDropTarget. */ 251 VBoxDnDDropSource *pDropSource; 252 /** The DnD effects which are wanted / allowed. */ 253 DWORD dwOKEffects; 254 255 } VBOXDNDSTARTUPINFO, *PVBOXDNDSTARTUPINFO; 256 257 /** 258 * Class for handling a DnD proxy window. 259 ** @todo Unify this and VBoxClient's DragInstance! 260 */ 261 class VBoxDnDWnd 262 { 263 /** 264 * Current state of a DnD proxy 265 * window. 266 */ 267 enum State 268 { 269 Uninitialized = 0, 270 Initialized, 271 Dragging, 272 Dropped, 273 Canceled 274 }; 275 276 /** 277 * Current operation mode of 278 * a DnD proxy window. 279 */ 280 enum Mode 281 { 282 /** Unknown mode. */ 283 Unknown = 0, 284 /** Host to guest. */ 285 HG, 286 /** Guest to host. */ 287 GH 288 }; 289 290 public: 291 292 VBoxDnDWnd(void); 293 virtual ~VBoxDnDWnd(void); 294 295 public: 296 297 int Initialize(PVBOXDNDCONTEXT pContext); 298 299 public: 300 301 /** The window's thread for the native message pump and 302 * OLE context. */ 303 static int Thread(RTTHREAD hThread, void *pvUser); 304 305 public: 306 307 static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM lParam); 308 /** The per-instance wndproc routine. */ 309 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 310 311 public: 312 313 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 314 int RegisterAsDropTarget(void); 315 int UnregisterAsDropTarget(void); 316 #endif 317 318 public: 319 320 int OnCreate(void); 321 void OnDestroy(void); 322 323 /* H->G */ 324 int OnHgEnter(const RTCList<RTCString> &formats, uint32_t uAllActions); 325 int OnHgMove(uint32_t u32xPos, uint32_t u32yPos, uint32_t uAllActions); 326 int OnHgDrop(void); 327 int OnHgLeave(void); 328 int OnHgDataReceived(const void *pvData, uint32_t cData); 329 int OnHgCancel(void); 330 331 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 332 /* G->H */ 333 int OnGhIsDnDPending(uint32_t uScreenID); 334 int OnGhDropped(const char *pszFormats, uint32_t cbFormats, uint32_t uDefAction); 335 #endif 336 337 int ProcessEvent(PVBOXDNDEVENT pEvent); 338 339 public: 340 341 int hide(void); 342 343 protected: 344 345 int dragRelease(void); 346 int makeFullscreen(void); 347 void reset(void); 348 349 public: /** @todo Make protected! */ 350 351 /** Pointer to DnD context. */ 352 PVBOXDNDCONTEXT pContext; 353 RTCRITSECT mCritSect; 354 RTSEMEVENT mEventSem; 355 #ifdef RT_OS_WINDOWS 356 /** The window's handle. */ 357 HWND hWnd; 358 /** List of allowed MIME types this 359 * client can handle. Make this a per-instance 360 * property so that we can selectively allow/forbid 361 * certain types later on runtime. */ 362 RTCList<RTCString> lstAllowedFormats; 363 /** List of formats for the current 364 * drag'n drop operation. */ 365 RTCList<RTCString> lstFormats; 366 /** Flags of all current drag'n drop 367 * actions allowed. */ 368 uint32_t uAllActions; 369 /** The startup information required 370 * for the actual DoDragDrop() call. */ 371 VBOXDNDSTARTUPINFO startupInfo; 372 /** Is the left mouse button being pressed 373 * currently while being in this window? */ 374 bool mfMouseButtonDown; 375 # ifdef VBOX_WITH_DRAG_AND_DROP_GH 376 IDropTarget *pDropTarget; 377 # endif /* VBOX_WITH_DRAG_AND_DROP_GH */ 378 #else 379 /** @todo Implement me. */ 380 #endif 381 382 /** The window's own HGCM client ID. */ 383 uint32_t mClientID; 384 /** The current operation mode. */ 385 Mode mMode; 386 /** The current state. */ 387 State mState; 388 RTCString mFormatRequested; 389 RTCList<RTCString> mLstFormats; 390 RTCList<RTCString> mLstActions; 391 }; 162 392 #endif /* __VBOXTRAYDND__H */ 163 393 -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnDDataObject.cpp
r49947 r50101 5 5 6 6 /* 7 * Copyright (C) 2013 Oracle Corporation7 * Copyright (C) 2013-2014 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 355 355 RTMemFree(pBuf); 356 356 } 357 else 358 rc = VERR_NO_MEMORY; 359 360 if (RT_FAILURE(rc)) 361 hr = DV_E_FORMATETC; 357 362 } 358 363 } … … 362 367 { 363 368 LogFlowFunc(("Copying medium ...\n")); 364 switch (pThisMedium->tymed)369 switch (pThisMedium->tymed) 365 370 { 366 371 367 372 case TYMED_HGLOBAL: 368 pMedium->hGlobal = (HGLOBAL)OleDuplicateData(pThisMedium->hGlobal, pThisFormat->cfFormat, NULL); 373 pMedium->hGlobal = (HGLOBAL)OleDuplicateData(pThisMedium->hGlobal, 374 pThisFormat->cfFormat, NULL); 369 375 break; 370 376 … … 373 379 } 374 380 375 pMedium->tymed 381 pMedium->tymed = pThisFormat->tymed; 376 382 pMedium->pUnkForRelease = NULL; 377 383 } … … 569 575 pFormatEtc->tymed, pFormatEtc->cfFormat, VBoxDnDDataObject::ClipboardFormatToString(pFormatEtc->cfFormat), 570 576 pFormatEtc->dwAspect)); 577 571 578 return false; 572 573 579 } 574 580
Note:
See TracChangeset
for help on using the changeset viewer.