VirtualBox

Changeset 50508 in vbox


Ignore:
Timestamp:
Feb 19, 2014 3:45:58 PM (11 years ago)
Author:
vboxsync
Message:

DnD: Update.

Location:
trunk
Files:
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/GuestHost/DragAndDrop.h

    r50460 r50508  
    11/* $Id$ */
    22/** @file
    3  * DnD: Share functions between host and guest.
     3 * DnD: Shared functions between host and guest.
    44 */
    55
     
    2222#include <iprt/cdefs.h>
    2323#include <iprt/err.h>
     24#include <iprt/file.h>
    2425#include <iprt/types.h>
    2526
     
    3637int DnDPathSanitize(char *pszPath, size_t cbPath);
    3738
    38 typedef struct DnDURIPath
     39class DnDURIObject
    3940{
    40     DnDURIPath(const RTCString &strSrcPath,
    41                const RTCString &strDstPath,
    42                uint32_t fMode, uint64_t cbSize)
    43         : m_strSrcPath(strSrcPath)
    44         , m_strDstPath(strDstPath)
    45         , m_fMode(fMode)
    46         , m_cbSize(cbSize) {}
     41public:
    4742
     43    enum Type
     44    {
     45        Unknown = 0,
     46        File,
     47        Directory
     48    };
     49
     50    DnDURIObject(Type type,
     51                 const RTCString &strSrcPath,
     52                 const RTCString &strDstPath,
     53                 uint32_t fMode, uint64_t cbSize);
     54    virtual ~DnDURIObject(void);
     55
     56public:
     57
     58    RTCString GetSourcePath(void) const { return m_strSrcPath; }
     59    RTCString GetDestPath(void) const { return m_strDstPath; }
     60    uint32_t GetMode(void) const { return m_fMode; }
     61    uint64_t GetSize(void) const { return m_cbSize; }
     62    Type GetType(void) const { return m_Type; }
     63
     64public:
     65
     66    bool IsComplete(void) const;
     67    static int RebaseURIPath(RTCString &strPath, const RTCString &strBaseOld, const RTCString &strBaseNew);
     68    int Read(void *pvBuf, uint32_t cbToRead, uint32_t *pcbRead);
     69
     70protected:
     71
     72    void closeInternal(void);
     73
     74protected:
     75
     76    Type      m_Type;
    4877    RTCString m_strSrcPath;
    4978    RTCString m_strDstPath;
    5079    uint32_t  m_fMode;
     80    /** Size (in bytes) to read/write. */
    5181    uint64_t  m_cbSize;
     82    /** Bytes processed reading/writing. */
     83    uint64_t  m_cbProcessed;
    5284
    53 } DnDURIPath;
     85    union
     86    {
     87        RTFILE m_hFile;
     88    } u;
     89};
    5490
    5591class DnDURIList
     
    6298public:
    6399
    64     int AppendPath(const char *pszPath, uint32_t fFlags);
    65     int AppendPathsFromList(const RTCList<RTCString> &lstURI, uint32_t fFlags);
     100    int AppendNativePath(const char *pszPath, uint32_t fFlags);
     101    int AppendNativePathsFromList(const char *pszNativePaths, size_t cbNativePaths, uint32_t fFlags);
     102    int AppendNativePathsFromList(const RTCList<RTCString> &lstNativePaths, uint32_t fFlags);
     103    int AppendURIPath(const char *pszURI, uint32_t fFlags);
     104    int AppendURIPathsFromList(const char *pszURIPaths, size_t cbURIPaths, uint32_t fFlags);
     105    int AppendURIPathsFromList(const RTCList<RTCString> &lstURI, uint32_t fFlags);
     106
    66107    void Clear(void);
    67     const DnDURIPath &First(void) const { return m_lstTree.first(); }
     108    DnDURIObject &First(void) { return m_lstTree.first(); }
    68109    bool IsEmpty(void) { return m_lstTree.isEmpty(); }
    69110    void RemoveFirst(void);
    70     RTCString RootToString(void) { return RTCString::join(m_lstRoot, "\r\n") + "\r\n"; }
     111    int RootFromURIData(const void *pvData, size_t cbData, uint32_t fFlags);
     112    RTCString RootToString(const RTCString &strBasePath = "");
     113    size_t RootCount(void) { return m_lstRoot.size(); }
    71114    size_t TotalBytes(void) { return m_cbTotal; }
    72115
     
    77120protected:
    78121
    79     /** List of top-level (root) URI entries. */
     122    /** List of all top-level file/directory entries. */
    80123    RTCList<RTCString>     m_lstRoot;
    81124    /** List of all URI objects added. */
    82     RTCList<DnDURIPath>    m_lstTree;
     125    RTCList<DnDURIObject>  m_lstTree;
    83126    /** Total size of all URI objects, that is, the file
    84127     *  size of all objects (in bytes). */
  • trunk/include/VBox/HostServices/DragAndDropSvc.h

    r50460 r50508  
    221221    HGCMFunctionParameter cFormat;      /* OUT uint32_t */
    222222    HGCMFunctionParameter pvData;       /* OUT ptr */
    223     HGCMFunctionParameter cData;        /* OUT uint32_t */
     223    HGCMFunctionParameter cbData;       /* OUT uint32_t */
    224224} VBOXDNDHGSENDDATAMSG;
    225225
     
    235235     */
    236236    HGCMFunctionParameter pvData;       /* OUT ptr */
    237     HGCMFunctionParameter cData;        /* OUT uint32_t */
     237    HGCMFunctionParameter cbData;       /* OUT uint32_t */
    238238} VBOXDNDHGSENDMOREDATAMSG;
    239239
     
    249249     */
    250250    HGCMFunctionParameter pvName;       /* OUT ptr */
    251     HGCMFunctionParameter cName;        /* OUT uint32_t */
     251    HGCMFunctionParameter cbName;       /* OUT uint32_t */
    252252    HGCMFunctionParameter fMode;        /* OUT uint32_t */
    253253} VBOXDNDHGSENDDIRMSG;
     
    264264     */
    265265    HGCMFunctionParameter pvName;       /* OUT ptr */
    266     HGCMFunctionParameter cName;        /* OUT uint32_t */
     266    HGCMFunctionParameter cbName;       /* OUT uint32_t */
    267267    HGCMFunctionParameter pvData;       /* OUT ptr */
    268     HGCMFunctionParameter cData;        /* OUT uint32_t */
     268    HGCMFunctionParameter cbData;       /* OUT uint32_t */
    269269    HGCMFunctionParameter fMode;        /* OUT uint32_t */
    270270} VBOXDNDHGSENDFILEMSG;
     
    316316    /** Number of parameters the message needs. */
    317317    HGCMFunctionParameter num_parms;    /* OUT uint32_t */
     318    /** Whether or not to block (wait) for a
     319     *  new message to arrive. */
    318320    HGCMFunctionParameter block;        /* OUT uint32_t */
    319321
     
    371373     * GUEST_DND_GH_SND_DATA
    372374     */
    373     HGCMFunctionParameter pData;        /* OUT ptr */
    374     HGCMFunctionParameter uSize;        /* OUT uint32_t */
     375    HGCMFunctionParameter pvData;       /* OUT ptr */
     376    /** Total bytes to send. This can be more than
     377     *  the data block specified in pvData above, e.g.
     378     *  when sending over file objects. */
     379    HGCMFunctionParameter cbTotalBytes; /* OUT uint32_t */
    375380} VBOXDNDGHSENDDATAMSG;
     381
     382typedef struct VBOXDNDGHSENDDIRMSG
     383{
     384    VBoxGuestHGCMCallInfo hdr;
     385
     386    /**
     387     * GH Directory event.
     388     *
     389     * Used by:
     390     * GUEST_DND_HG_SND_DIR
     391     */
     392    HGCMFunctionParameter pvName;       /* OUT ptr */
     393    HGCMFunctionParameter cbName;       /* OUT uint32_t */
     394    HGCMFunctionParameter fMode;        /* OUT uint32_t */
     395} VBOXDNDGHSENDDIRMSG;
     396
     397typedef struct VBOXDNDGHSENDFILEMSG
     398{
     399    VBoxGuestHGCMCallInfo hdr;
     400
     401    /**
     402     * GH File event.
     403     *
     404     * Used by:
     405     * GUEST_DND_HG_SND_FILE
     406     */
     407    HGCMFunctionParameter pvName;       /* OUT ptr */
     408    HGCMFunctionParameter cbName;       /* OUT uint32_t */
     409    HGCMFunctionParameter pvData;       /* OUT ptr */
     410    HGCMFunctionParameter cbData;       /* OUT uint32_t */
     411    HGCMFunctionParameter fMode;        /* OUT uint32_t */
     412} VBOXDNDGHSENDFILEMSG;
    376413
    377414typedef struct VBOXDNDGHEVTERRORMSG
     
    391428
    392429/*
    393  * Callback handler
     430 * Callback data magics.
    394431 */
    395432enum
     
    400437    CB_MAGIC_DND_GH_ACK_PENDING  = 0xbe975a14,
    401438    CB_MAGIC_DND_GH_SND_DATA     = 0x4eb61bff,
     439    CB_MAGIC_DND_GH_SND_DIR      = 0x411ca754,
     440    CB_MAGIC_DND_GH_SND_FILE     = 0x65e35eaf,
    402441    CB_MAGIC_DND_GH_EVT_ERROR    = 0x117a87c4
    403442};
     
    454493    void     *pvData;
    455494    uint32_t  cbData;
    456     uint32_t  cbAllSize; /** @todo Why is this transmitted every time? */
     495    /** Total metadata size (in bytes). This is transmitted
     496     *  with every message because the size can change. */
     497    uint32_t  cbTotalSize;
    457498} VBOXDNDCBSNDDATADATA;
    458499typedef VBOXDNDCBSNDDATADATA *PVBOXDNDCBSNDDATADATA;
     500
     501typedef struct VBOXDNDCBSNDDIRDATA
     502{
     503    /** Callback data header. */
     504    VBOXDNDCBHEADERDATA hdr;
     505    char     *pszPath;
     506    uint32_t  cbPath;
     507    uint32_t  fMode;
     508} VBOXDNDCBSNDDIRDATA;
     509typedef VBOXDNDCBSNDDIRDATA *PVBOXDNDCBSNDDIRDATA;
     510
     511typedef struct VBOXDNDCBSNDFILEDATA
     512{
     513    /** Callback data header. */
     514    VBOXDNDCBHEADERDATA hdr;
     515    char     *pszFilePath;
     516    uint32_t  cbFilePath;
     517    uint32_t  fMode;
     518    void     *pvData;
     519    uint32_t  cbData;
     520} VBOXDNDCBSNDFILEDATA;
     521typedef VBOXDNDCBSNDFILEDATA *PVBOXDNDCBSNDFILEDATA;
    459522
    460523typedef struct VBOXDNDCBEVTERRORDATA
  • trunk/include/VBox/VBoxGuestLib.h

    r50305 r50508  
    723723#  ifdef VBOX_WITH_DRAG_AND_DROP_GH
    724724VBGLR3DECL(int)     VbglR3DnDGHAcknowledgePending(uint32_t u32ClientId, uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats);
    725 VBGLR3DECL(int)     VbglR3DnDGHSendData(uint32_t u32ClientId, void *pvData, uint32_t cbData);
     725VBGLR3DECL(int)     VbglR3DnDGHSendData(uint32_t u32ClientId, const char *pszFormat, void *pvData, uint32_t cbData);
    726726VBGLR3DECL(int)     VbglR3DnDGHErrorEvent(uint32_t u32ClientId, int rcOp);
    727727#  endif /* VBOX_WITH_DRAG_AND_DROP_GH */
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp

    r50467 r50508  
    4949 *  at NT4 SP3+. */
    5050typedef BOOL (WINAPI *PFNSENDINPUT)(UINT, LPINPUT, int);
     51typedef BOOL (WINAPI* PFNENUMDISPLAYMONITORS)(HDC, LPCRECT, MONITORENUMPROC, LPARAM);
    5152
    5253/** Static pointer to SendInput() function. */
    5354static PFNSENDINPUT s_pfnSendInput = NULL;
     55static PFNENUMDISPLAYMONITORS s_pfnEnumDisplayMonitors = NULL;
    5456
    5557static LRESULT CALLBACK vboxDnDWndProcInstance(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
     
    5860VBoxDnDWnd::VBoxDnDWnd(void)
    5961    : hWnd(NULL),
    60       mpfnEnumDisplayMonitors(NULL),
    6162      mfMouseButtonDown(false),
    6263#ifdef VBOX_WITH_DRAG_AND_DROP_GH
     
    8586    /* Save the context. */
    8687    this->pContext = pContext;
    87 
    88     HMODULE hUser = GetModuleHandle("user32.dll");
    89     if (hUser)
    90     {
    91         *(uintptr_t *)&mpfnEnumDisplayMonitors = (uintptr_t)GetProcAddress(hUser, "EnumDisplayMonitors");
    92         Log(("DnD: EnumDisplayMonitors = %p\n", mpfnEnumDisplayMonitors));
    93     }
    9488
    9589    int rc = RTSemEventCreate(&mEventSem);
     
    10141008    AssertReturn(cbFormats, VERR_INVALID_PARAMETER);
    10151009
    1016     LogFlowThisFunc(("mMode=%ld, mState=%ld, pDropTarget=0x%p, uDefAction=0x%x\n",
    1017                      mMode, mState, pDropTarget, uDefAction));
     1010    LogFlowThisFunc(("mMode=%ld, mState=%ld, pDropTarget=0x%p, pszFormat=%s, uDefAction=0x%x\n",
     1011                     mMode, mState, pDropTarget, pszFormat, uDefAction));
    10181012
    10191013    int rc;
     
    10251019        {
    10261020            /** @todo Respect uDefAction. */
    1027             /** @todo Do data checking / conversion based on pszFormats. */
    1028 
    10291021            void *pvData = pDropTarget->DataMutableRaw();
    10301022            AssertPtr(pvData);
     
    10321024            Assert(cbData);
    10331025
    1034             rc = VbglR3DnDGHSendData(mClientID, pvData, cbData);
     1026            rc = VbglR3DnDGHSendData(mClientID, pszFormat, pvData, cbData);
    10351027            LogFlowFunc(("Sent pvData=0x%p, cbData=%RU32, rc=%Rrc\n",
    10361028                         pvData, cbData, rc));
     
    10941086    if (hDC)
    10951087    {
    1096         fRc = mpfnEnumDisplayMonitors?
    1097                   mpfnEnumDisplayMonitors(hDC, NULL, VBoxDnDWnd::MonitorEnumProc, (LPARAM)&r):
    1098                   FALSE;
     1088        fRc = s_pfnEnumDisplayMonitors
     1089            /* EnumDisplayMonitors is not available on NT4. */
     1090            ? s_pfnEnumDisplayMonitors(hDC, NULL, VBoxDnDWnd::MonitorEnumProc, (LPARAM)&r):
     1091              FALSE;
    10991092
    11001093        if (!fRc)
     
    12861279        RTLdrGetSystemSymbol("User32.dll", "SendInput");
    12871280    fSupportedOS = !RT_BOOL(s_pfnSendInput == NULL);
     1281    s_pfnEnumDisplayMonitors = (PFNENUMDISPLAYMONITORS)
     1282        RTLdrGetSystemSymbol("User32.dll", "EnumDisplayMonitors");
     1283    /* g_pfnEnumDisplayMonitors is optional. */
    12881284
    12891285    if (!fSupportedOS)
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.h

    r50467 r50508  
    366366    /** The window's handle. */
    367367    HWND                       hWnd;
    368     BOOL (WINAPI* mpfnEnumDisplayMonitors)(HDC, LPCRECT, MONITORENUMPROC, LPARAM);
    369368    /** List of allowed MIME types this
    370369     *  client can handle. Make this a per-instance
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnDDropTarget.cpp

    r50399 r50508  
    356356                                                     0 /* cchFile */);
    357357                            Assert(cch);
    358 
    359                             /* Add separation between filenames. */
    360                             if (i > 0)
    361                             {
    362                                 rc = RTStrAAppendExN(&pszFiles, 1 /* cPairs */,
    363                                                      "\r\n", 2 /* Bytes */);
    364                                 if (RT_SUCCESS(rc))
    365                                     cchFiles += 2; /* Include \r\n */
    366                             }
    367358
    368359                            if (RT_FAILURE(rc))
     
    418409                            if (RT_FAILURE(rc))
    419410                                break;
     411
     412                            /* Add separation between filenames.
     413                             * Note: Also do this for the last element of the list. */
     414                            if (i > 0)
     415                            {
     416                                rc = RTStrAAppendExN(&pszFiles, 1 /* cPairs */,
     417                                                     "\r\n", 2 /* Bytes */);
     418                                if (RT_SUCCESS(rc))
     419                                    cchFiles += 2; /* Include \r\n */
     420                            }
    420421                        }
    421422
  • trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp

    r50462 r50508  
    3838#include <iprt/cpp/ministring.h>
    3939
     40#ifdef LOG_GROUP
     41 #undef LOG_GROUP
     42#endif
     43#define LOG_GROUP LOG_GROUP_GUEST_DND
     44#include <VBox/log.h>
     45
    4046#include <VBox/GuestHost/DragAndDrop.h>
    4147#include <VBox/HostServices/DragAndDropSvc.h>
     
    7985        if (RT_SUCCESS(rc))
    8086        {
    81             /* Fetch results */
    8287            rc = Msg.msg.GetUInt32(puMsg);         AssertRC(rc);
    8388            rc = Msg.num_parms.GetUInt32(pcParms); AssertRC(rc);
     
    128133        if (RT_SUCCESS(rc))
    129134        {
    130             /* Fetch results */
    131135            rc = Msg.uScreenId.GetUInt32(puScreenId);     AssertRC(rc);
    132136            rc = Msg.uX.GetUInt32(puX);                   AssertRC(rc);
     
    135139            rc = Msg.uAllActions.GetUInt32(puAllActions); AssertRC(rc);
    136140            rc = Msg.cFormats.GetUInt32(pcbFormatsRecv);  AssertRC(rc);
    137             /* A little bit paranoia */
     141
    138142            AssertReturn(cbFormats >= *pcbFormatsRecv, VERR_TOO_MUCH_DATA);
    139143        }
     
    191195
    192196    Msg.pvName.SetPtr(pszDirname, cbDirname);
    193     Msg.cName.SetUInt32(0);
     197    Msg.cbName.SetUInt32(0);
    194198    Msg.fMode.SetUInt32(0);
    195199
     
    200204        if (RT_SUCCESS(Msg.hdr.result))
    201205        {
    202             /* Fetch results */
    203             rc = Msg.cName.GetUInt32(pcbDirnameRecv); AssertRC(rc);
    204             rc = Msg.fMode.GetUInt32(pfMode);         AssertRC(rc);
    205             /* A little bit paranoia */
     206            rc = Msg.cbName.GetUInt32(pcbDirnameRecv); AssertRC(rc);
     207            rc = Msg.fMode.GetUInt32(pfMode);          AssertRC(rc);
     208
    206209            AssertReturn(cbDirname >= *pcbDirnameRecv, VERR_TOO_MUCH_DATA);
    207210        }
     
    235238
    236239    Msg.pvName.SetPtr(pszFilename, cbFilename);
    237     Msg.cName.SetUInt32(0);
     240    Msg.cbName.SetUInt32(0);
    238241    Msg.pvData.SetPtr(pvData, cbData);
    239     Msg.cData.SetUInt32(0);
     242    Msg.cbData.SetUInt32(0);
    240243    Msg.fMode.SetUInt32(0);
    241244
     
    246249        if (RT_SUCCESS(rc))
    247250        {
    248             /* Fetch results */
    249             rc = Msg.cName.GetUInt32(pcbFilenameRecv); AssertRC(rc);
    250             rc = Msg.cData.GetUInt32(pcbDataRecv);     AssertRC(rc);
    251             rc = Msg.fMode.GetUInt32(pfMode);          AssertRC(rc);
    252             /* A little bit paranoia */
     251            rc = Msg.cbName.GetUInt32(pcbFilenameRecv); AssertRC(rc);
     252            rc = Msg.cbData.GetUInt32(pcbDataRecv);     AssertRC(rc);
     253            rc = Msg.fMode.GetUInt32(pfMode);           AssertRC(rc);
     254
    253255            AssertReturn(cbFilename >= *pcbFilenameRecv, VERR_TOO_MUCH_DATA);
    254256            AssertReturn(cbData     >= *pcbDataRecv,     VERR_TOO_MUCH_DATA);
     
    275277        return VERR_INVALID_PARAMETER;
    276278
    277     /* Make a string list out of the uri data. */
    278     RTCList<RTCString> uriList =
    279         RTCString(static_cast<char*>(*ppvData), *pcbDataRecv - 1).split("\r\n");
    280     if (uriList.isEmpty())
    281         return VINF_SUCCESS;
    282 
     279    /* Allocate temp buffer. */
    283280    uint32_t cbTmpData = _1M * 10; /** @todo r=andy 10MB, uh, really?? */
    284281    void *pvTmpData = RTMemAlloc(cbTmpData);
     
    297294    /* Patch the old drop data with the new drop directory, so the drop target
    298295     * can find the files. */
    299     RTCList<RTCString> guestUriList;
    300     for (size_t i = 0; i < uriList.size(); ++i)
    301     {
    302         const RTCString &strUri = uriList.at(i);
    303         /* Query the path component of a file URI. If this hasn't a
    304          * file scheme, null is returned. */
    305         char *pszFilePath = RTUriFilePath(strUri.c_str(), URI_FILE_FORMAT_AUTO);
    306         if (pszFilePath)
    307         {
    308             rc = DnDPathSanitize(pszFilePath, strlen(pszFilePath));
    309             if (RT_FAILURE(rc))
    310                 break;
    311 
    312             /** @todo Use RTPathJoin? */
    313             RTCString strFullPath
    314                 = RTCString().printf("%s%c%s", pszDropDir, RTPATH_SLASH, pszFilePath);
    315             char *pszNewUri = RTUriFileCreate(strFullPath.c_str());
    316             if (pszNewUri)
    317             {
    318                 guestUriList.append(pszNewUri);
    319                 RTStrFree(pszNewUri);
    320             }
    321         }
    322         else
    323             guestUriList.append(strUri);
    324     }
    325 
     296    DnDURIList lstURI;
     297    rc = lstURI.RootFromURIData(*ppvData, *pcbDataRecv,
     298                                0 /* fFlags */);
    326299    if (RT_SUCCESS(rc))
    327300    {
    328301        /* Cleanup the old data and write the new data back to the event. */
    329302        RTMemFree(*ppvData);
    330         RTCString newData = RTCString::join(guestUriList, "\r\n") + "\r\n";
    331 
    332         *ppvData = RTStrDupN(newData.c_str(), newData.length());
    333         *pcbDataRecv = newData.length() + 1;
     303
     304        RTCString strData = lstURI.RootToString(pszDropDir);
     305        *ppvData = RTStrDupN(strData.c_str(), strData.length());
     306        *pcbDataRecv = strData.length() + 1;
    334307    }
    335308
     
    403376                            if (RT_SUCCESS(rc))
    404377                            {
     378                                /** @todo r=andy Not very safe to assume that we were last appending to the current file. */
    405379                                rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, NULL);
    406380                                if (RT_SUCCESS(rc))
     
    488462    Msg.cFormat.SetUInt32(0);
    489463    Msg.pvData.SetPtr(pvData, cbData);
    490     Msg.cData.SetUInt32(0);
     464    Msg.cbData.SetUInt32(0);
    491465
    492466    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    497471            || rc == VERR_BUFFER_OVERFLOW)
    498472        {
    499             /* Fetch results */
    500473            rc = Msg.uScreenId.GetUInt32(puScreenId);  AssertRC(rc);
    501474            rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
    502             rc = Msg.cData.GetUInt32(pcbDataTotal);     AssertRC(rc);
    503             /* A little bit paranoia */
     475            rc = Msg.cbData.GetUInt32(pcbDataTotal);     AssertRC(rc);
     476
    504477            AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
    505478            AssertReturn(cbData   >= *pcbDataTotal,  VERR_TOO_MUCH_DATA);
     
    526499
    527500    Msg.pvData.SetPtr(pvData, cbData);
    528     Msg.cData.SetUInt32(0);
     501    Msg.cbData.SetUInt32(0);
    529502
    530503    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    535508            || rc == VERR_BUFFER_OVERFLOW)
    536509        {
    537             /* Fetch results */
    538             rc = Msg.cData.GetUInt32(pcbDataRecv); AssertRC(rc);
    539             /* A little bit paranoia */
     510            rc = Msg.cbData.GetUInt32(pcbDataRecv); AssertRC(rc);
    540511            AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA);
    541512        }
     
    629600         * This keeps the actual (guest OS-)dependent client (like VBoxClient /
    630601         * VBoxTray) small by not having too much redundant code. */
    631         if (RTStrNICmp(pszFormat, "text/uri-list", *pcbFormatRecv) == 0)
     602        AssertPtr(pcbFormatRecv);
     603        if (DnDMIMEHasFileURLs(pszFormat, *pcbFormatRecv))
    632604            rc = vbglR3DnDHGProcessURIMessages(uClientId,
    633605                                               puScreenId,
     
    661633        rc = Msg.hdr.result;
    662634        if (RT_SUCCESS(rc))
    663         {
    664             /* Fetch results */
    665635            rc = Msg.uScreenId.GetUInt32(puScreenId); AssertRC(rc);
    666         }
    667636    }
    668637
     
    697666        if (RT_SUCCESS(rc))
    698667        {
    699             /* Fetch results */
    700668            rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
    701669            rc = Msg.uAction.GetUInt32(puAction);      AssertRC(rc);
    702             /* A little bit paranoia */
     670
    703671            AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
    704672        }
     
    872840    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_ACK_OP;
    873841    Msg.hdr.cParms      = 1;
    874     /* Initialize parameter */
     842
    875843    Msg.uAction.SetUInt32(uAction);
    876     /* Do request */
     844
    877845    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    878846    if (RT_SUCCESS(rc))
     
    892860    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_REQ_DATA;
    893861    Msg.hdr.cParms      = 1;
    894     /* Initialize parameter */
     862
    895863    Msg.pFormat.SetPtr((void*)pcszFormat, (uint32_t)strlen(pcszFormat) + 1);
    896     /* Do request */
     864
    897865    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    898866    if (RT_SUCCESS(rc))
     
    914882    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_ACK_PENDING;
    915883    Msg.hdr.cParms      = 3;
    916     /* Initialize parameter */
     884
    917885    Msg.uDefAction.SetUInt32(uDefAction);
    918886    Msg.uAllActions.SetUInt32(uAllActions);
    919887    Msg.pFormat.SetPtr((void*)pcszFormats, (uint32_t)strlen(pcszFormats) + 1);
    920     /* Do request */
    921     int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    922     if (RT_SUCCESS(rc))
    923         rc = Msg.hdr.result;
    924 
    925     return rc;
    926 }
    927 
    928 VBGLR3DECL(int) VbglR3DnDGHSendData(uint32_t u32ClientId,
    929                                     void *pvData, uint32_t cbData)
     888
     889    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     890    if (RT_SUCCESS(rc))
     891        rc = Msg.hdr.result;
     892
     893    return rc;
     894}
     895
     896static int vbglR3DnDGHSendDataInternal(uint32_t u32ClientId,
     897                                       void *pvData, uint32_t cbData,
     898                                       uint32_t cbAdditionalData)
    930899{
    931900    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
    932     AssertReturn(cbData,    VERR_INVALID_PARAMETER);
     901    AssertReturn(cbData, VERR_INVALID_PARAMETER);
    933902
    934903    DragAndDropSvc::VBOXDNDGHSENDDATAMSG Msg;
     
    938907    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DATA;
    939908    Msg.hdr.cParms      = 2;
    940     Msg.uSize.SetUInt32(cbData);
    941 
    942     int rc          = VINF_SUCCESS;
    943     uint32_t cbMax  = _64K; /* Transfer max. 64K chunks per message. */
    944     uint32_t cbSent = 0;
     909
     910    /* Total amount of bytes to send (including this data block). */
     911    Msg.cbTotalBytes.SetUInt32(cbData + cbAdditionalData);
     912
     913    int rc;
     914
     915    uint32_t cbMaxChunk = _64K; /* Transfer max. 64K chunks per message. */
     916    uint32_t cbSent     = 0;
    945917
    946918    while (cbSent < cbData)
    947919    {
    948         uint32_t cbToSend = RT_MIN(cbData - cbSent, cbMax);
    949         Msg.pData.SetPtr(static_cast<uint8_t*>(pvData) + cbSent, cbToSend);
     920        uint32_t cbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk);
     921        Msg.pvData.SetPtr(static_cast<uint8_t*>(pvData) + cbSent, cbCurChunk);
    950922
    951923        rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    956928            break;
    957929
    958         cbSent += cbToSend;
     930        cbSent += cbCurChunk;
    959931    }
    960932
    961933    if (RT_SUCCESS(rc))
    962934        Assert(cbSent == cbData);
     935
     936    LogFlowFunc(("Returning rc=%Rrc, cbData=%RU32, cbAddtionalData=%RU32\n",
     937                 rc, cbData, cbAdditionalData));
     938    return rc;
     939}
     940
     941static int vbglR3DnDGHSendDir(uint32_t u32ClientId, DnDURIObject &obj)
     942{
     943    AssertReturn(obj.GetType() == DnDURIObject::Directory, VERR_INVALID_PARAMETER);
     944
     945    DragAndDropSvc::VBOXDNDGHSENDDIRMSG Msg;
     946    RT_ZERO(Msg);
     947    Msg.hdr.result      = VERR_WRONG_ORDER;
     948    Msg.hdr.u32ClientID = u32ClientId;
     949    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DIR;
     950    Msg.hdr.cParms      = 3;
     951
     952    RTCString strPath = obj.GetDestPath();
     953    LogFlowFunc(("strDir=%s (%zu), fMode=0x%x\n",
     954                 strPath.c_str(), strPath.length(), obj.GetMode()));
     955
     956    Msg.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
     957    Msg.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
     958    Msg.fMode.SetUInt32(obj.GetMode());
     959
     960    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     961    if (RT_SUCCESS(rc))
     962        rc = Msg.hdr.result;
     963
     964    LogFlowFuncLeaveRC(rc);
     965    return rc;
     966}
     967
     968static int vbglR3DnDGHSendFile(uint32_t u32ClientId, DnDURIObject &obj)
     969{
     970    AssertReturn(obj.GetType() == DnDURIObject::File, VERR_INVALID_PARAMETER);
     971
     972    uint32_t cbBuf = _64K; /** @todo Make this configurable? */
     973    void *pvBuf = RTMemAlloc(cbBuf);
     974    if (!pvBuf)
     975        return VERR_NO_MEMORY;
     976
     977    DragAndDropSvc::VBOXDNDGHSENDFILEMSG Msg;
     978    RT_ZERO(Msg);
     979    Msg.hdr.result      = VERR_WRONG_ORDER;
     980    Msg.hdr.u32ClientID = u32ClientId;
     981    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_FILE;
     982    Msg.hdr.cParms      = 5;
     983
     984    RTCString strPath = obj.GetDestPath();
     985    LogFlowFunc(("strFile=%s (%zu), fMode=0x%x\n",
     986                 strPath.c_str(), strPath.length(), obj.GetMode()));
     987
     988    Msg.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
     989    Msg.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
     990    Msg.fMode.SetUInt32(obj.GetMode());
     991
     992    int rc = VINF_SUCCESS;
     993    uint32_t cbData = obj.GetSize();
     994
     995    do
     996    {
     997        uint32_t cbToRead = RT_MIN(cbData, cbBuf);
     998        uint32_t cbRead   = 0;
     999        if (cbToRead)
     1000            rc = obj.Read(pvBuf, cbToRead, &cbRead);
     1001        if (RT_SUCCESS(rc))
     1002        {
     1003             Msg.cbData.SetUInt32(cbRead);
     1004             Msg.pvData.SetPtr(pvBuf, cbRead);
     1005
     1006             rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     1007             if (RT_SUCCESS(rc))
     1008                 rc = Msg.hdr.result;
     1009        }
     1010
     1011        if (RT_FAILURE(rc))
     1012            break;
     1013
     1014        Assert(cbRead <= cbData);
     1015        cbData -= cbRead;
     1016
     1017    } while (cbData);
     1018
     1019    RTMemFree(pvBuf);
     1020
     1021    LogFlowFuncLeaveRC(rc);
     1022    return rc;
     1023}
     1024
     1025static int vbglR3DnDGHSendURIObject(uint32_t u32ClientId, DnDURIObject &obj)
     1026{
     1027    int rc;
     1028
     1029    switch (obj.GetType())
     1030    {
     1031        case DnDURIObject::Directory:
     1032            rc = vbglR3DnDGHSendDir(u32ClientId, obj);
     1033            break;
     1034
     1035        case DnDURIObject::File:
     1036            rc = vbglR3DnDGHSendFile(u32ClientId, obj);
     1037            break;
     1038
     1039        default:
     1040            AssertMsgFailed(("Type %ld not implemented\n",
     1041                             obj.GetType()));
     1042            rc = VERR_NOT_IMPLEMENTED;
     1043            break;
     1044    }
     1045
     1046    return rc;
     1047}
     1048
     1049static int vbglR3DnDGHProcessURIMessages(uint32_t u32ClientId,
     1050                                         void *pvData, uint32_t cbData)
     1051{
     1052    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     1053    AssertReturn(cbData, VERR_INVALID_PARAMETER);
     1054
     1055    RTCList<RTCString> lstPaths =
     1056        RTCString((const char *)pvData, cbData).split("\r\n");
     1057
     1058    DnDURIList lstURI;
     1059    int rc = lstURI.AppendNativePathsFromList(lstPaths, 0 /* fFlags */);
     1060    if (RT_SUCCESS(rc))
     1061    {
     1062        /* Send metadata; in this case it's the (non-recursive) file/directory
     1063         * URI list the host needs to know to initialize the drag'n drop operation. */
     1064        RTCString strRootDest = lstURI.RootToString();
     1065        Assert(strRootDest.isNotEmpty());
     1066
     1067        void *pvToSend = (void *)strRootDest.c_str();
     1068        uint32_t cbToSend = (uint32_t)strRootDest.length() + 1;
     1069
     1070        rc = vbglR3DnDGHSendDataInternal(u32ClientId, pvToSend, cbToSend,
     1071                                         /* Include total bytes of all file paths,
     1072                                          * file sizes etc. */
     1073                                         lstURI.TotalBytes());
     1074    }
     1075
     1076    if (RT_SUCCESS(rc))
     1077    {
     1078        while (!lstURI.IsEmpty())
     1079        {
     1080            DnDURIObject &nextObj = lstURI.First();
     1081
     1082            rc = vbglR3DnDGHSendURIObject(u32ClientId, nextObj);
     1083            if (RT_FAILURE(rc))
     1084                break;
     1085
     1086            lstURI.RemoveFirst();
     1087        }
     1088    }
     1089
     1090    return rc;
     1091}
     1092
     1093VBGLR3DECL(int) VbglR3DnDGHSendData(uint32_t u32ClientId,
     1094                                    const char *pszFormat,
     1095                                    void *pvData, uint32_t cbData)
     1096{
     1097    AssertPtrReturn(pszFormat, VERR_INVALID_POINTER);
     1098    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     1099    AssertReturn(cbData, VERR_INVALID_PARAMETER);
     1100
     1101    int rc;
     1102    if (DnDMIMEHasFileURLs(pszFormat, strlen(pszFormat)))
     1103    {
     1104        rc = vbglR3DnDGHProcessURIMessages(u32ClientId, pvData, cbData);
     1105    }
     1106    else
     1107        rc = vbglR3DnDGHSendDataInternal(u32ClientId, pvData, cbData,
     1108                                         0 /* cbAdditionalData */);
    9631109
    9641110    return rc;
     
    9731119    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_EVT_ERROR;
    9741120    Msg.hdr.cParms      = 1;
    975     /* Initialize parameter */
     1121
    9761122    Msg.uRC.SetUInt32(rcOp);
    977     /* Do request */
    978     int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    979     if (RT_SUCCESS(rc))
    980         rc = Msg.hdr.result;
    981 
    982     return rc;
    983 }
    984 
    985 VBGLR3DECL(int) VbglR3DnDGHSendFile(uint32_t u32ClientId, const char *pszPath)
    986 {
    987     return 0;
    988 }
    989 
     1123
     1124    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     1125    if (RT_SUCCESS(rc))
     1126        rc = Msg.hdr.result;
     1127
     1128    return rc;
     1129}
     1130
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDDataObject_win.cpp

    r50460 r50508  
    5353    HRESULT hr;
    5454
    55     ULONG cAllFormats = lstFormats.size();
     55    ULONG cMaxFormats = 16; /* Maximum number of registered formats. */
    5656    ULONG cRegisteredFormats = 0;
    5757
    5858    try
    5959    {
    60         mpFormatEtc = new FORMATETC[cAllFormats];
    61         RT_BZERO(mpFormatEtc, sizeof(FORMATETC) * cAllFormats);
    62         mpStgMedium = new STGMEDIUM[cAllFormats];
    63         RT_BZERO(mpStgMedium, sizeof(STGMEDIUM) * cAllFormats);
     60        mpFormatEtc = new FORMATETC[cMaxFormats];
     61        RT_BZERO(mpFormatEtc, sizeof(FORMATETC) * cMaxFormats);
     62        mpStgMedium = new STGMEDIUM[cMaxFormats];
     63        RT_BZERO(mpStgMedium, sizeof(STGMEDIUM) * cMaxFormats);
    6464
    6565        for (int i = 0; i < lstFormats.size(); i++)
     
    6969                continue;
    7070
     71            /* URI data ("text/uri-list"). */
    7172            if (strFormat.contains("text/uri-list", Qt::CaseInsensitive))
    7273            {
    73                 /* URI data ("text/uri-list"). */
     74                RegisterFormat(&mpFormatEtc[cRegisteredFormats], CF_TEXT);
     75                mpStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
     76                RegisterFormat(&mpFormatEtc[cRegisteredFormats], CF_UNICODETEXT);
     77                mpStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
    7478                RegisterFormat(&mpFormatEtc[cRegisteredFormats], CF_HDROP);
    7579                mpStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
     
    7781                mlstFormats << strFormat;
    7882            }
     83            /* Plain text ("text/plain"). */
    7984            else if (strFormat.contains("text/plain", Qt::CaseInsensitive))
    8085            {
    81                 /* Plain text ("text/plain"). */
    8286                RegisterFormat(&mpFormatEtc[cRegisteredFormats], CF_TEXT);
    8387                mpStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
     88                RegisterFormat(&mpFormatEtc[cRegisteredFormats], CF_UNICODETEXT);
     89                mpStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
    8490
    8591                mlstFormats << strFormat;
     
    8995        LogFlowFunc(("Total registered formats: %RU32 (of %d total)\n",
    9096                     cRegisteredFormats, lstFormats.size()));
    91 #ifdef VBOX_STRICT
    92         AssertMsg(cRegisteredFormats == cAllFormats,
    93                   ("Registered formats count is not matching all formats count\n"));
    94 #endif
    9597        hr = S_OK;
    9698    }
     
    201203    AssertPtrReturn(pMedium, DV_E_FORMATETC);
    202204
     205#ifdef VBOX_DND_DEBUG_FORMATS
    203206    LogFlowFunc(("pFormatEtc=%p, pMedium=%p\n", pFormatEtc, pMedium));
     207#endif
    204208
    205209    ULONG lIndex;
     
    227231    if (mStatus == Dropped)
    228232    {
    229 #if 0
    230         LogFlowFunc(("Starting to transfer content from the guest ...\n"));
    231 
    232         /*
    233          * This is the right time starting to transfer the actual data
    234          * from the guest:
    235          * - The user just triggered an action that tells us to start, e.g. at
    236          *   the moment we only "listen" for releasing the left mouse button.
    237          * - We're still in OLE's (modal) drag'n drop context so that all data
    238          *   from the guest (hopefully) will be available on the host when the
    239          *   drag'n drop operation is about to finish through OLE.
    240          *
    241          * Note that in the URI case the guest files/dirs must be somewhere
    242          * on the host before OLE's drag'n drop operation is finished, otherwise
    243          * the whole operation will fail.
    244          */
    245 #endif
     233#ifdef VBOX_DND_DEBUG_FORMATS
    246234        LogFlowFunc(("cfFormat=%RI16, sFormat=%s, tyMed=%RU32, dwAspect=%RU32\n",
    247235                     pThisFormat->cfFormat, UIDnDDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
     
    249237        LogFlowFunc(("Got strFormat=%s, pvData=%p, cbData=%RU32\n",
    250238                     mstrFormat.toAscii().constData(), mpvData, mcbData));
    251 
     239#endif
    252240        QVariant::Type vaType;
    253241        QString strMIMEType;
     
    495483STDMETHODIMP UIDnDDataObject::QueryGetData(FORMATETC *pFormatEtc)
    496484{
    497     LogFlowFunc(("\n"));
    498485    return (LookupFormatEtc(pFormatEtc, NULL /* puIndex */)) ? S_OK : DV_E_FORMATETC;
    499486}
     
    648635            && pFormatEtc->dwAspect == mpFormatEtc[i].dwAspect)
    649636        {
     637#ifdef VBOX_DND_DEBUG_FORMATS
    650638            LogFlowFunc(("Format found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32, ulIndex=%RU32\n",
    651639                         pFormatEtc->tymed, pFormatEtc->cfFormat, UIDnDDataObject::ClipboardFormatToString(mpFormatEtc[i].cfFormat),
    652640                         pFormatEtc->dwAspect, i));
     641#endif
    653642            if (puIndex)
    654643                *puIndex = i;
     
    657646    }
    658647
     648#ifdef VBOX_DND_DEBUG_FORMATS
    659649    LogFlowFunc(("Format NOT found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32\n",
    660650                 pFormatEtc->tymed, pFormatEtc->cfFormat, UIDnDDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
    661651                 pFormatEtc->dwAspect));
    662 
     652#endif
    663653    return false;
    664654}
  • trunk/src/VBox/GuestHost/DragAndDrop/DnDURIList.cpp

    r50460 r50508  
    3434#include <VBox/GuestHost/DragAndDrop.h>
    3535
     36DnDURIObject::DnDURIObject(Type type,
     37                           const RTCString &strSrcPath,
     38                           const RTCString &strDstPath,
     39                           uint32_t fMode, uint64_t cbSize)
     40    : m_Type(type)
     41    , m_strSrcPath(strSrcPath)
     42    , m_strDstPath(strDstPath)
     43    , m_fMode(fMode)
     44    , m_cbSize(cbSize)
     45    , m_cbProcessed(0)
     46{
     47    RT_ZERO(u);
     48}
     49
     50DnDURIObject::~DnDURIObject(void)
     51{
     52    closeInternal();
     53}
     54
     55void DnDURIObject::closeInternal(void)
     56{
     57    if (m_Type == File)
     58    {
     59        if (u.m_hFile)
     60        {
     61            RTFileClose(u.m_hFile);
     62            u.m_hFile = NULL;
     63        }
     64    }
     65}
     66
     67bool DnDURIObject::IsComplete(void) const
     68{
     69    bool fComplete = false;
     70
     71    Assert(m_cbProcessed <= m_cbSize);
     72    if (m_cbProcessed == m_cbSize)
     73        fComplete = true;
     74
     75    switch (m_Type)
     76    {
     77        case File:
     78            if (!fComplete)
     79                fComplete = !u.m_hFile;
     80            break;
     81
     82        case Directory:
     83            fComplete = true;
     84            break;
     85
     86        default:
     87            break;
     88    }
     89
     90    return fComplete;
     91}
     92
     93/* static */
     94/** @todo Put this into an own class like DnDURIPath : public RTCString? */
     95int DnDURIObject::RebaseURIPath(RTCString &strPath,
     96                                const RTCString &strBaseOld,
     97                                const RTCString &strBaseNew)
     98{
     99    int rc;
     100    const char *pszPath = RTUriPath(strPath.c_str());
     101    if (pszPath)
     102    {
     103        const char *pszPathStart = pszPath;
     104        const char *pszBaseOld = strBaseOld.c_str();
     105        if (   pszBaseOld
     106            && RTPathStartsWith(pszPath, pszBaseOld))
     107        {
     108            pszPathStart += strlen(pszBaseOld);
     109        }
     110
     111        rc = VINF_SUCCESS;
     112
     113        if (RT_SUCCESS(rc))
     114        {
     115            char *pszPathNew = RTPathJoinA(strBaseNew.c_str(), pszPathStart);
     116            if (pszPathNew)
     117            {
     118                char *pszPathURI = RTUriCreate("file" /* pszScheme */, "/" /* pszAuthority */,
     119                                               pszPathNew /* pszPath */,
     120                                               NULL /* pszQuery */, NULL /* pszFragment */);
     121                if (pszPathURI)
     122                {
     123#ifdef DEBUG_andy
     124                    LogFlowFunc(("Rebasing \"%s\" to \"%s\"", strPath.c_str(), pszPathURI));
     125#endif
     126                    strPath = RTCString(pszPathURI) + "\r\n";
     127                    RTStrFree(pszPathURI);
     128
     129                    rc = VINF_SUCCESS;
     130                }
     131                else
     132                    rc = VERR_INVALID_PARAMETER;
     133
     134                RTStrFree(pszPathNew);
     135            }
     136            else
     137                rc = VERR_NO_MEMORY;
     138        }
     139    }
     140    else
     141        rc = VERR_INVALID_PARAMETER;
     142
     143#ifdef DEBUG_andy
     144    LogFlowFuncLeaveRC(rc);
     145#endif
     146    return rc;
     147}
     148
     149int DnDURIObject::Read(void *pvBuf, uint32_t cbToRead, uint32_t *pcbRead)
     150{
     151    AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
     152    AssertReturn(cbToRead, VERR_INVALID_PARAMETER);
     153    /* pcbRead is optional. */
     154
     155    int rc;
     156    switch (m_Type)
     157    {
     158        case File:
     159        {
     160            if (!u.m_hFile)
     161            {
     162                /* Open files on the source with RTFILE_O_DENY_WRITE to prevent races
     163                 * where the OS writes to the file while the destination side transfers
     164                 * it over. */
     165                rc = RTFileOpen(&u.m_hFile, m_strSrcPath.c_str(),
     166                                RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
     167            }
     168            else
     169                rc = VINF_SUCCESS;
     170
     171            bool fDone = false;
     172            if (RT_SUCCESS(rc))
     173            {
     174                size_t cbRead;
     175                rc = RTFileRead(u.m_hFile, pvBuf, cbToRead, &cbRead);
     176                if (RT_SUCCESS(rc))
     177                {
     178                    if (pcbRead)
     179                        *pcbRead = (uint32_t)cbRead;
     180
     181                    m_cbProcessed += cbRead;
     182                    Assert(m_cbProcessed <= m_cbSize);
     183
     184                    /* End of file reached or error occurred? */
     185                    if (   cbRead < cbToRead
     186                        || RT_FAILURE(rc))
     187                        closeInternal();
     188                }
     189            }
     190
     191            break;
     192        }
     193
     194        case Directory:
     195        {
     196            rc = VINF_SUCCESS;
     197            break;
     198        }
     199
     200        default:
     201            rc = VERR_NOT_IMPLEMENTED;
     202            break;
     203    }
     204
     205    LogFlowFunc(("Returning strSourcePath=%s, rc=%Rrc\n",
     206                 m_strSrcPath.c_str(), rc));
     207    return rc;
     208}
     209
     210/*** */
     211
    36212DnDURIList::DnDURIList(void)
    37213    : m_cbTotal(0)
     
    47223{
    48224    AssertPtrReturn(pcszPath, VERR_INVALID_POINTER);
    49     AssertReturn(cbBaseLen, VERR_INVALID_PARAMETER);
    50225
    51226    RTFSOBJINFO objInfo;
     
    74249        return rc;
    75250
    76     m_lstTree.append(DnDURIPath(pcszPath, &pcszPath[cbBaseLen],
    77                                 objInfo.Attr.fMode, cbSize));
     251    m_lstTree.append(DnDURIObject(  RTFS_IS_DIRECTORY(objInfo.Attr.fMode)
     252                                  ? DnDURIObject::Directory
     253                                  : DnDURIObject::File,
     254                                  pcszPath, &pcszPath[cbBaseLen],
     255                                  objInfo.Attr.fMode, cbSize));
    78256    m_cbTotal += cbSize;
    79257#ifdef DEBUG_andy
    80     LogFlowFunc(("strHostPath=%s, strGuestPath=%s, fMode=0x%x, cbSize=%RU64, cbTotal=%zu\n",
     258    LogFlowFunc(("strSrcPath=%s, strDstPath=%s, fMode=0x%x, cbSize=%RU64, cbTotal=%zu\n",
    81259                 pcszPath, &pcszPath[cbBaseLen], objInfo.Attr.fMode, cbSize, m_cbTotal));
    82260#endif
     
    140318                        break;
    141319
    142                     m_lstTree.append(DnDURIPath(pszNewFile, &pszNewFile[cbBaseLen],
    143                                                 objInfo1.Attr.fMode, cbSize));
     320                    m_lstTree.append(DnDURIObject(DnDURIObject::File,
     321                                                  pszNewFile, &pszNewFile[cbBaseLen],
     322                                                  objInfo1.Attr.fMode, cbSize));
    144323                    m_cbTotal += cbSize;
    145324#ifdef DEBUG_andy
    146                     LogFlowFunc(("strHostPath=%s, strGuestPath=%s, fMode=0x%x, cbSize=%RU64, cbTotal=%zu\n",
     325                    LogFlowFunc(("strSrcPath=%s, strDstPath=%s, fMode=0x%x, cbSize=%RU64, cbTotal=%zu\n",
    147326                                 pszNewFile, &pszNewFile[cbBaseLen], objInfo1.Attr.fMode, cbSize, m_cbTotal));
    148327#endif
     
    163342}
    164343
    165 int DnDURIList::AppendPath(const char *pszPath, uint32_t fFlags)
     344int DnDURIList::AppendNativePath(const char *pszPath, uint32_t fFlags)
    166345{
    167346    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
    168347
     348    char *pszPathURI = RTUriCreate("file" /* pszScheme */, "/" /* pszAuthority */,
     349                                   pszPath, NULL /* pszQuery */, NULL /* pszFragment */);
     350    int rc;
     351    if (pszPathURI)
     352    {
     353        rc = AppendURIPath(pszPathURI, fFlags);
     354        RTStrFree(pszPathURI);
     355    }
     356    else
     357        rc = VERR_INVALID_PARAMETER;
     358
     359    return rc;
     360}
     361
     362int DnDURIList::AppendNativePathsFromList(const char *pszNativePaths, size_t cbNativePaths,
     363                                          uint32_t fFlags)
     364{
     365    AssertPtrReturn(pszNativePaths, VERR_INVALID_POINTER);
     366    AssertReturn(cbNativePaths, VERR_INVALID_PARAMETER);
     367
     368    RTCList<RTCString> lstPaths
     369        = RTCString(pszNativePaths, cbNativePaths - 1).split("\r\n");
     370    return AppendNativePathsFromList(lstPaths, fFlags);
     371}
     372
     373int DnDURIList::AppendNativePathsFromList(const RTCList<RTCString> &lstNativePaths,
     374                                          uint32_t fFlags)
     375{
     376    int rc = VINF_SUCCESS;
     377
     378    for (size_t i = 0; i < lstNativePaths.size(); i++)
     379    {
     380        const RTCString &strPath = lstNativePaths.at(i);
     381        rc = AppendNativePath(strPath.c_str(), fFlags);
     382        if (RT_FAILURE(rc))
     383            break;
     384    }
     385
     386    LogFlowFuncLeaveRC(rc);
     387    return rc;
     388}
     389
     390int DnDURIList::AppendURIPath(const char *pszURI, uint32_t fFlags)
     391{
     392    AssertPtrReturn(pszURI, VERR_INVALID_POINTER);
     393
    169394#ifdef DEBUG_andy
    170     LogFlowFunc(("pszPath=%s, fFlags=0x%x\n", pszPath, fFlags));
     395    LogFlowFunc(("pszPath=%s, fFlags=0x%x\n", pszURI, fFlags));
    171396#endif
    172397    int rc = VINF_SUCCESS;
     
    174399    /* Query the path component of a file URI. If this hasn't a
    175400     * file scheme NULL is returned. */
    176     char *pszFilePath = RTUriFilePath(pszPath, URI_FILE_FORMAT_AUTO);
     401    char *pszFilePath = RTUriFilePath(pszURI, URI_FILE_FORMAT_AUTO);
    177402    if (pszFilePath)
    178403    {
     
    182407        if (pszFileName)
    183408        {
    184             char *pszNewURI = RTUriFileCreate(pszFileName);
    185             if (pszNewURI)
    186             {
    187                 m_lstRoot.append(pszNewURI);
    188                 RTStrFree(pszNewURI);
    189 
    190                 rc = appendPathRecursive(pszFilePath,
    191                                          pszFileName - pszFilePath,
    192                                          fFlags);
    193             }
    194         }
     409            Assert(pszFileName >= pszFilePath);
     410            char *pszRoot = &pszFilePath[pszFileName - pszFilePath];
     411            m_lstRoot.append(pszRoot);
     412#ifdef DEBUG_andy
     413            LogFlowFunc(("pszFilePath=%s, pszFileName=%s, pszRoot=%s\n",
     414                         pszFilePath, pszFileName, pszRoot));
     415#endif
     416            rc = appendPathRecursive(pszFilePath,
     417                                     pszFileName - pszFilePath,
     418                                     fFlags);
     419        }
     420        else
     421            rc = VERR_NOT_FOUND;
    195422
    196423        RTStrFree(pszFilePath);
    197424    }
    198     else /* Just append the raw data. */
    199         m_lstRoot.append(pszPath);
     425    else
     426        rc = VERR_INVALID_PARAMETER;
    200427
    201428    LogFlowFuncLeaveRC(rc);
     
    203430}
    204431
    205 int DnDURIList::AppendPathsFromList(const RTCList<RTCString> &lstURI,
    206                                     uint32_t fFlags)
     432int DnDURIList::AppendURIPathsFromList(const char *pszURIPaths, size_t cbURIPaths,
     433                                       uint32_t fFlags)
     434{
     435    AssertPtrReturn(pszURIPaths, VERR_INVALID_POINTER);
     436    AssertReturn(cbURIPaths, VERR_INVALID_PARAMETER);
     437
     438    RTCList<RTCString> lstPaths
     439        = RTCString(pszURIPaths, cbURIPaths - 1).split("\r\n");
     440    return AppendURIPathsFromList(lstPaths, fFlags);
     441}
     442
     443int DnDURIList::AppendURIPathsFromList(const RTCList<RTCString> &lstURI,
     444                                       uint32_t fFlags)
    207445{
    208446    int rc = VINF_SUCCESS;
     
    210448    for (size_t i = 0; i < lstURI.size(); i++)
    211449    {
    212         const RTCString &strURI = lstURI.at(i);
    213         rc = AppendPath(strURI.c_str(), fFlags);
     450        RTCString strURI = lstURI.at(i);
     451        rc = AppendURIPath(strURI.c_str(), fFlags);
     452
    214453        if (RT_FAILURE(rc))
    215454            break;
     
    228467}
    229468
     469#if 0
     470int DnDURIList::FromData(const void *pvData, size_t cbData,
     471
     472                         uint32_t fFlags)
     473{
     474    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     475    AssertReturn(cbData, VERR_INVALID_PARAMETER);
     476
     477    RTCList<RTCString> lstURI =
     478        RTCString(static_cast<const char*>(pvData), cbData - 1).split("\r\n");
     479    if (lstURI.isEmpty())
     480        return VINF_SUCCESS;
     481
     482    int rc = VINF_SUCCESS;
     483
     484    for (size_t i = 0; i < lstURI.size(); ++i)
     485    {
     486        const RTCString &strUri = lstURI.at(i);
     487        /* Query the path component of a file URI. If this hasn't a
     488         * file scheme, null is returned. */
     489        char *pszFilePath = RTUriFilePath(strUri.c_str(), URI_FILE_FORMAT_AUTO);
     490        if (pszFilePath)
     491        {
     492            rc = DnDPathSanitize(pszFilePath, strlen(pszFilePath));
     493            if (RT_SUCCESS(rc))
     494            {
     495                /** @todo Use RTPathJoin? */
     496                RTCString strFullPath;
     497                if (strBasePath.isNotEmpty())
     498                    strFullPath = RTCString().printf("%s%c%s", strBasePath.c_str(),
     499                                                     RTPATH_SLASH, pszFilePath);
     500                else
     501                    strFullPath = pszFilePath;
     502
     503                char *pszNewUri = RTUriFileCreate(strFullPath.c_str());
     504                if (pszNewUri)
     505                {
     506                    m_lstRoot.append(pszNewUri);
     507                    RTStrFree(pszNewUri);
     508                }
     509            }
     510        }
     511        else
     512            rc = VERR_INVALID_PARAMETER;
     513
     514        if (RT_FAILURE(rc))
     515            break;
     516    }
     517
     518    return rc;
     519}
     520#endif
     521
    230522void DnDURIList::RemoveFirst(void)
    231523{
    232     const DnDURIPath &curPath = m_lstTree.first();
    233 
    234     Assert(m_cbTotal >= curPath.m_cbSize);
    235     m_cbTotal -= curPath.m_cbSize; /* Adjust total size. */
     524    DnDURIObject &curPath = m_lstTree.first();
     525
     526    uint64_t cbSize = curPath.GetSize();
     527    Assert(m_cbTotal >= cbSize);
     528    m_cbTotal -= cbSize; /* Adjust total size. */
    236529
    237530    m_lstTree.removeFirst();
    238531}
    239532
     533int DnDURIList::RootFromURIData(const void *pvData, size_t cbData,
     534                                uint32_t fFlags)
     535{
     536    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     537    AssertReturn(cbData, VERR_INVALID_PARAMETER);
     538
     539    RTCList<RTCString> lstURI =
     540        RTCString(static_cast<const char*>(pvData), cbData - 1).split("\r\n");
     541    if (lstURI.isEmpty())
     542        return VINF_SUCCESS;
     543
     544    int rc = VINF_SUCCESS;
     545
     546    for (size_t i = 0; i < lstURI.size(); ++i)
     547    {
     548        /* Query the path component of a file URI. If this hasn't a
     549         * file scheme, NULL is returned. */
     550        const char *pszURI = lstURI.at(i).c_str();
     551        char *pszFilePath = RTUriFilePath(pszURI,
     552                                          URI_FILE_FORMAT_AUTO);
     553#ifdef DEBUG_andy
     554        LogFlowFunc(("pszURI=%s, pszFilePath=%s\n", pszURI, pszFilePath));
     555#endif
     556        if (pszFilePath)
     557        {
     558            rc = DnDPathSanitize(pszFilePath, strlen(pszFilePath));
     559            if (RT_SUCCESS(rc))
     560                m_lstRoot.append(pszFilePath);
     561
     562            RTStrFree(pszFilePath);
     563        }
     564        else
     565            rc = VERR_INVALID_PARAMETER;
     566
     567        if (RT_FAILURE(rc))
     568            break;
     569    }
     570
     571    return rc;
     572}
     573
     574RTCString DnDURIList::RootToString(const RTCString &strBasePath /* = "" */)
     575{
     576    RTCString strRet;
     577    for (size_t i = 0; i < m_lstRoot.size(); i++)
     578    {
     579        const char *pszCurRoot = m_lstRoot.at(i).c_str();
     580        if (strBasePath.isNotEmpty())
     581        {
     582            char *pszPath = RTPathJoinA(strBasePath.c_str(), pszCurRoot);
     583            if (pszPath)
     584            {
     585                char *pszPathURI = RTUriFileCreate(pszPath);
     586                if (pszPathURI)
     587                {
     588                    strRet += RTCString(pszPathURI) + "\r\n";
     589                    RTStrFree(pszPathURI);
     590                }
     591                RTStrFree(pszPath);
     592            }
     593            else
     594                break;
     595        }
     596        else
     597        {
     598            char *pszPathURI = RTUriFileCreate(pszCurRoot);
     599            if (pszPathURI)
     600            {
     601                strRet += RTCString(pszPathURI) + "\r\n";
     602                RTStrFree(pszPathURI);
     603            }
     604            else
     605                break;
     606        }
     607    }
     608
     609    return strRet;
     610}
     611
  • trunk/src/VBox/HostServices/DragAndDrop/dndmanager.cpp

    r50477 r50508  
    4949public:
    5050
    51     DnDHGSendDirPrivate(const RTCString &strPath,
    52                         uint32_t fMode, uint64_t cbSize,
     51    DnDHGSendDirPrivate(DnDURIObject URIObject,
    5352                        PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser)
    54         : m_strPath(strPath)
    55         , m_cbSize(cbSize)
     53        : m_URIObject(URIObject)
    5654        , m_pfnProgressCallback(pfnProgressCallback)
    5755        , m_pvProgressUser(pvProgressUser)
    5856    {
    5957        VBOXHGCMSVCPARM paTmpParms[3];
    60         paTmpParms[0].setString(m_strPath.c_str());
    61         paTmpParms[1].setUInt32((uint32_t)(m_strPath.length() + 1));
    62         paTmpParms[2].setUInt32(fMode);
     58        paTmpParms[0].setString(m_URIObject.GetDestPath().c_str());
     59        paTmpParms[1].setUInt32((uint32_t)(m_URIObject.GetDestPath().length() + 1));
     60        paTmpParms[2].setUInt32(m_URIObject.GetMode());
    6361
    6462        m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_DIR, 3, paTmpParms);
     
    7169        if (   RT_SUCCESS(rc)
    7270            && m_pfnProgressCallback)
    73             rc = m_pfnProgressCallback(m_cbSize, m_pvProgressUser);
     71            rc = m_pfnProgressCallback(m_URIObject.GetSize(), m_pvProgressUser);
    7472
    7573        return rc;
     
    7775
    7876protected:
    79     RTCString              m_strPath;
     77
     78    DnDURIObject           m_URIObject;
    8079
    8180    /* Progress stuff */
    82     size_t                 m_cbSize;
    8381    PFNDNDPRIVATEPROGRESS  m_pfnProgressCallback;
    8482    void                  *m_pvProgressUser;
     
    9492public:
    9593
    96     DnDHGSendFilePrivate(const RTCString &strHostPath,
    97                          const RTCString &strGuestPath,
    98                          uint32_t fMode, uint64_t cbSize,
     94    DnDHGSendFilePrivate(DnDURIObject URIObject,
    9995                         PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser);
    10096    virtual ~DnDHGSendFilePrivate(void);
     
    10399
    104100protected:
    105     RTCString              m_strHostPath;
    106     RTCString              m_strGuestPath;
    107     uint64_t               m_cbFileSize;
    108     uint64_t               m_cbFileProcessed;
    109     RTFILE                 m_hCurFile;
     101
     102    DnDURIObject           m_URIObject;
    110103    VBOXHGCMSVCPARM        m_paSkelParms[5];
    111104
     
    144137
    145138/******************************************************************************
    146  *   DnDHGSendFilePrivate                                                *
     139 *   DnDHGSendFilePrivate                                                     *
    147140 ******************************************************************************/
    148141
    149 DnDHGSendFilePrivate::DnDHGSendFilePrivate(const RTCString &strHostPath, const RTCString &strGuestPath,
    150                                            uint32_t fMode, uint64_t cbSize,
     142DnDHGSendFilePrivate::DnDHGSendFilePrivate(DnDURIObject URIObject,
    151143                                           PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser)
    152     : m_strHostPath(strHostPath)
    153     , m_strGuestPath(strGuestPath)
    154     , m_cbFileSize(cbSize)
    155     , m_cbFileProcessed(0)
    156     , m_hCurFile(0)
     144    : m_URIObject(URIObject)
    157145    , m_pfnProgressCallback(pfnProgressCallback)
    158146    , m_pvProgressUser(pvProgressUser)
    159147{
    160     m_paSkelParms[0].setString(m_strGuestPath.c_str());
    161     m_paSkelParms[1].setUInt32((uint32_t)(m_strGuestPath.length() + 1));
     148    m_paSkelParms[0].setString(m_URIObject.GetDestPath().c_str());
     149    m_paSkelParms[1].setUInt32((uint32_t)(m_URIObject.GetDestPath().length() + 1));
    162150    m_paSkelParms[2].setPointer(NULL, 0);
    163151    m_paSkelParms[3].setUInt32(0);
    164     m_paSkelParms[4].setUInt32(fMode);
     152    m_paSkelParms[4].setUInt32(m_URIObject.GetMode());
    165153
    166154    m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_FILE, 5, m_paSkelParms);
     
    169157DnDHGSendFilePrivate::~DnDHGSendFilePrivate(void)
    170158{
    171     if (m_hCurFile)
    172         RTFileClose(m_hCurFile);
    173159}
    174160
     
    184170        return rc;
    185171
    186     if (!m_hCurFile)
    187     {
    188         /* Open files on the host with RTFILE_O_DENY_WRITE to prevent races where the host
    189          * writes to the file while the guest transfers it over. */
    190         rc = RTFileOpen(&m_hCurFile, m_strHostPath.c_str(),
    191                         RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
    192     }
    193 
    194     size_t cbRead;
     172    uint32_t cbRead;
    195173    if (RT_SUCCESS(rc))
    196174    {
     
    200178        void *pvBuf = paParms[2].u.pointer.addr;
    201179        AssertPtr(pvBuf);
    202         rc = RTFileRead(m_hCurFile, pvBuf, cbToRead, &cbRead);
     180
     181        rc = m_URIObject.Read(pvBuf, cbToRead, &cbRead);
    203182        if (RT_LIKELY(RT_SUCCESS(rc)))
    204183        {
    205             /* Advance. */
    206             m_cbFileProcessed += cbRead;
    207             Assert(m_cbFileProcessed <= m_cbFileSize);
    208 
    209184            /* Tell the guest the actual size. */
    210185            paParms[3].setUInt32((uint32_t)cbRead);
     
    214189    if (RT_SUCCESS(rc))
    215190    {
    216         /* Check if we are done. */
    217         Assert(m_cbFileProcessed <= m_cbFileSize);
    218         bool fDone = m_cbFileSize == m_cbFileProcessed;
    219         if (!fDone)
     191        if (!m_URIObject.IsComplete())
    220192        {
    221193            try
    222194            {
    223                 /* More data! Prepare the next message. */
     195                /* More data needed to send over. Prepare the next message. */
    224196                m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_FILE, 5 /* cParms */,
    225197                                               m_paSkelParms);
     
    236208        {
    237209            rc = m_pfnProgressCallback(cbRead, m_pvProgressUser);
    238         }
    239 
    240         if (   fDone
    241             || RT_FAILURE(rc))
    242         {
    243             RTFileClose(m_hCurFile);
    244             m_hCurFile = NIL_RTFILE;
    245210        }
    246211    }
     
    365330        if (!lstURIOrg.isEmpty())
    366331        {
    367             rc = m_lstURI.AppendPathsFromList(lstURIOrg, 0 /* fFlags */);
     332            rc = m_lstURI.AppendNativePathsFromList(lstURIOrg, 0 /* fFlags */);
    368333            if (RT_SUCCESS(rc))
    369334            {
    370335                /* Add the total size of all meta data + files transferred to
    371                  * the message's total count. */
     336                 * the message's total byte count. */
    372337                m_cbTotal += m_lstURI.TotalBytes();
    373338
    374339                /* We have to change the actual DnD data. Remove any host paths and
    375                  * just decode the filename into the new data. The guest tools will
    376                  * add the correct path again, before sending the DnD drop event to
     340                 * just decode the filename into the new data. The Guest Additions will
     341                 * add the correct path again before sending the DnD drop event to
    377342                 * some window. */
    378343                strNewURIs = m_lstURI.RootToString();
     
    445410        /* Create new messages based on our internal path list. Currently
    446411         * this could be directories or regular files. */
    447         const DnDURIPath &nextPath = m_lstURI.First();
     412        const DnDURIObject &nextObj = m_lstURI.First();
    448413        try
    449414        {
     415            uint32_t fMode = nextObj.GetMode();
    450416            LogFlowFunc(("Processing srcPath=%s, dstPath=%s, fMode=0x%x, cbSize=%RU32, fIsDir=%RTbool, fIsFile=%RTbool\n",
    451                          nextPath.m_strSrcPath.c_str(), nextPath.m_strDstPath.c_str(),
    452                          nextPath.m_fMode, nextPath.m_cbSize,
    453                          RTFS_IS_DIRECTORY(nextPath.m_fMode), RTFS_IS_FILE(nextPath.m_fMode)));
    454 
    455             if (RTFS_IS_DIRECTORY(nextPath.m_fMode))
    456                 m_pNextPathMsg = new DnDHGSendDirPrivate(nextPath.m_strDstPath,
    457                                                          nextPath.m_fMode, nextPath.m_cbSize,
    458                                                          &DnDHGSendDataMessage::progressCallback,
     417                         nextObj.GetSourcePath().c_str(), nextObj.GetDestPath().c_str(),
     418                         fMode, nextObj.GetSize(),
     419                         RTFS_IS_DIRECTORY(fMode), RTFS_IS_FILE(fMode)));
     420
     421            if (RTFS_IS_DIRECTORY(fMode))
     422                m_pNextPathMsg = new DnDHGSendDirPrivate(nextObj,
     423                                                         &DnDHGSendDataMessage::progressCallback /* pfnProgressCallback */,
    459424                                                         this /* pvProgressUser */);
    460             else if (RTFS_IS_FILE(nextPath.m_fMode))
    461                 m_pNextPathMsg = new DnDHGSendFilePrivate(nextPath.m_strSrcPath, nextPath.m_strDstPath,
    462                                                           nextPath.m_fMode, nextPath.m_cbSize,
    463                                                           &DnDHGSendDataMessage::progressCallback,
     425            else if (RTFS_IS_FILE(fMode))
     426                m_pNextPathMsg = new DnDHGSendFilePrivate(nextObj,
     427                                                          &DnDHGSendDataMessage::progressCallback /* pfnProgressCallback */,
    464428                                                          this /* pvProgressUser */);
    465429            else
    466430                AssertMsgFailedReturn(("fMode=0x%x is not supported for srcPath=%s, dstPath=%s\n",
    467                                        nextPath.m_fMode, nextPath.m_strSrcPath.c_str(), nextPath.m_strDstPath.c_str()),
     431                                       fMode, nextObj.GetSourcePath().c_str(), nextObj.GetDestPath().c_str()),
    468432                                       VERR_NO_DATA);
    469433
  • trunk/src/VBox/HostServices/DragAndDrop/service.cpp

    r50463 r50508  
    169169}
    170170
    171 void DragAndDropService::guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     171void DragAndDropService::guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
     172                                   void *pvClient, uint32_t u32Function,
     173                                   uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    172174{
    173175    LogFlowFunc(("u32ClientID=%RU32, u32Function=%RU32, cParms=%RU32\n",
    174176                 u32ClientID, u32Function, cParms));
    175177
    176     int rc = VINF_SUCCESS;
     178    /* Check if we've the right mode set. */
     179    bool fIgnoreRequest = true; /* Play safe. */
    177180    switch (u32Function)
    178181    {
    179         /* Note: Older VBox versions with enabled DnD guest->host support (< 4.4)
    180          *       used the same ID (300) for GUEST_DND_GET_NEXT_HOST_MSG and
    181          *       HOST_DND_GH_REQ_PENDING, which led this service returning
    182          *       VERR_INVALID_PARAMETER when the guest wanted to actually
    183          *       handle HOST_DND_GH_REQ_PENDING. */
    184182        case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
    185         {
    186             LogFlowFunc(("GUEST_DND_GET_NEXT_HOST_MSG\n"));
    187             if (   cParms != 3
    188                 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* message */
    189                 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* parameter count */
    190                 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* blocking */)
    191                 rc = VERR_INVALID_PARAMETER;
     183            if (modeGet() != VBOX_DRAG_AND_DROP_MODE_OFF)
     184            {
     185                fIgnoreRequest = false;
     186            }
    192187            else
    193             {
    194                 rc = m_pManager->nextMessageInfo(&paParms[0].u.uint32, &paParms[1].u.uint32);
    195                 if (   RT_FAILURE(rc)
    196                     && paParms[2].u.uint32) /* Blocking? */
    197                 {
    198                     m_clientQueue.append(new HGCM::Client(u32ClientID, callHandle, u32Function, cParms, paParms));
    199                     rc = VINF_HGCM_ASYNC_EXECUTE;
    200                 }
    201             }
     188                LogFlowFunc(("Drag'n drop disabled, ignoring request\n"));
    202189            break;
    203         }
    204190        case DragAndDropSvc::GUEST_DND_HG_ACK_OP:
    205         {
    206             LogFlowFunc(("GUEST_DND_HG_ACK_OP\n"));
    207             if (   modeGet() != VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
    208                 && modeGet() != VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST)
    209             {
    210                 LogFlowFunc(("Wrong DnD mode, ignoring request\n"));
    211                 break;
    212             }
    213 
    214             if (   cParms != 1
    215                 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* action */)
    216                 rc = VERR_INVALID_PARAMETER;
     191        case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
     192            if (   modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
     193                || modeGet() == VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST)
     194            {
     195                fIgnoreRequest = false;
     196            }
    217197            else
    218             {
    219                 DragAndDropSvc::VBOXDNDCBHGACKOPDATA data;
    220                 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_ACK_OP;
    221                 paParms[0].getUInt32(&data.uAction);
    222                 if (m_pfnHostCallback)
    223                     rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
    224 //                m_pHelpers->pfnCallComplete(callHandle, rc);
    225             }
     198                LogFlowFunc(("Host -> guest DnD mode disabled, ignoring request\n"));
    226199            break;
    227         }
    228         case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
    229         {
    230             LogFlowFunc(("GUEST_DND_HG_REQ_DATA\n"));
    231             if (   modeGet() != VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
    232                 && modeGet() != VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST)
    233             {
    234                 LogFlowFunc(("Wrong DnD mode, ignoring request\n"));
    235                 break;
    236             }
    237 
    238             if (   cParms != 1
    239                 || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* format */)
    240                 rc = VERR_INVALID_PARAMETER;
    241             else
    242             {
    243                 DragAndDropSvc::VBOXDNDCBHGREQDATADATA data;
    244                 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_REQ_DATA;
    245                 uint32_t cTmp;
    246                 paParms[0].getPointer((void**)&data.pszFormat, &cTmp);
    247                 if (m_pfnHostCallback)
    248                     rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
    249 //                m_pHelpers->pfnCallComplete(callHandle, rc);
    250 //                if (data.pszFormat)
    251 //                    RTMemFree(data.pszFormat);
    252 //                if (data.pszTmpPath)
    253 //                    RTMemFree(data.pszTmpPath);
    254             }
    255             break;
    256         }
    257200#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    258201        case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
    259         {
    260             LogFlowFunc(("GUEST_DND_GH_ACK_PENDING\n"));
    261             if (   modeGet() != VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
    262                 && modeGet() != VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST)
    263             {
    264                 LogFlowFunc(("Wrong DnD mode, ignoring request\n"));
    265                 break;
    266             }
    267 
    268             if (   cParms != 3
    269                 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* defaction */
    270                 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* allactions */
    271                 || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR   /* format */)
    272                 rc = VERR_INVALID_PARAMETER;
     202        case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
     203        case DragAndDropSvc::GUEST_DND_GH_SND_DIR:
     204        case DragAndDropSvc::GUEST_DND_GH_SND_FILE:
     205        case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
     206            if (   modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
     207                || modeGet() == VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST)
     208            {
     209                fIgnoreRequest = false;
     210            }
    273211            else
    274             {
    275                 DragAndDropSvc::VBOXDNDCBGHACKPENDINGDATA data;
    276                 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_ACK_PENDING;
    277                 paParms[0].getUInt32(&data.uDefAction);
    278                 paParms[1].getUInt32(&data.uAllActions);
    279                 uint32_t cTmp;
    280                 paParms[2].getPointer((void**)&data.pszFormat, &cTmp);
    281                 if (m_pfnHostCallback)
    282                     rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
    283             }
     212                LogFlowFunc(("Guest -> host DnD mode disabled, ignoring request\n"));
    284213            break;
    285         }
    286         case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
    287         {
    288             LogFlowFunc(("GUEST_DND_GH_SND_DATA\n"));
    289             if (   modeGet() != VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
    290                 && modeGet() != VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST)
    291             {
    292                 LogFlowFunc(("Wrong DnD mode, ignoring request\n"));
    293                 break;
    294             }
    295 
    296             if (   cParms != 2
    297                 || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR   /* data */
    298                 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
    299                 rc = VERR_INVALID_PARAMETER;
    300             else
    301             {
    302                 DragAndDropSvc::VBOXDNDCBSNDDATADATA data;
    303                 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA;
    304                 paParms[0].getPointer((void**)&data.pvData, &data.cbData);
    305                 paParms[1].getUInt32(&data.cbAllSize);
    306                 if (m_pfnHostCallback)
    307                     rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
    308             }
    309             break;
    310         }
    311         case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
    312         {
    313             LogFlowFunc(("GUEST_DND_GH_EVT_ERROR\n"));
    314             if (   modeGet() != VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
    315                 && modeGet() != VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST)
    316             {
    317                 LogFlowFunc(("Wrong DnD mode, ignoring request\n"));
    318                 break;
    319             }
    320 
    321             if (   cParms != 1
    322                 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* rc */)
    323                 rc = VERR_INVALID_PARAMETER;
    324             else
    325             {
    326                 DragAndDropSvc::VBOXDNDCBEVTERRORDATA data;
    327                 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR;
    328                 uint32_t rcOp;
    329                 paParms[0].getUInt32(&rcOp);
    330                 data.rc = rcOp;
    331                 if (m_pfnHostCallback)
    332                     rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
    333             }
    334             break;
    335         }
    336214#endif
    337215        default:
     216            /* Reach through to DnD manager. */
     217            fIgnoreRequest = false;
     218            break;
     219    }
     220
     221    int rc;
     222    if (!fIgnoreRequest)
     223    {
     224        rc = VINF_SUCCESS;
     225        switch (u32Function)
    338226        {
    339             /* All other messages are handled by the DnD manager. */
    340             rc = m_pManager->nextMessage(u32Function, cParms, paParms);
    341             break;
     227            /* Note: Older VBox versions with enabled DnD guest->host support (< 4.4)
     228             *       used the same message ID (300) for GUEST_DND_GET_NEXT_HOST_MSG and
     229             *       HOST_DND_GH_REQ_PENDING, which led this service returning
     230             *       VERR_INVALID_PARAMETER when the guest wanted to actually
     231             *       handle HOST_DND_GH_REQ_PENDING. */
     232            case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
     233            {
     234                LogFlowFunc(("GUEST_DND_GET_NEXT_HOST_MSG\n"));
     235                if (   cParms != 3
     236                    || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* message */
     237                    || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* parameter count */
     238                    || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* blocking */)
     239                    rc = VERR_INVALID_PARAMETER;
     240                else
     241                {
     242                    rc = m_pManager->nextMessageInfo(&paParms[0].u.uint32, &paParms[1].u.uint32);
     243                    if (   RT_FAILURE(rc)
     244                        && paParms[2].u.uint32) /* Blocking? */
     245                    {
     246                        m_clientQueue.append(new HGCM::Client(u32ClientID, callHandle, u32Function, cParms, paParms));
     247                        rc = VINF_HGCM_ASYNC_EXECUTE;
     248                    }
     249                }
     250                break;
     251            }
     252            case DragAndDropSvc::GUEST_DND_HG_ACK_OP:
     253            {
     254                LogFlowFunc(("GUEST_DND_HG_ACK_OP\n"));
     255                if (   cParms != 1
     256                    || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* action */)
     257                    rc = VERR_INVALID_PARAMETER;
     258                else
     259                {
     260                    DragAndDropSvc::VBOXDNDCBHGACKOPDATA data;
     261                    data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_ACK_OP;
     262                    paParms[0].getUInt32(&data.uAction);
     263                    if (m_pfnHostCallback)
     264                        rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
     265    //                m_pHelpers->pfnCallComplete(callHandle, rc);
     266                }
     267                break;
     268            }
     269            case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
     270            {
     271                LogFlowFunc(("GUEST_DND_HG_REQ_DATA\n"));
     272                if (   cParms != 1
     273                    || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* format */)
     274                    rc = VERR_INVALID_PARAMETER;
     275                else
     276                {
     277                    DragAndDropSvc::VBOXDNDCBHGREQDATADATA data;
     278                    data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_REQ_DATA;
     279                    uint32_t cTmp;
     280                    paParms[0].getPointer((void**)&data.pszFormat, &cTmp);
     281                    if (m_pfnHostCallback)
     282                        rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
     283    //                m_pHelpers->pfnCallComplete(callHandle, rc);
     284    //                if (data.pszFormat)
     285    //                    RTMemFree(data.pszFormat);
     286    //                if (data.pszTmpPath)
     287    //                    RTMemFree(data.pszTmpPath);
     288                }
     289                break;
     290            }
     291#ifdef VBOX_WITH_DRAG_AND_DROP_GH
     292            case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
     293            {
     294                LogFlowFunc(("GUEST_DND_GH_ACK_PENDING\n"));
     295                if (   cParms != 3
     296                    || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* defaction */
     297                    || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* allactions */
     298                    || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR   /* format */)
     299                    rc = VERR_INVALID_PARAMETER;
     300                else
     301                {
     302                    DragAndDropSvc::VBOXDNDCBGHACKPENDINGDATA data;
     303                    data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_ACK_PENDING;
     304                    paParms[0].getUInt32(&data.uDefAction);
     305                    paParms[1].getUInt32(&data.uAllActions);
     306                    uint32_t cTmp;
     307                    paParms[2].getPointer((void**)&data.pszFormat, &cTmp);
     308                    if (m_pfnHostCallback)
     309                        rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
     310                }
     311                break;
     312            }
     313            case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
     314            {
     315                LogFlowFunc(("GUEST_DND_GH_SND_DATA\n"));
     316                if (   cParms != 2
     317                    || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR   /* data */
     318                    || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
     319                    rc = VERR_INVALID_PARAMETER;
     320                else
     321                {
     322                    DragAndDropSvc::VBOXDNDCBSNDDATADATA data;
     323                    data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA;
     324                    paParms[0].getPointer((void**)&data.pvData, &data.cbData);
     325                    paParms[1].getUInt32(&data.cbTotalSize);
     326                    if (m_pfnHostCallback)
     327                        rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
     328                }
     329                break;
     330            }
     331            case DragAndDropSvc::GUEST_DND_GH_SND_DIR:
     332            {
     333                LogFlowFunc(("GUEST_DND_GH_SND_DIR\n"));
     334                if (   cParms != 3
     335                    || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR   /* path */
     336                    || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* path length */
     337                    || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* creation mode */)
     338                    rc = VERR_INVALID_PARAMETER;
     339                else
     340                {
     341                    DragAndDropSvc::VBOXDNDCBSNDDIRDATA data;
     342                    data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_DIR;
     343                    uint32_t cTmp;
     344                    paParms[0].getPointer((void**)&data.pszPath, &cTmp);
     345                    paParms[1].getUInt32(&data.cbPath);
     346                    paParms[2].getUInt32(&data.fMode);
     347#ifdef DEBUG_andy
     348                    LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x\n",
     349                                 data.pszPath, data.cbPath, data.fMode));
     350#endif
     351                    if (m_pfnHostCallback)
     352                        rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
     353                }
     354                break;
     355            }
     356            case DragAndDropSvc::GUEST_DND_GH_SND_FILE:
     357            {
     358                LogFlowFunc(("GUEST_DND_GH_SND_FILE\n"));
     359                if (   cParms != 5
     360                    || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR   /* file path */
     361                    || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* file path length */
     362                    || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR   /* file data */
     363                    || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* file data length */
     364                    || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* creation mode */)
     365                    rc = VERR_INVALID_PARAMETER;
     366                else
     367                {
     368                    DragAndDropSvc::VBOXDNDCBSNDFILEDATA data;
     369                    data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE;
     370                    uint32_t cTmp;
     371                    paParms[0].getPointer((void**)&data.pszFilePath, &cTmp);
     372                    paParms[1].getUInt32(&data.cbFilePath);
     373                    paParms[2].getPointer((void**)&data.pvData, &data.cbData);
     374                    /* paParms[3] is cbData. */
     375                    paParms[4].getUInt32(&data.fMode);
     376#ifdef DEBUG_andy
     377                    LogFlowFunc(("pszFilePath=%s, cbData=%RU32, pvData=0x%p, fMode=0x%x\n",
     378                                 data.pszFilePath, data.cbData, data.pvData, data.fMode));
     379#endif
     380                    if (m_pfnHostCallback)
     381                        rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
     382                }
     383                break;
     384            }
     385            case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
     386            {
     387                LogFlowFunc(("GUEST_DND_GH_EVT_ERROR\n"));
     388                if (   cParms != 1
     389                    || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* rc */)
     390                    rc = VERR_INVALID_PARAMETER;
     391                else
     392                {
     393                    DragAndDropSvc::VBOXDNDCBEVTERRORDATA data;
     394                    data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR;
     395                    uint32_t rcOp;
     396                    paParms[0].getUInt32(&rcOp);
     397                    data.rc = rcOp;
     398                    if (m_pfnHostCallback)
     399                        rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
     400                }
     401                break;
     402            }
     403#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
     404            default:
     405            {
     406                /* All other messages are handled by the DnD manager. */
     407                rc = m_pManager->nextMessage(u32Function, cParms, paParms);
     408                break;
     409            }
    342410        }
    343411    }
     412    else
     413        rc = VERR_NOT_SUPPORTED;
     414
    344415    /* If async execute is requested, we didn't notify the guest about
    345416     * completion. The client is queued into the waiters list and will be
  • trunk/src/VBox/Main/include/GuestDnDImpl.h

    r42866 r50508  
    44
    55/*
    6  * Copyright (C) 2011-2012 Oracle Corporation
     6 * Copyright (C) 2011-2014 Oracle Corporation
    77 *
    88 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2020/* Forward declaration of the d-pointer. */
    2121class GuestDnDPrivate;
     22#ifdef VBOX_WITH_DRAG_AND_DROP_GH
     23 class DnDGuestResponse;
     24#endif
    2225
    2326class GuestDnD
     
    4245    static DECLCALLBACK(int) notifyGuestDragAndDropEvent(void *pvExtension, uint32_t u32Function, void *pvParms, uint32_t cbParms);
    4346
     47protected:
     48
     49#ifdef VBOX_WITH_DRAG_AND_DROP_GH
     50    int onGHSendData(DnDGuestResponse *pResp, const void *pvData, size_t cbData, size_t cbTotalSize);
     51    int onGHSendDir(DnDGuestResponse *pResp, const char *pszPath, size_t cbPath, uint32_t fMode);
     52    int onGHSendFile(DnDGuestResponse *pResp, const char *pszPath, size_t cbPath, void *pvData, size_t cbData, uint32_t fMode);
     53#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
     54
    4455private:
    4556
  • trunk/src/VBox/Main/src-client/GuestDnDImpl.cpp

    r50460 r50508  
    191191    Utf8Str format(void) const { return m_strFormat; }
    192192
    193     int dataAdd(void *pvData, uint32_t cbData, uint32_t *pcbCurSize);
     193    void setDropDir(const Utf8Str &strDropDir) { m_strDropDir = strDropDir; }
     194    Utf8Str dropDir(void) const { return m_strDropDir; }
     195
     196    int dataAdd(const void *pvData, uint32_t cbData, uint32_t *pcbCurSize);
     197    int dataSetStatus(size_t cbDataAdd, size_t cbDataTotal = 0);
    194198    void reset(void);
    195199    const void *data(void) { return m_pvData; }
     
    205209    uint32_t             m_allActions;
    206210    Utf8Str              m_strFormat;
     211
     212    /** The actual MIME data.*/
    207213    void                *m_pvData;
     214    /** Size (in bytes) of MIME data. */
    208215    uint32_t             m_cbData;
     216
     217    size_t               m_cbDataCurrent;
     218    size_t               m_cbDataTotal;
     219    /** Dropped files directory on the host. */
     220    Utf8Str              m_strDropDir;
    209221
    210222    ComObjPtr<Guest>     m_parent;
     
    276288  , m_pvData(0)
    277289  , m_cbData(0)
     290  , m_cbDataCurrent(0)
     291  , m_cbDataTotal(0)
    278292  , m_parent(pGuest)
    279293{
     
    303317}
    304318
    305 int DnDGuestResponse::dataAdd(void *pvData, uint32_t cbData, uint32_t *pcbCurSize)
    306 {
     319int DnDGuestResponse::dataAdd(const void *pvData, uint32_t cbData,
     320                              uint32_t *pcbCurSize)
     321{
     322    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     323    AssertReturn(cbData, VERR_INVALID_PARAMETER);
     324    /* pcbCurSize is optional. */
     325
    307326    int rc = VINF_SUCCESS;
    308327
     
    348367}
    349368
    350 int DnDGuestResponse::setProgress(unsigned uPercentage, uint32_t uState, int rcOp /* = VINF_SUCCESS */)
    351 {
    352     LogFlowFunc(("uPercentage=%RU32, uState=%ld, rcOp=%Rrc\n", uPercentage, uState, rcOp));
     369int DnDGuestResponse::setProgress(unsigned uPercentage,
     370                                  uint32_t uState, int rcOp /* = VINF_SUCCESS */)
     371{
     372    LogFlowFunc(("uPercentage=%RU32, uState=%ld, rcOp=%Rrc\n",
     373                 uPercentage, uState, rcOp));
    353374
    354375    int vrc = VINF_SUCCESS;
     
    364385                                                COM_IIDOF(IGuest),
    365386                                                m_parent->getComponentName(),
    366                                                 m_parent->tr("Guest error (%Rrc)"), rcOp);
     387                                                m_parent->tr("Drag'n drop guest error (%Rrc)"), rcOp);
    367388            }
    368389            else if (uState == DragAndDropSvc::DND_PROGRESS_CANCELLED)
     
    390411}
    391412
     413int DnDGuestResponse::dataSetStatus(size_t cbDataAdd, size_t cbDataTotal /* = 0 */)
     414{
     415    if (cbDataTotal)
     416    {
     417        AssertMsg(m_cbDataTotal <= cbDataTotal, ("New data size size must not be smaller (%zu) than old value (%zu)\n",
     418                                                 cbDataTotal, m_cbDataTotal));
     419        m_cbDataTotal = cbDataTotal;
     420        LogFlowFunc(("Updating total data size to: %zu\n", m_cbDataTotal));
     421    }
     422    AssertMsg(m_cbDataTotal, ("m_cbDataTotal must not be <= 0\n"));
     423
     424    m_cbDataCurrent += cbDataAdd;
     425    unsigned int cPercentage = RT_MIN(m_cbDataCurrent * 100.0 / m_cbDataTotal, 100);
     426
     427    /** @todo Don't use anonymous enums (uint32_t). */
     428    uint32_t uStatus = DragAndDropSvc::DND_PROGRESS_RUNNING;
     429    if (m_cbDataCurrent >= m_cbDataTotal)
     430        uStatus = DragAndDropSvc::DND_PROGRESS_COMPLETE;
     431
     432#ifdef DEBUG_andy
     433    LogFlowFunc(("Updating transfer status (%zu/%zu), status=%ld\n",
     434                 m_cbDataCurrent, m_cbDataTotal, uStatus));
     435#endif
     436
     437    AssertMsg(m_cbDataCurrent <= m_cbDataTotal,
     438              ("More data transferred (%RU32) than initially announced (%RU32)\n",
     439              m_cbDataCurrent, m_cbDataTotal));
     440
     441    int rc = setProgress(cPercentage, uStatus);
     442
     443    /** @todo For now we instantly confirm the cancel. Check if the
     444     *        guest should first clean up stuff itself and than really confirm
     445     *        the cancel request by an extra message. */
     446    if (rc == VERR_CANCELLED)
     447        rc = setProgress(100, DragAndDropSvc::DND_PROGRESS_CANCELLED);
     448
     449    return rc;
     450}
     451
    392452HRESULT DnDGuestResponse::queryProgressTo(IProgress **ppProgress)
    393453{
     
    503563
    504564/* static */
    505 void GuestDnDPrivate::toHGCMActions(DragAndDropAction_T inDefAction, uint32_t *pOutDefAction, ComSafeArrayIn(DragAndDropAction_T, inAllowedActions), uint32_t *pOutAllowedActions)
     565void GuestDnDPrivate::toHGCMActions(DragAndDropAction_T inDefAction,
     566                                    uint32_t *pOutDefAction,
     567                                    ComSafeArrayIn(DragAndDropAction_T, inAllowedActions),
     568                                    uint32_t *pOutAllowedActions)
    506569{
    507570    const com::SafeArray<DragAndDropAction_T> sfaInActions(ComSafeArrayInArg(inAllowedActions));
     
    529592DragAndDropAction_T GuestDnDPrivate::toMainAction(uint32_t uAction)
    530593{
    531     /* For now it doesn't seems useful to allow a link action between host & guest. Maybe later! */
     594    /* For now it doesn't seems useful to allow a
     595     * link action between host & guest. Maybe later! */
    532596    return (isDnDCopyAction(uAction) ? (DragAndDropAction_T)DragAndDropAction_Copy :
    533597            isDnDMoveAction(uAction) ? (DragAndDropAction_T)DragAndDropAction_Move :
     
    536600
    537601/* static */
    538 void GuestDnDPrivate::toMainActions(uint32_t uActions, ComSafeArrayOut(DragAndDropAction_T, actions))
    539 {
    540     /* For now it doesn't seems useful to allow a link action between host & guest. Maybe later! */
     602void GuestDnDPrivate::toMainActions(uint32_t uActions,
     603                                    ComSafeArrayOut(DragAndDropAction_T, actions))
     604{
     605    /* For now it doesn't seems useful to allow a
     606     * link action between host & guest. Maybe later! */
    541607    RTCList<DragAndDropAction_T> list;
    542608    if (hasDnDCopyAction(uActions))
     
    556622}
    557623
    558 GuestDnD::~GuestDnD()
     624GuestDnD::~GuestDnD(void)
    559625{
    560626    delete d_ptr;
    561627}
    562628
    563 HRESULT GuestDnD::dragHGEnter(ULONG uScreenId, ULONG uX, ULONG uY, DragAndDropAction_T defaultAction, ComSafeArrayIn(DragAndDropAction_T, allowedActions), ComSafeArrayIn(IN_BSTR, formats), DragAndDropAction_T *pResultAction)
     629HRESULT GuestDnD::dragHGEnter(ULONG uScreenId, ULONG uX, ULONG uY,
     630                              DragAndDropAction_T defaultAction,
     631                              ComSafeArrayIn(DragAndDropAction_T, allowedActions),
     632                              ComSafeArrayIn(IN_BSTR, formats),
     633                              DragAndDropAction_T *pResultAction)
    564634{
    565635    DPTR(GuestDnD);
     
    621691}
    622692
    623 HRESULT GuestDnD::dragHGMove(ULONG uScreenId, ULONG uX, ULONG uY, DragAndDropAction_T defaultAction, ComSafeArrayIn(DragAndDropAction_T, allowedActions), ComSafeArrayIn(IN_BSTR, formats), DragAndDropAction_T *pResultAction)
     693HRESULT GuestDnD::dragHGMove(ULONG uScreenId, ULONG uX, ULONG uY,
     694                             DragAndDropAction_T defaultAction,
     695                             ComSafeArrayIn(DragAndDropAction_T, allowedActions),
     696                             ComSafeArrayIn(IN_BSTR, formats),
     697                             DragAndDropAction_T *pResultAction)
    624698{
    625699    DPTR(GuestDnD);
     
    879953
    880954    const char *pcszFormat = strFormat.c_str();
    881     LogFlowFunc(("strFormat=%s, uAction=0x%x\n", pcszFormat, uAction));
    882     if (DnDMIMENeedsDropDir(pcszFormat, strlen(pcszFormat)))
     955    bool fNeedsDropDir = DnDMIMENeedsDropDir(pcszFormat, strlen(pcszFormat));
     956    LogFlowFunc(("strFormat=%s, uAction=0x%x, fNeedsDropDir=%RTbool\n",
     957                 pcszFormat, uAction, fNeedsDropDir));
     958
     959    DnDGuestResponse *pDnD = d->response();
     960    AssertPtr(pDnD);
     961
     962    if (fNeedsDropDir)
    883963    {
    884964        char szDropDir[RTPATH_MAX];
     
    889969                               szDropDir, rc);
    890970        LogFlowFunc(("Dropped files directory on the host is: %s\n", szDropDir));
     971
     972        pDnD->setDropDir(szDropDir);
    891973    }
    892974
     
    899981        paParms[i++].setUInt32(uAction);
    900982
    901         DnDGuestResponse *pDnD = d->response();
    902 
    903983        /* Reset any old data and the progress status. */
    904984        pDnD->reset();
     
    9251005    const ComObjPtr<Guest> &p = d->p;
    9261006
    927     HRESULT rc = S_OK;
    928 
    929     DnDGuestResponse *pDnD = d->response();
    930     if (pDnD)
     1007    HRESULT hr = S_OK;
     1008
     1009    DnDGuestResponse *pResp = d->response();
     1010    if (pResp)
    9311011    {
    9321012        com::SafeArray<BYTE> sfaData;
    9331013
    934         uint32_t cbData = pDnD->size();
     1014        size_t cbData = pResp->size();
    9351015        if (cbData)
    9361016        {
    937             /* Copy the data into a safe array of bytes. */
    938             const void *pvData = pDnD->data();
    939             if (sfaData.resize(cbData))
    940                 memcpy(sfaData.raw(), pvData, cbData);
     1017            const void *pvData = pResp->data();
     1018            AssertPtr(pvData);
     1019
     1020            Utf8Str strFormat = pResp->format();
     1021            LogFlowFunc(("strFormat=%s, strDropDir=%s\n",
     1022                         strFormat.c_str(), pResp->dropDir().c_str()));
     1023
     1024            if (DnDMIMEHasFileURLs(strFormat.c_str(), strFormat.length()))
     1025            {
     1026                DnDURIList lstURI;
     1027                int rc2 = lstURI.RootFromURIData(pvData, cbData, 0 /* fFlags */);
     1028                if (RT_SUCCESS(rc2))
     1029                {
     1030                    Utf8Str strURIs = lstURI.RootToString(pResp->dropDir());
     1031                    if (sfaData.resize(strURIs.length()))
     1032                        memcpy(sfaData.raw(), strURIs.c_str(), strURIs.length());
     1033                    else
     1034                        hr = E_OUTOFMEMORY;
     1035                }
     1036                else
     1037                    hr = VBOX_E_IPRT_ERROR;
     1038
     1039                LogFlowFunc(("Found %zu root URIs, rc=%Rrc\n", lstURI.RootCount(), rc2));
     1040            }
    9411041            else
    942                 rc = E_OUTOFMEMORY;
     1042            {
     1043                /* Copy the data into a safe array of bytes. */
     1044                if (sfaData.resize(cbData))
     1045                    memcpy(sfaData.raw(), pvData, cbData);
     1046                else
     1047                    hr = E_OUTOFMEMORY;
     1048            }
    9431049        }
    9441050
    945 #ifdef DEBUG_andy
    946         LogFlowFunc(("Received %RU32 bytes\n", cbData));
    947 #endif
     1051        LogFlowFunc(("cbData=%zu\n", cbData));
     1052
    9481053        /* Detach in any case, regardless of data size. */
    9491054        sfaData.detachTo(ComSafeArrayOutArg(data));
    9501055
    9511056        /* Delete the data. */
    952         pDnD->reset();
     1057        pResp->reset();
    9531058    }
    9541059    else
    955         rc = VBOX_E_INVALID_OBJECT_STATE;
    956 
     1060        hr = VBOX_E_INVALID_OBJECT_STATE;
     1061
     1062    LogFlowFunc(("Returning hr=%Rhrc\n", hr));
     1063    return hr;
     1064}
     1065
     1066int GuestDnD::onGHSendData(DnDGuestResponse *pResp,
     1067                           const void *pvData, size_t cbData,
     1068                           size_t cbTotalSize)
     1069{
     1070    AssertPtrReturn(pResp, VERR_INVALID_POINTER);
     1071    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     1072    AssertReturn(cbData, VERR_INVALID_PARAMETER);
     1073    AssertReturn(cbTotalSize, VERR_INVALID_PARAMETER);
     1074
     1075    int rc = pResp->dataAdd(pvData, cbData, NULL /* Current size */);
     1076    if (RT_SUCCESS(rc))
     1077        rc = pResp->dataSetStatus(cbData, cbTotalSize);
     1078
     1079    LogFlowFuncLeaveRC(rc);
    9571080    return rc;
    9581081}
     1082
     1083int GuestDnD::onGHSendDir(DnDGuestResponse *pResp,
     1084                          const char *pszPath, size_t cbPath,
     1085                          uint32_t fMode)
     1086{
     1087    AssertPtrReturn(pResp, VERR_INVALID_POINTER);
     1088    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
     1089    AssertReturn(cbPath, VERR_INVALID_PARAMETER);
     1090
     1091    LogFlowFunc(("strDir=%s, cbPath=%zu, fMode=0x%x\n",
     1092                 pszPath, cbPath, fMode));
     1093
     1094    int rc;
     1095    char *pszDir = RTPathJoinA(pResp->dropDir().c_str(), pszPath);
     1096    if (pszDir)
     1097    {
     1098        rc = RTDirCreateFullPath(pszDir, fMode);
     1099        RTStrFree(pszDir);
     1100    }
     1101    else
     1102        rc = VERR_NO_MEMORY;
     1103
     1104    if (RT_SUCCESS(rc))
     1105        rc = pResp->dataSetStatus(cbPath);
     1106
     1107    LogFlowFuncLeaveRC(rc);
     1108    return rc;
     1109}
     1110
     1111int GuestDnD::onGHSendFile(DnDGuestResponse *pResp,
     1112                           const char *pszPath, size_t cbPath,
     1113                           void *pvData, size_t cbData, uint32_t fMode)
     1114{
     1115    AssertPtrReturn(pResp, VERR_INVALID_POINTER);
     1116    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
     1117    AssertReturn(cbPath, VERR_INVALID_PARAMETER);
     1118
     1119    LogFlowFunc(("strFile=%s, cbPath=%zu, fMode=0x%x\n",
     1120                 pszPath, cbPath, fMode));
     1121
     1122    /** @todo Add file locking between calls! */
     1123    int rc;
     1124    char *pszFile = RTPathJoinA(pResp->dropDir().c_str(), pszPath);
     1125    if (pszFile)
     1126    {
     1127        RTFILE hFile;
     1128        rc = RTFileOpen(&hFile, pszFile,
     1129                        RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE | RTFILE_O_WRITE);
     1130        if (RT_SUCCESS(rc))
     1131        {
     1132            rc = RTFileWrite(hFile, pvData, cbData,
     1133                             NULL /* No partial writes */);
     1134            RTFileClose(hFile);
     1135        }
     1136        RTStrFree(pszFile);
     1137    }
     1138    else
     1139        rc = VERR_NO_MEMORY;
     1140
     1141    if (RT_SUCCESS(rc))
     1142        rc = pResp->dataSetStatus(cbData);
     1143
     1144    LogFlowFuncLeaveRC(rc);
     1145    return rc;
     1146}
    9591147#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
    9601148
    961 DECLCALLBACK(int) GuestDnD::notifyGuestDragAndDropEvent(void *pvExtension, uint32_t u32Function, void *pvParms, uint32_t cbParms)
     1149/* static */
     1150DECLCALLBACK(int) GuestDnD::notifyGuestDragAndDropEvent(void *pvExtension, uint32_t u32Function,
     1151                                                        void *pvParms, uint32_t cbParms)
    9621152{
    9631153    LogFlowFunc(("pvExtension=%p, u32Function=%RU32, pvParms=%p, cbParms=%RU32\n",
     
    9671157    if (!pGuest->m_pGuestDnD)
    9681158        return VINF_SUCCESS;
     1159
     1160    GuestDnD *pGuestDnD = pGuest->m_pGuestDnD;
     1161    AssertPtr(pGuestDnD);
    9691162
    9701163    GuestDnDPrivate *d = static_cast<GuestDnDPrivate*>(pGuest->m_pGuestDnD->d_ptr);
     
    9841177            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGACKOPDATA) == cbParms, VERR_INVALID_PARAMETER);
    9851178            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_ACK_OP == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1179
    9861180            pResp->setDefAction(pCBData->uAction);
     1181
    9871182            rc = pResp->notifyAboutGuestResponse();
    9881183            break;
     
    9951190            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGREQDATADATA) == cbParms, VERR_INVALID_PARAMETER);
    9961191            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_REQ_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1192
    9971193            pResp->setFormat(pCBData->pszFormat);
     1194
    9981195            rc = pResp->notifyAboutGuestResponse();
    9991196            break;
     
    10061203            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA) == cbParms, VERR_INVALID_PARAMETER);
    10071204            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1205
    10081206            rc = pResp->setProgress(pCBData->uPercentage, pCBData->uState, pCBData->rc);
    10091207            break;
     
    10171215            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBGHACKPENDINGDATA) == cbParms, VERR_INVALID_PARAMETER);
    10181216            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_ACK_PENDING == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1217
    10191218            pResp->setFormat(pCBData->pszFormat);
    10201219            pResp->setDefAction(pCBData->uDefAction);
    10211220            pResp->setAllActions(pCBData->uAllActions);
     1221
    10221222            rc = pResp->notifyAboutGuestResponse();
    10231223            break;
     
    10311231            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    10321232
    1033             uint32_t cbCurSize = 0;
    1034             rc = pResp->dataAdd(pCBData->pvData, pCBData->cbData, &cbCurSize);
    1035             if (RT_SUCCESS(rc))
    1036             {
    1037                 /** @todo Store pCBData->cbAllSize in the guest's response struct
    1038                  *        if not set already. */
    1039                 uint32_t cbTotalSize = pCBData->cbAllSize;
    1040                 unsigned int cPercentage;
    1041                 if (!cbTotalSize) /* Watch out for division by zero. */
    1042                     cPercentage = 100;
    1043                 else
    1044                     cPercentage = cbCurSize * 100.0 / cbTotalSize;
    1045 
    1046                 /** @todo Don't use anonymous enums. */
    1047                 uint32_t uState = DragAndDropSvc::DND_PROGRESS_RUNNING;
    1048                 if (   cbTotalSize == cbCurSize
    1049                     /* Empty data? Should not happen, but anyway ... */
    1050                     || !cbTotalSize)
    1051                 {
    1052                     uState = DragAndDropSvc::DND_PROGRESS_COMPLETE;
    1053                 }
    1054 
    1055                 rc = pResp->setProgress(cPercentage, uState);
    1056             }
    1057 
    1058             /** @todo For now we instantly confirm the cancel. Check if the
    1059              *        guest should first clean up stuff itself and than really confirm
    1060              *        the cancel request by an extra message. */
    1061             if (rc == VERR_CANCELLED)
    1062                 pResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_CANCELLED);
     1233            rc = pGuestDnD->onGHSendData(pResp, pCBData->pvData, pCBData->cbData,
     1234                                         pCBData->cbTotalSize);
     1235            break;
     1236        }
     1237
     1238        case DragAndDropSvc::GUEST_DND_GH_SND_DIR:
     1239        {
     1240            DragAndDropSvc::PVBOXDNDCBSNDDIRDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDDIRDATA>(pvParms);
     1241            AssertPtr(pCBData);
     1242            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDDIRDATA) == cbParms, VERR_INVALID_PARAMETER);
     1243            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DIR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1244
     1245            rc = pGuestDnD->onGHSendDir(pResp, pCBData->pszPath, pCBData->cbPath, pCBData->fMode);
     1246            break;
     1247        }
     1248
     1249        case DragAndDropSvc::GUEST_DND_GH_SND_FILE:
     1250        {
     1251            DragAndDropSvc::PVBOXDNDCBSNDFILEDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDFILEDATA>(pvParms);
     1252            AssertPtr(pCBData);
     1253            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDFILEDATA) == cbParms, VERR_INVALID_PARAMETER);
     1254            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1255
     1256            rc = pGuestDnD->onGHSendFile(pResp, pCBData->pszFilePath, pCBData->cbFilePath,
     1257                                         pCBData->pvData, pCBData->cbData, pCBData->fMode);
    10631258            break;
    10641259        }
     
    10711266            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    10721267
    1073             /* Cleanup */
     1268            /* Cleanup. */
    10741269            pResp->reset();
    10751270            rc = pResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, pCBData->rc);
  • trunk/src/VBox/Runtime/common/misc/uri.cpp

    r49996 r50508  
    137137            szNum[1] = pszString[iIn++];
    138138            szNum[2] = '\0';
    139            
     139
    140140            uint8_t u8;
    141141            rc = RTStrToUInt8Ex(szNum, NULL, 16, &u8);
     
    654654    {
    655655        uint32_t uFIntern = uFormat;
    656         /* Auto is based on the current host OS. */
     656        /* Auto is based on the current OS. */
    657657        if (uFormat == URI_FILE_FORMAT_AUTO)
    658658#ifdef RT_OS_WINDOWS
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