VirtualBox

Ignore:
Timestamp:
Jun 19, 2023 9:11:37 AM (18 months ago)
Author:
vboxsync
Message:

Shared Clipboard: Unified root list entry code to also use the generic list entry code, a lot of updates for the cross OS transfer handling code, more updates for HTTP server transfer handling.

This also changed the handling of how that transfers are being initiated, as we needed to have this for X11: Before, transfers were initiated as soon as on side announced the URI list format -- now we postpone initiating the transfer until the receiving side requests the data as URI list.

bugref:9437

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp

    r99967 r100204  
    3838#include <iprt/win/shlwapi.h>
    3939
     40#include <iprt/thread.h> // REMOVE
     41
    4042#include <iprt/asm.h>
    4143#include <iprt/err.h>
     
    5254//#define VBOX_CLIPBOARD_WITH_UNICODE_SUPPORT 1
    5355
    54 SharedClipboardWinDataObject::SharedClipboardWinDataObject(PSHCLTRANSFER pTransfer,
    55                                                            LPFORMATETC pFormatEtc, LPSTGMEDIUM pStgMed, ULONG cFormats)
    56     : m_enmStatus(Uninitialized)
     56SharedClipboardWinDataObject::SharedClipboardWinDataObject(void)
     57    : m_pCtx(NULL)
     58    , m_enmStatus(Uninitialized)
    5759    , m_lRefCount(0)
    5860    , m_cFormats(0)
    59     , m_pTransfer(pTransfer)
     61    , m_pTransfer(NULL)
    6062    , m_pStream(NULL)
    6163    , m_uObjIdx(0)
    62     , m_fRunning(false)
     64    , m_fThreadRunning(false)
    6365    , m_EventListComplete(NIL_RTSEMEVENT)
    64     , m_EventTransferComplete(NIL_RTSEMEVENT)
    65 {
    66     AssertPtr(m_pTransfer);
    67 
    68     HRESULT hr;
     66    , m_EventStatusChanged(NIL_RTSEMEVENT)
     67{
     68}
     69
     70SharedClipboardWinDataObject::~SharedClipboardWinDataObject(void)
     71{
     72    Destroy();
     73
     74    LogFlowFunc(("mRefCount=%RI32\n", m_lRefCount));
     75}
     76
     77/**
     78 * Initializes a data object instance.
     79 *
     80 * @returns VBox status code.
     81 * @param   pFormatEtc          FormatETC to use.
     82 * @param   pStgMed             Storage medium to use.
     83 * @param   cFormats            Number of formats in \a pFormatEtc and \a pStgMed.
     84 */
     85int SharedClipboardWinDataObject::Init(PSHCLCONTEXT pCtx,
     86                                       LPFORMATETC pFormatEtc /* = NULL */, LPSTGMEDIUM pStgMed /* = NULL */,
     87                                       ULONG cFormats /* = 0 */)
     88{
     89    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     90    AssertReturn(cFormats == 0 || (RT_VALID_PTR(pFormatEtc) && RT_VALID_PTR(pStgMed)), VERR_INVALID_POINTER);
     91
     92    int rc = VINF_SUCCESS;
     93
     94    m_pCtx = pCtx; /* Save opaque context. */
    6995
    7096    ULONG cFixedFormats = 3; /* CFSTR_FILEDESCRIPTORA + CFSTR_FILECONTENTS + CFSTR_PERFORMEDDROPEFFECT */
     
    74100    const ULONG cAllFormats   = cFormats + cFixedFormats;
    75101
    76     try
    77     {
    78         m_pFormatEtc = new FORMATETC[cAllFormats];
    79         RT_BZERO(m_pFormatEtc, sizeof(FORMATETC) * cAllFormats);
    80         m_pStgMedium = new STGMEDIUM[cAllFormats];
    81         RT_BZERO(m_pStgMedium, sizeof(STGMEDIUM) * cAllFormats);
    82 
    83         /** @todo Do we need CFSTR_FILENAME / CFSTR_SHELLIDLIST here? */
    84 
    85         /*
    86          * Register fixed formats.
    87          */
    88         unsigned uIdx = 0;
    89 
    90         LogFlowFunc(("Registering CFSTR_FILEDESCRIPTORA ...\n"));
    91         m_cfFileDescriptorA = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
    92         registerFormat(&m_pFormatEtc[uIdx++], m_cfFileDescriptorA);
     102    m_pFormatEtc = new FORMATETC[cAllFormats];
     103    AssertPtrReturn(m_pFormatEtc, VERR_NO_MEMORY);
     104    RT_BZERO(m_pFormatEtc, sizeof(FORMATETC) * cAllFormats);
     105    m_pStgMedium = new STGMEDIUM[cAllFormats];
     106    AssertPtrReturn(m_pStgMedium, VERR_NO_MEMORY);
     107    RT_BZERO(m_pStgMedium, sizeof(STGMEDIUM) * cAllFormats);
     108
     109    /** @todo Do we need CFSTR_FILENAME / CFSTR_SHELLIDLIST here? */
     110
     111    /*
     112     * Register fixed formats.
     113     */
     114    unsigned uIdx = 0;
     115
     116    LogFlowFunc(("Registering CFSTR_FILEDESCRIPTORA ...\n"));
     117    m_cfFileDescriptorA = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
     118    registerFormat(&m_pFormatEtc[uIdx++], m_cfFileDescriptorA);
    93119#ifdef VBOX_CLIPBOARD_WITH_UNICODE_SUPPORT
    94         LogFlowFunc(("Registering CFSTR_FILEDESCRIPTORW ...\n"));
    95         m_cfFileDescriptorW = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
    96         registerFormat(&m_pFormatEtc[uIdx++], m_cfFileDescriptorW);
     120    LogFlowFunc(("Registering CFSTR_FILEDESCRIPTORW ...\n"));
     121    m_cfFileDescriptorW = RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
     122    registerFormat(&m_pFormatEtc[uIdx++], m_cfFileDescriptorW);
    97123#endif
    98124
    99         /* IStream interface, implemented in ClipboardStreamImpl-win.cpp. */
    100         LogFlowFunc(("Registering CFSTR_FILECONTENTS ...\n"));
    101         m_cfFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS);
    102         registerFormat(&m_pFormatEtc[uIdx++], m_cfFileContents, TYMED_ISTREAM, 0 /* lIndex */);
    103 
    104         /* We want to know from the target what the outcome of the operation was to react accordingly (e.g. abort a transfer). */
    105         LogFlowFunc(("Registering CFSTR_PERFORMEDDROPEFFECT ...\n"));
    106         m_cfPerformedDropEffect = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
    107         registerFormat(&m_pFormatEtc[uIdx++], m_cfPerformedDropEffect, TYMED_HGLOBAL, -1 /* lIndex */, DVASPECT_CONTENT);
    108 
    109         /*
    110          * Registration of dynamic formats needed?
    111          */
    112         LogFlowFunc(("%RU32 dynamic formats\n", cFormats));
    113         if (cFormats)
    114         {
    115             AssertPtr(pFormatEtc);
    116             AssertPtr(pStgMed);
    117 
    118             for (ULONG i = 0; i < cFormats; i++)
    119             {
    120                 LogFlowFunc(("Format %RU32: cfFormat=%RI16, tyMed=%RU32, dwAspect=%RU32\n",
    121                              i, pFormatEtc[i].cfFormat, pFormatEtc[i].tymed, pFormatEtc[i].dwAspect));
    122                 m_pFormatEtc[cFixedFormats + i] = pFormatEtc[i];
    123                 m_pStgMedium[cFixedFormats + i] = pStgMed[i];
    124             }
    125         }
    126 
    127         hr = S_OK;
    128     }
    129     catch (std::bad_alloc &)
    130     {
    131         hr = E_OUTOFMEMORY;
    132     }
    133 
    134     if (SUCCEEDED(hr))
     125    /* IStream interface, implemented in ClipboardStreamImpl-win.cpp. */
     126    LogFlowFunc(("Registering CFSTR_FILECONTENTS ...\n"));
     127    m_cfFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS);
     128    registerFormat(&m_pFormatEtc[uIdx++], m_cfFileContents, TYMED_ISTREAM, 0 /* lIndex */);
     129
     130    /* We want to know from the target what the outcome of the operation was to react accordingly (e.g. abort a transfer). */
     131    LogFlowFunc(("Registering CFSTR_PERFORMEDDROPEFFECT ...\n"));
     132    m_cfPerformedDropEffect = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
     133    registerFormat(&m_pFormatEtc[uIdx++], m_cfPerformedDropEffect, TYMED_HGLOBAL, -1 /* lIndex */, DVASPECT_CONTENT);
     134
     135    /*
     136     * Registration of dynamic formats needed?
     137     */
     138    LogFlowFunc(("%RU32 dynamic formats\n", cFormats));
     139    if (cFormats)
     140    {
     141        for (ULONG i = 0; i < cFormats; i++)
     142        {
     143            LogFlowFunc(("Format %RU32: cfFormat=%RI16, tyMed=%RU32, dwAspect=%RU32\n",
     144                         i, pFormatEtc[i].cfFormat, pFormatEtc[i].tymed, pFormatEtc[i].dwAspect));
     145            m_pFormatEtc[cFixedFormats + i] = pFormatEtc[i];
     146            m_pStgMedium[cFixedFormats + i] = pStgMed[i];
     147        }
     148    }
     149
     150    if (RT_SUCCESS(rc))
    135151    {
    136152        m_cFormats  = cAllFormats;
    137153        m_enmStatus = Initialized;
    138154
    139         int rc2 = RTSemEventCreate(&m_EventListComplete);
    140         AssertRC(rc2);
    141         rc2 = RTSemEventCreate(&m_EventTransferComplete);
    142         AssertRC(rc2);
    143     }
    144 
    145     LogFlowFunc(("cAllFormats=%RU32, hr=%Rhrc\n", cAllFormats, hr));
    146 }
    147 
    148 SharedClipboardWinDataObject::~SharedClipboardWinDataObject(void)
     155        rc = RTCritSectInit(&m_CritSect);
     156        if (RT_SUCCESS(rc))
     157        {
     158            rc = RTSemEventCreate(&m_EventListComplete);
     159            if (RT_SUCCESS(rc))
     160                rc = RTSemEventCreate(&m_EventStatusChanged);
     161        }
     162    }
     163
     164    LogFlowFunc(("cAllFormats=%RU32, rc=%Rrc\n", cAllFormats, rc));
     165    return rc;
     166}
     167
     168/**
     169 * Destroys a data object instance.
     170 */
     171void SharedClipboardWinDataObject::Destroy(void)
    149172{
    150173    LogFlowFuncEnter();
    151174
    152     RTSemEventDestroy(m_EventListComplete);
    153     m_EventListComplete = NIL_RTSEMEVENT;
    154 
    155     RTSemEventDestroy(m_EventTransferComplete);
    156     m_EventTransferComplete = NIL_RTSEMEVENT;
     175    AssertReturnVoid(m_lRefCount == 0);
     176
     177    int rc = RTCritSectDelete(&m_CritSect);
     178    AssertRC(rc);
     179
     180    if (m_EventListComplete != NIL_RTSEMEVENT)
     181    {
     182        rc = RTSemEventDestroy(m_EventListComplete);
     183        AssertRC(rc);
     184        m_EventListComplete = NIL_RTSEMEVENT;
     185    }
     186
     187    if (m_EventStatusChanged != NIL_RTSEMEVENT)
     188    {
     189        rc = RTSemEventDestroy(m_EventStatusChanged);
     190        AssertRC(rc);
     191        m_EventStatusChanged = NIL_RTSEMEVENT;
     192    }
    157193
    158194    if (m_pStream)
     195    {
    159196        m_pStream->Release();
     197        m_pStream = NULL;
     198    }
    160199
    161200    if (m_pFormatEtc)
     201    {
    162202        delete[] m_pFormatEtc;
     203        m_pFormatEtc = NULL;
     204    }
    163205
    164206    if (m_pStgMedium)
     207    {
    165208        delete[] m_pStgMedium;
    166 
    167     LogFlowFunc(("mRefCount=%RI32\n", m_lRefCount));
    168 }
    169 
    170 /*
     209        m_pStgMedium = NULL;
     210    }
     211
     212    if (m_pTransfer)
     213        ShClTransferRelease(m_pTransfer);
     214
     215    FsObjEntryList::const_iterator itRoot = m_lstEntries.cbegin();
     216    while (itRoot != m_lstEntries.end())
     217    {
     218        RTStrFree(itRoot->pszPath);
     219        ++itRoot;
     220    }
     221    m_lstEntries.clear();
     222
     223    m_enmStatus = Uninitialized;
     224    m_fThreadRunning = false;
     225    m_pTransfer = NULL;
     226}
     227
     228/**
     229 * Sets the callbacks for this object.
     230 *
     231 * @param   pCallbacks          Pointer to callbacks table to use.
     232 */
     233void SharedClipboardWinDataObject::SetCallbacks(PSHCLCALLBACKS pCallbacks)
     234{
     235    AssertPtrReturnVoid(pCallbacks);
     236
     237    RT_ZERO(m_Callbacks);
     238
     239    m_Callbacks.pfnOnRequestDataFromSource = pCallbacks->pfnOnRequestDataFromSource;
     240}
     241
     242
     243/*********************************************************************************************************************************
    171244 * IUnknown methods.
    172  */
     245 ********************************************************************************************************************************/
    173246
    174247STDMETHODIMP_(ULONG) SharedClipboardWinDataObject::AddRef(void)
     
    270343                {
    271344                    LogFlowFunc(("cTotalObjects=%RU64, cbTotalSize=%RU64\n\n",
    272                                  hdrList.cTotalObjects, hdrList.cbTotalSize));
    273 
    274                     for (uint64_t o = 0; o < hdrList.cTotalObjects; o++)
     345                                 hdrList.cEntries, hdrList.cbTotalSize));
     346
     347                    for (uint64_t o = 0; o < hdrList.cEntries; o++)
    275348                    {
    276349                        SHCLLISTENTRY entryList;
     
    291364                                                 entryList.pszName, pFsObjInfo->cbObject, strPath.c_str()));
    292365
    293                                     if (RTFS_IS_DIRECTORY(pFsObjInfo->Attr.fMode))
     366                                    if (   RTFS_IS_DIRECTORY(pFsObjInfo->Attr.fMode)
     367                                        || RTFS_IS_FILE     (pFsObjInfo->Attr.fMode))
    294368                                    {
    295                                         FSOBJENTRY objEntry = { strPath.c_str(), *pFsObjInfo };
    296 
    297                                         m_lstEntries.push_back(objEntry); /** @todo Can this throw? */
    298 
    299                                         rc = readDir(pTransfer, strPath.c_str());
    300                                     }
    301                                     else if (RTFS_IS_FILE(pFsObjInfo->Attr.fMode))
    302                                     {
    303                                         FSOBJENTRY objEntry = { strPath.c_str(), *pFsObjInfo };
     369                                        FSOBJENTRY objEntry;
     370                                        objEntry.pszPath = RTStrDup(strPath.c_str());
     371                                        AssertPtrBreakStmt(objEntry.pszPath, rc = VERR_NO_MEMORY);
     372                                        objEntry.objInfo = *pFsObjInfo;
    304373
    305374                                        m_lstEntries.push_back(objEntry); /** @todo Can this throw? */
    306375                                    }
    307                                     else
    308                                         rc = VERR_NOT_SUPPORTED;
     376                                    else /* Not fatal, just skip. */
     377                                        LogRel(("Shared Clipboard: Warning: File system object '%s' of type %#x not supported, skipping\n",
     378                                                strPath.c_str(), pFsObjInfo->Attr.fMode & RTFS_TYPE_MASK));
    309379
    310380                                    /** @todo Handle symlinks. */
     
    330400    }
    331401
     402    if (RT_FAILURE(rc))
     403        LogRel(("Shared Clipboard: Reading directory '%s' failed with %Rrc\n", strDir.c_str(), rc));
     404
    332405    LogFlowFuncLeaveRC(rc);
    333406    return rc;
     
    362435    LogRel2(("Shared Clipboard: Calculating transfer ...\n"));
    363436
    364     PSHCLROOTLIST pRootList;
    365     int rc = ShClTransferRootsGet(pTransfer, &pRootList);
     437    int rc = ShClTransferRootListRead(pTransfer);
    366438    if (RT_SUCCESS(rc))
    367439    {
    368         LogFlowFunc(("cRoots=%RU32\n\n", pRootList->Hdr.cRoots));
    369 
    370         for (uint32_t i = 0; i < pRootList->Hdr.cRoots; i++)
    371         {
    372             PSHCLLISTENTRY pRootEntry = &pRootList->paEntries[i];
    373             AssertPtr(pRootEntry);
    374 
    375             Assert(pRootEntry->cbInfo == sizeof(SHCLFSOBJINFO));
    376             PSHCLFSOBJINFO pFsObjInfo = (PSHCLFSOBJINFO)pRootEntry->pvInfo;
    377 
    378             LogFlowFunc(("pszRoot=%s, fMode=0x%x\n", pRootEntry->pszName, pFsObjInfo->Attr.fMode));
     440        uint64_t const cRoots = ShClTransferRootsCount(pTransfer);
     441
     442        LogFlowFunc(("cRoots=%RU64\n\n", cRoots));
     443
     444        for (uint32_t i = 0; i < cRoots; i++)
     445        {
     446            PCSHCLLISTENTRY pRootEntry = ShClTransferRootsEntryGet(pTransfer, i);
     447
     448            AssertBreakStmt(pRootEntry->cbInfo == sizeof(SHCLFSOBJINFO), rc = VERR_INVALID_PARAMETER);
     449            PSHCLFSOBJINFO const pFsObjInfo = (PSHCLFSOBJINFO)pRootEntry->pvInfo;
     450
     451            LogFlowFunc(("pszRoot=%s, fMode=0x%x (type %#x)\n",
     452                         pRootEntry->pszName, pFsObjInfo->Attr.fMode, (pFsObjInfo->Attr.fMode & RTFS_TYPE_MASK)));
    379453
    380454            if (RTFS_IS_DIRECTORY(pFsObjInfo->Attr.fMode))
    381455            {
    382                 FSOBJENTRY objEntry = { pRootEntry->pszName, *pFsObjInfo };
     456                FSOBJENTRY objEntry;
     457                objEntry.pszPath = RTStrDup(pRootEntry->pszName);
     458                AssertPtrBreakStmt(objEntry.pszPath, rc = VERR_NO_MEMORY);
     459                objEntry.objInfo = *pFsObjInfo;
    383460
    384461                pThis->m_lstEntries.push_back(objEntry); /** @todo Can this throw? */
     
    388465            else if (RTFS_IS_FILE(pFsObjInfo->Attr.fMode))
    389466            {
    390                 FSOBJENTRY objEntry = { pRootEntry->pszName, *pFsObjInfo };
     467                FSOBJENTRY objEntry;
     468                objEntry.pszPath = RTStrDup(pRootEntry->pszName);
     469                AssertPtrBreakStmt(objEntry.pszPath, rc = VERR_NO_MEMORY);
     470                objEntry.objInfo = *pFsObjInfo;
    391471
    392472                pThis->m_lstEntries.push_back(objEntry); /** @todo Can this throw? */
    393473            }
    394474            else
     475            {
     476                LogRel(("Shared Clipboard: Root entry '%s': File type %#x not supported\n",
     477                        pRootEntry->pszName, (pFsObjInfo->Attr.fMode & RTFS_TYPE_MASK)));
    395478                rc = VERR_NOT_SUPPORTED;
     479            }
    396480
    397481            if (ASMAtomicReadBool(&pTransfer->Thread.fStop))
     
    404488                break;
    405489        }
    406 
    407         ShClTransferRootListFree(pRootList);
    408         pRootList = NULL;
    409490
    410491        if (   RT_SUCCESS(rc)
     
    424505                LogRel2(("Shared Clipboard: Waiting for transfer to complete ...\n"));
    425506
    426                 LogFlowFunc(("Waiting for transfer to complete ...\n"));
    427 
    428507                /* Transferring stuff can take a while, so don't use any timeout here. */
    429                 rc2 = RTSemEventWait(pThis->m_EventTransferComplete, RT_INDEFINITE_WAIT);
     508                rc2 = RTSemEventWait(pThis->m_EventStatusChanged, RT_INDEFINITE_WAIT);
    430509                AssertRC(rc2);
    431510
     
    499578    char *pszFileSpec = NULL;
    500579
    501     FsObjEntryList::const_iterator itRoot = m_lstEntries.begin();
     580    FsObjEntryList::const_iterator itRoot = m_lstEntries.cbegin();
    502581    while (itRoot != m_lstEntries.end())
    503582    {
     
    505584        RT_BZERO(pFD, cbFileDescriptor);
    506585
    507         const char *pszFile = itRoot->strPath.c_str();
     586        const char *pszFile = itRoot->pszPath;
    508587        AssertPtr(pszFile);
    509588
     
    584663
    585664/**
    586  * Retrieves the data stored in this object and store the result in
    587  * pMedium.
    588  *
    589  * @return  IPRT status code.
     665 * Retrieves the data stored in this object and store the result in pMedium.
     666 *
    590667 * @return  HRESULT
    591  * @param   pFormatEtc
    592  * @param   pMedium
     668 * @param   pFormatEtc          Format to retrieve.
     669 * @param   pMedium             Where to store the data on success.
     670 *
     671 * @thread  Windows event thread.
    593672 */
    594673STDMETHODIMP SharedClipboardWinDataObject::GetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium)
     
    597676    AssertPtrReturn(pMedium, DV_E_FORMATETC);
    598677
    599     LogFlowFuncEnter();
    600 
    601     LogFlowFunc(("lIndex=%RI32\n", pFormatEtc->lindex));
     678    int rc2 = RTCritSectEnter(&m_CritSect);
     679    AssertRCReturn(rc2, E_UNEXPECTED);
     680
     681    LogFlowFunc(("lIndex=%RI32, enmStatus=%#x\n", pFormatEtc->lindex, m_enmStatus));
    602682
    603683    /*
     
    607687
    608688    HRESULT hr = DV_E_FORMATETC; /* Play safe. */
     689
     690    int rc = VINF_SUCCESS;
    609691
    610692    if (   pFormatEtc->cfFormat == m_cfFileDescriptorA
     
    614696       )
    615697    {
    616         const bool fUnicode = pFormatEtc->cfFormat == m_cfFileDescriptorW;
    617 
    618         const uint32_t enmTransferStatus = ShClTransferGetStatus(m_pTransfer);
    619         RT_NOREF(enmTransferStatus);
    620 
    621         LogFlowFunc(("FormatIndex_FileDescriptor%s, enmTransferStatus=%s, m_fRunning=%RTbool\n",
    622                      fUnicode ? "W" : "A", ShClTransferStatusToStr(enmTransferStatus), m_fRunning));
    623 
    624         int rc;
    625 
    626         /* The caller can call GetData() several times, so make sure we don't do the same transfer multiple times. */
    627         if (!m_fRunning)
    628         {
    629             /* Start the transfer asynchronously in a separate thread. */
    630             rc = ShClTransferRun(m_pTransfer, &SharedClipboardWinDataObject::readThread, this);
    631             if (RT_SUCCESS(rc))
     698        switch (m_enmStatus)
     699        {
     700            case Initialized:
    632701            {
    633                 m_fRunning = true;
    634 
    635                 /* Don't block for too long here, as this also will screw other apps running on the OS. */
    636                 LogFunc(("Waiting for listing to arrive ...\n"));
    637                 rc = RTSemEventWait(m_EventListComplete, SHCL_TIMEOUT_DEFAULT_MS);
     702                LogRel2(("Shared Clipboard: Requesting data for IDataObject ...\n"));
     703
     704                /* Leave lock while requesting + waiting. */
     705                rc2 = RTCritSectLeave(&m_CritSect);
     706                AssertRCReturn(rc2, E_UNEXPECTED);
     707
     708                /* Request the transfer from the source.
     709                 * This will generate a transfer status message which we're waiting for here. */
     710                AssertPtr(m_Callbacks.pfnOnRequestDataFromSource);
     711                rc = m_Callbacks.pfnOnRequestDataFromSource(m_pCtx,
     712                                                            VBOX_SHCL_FMT_URI_LIST, NULL /* ppv */, NULL /* pv */,
     713                                                            this /* pvUser */);
     714                AssertRCBreak(rc);
     715
     716                LogRel2(("Shared Clipboard: Waiting for IDataObject started status ...\n"));
     717
     718                rc = RTSemEventWait(m_EventStatusChanged, SHCL_TIMEOUT_DEFAULT_MS);
     719
     720                /* Re-acquire lock. */
     721                rc2 = RTCritSectEnter(&m_CritSect);
     722                AssertRCReturn(rc2, E_UNEXPECTED);
     723
    638724                if (RT_SUCCESS(rc))
    639725                {
    640                     LogFunc(("Listing complete\n"));
     726                    if (m_enmStatus != Running)
     727                    {
     728                        LogRel(("Shared Clipboard: Received wrong IDataObject status (%#x)\n", m_enmStatus));
     729                        rc = VERR_WRONG_ORDER;
     730                        break;
     731                    }
     732
     733                    /* There now must be a transfer assigned. */
     734                    AssertPtrBreakStmt(m_pTransfer, rc = VERR_WRONG_ORDER);
     735                }
     736                else /* Bail out on failure. */
     737                    break;
     738
     739                RT_FALL_THROUGH();
     740            }
     741
     742            case Running:
     743            {
     744                const bool fUnicode = pFormatEtc->cfFormat == m_cfFileDescriptorW;
     745
     746                const uint32_t enmTransferStatus = ShClTransferGetStatus(m_pTransfer);
     747                RT_NOREF(enmTransferStatus);
     748
     749                LogFlowFunc(("FormatIndex_FileDescriptor%s, enmTransferStatus=%s, m_fRunning=%RTbool\n",
     750                             fUnicode ? "W" : "A", ShClTransferStatusToStr(enmTransferStatus), m_fThreadRunning));
     751
     752                /* The caller can call GetData() several times, so make sure we don't do the same transfer multiple times. */
     753                if (!m_fThreadRunning)
     754                {
     755                    /* Start the transfer asynchronously in a separate thread. */
     756                    rc = ShClTransferRun(m_pTransfer, &SharedClipboardWinDataObject::readThread, this /* pvUser */);
     757                    if (RT_SUCCESS(rc))
     758                    {
     759                        m_fThreadRunning = true;
     760
     761                        /* Leave lock while waiting. */
     762                        rc2 = RTCritSectLeave(&m_CritSect);
     763                        AssertRCReturn(rc2, E_UNEXPECTED);
     764
     765                        /* Don't block for too long here, as this also will screw other apps running on the OS. */
     766                        LogRel2(("Shared Clipboard: Waiting for IDataObject listing to arrive ...\n"));
     767                        rc = RTSemEventWait(m_EventListComplete, SHCL_TIMEOUT_DEFAULT_MS);
     768
     769                        /* Re-acquire lock. */
     770                        rc2 = RTCritSectEnter(&m_CritSect);
     771                        AssertRCReturn(rc2, E_UNEXPECTED);
     772                    }
     773                }
     774
     775                if (RT_SUCCESS(rc))
     776                {
     777                    HGLOBAL hGlobal;
     778                    rc = createFileGroupDescriptorFromTransfer(m_pTransfer, fUnicode, &hGlobal);
     779                    if (RT_SUCCESS(rc))
     780                    {
     781                        pMedium->tymed   = TYMED_HGLOBAL;
     782                        pMedium->hGlobal = hGlobal;
     783                        /* Note: hGlobal now is being owned by pMedium / the caller. */
     784
     785                        hr = S_OK;
     786                    }
     787                }
     788
     789                break;
     790            }
     791
     792            default:
     793                break;
     794        }
     795
     796        if (RT_FAILURE(rc))
     797        {
     798            LogRel(("Shared Clipboard: Error getting data for IDataObject, rc=%Rrc\n", rc));
     799            hr = E_UNEXPECTED; /* We can't tell any better to the caller, unfortunately. */
     800        }
     801    }
     802
     803    if (RT_SUCCESS(rc))
     804    {
     805        if (pFormatEtc->cfFormat == m_cfFileContents)
     806        {
     807            if (          pFormatEtc->lindex >= 0
     808                && (ULONG)pFormatEtc->lindex <  m_lstEntries.size())
     809            {
     810                m_uObjIdx = pFormatEtc->lindex; /* lIndex of FormatEtc contains the actual index to the object being handled. */
     811
     812                FSOBJENTRY &fsObjEntry = m_lstEntries.at(m_uObjIdx);
     813
     814                LogFlowFunc(("FormatIndex_FileContents: m_uObjIdx=%u (entry '%s')\n", m_uObjIdx, fsObjEntry.pszPath));
     815
     816                LogRel2(("Shared Clipboard: Receiving object '%s' ...\n", fsObjEntry.pszPath));
     817
     818                /* Hand-in the provider so that our IStream implementation can continue working with it. */
     819                hr = SharedClipboardWinStreamImpl::Create(this /* pParent */, m_pTransfer,
     820                                                          fsObjEntry.pszPath /* File name */, &fsObjEntry.objInfo /* PSHCLFSOBJINFO */,
     821                                                          &m_pStream);
     822                if (SUCCEEDED(hr))
     823                {
     824                    /* Hand over the stream to the caller. */
     825                    pMedium->tymed = TYMED_ISTREAM;
     826                    pMedium->pstm  = m_pStream;
    641827                }
    642828            }
    643829        }
    644         else
    645             rc = VINF_SUCCESS;
    646 
    647         if (RT_SUCCESS(rc))
    648         {
    649             HGLOBAL hGlobal;
    650             rc = createFileGroupDescriptorFromTransfer(m_pTransfer, fUnicode, &hGlobal);
    651             if (RT_SUCCESS(rc))
    652             {
    653                 pMedium->tymed   = TYMED_HGLOBAL;
    654                 pMedium->hGlobal = hGlobal;
    655                 /* Note: hGlobal now is being owned by pMedium / the caller. */
    656 
    657                 hr = S_OK;
    658             }
    659             else /* We can't tell any better to the caller, unfortunately. */
    660                 hr = E_UNEXPECTED;
    661         }
    662 
    663         if (RT_FAILURE(rc))
    664             LogRel(("Shared Clipboard: Data object unable to get data, rc=%Rrc\n", rc));
    665     }
    666 
    667     if (pFormatEtc->cfFormat == m_cfFileContents)
    668     {
    669         if (          pFormatEtc->lindex >= 0
    670             && (ULONG)pFormatEtc->lindex <  m_lstEntries.size())
    671         {
    672             m_uObjIdx = pFormatEtc->lindex; /* lIndex of FormatEtc contains the actual index to the object being handled. */
    673 
    674             FSOBJENTRY &fsObjEntry = m_lstEntries.at(m_uObjIdx);
    675 
    676             LogFlowFunc(("FormatIndex_FileContents: m_uObjIdx=%u (entry '%s')\n", m_uObjIdx, fsObjEntry.strPath.c_str()));
    677 
    678             LogRel2(("Shared Clipboard: Receiving object '%s' ...\n", fsObjEntry.strPath.c_str()));
    679 
    680             /* Hand-in the provider so that our IStream implementation can continue working with it. */
    681             hr = SharedClipboardWinStreamImpl::Create(this /* pParent */, m_pTransfer,
    682                                                       fsObjEntry.strPath.c_str()/* File name */, &fsObjEntry.objInfo /* PSHCLFSOBJINFO */,
    683                                                       &m_pStream);
    684             if (SUCCEEDED(hr))
    685             {
    686                 /* Hand over the stream to the caller. */
    687                 pMedium->tymed = TYMED_ISTREAM;
    688                 pMedium->pstm  = m_pStream;
    689             }
    690         }
    691     }
    692     else if (pFormatEtc->cfFormat == m_cfPerformedDropEffect)
    693     {
    694         HGLOBAL hGlobal = GlobalAlloc(GHND, sizeof(DWORD));
    695 
    696         DWORD* pdwDropEffect = (DWORD*)GlobalLock(hGlobal);
    697         *pdwDropEffect = DROPEFFECT_COPY;
    698 
    699         GlobalUnlock(hGlobal);
    700 
    701         pMedium->tymed          = TYMED_HGLOBAL;
    702         pMedium->hGlobal        = hGlobal;
    703         pMedium->pUnkForRelease = NULL;
    704     }
    705 
    706     if (   FAILED(hr)
    707         && hr != DV_E_FORMATETC) /* Can happen if the caller queries unknown / unhandled formats. */
    708     {
    709         LogRel(("Shared Clipboard: Error returning data from data object (%Rhrc)\n", hr));
    710     }
     830        else if (pFormatEtc->cfFormat == m_cfPerformedDropEffect)
     831        {
     832            HGLOBAL hGlobal = GlobalAlloc(GHND, sizeof(DWORD));
     833
     834            DWORD* pdwDropEffect = (DWORD*)GlobalLock(hGlobal);
     835            *pdwDropEffect = DROPEFFECT_COPY;
     836
     837            GlobalUnlock(hGlobal);
     838
     839            pMedium->tymed          = TYMED_HGLOBAL;
     840            pMedium->hGlobal        = hGlobal;
     841            pMedium->pUnkForRelease = NULL;
     842        }
     843
     844        if (   FAILED(hr)
     845            && hr != DV_E_FORMATETC) /* Can happen if the caller queries unknown / unhandled formats. */
     846        {
     847            LogRel(("Shared Clipboard: Error returning data from data object (%Rhrc)\n", hr));
     848        }
     849    }
     850
     851    rc2 = RTCritSectLeave(&m_CritSect);
     852    AssertRCReturn(rc2, E_UNEXPECTED);
    711853
    712854    LogFlowFunc(("hr=%Rhrc\n", hr));
     
    786928            LogRel2(("Shared Clipboard: Transfer canceled by user interaction\n"));
    787929
    788             OnTransferCanceled();
     930            SetStatus(Canceled);
    789931        }
    790932        /** @todo Detect move / overwrite actions here. */
     
    8711013 */
    8721014
    873 int SharedClipboardWinDataObject::Init(void)
    874 {
    875     LogFlowFuncLeaveRC(VINF_SUCCESS);
    876     return VINF_SUCCESS;
    877 }
    878 
    879 void SharedClipboardWinDataObject::OnTransferComplete(int rc /* = VINF_SUCESS */)
    880 {
    881     RT_NOREF(rc);
    882 
    883     LogFlowFunc(("m_uObjIdx=%RU32 (total: %zu)\n", m_uObjIdx, m_lstEntries.size()));
    884 
     1015/**
     1016 * Assigns a transfer object and starts the transfer for the data object.
     1017 *
     1018 * @returns VBox status code.
     1019 * @param   pTransfer           Transfer to assign.
     1020 */
     1021int SharedClipboardWinDataObject::SetAndStartTransfer(PSHCLTRANSFER pTransfer)
     1022{
     1023    AssertReturn(m_pTransfer == NULL, VERR_WRONG_ORDER); /* Transfer already set? */
     1024
     1025    int rc = RTCritSectEnter(&m_CritSect);
    8851026    if (RT_SUCCESS(rc))
    8861027    {
    887         const bool fComplete = m_uObjIdx == m_lstEntries.size() - 1 /* Object index is zero-based */;
    888         if (fComplete)
    889         {
    890             m_enmStatus = Completed;
    891         }
    892     }
    893     else
    894         m_enmStatus = Error;
    895 
    896     if (m_enmStatus != Initialized)
    897     {
    898         if (m_EventTransferComplete != NIL_RTSEMEVENT)
    899         {
    900             int rc2 = RTSemEventSignal(m_EventTransferComplete);
    901             AssertRC(rc2);
    902         }
    903     }
    904 
    905     LogFlowFuncLeaveRC(rc);
    906 }
    907 
    908 void SharedClipboardWinDataObject::OnTransferCanceled(void)
    909 {
    910     LogFlowFuncEnter();
    911 
    912     m_enmStatus = Canceled;
    913 
    914     if (m_EventTransferComplete != NIL_RTSEMEVENT)
    915     {
    916         int rc2 = RTSemEventSignal(m_EventTransferComplete);
    917         AssertRC(rc2);
    918     }
    919 
    920     LogFlowFuncLeave();
     1028        if (m_enmStatus == Initialized)
     1029        {
     1030            m_pTransfer = pTransfer;
     1031
     1032            ShClTransferAcquire(pTransfer);
     1033
     1034            rc = setStatusLocked(Running);
     1035        }
     1036        else
     1037            AssertFailedStmt(rc = VERR_WRONG_ORDER);
     1038
     1039        RTCritSectLeave(&m_CritSect);
     1040    }
     1041
     1042    return rc;
     1043}
     1044
     1045/**
     1046 * Sets a new status to the data object and signals its waiter.
     1047 *
     1048 * @returns VBox status code.
     1049 * @param   enmStatus           New status to signal.
     1050 * @param   rc                  Result code. Optional.
     1051 *
     1052 * @note    Called by the main clipboard thread + SharedClipboardWinStreamImpl.
     1053 */
     1054int SharedClipboardWinDataObject::SetStatus(Status enmStatus, int rc /* = VINF_SUCCESS */)
     1055{
     1056    int rc2 = RTCritSectEnter(&m_CritSect);
     1057    if (RT_SUCCESS(rc2))
     1058    {
     1059        setStatusLocked(enmStatus, rc);
     1060
     1061        RTCritSectLeave(&m_CritSect);
     1062    }
     1063
     1064    return rc2;
    9211065}
    9221066
     
    9771121    logFormat(pFormatEtc->cfFormat);
    9781122}
     1123
     1124/**
     1125 * Sets a new status to the data object and signals its waiter.
     1126 *
     1127 * @returns VBox status code.
     1128 * @param   enmStatus           New status to signal.
     1129 * @param   rc                  Result code. Optional.
     1130 *
     1131 * @note    Caller must have taken the critical section.
     1132 */
     1133int SharedClipboardWinDataObject::setStatusLocked(Status enmStatus, int rc /* = VINF_SUCCESS */)
     1134{
     1135    AssertReturn(enmStatus == Error || RT_SUCCESS(rc), VERR_INVALID_PARAMETER);
     1136    AssertReturn(RTCritSectIsOwned(&m_CritSect), VERR_WRONG_ORDER);
     1137
     1138    RT_NOREF(rc);
     1139
     1140    int rc2 = RTCritSectEnter(&m_CritSect);
     1141    if (RT_SUCCESS(rc2))
     1142    {
     1143        LogFlowFunc(("enmStatus=%#x (current is: %#x)\n", enmStatus, m_enmStatus));
     1144
     1145        switch (enmStatus)
     1146        {
     1147            case Completed:
     1148            {
     1149                LogFlowFunc(("m_uObjIdx=%RU32 (total: %zu)\n", m_uObjIdx, m_lstEntries.size()));
     1150
     1151                const bool fComplete = m_uObjIdx == m_lstEntries.size() - 1 /* Object index is zero-based */;
     1152                if (fComplete)
     1153                    m_enmStatus = Completed;
     1154                break;
     1155            }
     1156
     1157            default:
     1158            {
     1159                m_enmStatus = enmStatus;
     1160                break;
     1161            }
     1162        }
     1163
     1164        if (RT_FAILURE(rc))
     1165            LogRel(("Shared Clipboard: Data object received error %Rrc (status %#x)\n", rc, enmStatus));
     1166
     1167        if (m_EventStatusChanged != NIL_RTSEMEVENT)
     1168            rc2 = RTSemEventSignal(m_EventStatusChanged);
     1169
     1170        RTCritSectLeave(&m_CritSect);
     1171    }
     1172
     1173    return rc2;
     1174}
     1175
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