VirtualBox

Changeset 50265 in vbox for trunk/src/VBox/Additions/WINNT


Ignore:
Timestamp:
Jan 29, 2014 11:12:44 AM (11 years ago)
Author:
vboxsync
Message:

DnD: First working implementation for Windows guest->host support; still work in progress. As for now only pure text data can be dragged over.

Location:
trunk/src/VBox/Additions/WINNT/VBoxTray
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp

    r50179 r50265  
    229229        } while (RT_SUCCESS(rc));
    230230
     231        int rc2 = pThis->UnregisterAsDropTarget();
     232        if (RT_SUCCESS(rc))
     233            rc = rc2;
     234
    231235        OleUninitialize();
    232236    }
     
    405409                    reset();
    406410
    407                     Assert(mMode == Unknown);
    408411                    mMode = HG;
    409412
     
    464467
    465468                    rc = OnHgCancel();
    466 
    467                     reset();
    468469                    break;
    469470                }
     
    473474                    LogFlowThisFunc(("HOST_DND_GH_REQ_PENDING\n"));
    474475#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    475                     Assert(   mMode == Unknown
    476                            || mMode == GH);
    477                     mMode = GH;
    478                     rc = OnGhIsDnDPending(pEvent->Event.uScreenId);
     476                    if (   mMode == Unknown
     477                        /* There can be more than one HOST_DND_GH_REQ_PENDING
     478                         * messages coming in. */
     479                        || mMode == GH)
     480                    {
     481                        mMode = GH;
     482                        rc = OnGhIsDnDPending(pEvent->Event.uScreenId);
     483                    }
     484                    else
     485                        rc = VERR_WRONG_ORDER;
    479486#else
    480487                    rc = VERR_NOT_SUPPORTED;
     
    487494                    LogFlowThisFunc(("HOST_DND_GH_EVT_DROPPED\n"));
    488495#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    489                     Assert(mMode == GH);
    490                     rc = OnGhDropped(pEvent->Event.pszFormats,
    491                                      pEvent->Event.cbFormats,
    492                                      pEvent->Event.u.a.uDefAction);
    493                     mMode = Unknown;
     496                    if (mMode == GH)
     497                    {
     498                        rc = OnGhDropped(pEvent->Event.pszFormats,
     499                                         pEvent->Event.cbFormats,
     500                                         pEvent->Event.u.a.uDefAction);
     501                    }
     502                    else
     503                        rc = VERR_WRONG_ORDER;
    494504#else
    495505                    rc = VERR_NOT_SUPPORTED;
     
    585595        }
    586596        else
     597        {
    587598            rc = VINF_SUCCESS;
     599        }
    588600    }
    589601    catch (std::bad_alloc)
     
    598610int VBoxDnDWnd::UnregisterAsDropTarget(void)
    599611{
     612    LogFlowFuncEnter();
     613
    600614    if (!pDropTarget) /* No drop target? Bail out. */
    601615        return VINF_SUCCESS;
     
    606620                                  TRUE /* fLastUnlockReleases */);
    607621    if (SUCCEEDED(hr))
    608         pDropTarget->Release();
     622    {
     623        ULONG cRefs = pDropTarget->Release();
     624
     625        Assert(cRefs == 0);
     626        pDropTarget = NULL;
     627    }
    609628
    610629    int rc = SUCCEEDED(hr)
     
    652671     */
    653672    const RTCList<RTCString> lstAllowedMimeTypes = RTCList<RTCString>()
    654         /* Uri's */
     673        /* URI's */
    655674        << "text/uri-list"
    656675        /* Text */
     
    661680        << "TEXT"
    662681        << "STRING"
    663         /* OpenOffice formates */
     682        /* OpenOffice formats */
    664683        << "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\""
    665684        << "application/x-openoffice-drawing;windows_formatname=\"Drawing Format\"";
     
    855874    if (RT_SUCCESS(rc))
    856875        rc = rc2;
     876
     877    reset();
    857878
    858879    return rc;
     
    959980    if (RT_SUCCESS(rc))
    960981    {
     982        AssertPtr(pDropTarget);
     983
    961984        uint32_t uDefAction = DND_IGNORE_ACTION;
    962985        RTCString strFormat = "unknown";
    963         if (   pDropTarget
    964             && pDropTarget->HasData())
     986        if (pDropTarget->HasData())
    965987        {
    966988            uDefAction = DND_COPY_ACTION;
     
    970992             *        with \r\n. */
    971993            strFormat = "text/plain;charset=utf-8";
    972         }
    973 
    974         LogFlowFunc(("Acknowledging pDropTarget=0x%p, uDefAction=0x%x, uAllActions=0x%x, strFormat=%s\n",
    975                      pDropTarget, uDefAction, uAllActions, strFormat.c_str()));
    976         rc = VbglR3DnDGHAcknowledgePending(mClientID,
    977                                            uDefAction, uAllActions, strFormat.c_str());
     994
     995            LogFlowFunc(("Acknowledging pDropTarget=0x%p, uDefAction=0x%x, uAllActions=0x%x, strFormat=%s\n",
     996                         pDropTarget, uDefAction, uAllActions, strFormat.c_str()));
     997            rc = VbglR3DnDGHAcknowledgePending(mClientID,
     998                                               uDefAction, uAllActions, strFormat.c_str());
     999        }
    9781000    }
    9791001
     
    9851007                            uint32_t uDefAction)
    9861008{
    987     LogFlowThisFunc(("mMode=%ld, mState=%ld, cbFormats=%RU32, uDefAction=0x%x\n",
    988                      mMode, mState, cbFormats, uDefAction));
     1009    LogFlowThisFunc(("mMode=%ld, mState=%ld, pDropTarget=0x%p, cbFormats=%RU32, uDefAction=0x%x\n",
     1010                     mMode, mState, pDropTarget, cbFormats, uDefAction));
    9891011    int rc;
    9901012    if (mState == Dragging)
    9911013    {
    9921014        AssertPtr(pDropTarget);
     1015        rc = pDropTarget->WaitForDrop(30 * 1000 /* Timeout */);
     1016        if (RT_SUCCESS(rc))
     1017        {
     1018            /** @todo Respect uDefAction. */
     1019            /** @todo Do data checking / conversion based on pszFormats. */
     1020
     1021            void *pvData = pDropTarget->DataMutableRaw();
     1022            AssertPtr(pvData);
     1023            uint32_t cbData = pDropTarget->DataSize();
     1024            Assert(cbData);
     1025
     1026            rc = VbglR3DnDGHSendData(mClientID, pvData, cbData);
     1027            LogFlowFunc(("Sent pvData=0x%p, cbData=%RU32, rc=%Rrc\n",
     1028                         pvData, cbData, rc));
     1029        }
     1030
     1031        reset();
    9931032    }
    9941033    else
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.h

    r50177 r50265  
    151151
    152152    static DWORD GetDropEffect(DWORD grfKeyState, DWORD dwAllowedEffects);
    153 
    154 public:
    155 
    156     const IDataObject *GetDataObject(void) { return mpDataObject; }
    157     bool HasData(void) { return mfHasDropData; }
     153    void reset(void);
     154
     155public:
     156
     157    bool HasData(void) { return RT_BOOL(mFormatEtc.cfFormat != 0); }
     158    void *DataMutableRaw(void) { return mpvData; }
     159    uint32_t DataSize(void) { return mcbData; }
     160    int WaitForDrop(RTMSINTERVAL msTimeout);
    158161
    159162protected:
     
    163166    uint32_t mClientID;
    164167    DWORD mdwCurEffect;
    165     IDataObject *mpDataObject;
    166     bool mfHasDropData;
     168    /** Copy of the data object's FORMATETC struct.
     169     *  Note: We don't keep the pointer of the
     170     *        DVTARGETDEVICE here! */
     171    FORMATETC mFormatEtc;
     172    void *mpvData;
     173    uint32_t mcbData;
     174    RTSEMEVENT hEventDrop;
    167175};
    168176
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnDDropTarget.cpp

    r50177 r50265  
    3131      mClientID(UINT32_MAX),
    3232      mdwCurEffect(0),
    33       mpDataObject(NULL),
    34       mfHasDropData(false)
     33      mpvData(NULL),
     34      mcbData(0),
     35      hEventDrop(NIL_RTSEMEVENT)
    3536{
    3637    int rc = VbglR3DnDConnect(&mClientID);
     38    if (RT_SUCCESS(rc))
     39        rc = RTSemEventCreate(&hEventDrop);
    3740
    3841    LogFlowFunc(("clientID=%RU32, rc=%Rrc\n",
     
    4245VBoxDnDDropTarget::~VBoxDnDDropTarget(void)
    4346{
    44     int rc = VbglR3DnDDisconnect(mClientID);
    45 
    46     LogFlowFunc(("rc=%Rrc, mRefCount=%RI32\n", rc, mRefCount));
     47    reset();
     48
     49    int rc2 = VbglR3DnDDisconnect(mClientID);
     50    AssertRC(rc2);
     51    rc2 = RTSemEventDestroy(hEventDrop);
     52    AssertRC(rc2);
     53
     54    LogFlowFunc(("rc=%Rrc, mRefCount=%RI32\n", rc2, mRefCount));
    4755}
    4856
     
    94102    AssertPtrReturn(pdwEffect, E_INVALIDARG);
    95103
    96     LogFlowFunc(("mfHasDropData=%RTbool, pDataObject=0x%p, grfKeyState=0x%x, x=%ld, y=%ld, dwEffect=%RU32\n",
    97                  mfHasDropData, pDataObject, grfKeyState, pt.x, pt.y, *pdwEffect));
    98 
    99     FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
    100 
    101     /* We only handle CF_HDROP in an HGLOBAL medium at the moment. */
    102     HRESULT hr = pDataObject->QueryGetData(&fmtetc);
    103     mfHasDropData = hr == S_OK;
    104 
    105     if (mfHasDropData)
    106     {
     104    LogFlowFunc(("pDataObject=0x%p, grfKeyState=0x%x, x=%ld, y=%ld, dwEffect=%RU32\n",
     105                 pDataObject, grfKeyState, pt.x, pt.y, *pdwEffect));
     106
     107    reset();
     108
     109    /* Try different formats. CF_HDROP is the most common one, so start
     110     * with this. */
     111    /** @todo At the moment we only support TYMED_HGLOBAL. */
     112    FORMATETC fmtEtc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
     113    HRESULT hr = pDataObject->QueryGetData(&fmtEtc);
     114    if (hr != S_OK)
     115    {
     116        LogFlowFunc(("CF_HDROP not supported, hr=%Rhrc\n", hr));
     117
     118        /* So we couldn't retrieve the data in CF_HDROP format; try with
     119         * CF_TEXT format now. Rest stays the same. */
     120        fmtEtc.cfFormat = CF_TEXT;
     121        hr = pDataObject->QueryGetData(&fmtEtc);
     122        if (hr != S_OK)
     123        {
     124            LogFlowFunc(("CF_TEXT not supported, hr=%Rhrc\n", hr));
     125            fmtEtc.cfFormat = 0; /* Mark it to not supported. */
     126        }
     127    }
     128
     129    /* Did we find a format that we support? */
     130    if (fmtEtc.cfFormat)
     131    {
     132        LogFlowFunc(("Found supported format %RI16\n", fmtEtc.cfFormat));
     133
     134        /* Make a copy of the FORMATETC structure so that we later can
     135         * use this for comparrison and stuff. */
     136        /** Note: The DVTARGETDEVICE member only is a shallow copy! */
     137        memcpy(&mFormatEtc, &fmtEtc, sizeof(FORMATETC));
     138
    107139        /* Which drop effect we're going to use? */
    108140        /* Note: pt is not used since we don't need to differentiate within our
     
    114146        /* No or incompatible data -- so no drop effect required. */
    115147        *pdwEffect = DROPEFFECT_NONE;
    116     }
    117 
    118     LogFlowFunc(("Returning mfHasDropData=%RTbool, pdwEffect=%ld, hr=%Rhrc\n",
    119                  mfHasDropData, *pdwEffect, hr));
     148
     149        switch (hr)
     150        {
     151            case ERROR_INVALID_FUNCTION:
     152            {
     153                LogRel(("DnD: Drag'n drop format is not supported by VBoxTray\n"));
     154
     155                /* Enumerate supported source formats. This shouldn't happen too often
     156                 * on day to day use, but still keep it in here. */
     157                IEnumFORMATETC *pEnumFormats;
     158                HRESULT hr2 = pDataObject->EnumFormatEtc(DATADIR_GET, &pEnumFormats);
     159                if (SUCCEEDED(hr2))
     160                {
     161                    LogRel(("DnD: The following formats were offered to us:\n"));
     162
     163                    FORMATETC curFormatEtc;
     164                    while (pEnumFormats->Next(1, &curFormatEtc,
     165                                              NULL /* pceltFetched */) == S_OK)
     166                        {
     167                        WCHAR wszCfName[128]; /* 128 chars should be enough, rest will be truncated. */
     168                        hr2 = GetClipboardFormatNameW(curFormatEtc.cfFormat, wszCfName,
     169                                                      sizeof(wszCfName) / sizeof(WCHAR));
     170                        LogRel(("\tcfFormat=%RI16, tyMed=%RI32, dwAspect=%RI32, strCustomName=%ls, hr=%Rhrc\n",
     171                                curFormatEtc.cfFormat,
     172                                curFormatEtc.tymed,
     173                                curFormatEtc.dwAspect,
     174                                wszCfName, hr2));
     175                    }
     176
     177                    pEnumFormats->Release();
     178                }
     179
     180                break;
     181            }
     182
     183            default:
     184                break;
     185        }
     186    }
     187
     188    LogFlowFunc(("Returning cfFormat=%RI16, pdwEffect=%ld, hr=%Rhrc\n",
     189                 fmtEtc.cfFormat, *pdwEffect, hr));
    120190    return hr;
    121191}
     
    126196
    127197#ifdef DEBUG_andy
    128     LogFlowFunc(("mfHasDropData=%RTbool, grfKeyState=0x%x, x=%ld, y=%ld\n",
    129                  mfHasDropData, grfKeyState, pt.x, pt.y));
     198    LogFlowFunc(("cfFormat=%RI16, grfKeyState=0x%x, x=%ld, y=%ld\n",
     199                 mFormatEtc.cfFormat, grfKeyState, pt.x, pt.y));
    130200#endif
    131201
    132     if (mfHasDropData)
     202    if (mFormatEtc.cfFormat)
    133203    {
    134204        /* Note: pt is not used since we don't need to differentiate within our
     
    150220{
    151221#ifdef DEBUG_andy
    152     LogFlowFunc(("mfHasDropData=%RTbool\n", mfHasDropData));
     222    LogFlowFunc(("cfFormat=%RI16\n", mFormatEtc.cfFormat));
    153223#endif
    154224
    155     mpWndParent->hide();
     225    if (mpWndParent)
     226        mpWndParent->hide();
    156227
    157228    return S_OK;
     
    165236
    166237#ifdef DEBUG
    167     LogFlowFunc(("mfHasDropData=%RTbool, pDataObject=0x%p, grfKeyState=0x%x, x=%ld, y=%ld\n",
    168                  mfHasDropData, pDataObject, grfKeyState, pt.x, pt.y));
     238    LogFlowFunc(("mFormatEtc.cfFormat=%RI16, pDataObject=0x%p, grfKeyState=0x%x, x=%ld, y=%ld\n",
     239                 mFormatEtc.cfFormat, pDataObject, grfKeyState, pt.x, pt.y));
    169240#endif
     241    HRESULT hr = S_OK;
     242
    170243    bool fCanDrop = false;
    171     if (mfHasDropData)
    172     {
    173         FORMATETC fmtEtc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
     244    if (mFormatEtc.cfFormat) /* Did we get a supported format yet? */
     245    {
     246        /* Make sure the data object's data format is still the same
     247         * as we got it in DragEnter(). */
     248        hr = pDataObject->QueryGetData(&mFormatEtc);
     249        AssertMsg(SUCCEEDED(hr),
     250                  ("Data format changed between DragEnter() and Drop(), cfFormat=%RI16, hr=%Rhrc\n",
     251                  mFormatEtc.cfFormat, hr));
     252    }
     253
     254    if (SUCCEEDED(hr))
     255    {
    174256        STGMEDIUM stgMed;
    175 
    176         AssertPtr(pDataObject);
    177         if (   (pDataObject->QueryGetData(&fmtEtc)     == S_OK)
    178             && (pDataObject->GetData(&fmtEtc, &stgMed) == S_OK))
     257        hr = pDataObject->GetData(&mFormatEtc, &stgMed);
     258        if (SUCCEEDED(hr))
    179259        {
    180             PVOID pvData = GlobalLock(stgMed.hGlobal);
    181 #ifdef DEBUG
    182             if (fmtEtc.cfFormat == CF_TEXT)
    183                 LogFlowFunc(("pvData=%s\n", (char*)pvData));
    184 #endif
    185             GlobalUnlock(stgMed.hGlobal);
     260            /*
     261             * First stage: Prepare the access to the storage medium.
     262             *              For now we only support HGLOBAL stuff.
     263             */
     264            PVOID pvData = NULL; /** @todo Put this in an own union? */
     265
     266            switch (mFormatEtc.tymed)
     267            {
     268                case TYMED_HGLOBAL:
     269                    pvData = GlobalLock(stgMed.hGlobal);
     270                    if (!pvData)
     271                    {
     272                        LogFlowFunc(("Locking HGLOBAL storage failed with %Rrc\n",
     273                                     RTErrConvertFromWin32(GetLastError())));
     274                        hr = ERROR_INVALID_HANDLE;
     275                    }
     276                    break;
     277
     278                default:
     279                    AssertMsgFailed(("Storage medium type %RI32 supported\n",
     280                                     mFormatEtc.tymed));
     281                    hr = ERROR_NOT_SUPPORTED;
     282                    break;
     283            }
     284
     285            if (SUCCEEDED(hr))
     286            {
     287                /* Second stage: Do the actual copying of the data object's data,
     288                                 based on the storage medium type. */
     289                switch (mFormatEtc.cfFormat)
     290                {
     291                    case CF_TEXT:
     292                    {
     293                        LogFlowFunc(("pvData=%s\n", (char*)pvData));
     294
     295                        uint32_t cbSize = strlen((char*)pvData); /** @todo Evil hack, fix this! */
     296                        mpvData = RTMemDup(pvData, cbSize);
     297                        mcbData = cbSize;
     298                        break;
     299                    }
     300
     301                    case CF_HDROP:
     302                        break;
     303
     304                    default:
     305                        AssertMsgFailed(("Format of type %RI16 supported\n",
     306                                         mFormatEtc.cfFormat));
     307                        hr = ERROR_NOT_SUPPORTED;
     308                        break;
     309                }
     310            }
     311
     312            /*
     313             * Third stage: Release access to the storage medium again.
     314             */
     315            switch (mFormatEtc.tymed)
     316            {
     317                case TYMED_HGLOBAL:
     318                    GlobalUnlock(stgMed.hGlobal);
     319                    break;
     320
     321                default:
     322                    AssertMsgFailed(("Storage medium type %RI32 supported\n",
     323                                     mFormatEtc.tymed));
     324                    hr = ERROR_NOT_SUPPORTED;
     325                    break;
     326            }
    186327
    187328            /* Release storage medium again. */
    188329            ReleaseStgMedium(&stgMed);
    189330
    190             fCanDrop = true;
     331            if (SUCCEEDED(hr))
     332            {
     333                RTSemEventSignal(hEventDrop);
     334                fCanDrop = true;
     335            }
    191336        }
    192337    }
     
    201346        *pdwEffect = DROPEFFECT_NONE;
    202347
    203     LogFlowFunc(("Returning with mfHasDropData=%RTbool, fCanDrop=%RTbool, *pdwEffect=%RI32\n",
    204                  mfHasDropData, fCanDrop, *pdwEffect));
    205     return S_OK;
     348    if (mpWndParent)
     349        mpWndParent->hide();
     350
     351    LogFlowFunc(("Returning with mFormatEtc.cfFormat=%RI16, fCanDrop=%RTbool, *pdwEffect=%RI32\n",
     352                 mFormatEtc.cfFormat, fCanDrop, *pdwEffect));
     353    return hr;
    206354}
    207355
     
    235383}
    236384
     385void VBoxDnDDropTarget::reset(void)
     386{
     387    LogFlowFuncEnter();
     388
     389    if (mpvData)
     390    {
     391        RTMemFree(mpvData);
     392        mpvData = NULL;
     393    }
     394
     395    mcbData = 0;
     396    RT_ZERO(mFormatEtc);
     397}
     398
     399int VBoxDnDDropTarget::WaitForDrop(RTMSINTERVAL msTimeout)
     400{
     401    LogFlowFunc(("msTimeout=%RU32\n", msTimeout));
     402    int rc = RTSemEventWait(hEventDrop, msTimeout);
     403    LogFlowFuncLeaveRC(rc);
     404    return rc;
     405}
     406
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette