VirtualBox

Changeset 55422 in vbox


Ignore:
Timestamp:
Apr 24, 2015 1:52:33 PM (10 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
99765
Message:

DnD: Protocol overhaul with versioning added which now can communicate with Main.

Location:
trunk
Files:
1 added
26 edited

Legend:

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

    r51211 r55422  
    6060    };
    6161
     62    enum Dest
     63    {
     64        Source = 0,
     65        Target
     66    };
     67
     68    DnDURIObject(void);
    6269    DnDURIObject(Type type,
    63                  const RTCString &strSrcPath,
    64                  const RTCString &strDstPath,
    65                  uint32_t fMode, uint64_t cbSize);
     70                 const RTCString &strSrcPath = "",
     71                 const RTCString &strDstPath = "",
     72                 uint32_t fMode = 0, uint64_t cbSize = 0);
    6673    virtual ~DnDURIObject(void);
    6774
     
    6976
    7077    const RTCString &GetSourcePath(void) const { return m_strSrcPath; }
    71     const RTCString &GetDestPath(void) const { return m_strDstPath; }
    72     uint32_t GetMode(void) const { return m_fMode; }
     78    const RTCString &GetDestPath(void) const { return m_strTgtPath; }
     79    uint64_t GetMode(void) const { return m_fMode; }
     80    uint64_t GetProcessed(void) const { return m_cbProcessed; }
    7381    uint64_t GetSize(void) const { return m_cbSize; }
    7482    Type GetType(void) const { return m_Type; }
     
    7684public:
    7785
     86    int SetSize(uint64_t uSize) { m_cbSize = uSize; return VINF_SUCCESS; }
     87
     88public:
     89
     90    void Close(void);
    7891    bool IsComplete(void) const;
    79     static int RebaseURIPath(RTCString &strPath, const RTCString &strBaseOld, const RTCString &strBaseNew);
    80     int Read(void *pvBuf, uint32_t cbToRead, uint32_t *pcbRead);
     92    bool IsOpen(void) const;
     93    int Open(Dest enmDest, uint64_t fOpen);
     94    int OpenEx(const RTCString &strPath, Type enmType, Dest enmDest, uint64_t fMode = 0, uint32_t fFlags = 0);
     95    int Read(void *pvBuf, size_t cbBuf, uint32_t *pcbRead);
     96    int Write(const void *pvBuf, size_t cbBuf, uint32_t *pcbWritten);
     97
     98public:
     99
     100    static int RebaseURIPath(RTCString &strPath, const RTCString &strBaseOld = "", const RTCString &strBaseNew = "");
    81101
    82102protected:
     
    88108    Type      m_Type;
    89109    RTCString m_strSrcPath;
    90     RTCString m_strDstPath;
    91     uint32_t  m_fMode;
     110    RTCString m_strTgtPath;
     111    /** File mode. */
     112    uint64_t  m_fMode;
    92113    /** Size (in bytes) to read/write. */
    93114    uint64_t  m_cbSize;
  • trunk/include/VBox/HostServices/DragAndDropSvc.h

    r55091 r55422  
    44
    55/*
    6  * Copyright (C) 2011-2014 Oracle Corporation
     6 * Copyright (C) 2011-2015 Oracle Corporation
    77 *
    88 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2727#define ___VBox_HostService_DragAndDropSvc_h
    2828
     29#include <VBox/hgcmsvc.h>
    2930#include <VBox/VMMDev.h>
    3031#include <VBox/VBoxGuest2.h>
     
    8687enum eHostFn
    8788{
     89    /** The host just has set a new DnD mode. */
    8890    HOST_DND_SET_MODE                  = 100,
    8991
     
    9294     */
    9395
     96    /** The host entered the VM window for starting an actual
     97     *  DnD operation. */
    9498    HOST_DND_HG_EVT_ENTER              = 200,
     99    /** The host's DnD cursor moved within the VM window. */
    95100    HOST_DND_HG_EVT_MOVE               = 201,
     101    /** The host left the guest VM window. */
    96102    HOST_DND_HG_EVT_LEAVE              = 202,
     103    /** The host issued a "drop" event, meaning that the host is
     104     *  ready to transfer data over to the guest. */
    97105    HOST_DND_HG_EVT_DROPPED            = 203,
     106    /** The host requested to cancel the current DnD operation. */
    98107    HOST_DND_HG_EVT_CANCEL             = 204,
    99108    /** Gets the actual MIME data, based on
    100      *  the format(s) specified by HOST_DND_HG_EVT_ENTER. */
     109     *  the format(s) specified by HOST_DND_HG_EVT_ENTER. If the guest
     110     *  supplied buffer too small to send the actual data, the host
     111     *  will send a HOST_DND_HG_SND_MORE_DATA message as follow-up. */
    101112    HOST_DND_HG_SND_DATA               = 205,
    102113    /** Sent when the actual buffer for HOST_DND_HG_SND_DATA
    103114     *  was too small, issued by the DnD host service. */
    104115    HOST_DND_HG_SND_MORE_DATA          = 206,
    105     /** Directory entry to be handled on the guest. */
     116    /** Directory entry to be sent to the guest. */
    106117    HOST_DND_HG_SND_DIR                = 207,
    107     /** File entry to be handled on the guest. */
    108     HOST_DND_HG_SND_FILE               = 208,
     118    /** File data chunk to send to the guest. */
     119    HOST_DND_HG_SND_FILE_DATA          = 208,
     120    /** File header to send to the guest.
     121     *  Note: Only for protocol version 2 and up (>= VBox 5.0). */
     122    HOST_DND_HG_SND_FILE_HDR           = 209,
    109123
    110124    /*
     
    118132     *  has been started and that the host wants the data in
    119133     *  a specific MIME type. */
    120     HOST_DND_GH_EVT_DROPPED,
    121 
     134    HOST_DND_GH_EVT_DROPPED            = 601,
     135    /** Creates a directory on the guest. */
    122136    HOST_DND_GH_RECV_DIR               = 650,
    123     HOST_DND_GH_RECV_FILE              = 670
     137    /** Retrieves file data from the guest. */
     138    HOST_DND_GH_RECV_FILE_DATA         = 670,
     139    /** Retrieves a file header from the guest.
     140     *  Note: Only for protocol version 2 and up (>= VBox 5.0). */
     141    HOST_DND_GH_RECV_FILE_HDR          = 671,
     142    /** Blow the type up to 32-bit. */
     143    HOST_DND_32BIT_HACK                = 0x7fffffff
    124144};
    125145
     
    127147 * The service functions which are called by guest.
    128148 * Note: When adding new functions to this table, make sure that the actual ID
    129  *       does *not* overlap with the eGuestFn enumeration above!
     149 *       does *not* overlap with the eHostFn enumeration above!
    130150 */
    131151enum eGuestFn
    132152{
     153    /* Guest sends a connection request to the HGCM service.
     154     * Note: New since protocol version 2. */
     155    GUEST_DND_CONNECT                  = 10,
     156
    133157    /**
    134158     * Guest waits for a new message the host wants to process
     
    137161    GUEST_DND_GET_NEXT_HOST_MSG        = 300,
    138162
    139     /* H->G */
     163    /*
     164     * Host -> Guest operation messages.
     165     */
     166
    140167    /** The guest acknowledges that the pending DnD data from
    141168     *  the host can be dropped on the currently selected source
     
    145172     *  from the host. */
    146173    GUEST_DND_HG_REQ_DATA              = 401,
     174    /** Reports back the guest's progress on a host -> guest operation. */
    147175    GUEST_DND_HG_EVT_PROGRESS          = 402,
    148176
    149     /* G->H */
     177    /*
     178     * Guest -> Host operation messages.
     179     */
     180
    150181    /**
    151182     * The guests acknowledges that it currently has a drag'n drop
     
    160191     */
    161192    GUEST_DND_GH_SND_DATA              = 501,
     193    /** Reports an error back to the host. */
    162194    GUEST_DND_GH_EVT_ERROR             = 502,
    163 
     195    /** Guest sends a directory entry to the host. */
    164196    GUEST_DND_GH_SND_DIR               = 700,
    165     GUEST_DND_GH_SND_FILE              = 701
     197    /** Guest sends file data to the host. */
     198    /*  Note: On protocol version 1 this also contains the file name
     199     *        and other attributes. */
     200    GUEST_DND_GH_SND_FILE_DATA         = 701,
     201    /** Guest sends a file header to the host, marking the
     202     *  beginning of a (new) file transfer.
     203     *  Note: Available since protocol version 2 (VBox 5.0). */
     204    GUEST_DND_GH_SND_FILE_HDR          = 702,
     205    /** Blow the type up to 32-bit. */
     206    GUEST_DND_32BIT_HACK               = 0x7fffffff
    166207};
    167208
    168209/**
    169  * The possible states for the progress operations.
    170  */
    171 enum
    172 {
    173     DND_PROGRESS_RUNNING = 1,
     210 * DnD operation progress states.
     211 */
     212typedef enum DNDPROGRESS
     213{
     214    DND_PROGRESS_UNKNOWN               = 0,
     215    DND_PROGRESS_RUNNING               = 1,
    174216    DND_PROGRESS_COMPLETE,
    175217    DND_PROGRESS_CANCELLED,
    176     DND_PROGRESS_ERROR
    177 };
     218    DND_PROGRESS_ERROR,
     219    /** Blow the type up to 32-bit. */
     220    DND_PROGRESS_32BIT_HACK            = 0x7fffffff
     221} DNDPROGRESS, *PDNDPROGRESS;
    178222
    179223#pragma pack (1)
     
    273317} VBOXDNDHGSENDDIRMSG;
    274318
    275 typedef struct VBOXDNDHGSENDFILEMSG
    276 {
    277     VBoxGuestHGCMCallInfo hdr;
    278 
    279     /**
    280      * HG File event.
    281      *
    282      * Used by:
    283      * HOST_DND_HG_SND_FILE
    284      */
     319/**
     320 * File header event.
     321 * Note: Only for protocol version 2 and up.
     322 *
     323 * Used by:
     324 * HOST_DND_HG_SND_FILE_HDR
     325 * HOST_DND_GH_SND_FILE_HDR
     326 */
     327typedef struct VBOXDNDHGSENDFILEHDRMSG
     328{
     329    VBoxGuestHGCMCallInfo hdr;
     330
     331    /** Context ID. Unused at the moment. */
     332    HGCMFunctionParameter uContext;     /* OUT uint32_t */
     333    /** File path. */
    285334    HGCMFunctionParameter pvName;       /* OUT ptr */
     335    /** Size (in bytes) of file path. */
    286336    HGCMFunctionParameter cbName;       /* OUT uint32_t */
    287     HGCMFunctionParameter pvData;       /* OUT ptr */
    288     HGCMFunctionParameter cbData;       /* OUT uint32_t */
     337    /** Optional flags; unused at the moment. */
     338    HGCMFunctionParameter uFlags;       /* OUT uint32_t */
     339    /** File creation mode. */
    289340    HGCMFunctionParameter fMode;        /* OUT uint32_t */
    290 } VBOXDNDHGSENDFILEMSG;
     341    /** Total size (in bytes). */
     342    HGCMFunctionParameter cbTotal;      /* OUT uint64_t */
     343
     344} VBOXDNDHGSENDFILEHDRMSG;
     345
     346/**
     347 * HG: File data (chunk) event.
     348 *
     349 * Used by:
     350 * HOST_DND_HG_SND_FILE
     351 */
     352typedef struct VBOXDNDHGSENDFILEDATAMSG
     353{
     354    VBoxGuestHGCMCallInfo hdr;
     355
     356    union
     357    {
     358        struct
     359        {
     360            HGCMFunctionParameter pvName;       /* OUT ptr */
     361            HGCMFunctionParameter cbName;       /* OUT uint32_t */
     362            HGCMFunctionParameter pvData;       /* OUT ptr */
     363            HGCMFunctionParameter cbData;       /* OUT uint32_t */
     364            HGCMFunctionParameter fMode;        /* OUT uint32_t */
     365        } v1;
     366        struct
     367        {
     368            /** Note: pvName is now part of the VBOXDNDHGSENDFILEHDRMSG message. */
     369            /** Note: cbName is now part of the VBOXDNDHGSENDFILEHDRMSG message. */
     370            HGCMFunctionParameter uContext;     /* OUT uint32_t */
     371            HGCMFunctionParameter pvData;       /* OUT ptr */
     372            HGCMFunctionParameter cbData;       /* OUT uint32_t */
     373            /** Note: fMode is now part of the VBOXDNDHGSENDFILEHDRMSG message. */
     374        } v2;
     375    } u;
     376
     377} VBOXDNDHGSENDFILEDATAMSG;
    291378
    292379typedef struct VBOXDNDGHREQPENDINGMSG
     
    322409 */
    323410
     411/**
     412 * The returned command the host wants to
     413 * run on the guest.
     414 *
     415 * Used by:
     416 * GUEST_DND_GET_NEXT_HOST_MSG
     417 */
    324418typedef struct VBOXDNDNEXTMSGMSG
    325419{
    326420    VBoxGuestHGCMCallInfo hdr;
    327421
    328     /**
    329      * The returned command the host wants to
    330      * run on the guest.
    331      *
    332      * Used by:
    333      * GUEST_DND_GET_NEXT_HOST_MSG
    334      */
    335422    HGCMFunctionParameter msg;          /* OUT uint32_t */
    336423    /** Number of parameters the message needs. */
     
    342429} VBOXDNDNEXTMSGMSG;
    343430
     431/**
     432 * Connection request. Used to tell the DnD protocol
     433 * version to the (host) service.
     434 *
     435 * Used by:
     436 * GUEST_DND_CONNECT
     437 */
     438typedef struct VBOXDNDCONNECTPMSG
     439{
     440    VBoxGuestHGCMCallInfo hdr;
     441
     442    /** Protocol version to use. */
     443    HGCMFunctionParameter uProtocol;     /* OUT uint32_t */
     444    /** Connection flags. Optional. */
     445    HGCMFunctionParameter uFlags;        /* OUT uint32_t */
     446
     447} VBOXDNDCONNECTPMSG;
     448
     449/**
     450 * HG Acknowledge Operation event.
     451 *
     452 * Used by:
     453 * GUEST_DND_HG_ACK_OP
     454 */
    344455typedef struct VBOXDNDHGACKOPMSG
    345456{
    346457    VBoxGuestHGCMCallInfo hdr;
    347458
    348     /**
    349      * HG Acknowledge Operation event.
    350      *
    351      * Used by:
    352      * GUEST_DND_HG_ACK_OP
    353      */
    354459    HGCMFunctionParameter uAction;      /* OUT uint32_t */
    355460} VBOXDNDHGACKOPMSG;
    356461
     462/**
     463 * HG request for data event.
     464 *
     465 * Used by:
     466 * GUEST_DND_HG_REQ_DATA
     467 */
    357468typedef struct VBOXDNDHGREQDATAMSG
    358469{
    359470    VBoxGuestHGCMCallInfo hdr;
    360471
    361     /**
    362      * HG request for data event.
    363      *
    364      * Used by:
    365      * GUEST_DND_HG_REQ_DATA
    366      */
    367472    HGCMFunctionParameter pFormat;      /* OUT ptr */
    368473} VBOXDNDHGREQDATAMSG;
    369474
     475typedef struct VBOXDNDHGEVTPROGRESSMSG
     476{
     477    VBoxGuestHGCMCallInfo hdr;
     478
     479    HGCMFunctionParameter uStatus;
     480    HGCMFunctionParameter uPercent;
     481    HGCMFunctionParameter rc;
     482} VBOXDNDHGEVTPROGRESSMSG;
     483
     484/**
     485 * GH Acknowledge Pending event.
     486 *
     487 * Used by:
     488 * GUEST_DND_GH_ACK_PENDING
     489 */
    370490typedef struct VBOXDNDGHACKPENDINGMSG
    371491{
    372492    VBoxGuestHGCMCallInfo hdr;
    373493
    374     /**
    375      * GH Acknowledge Pending event.
    376      *
    377      * Used by:
    378      * GUEST_DND_GH_ACK_PENDING
    379      */
    380494    HGCMFunctionParameter uDefAction;   /* OUT uint32_t */
    381495    HGCMFunctionParameter uAllActions;  /* OUT uint32_t */
     
    383497} VBOXDNDGHACKPENDINGMSG;
    384498
     499/**
     500 * GH Send Data event.
     501 *
     502 * Used by:
     503 * GUEST_DND_GH_SND_DATA
     504 */
    385505typedef struct VBOXDNDGHSENDDATAMSG
    386506{
    387507    VBoxGuestHGCMCallInfo hdr;
    388508
    389     /**
    390      * GH Send Data event.
    391      *
    392      * Used by:
    393      * GUEST_DND_GH_SND_DATA
    394      */
    395509    HGCMFunctionParameter pvData;       /* OUT ptr */
    396510    /** Total bytes to send. This can be more than
     
    400514} VBOXDNDGHSENDDATAMSG;
    401515
     516/**
     517 * GH Directory event.
     518 *
     519 * Used by:
     520 * GUEST_DND_GH_SND_DIR
     521 */
    402522typedef struct VBOXDNDGHSENDDIRMSG
    403523{
    404524    VBoxGuestHGCMCallInfo hdr;
    405525
    406     /**
    407      * GH Directory event.
    408      *
    409      * Used by:
    410      * GUEST_DND_HG_SND_DIR
    411      */
    412526    HGCMFunctionParameter pvName;       /* OUT ptr */
    413527    HGCMFunctionParameter cbName;       /* OUT uint32_t */
     
    415529} VBOXDNDGHSENDDIRMSG;
    416530
    417 typedef struct VBOXDNDGHSENDFILEMSG
    418 {
    419     VBoxGuestHGCMCallInfo hdr;
    420 
    421     /**
    422      * GH File event.
    423      *
    424      * Used by:
    425      * GUEST_DND_HG_SND_FILE
    426      */
    427     HGCMFunctionParameter pvName;       /* OUT ptr */
    428     HGCMFunctionParameter cbName;       /* OUT uint32_t */
    429     HGCMFunctionParameter pvData;       /* OUT ptr */
    430     HGCMFunctionParameter cbData;       /* OUT uint32_t */
    431     HGCMFunctionParameter fMode;        /* OUT uint32_t */
    432 } VBOXDNDGHSENDFILEMSG;
    433 
     531/**
     532 * GH File header event.
     533 * Note: Only for protocol version 2 and up.
     534 *
     535 * Used by:
     536 * HOST_DND_GH_SND_FILE_HDR
     537 */
     538typedef struct VBOXDNDHGSENDFILEHDRMSG VBOXDNDGHSENDFILEHDRMSG;
     539
     540/**
     541 * GH File data event.
     542 *
     543 * Used by:
     544 * GUEST_DND_HG_SND_FILE_DATA
     545 */
     546typedef struct VBOXDNDGHSENDFILEDATAMSG
     547{
     548    VBoxGuestHGCMCallInfo hdr;
     549
     550    union
     551    {
     552        /* Note: Protocol v1 sends the file name + file mode
     553         *       every time a file data chunk is being sent. */
     554        struct
     555        {
     556            HGCMFunctionParameter pvName;   /* OUT ptr */
     557            HGCMFunctionParameter cbName;   /* OUT uint32_t */
     558            HGCMFunctionParameter fMode;    /* OUT uint32_t */
     559            HGCMFunctionParameter pvData;   /* OUT ptr */
     560            HGCMFunctionParameter cbData;   /* OUT uint32_t */
     561        } v1;
     562        struct
     563        {
     564            /** Context ID. Unused at the moment. */
     565            HGCMFunctionParameter uContext; /* OUT uint32_t */
     566            HGCMFunctionParameter pvData;   /* OUT ptr */
     567            HGCMFunctionParameter cbData;   /* OUT uint32_t */
     568        } v2;
     569    } u;
     570
     571} VBOXDNDGHSENDFILEDATAMSG;
     572
     573/**
     574 * GH Error event.
     575 *
     576 * Used by:
     577 * GUEST_DND_GH_EVT_ERROR
     578 */
    434579typedef struct VBOXDNDGHEVTERRORMSG
    435580{
    436581    VBoxGuestHGCMCallInfo hdr;
    437582
    438     /**
    439      * GH Error event.
    440      *
    441      * Used by:
    442      * GUEST_DND_GH_EVT_ERROR
    443      */
    444     HGCMFunctionParameter uRC;          /* OUT uint32_t */
     583    HGCMFunctionParameter rc;               /* OUT uint32_t */
    445584} VBOXDNDGHEVTERRORMSG;
    446585
     
    452591enum
    453592{
    454     CB_MAGIC_DND_HG_ACK_OP       = 0xe2100b93,
    455     CB_MAGIC_DND_HG_REQ_DATA     = 0x5cb3faf9,
    456     CB_MAGIC_DND_HG_EVT_PROGRESS = 0x8c8a6956,
    457     CB_MAGIC_DND_GH_ACK_PENDING  = 0xbe975a14,
    458     CB_MAGIC_DND_GH_SND_DATA     = 0x4eb61bff,
    459     CB_MAGIC_DND_GH_SND_DIR      = 0x411ca754,
    460     CB_MAGIC_DND_GH_SND_FILE     = 0x65e35eaf,
    461     CB_MAGIC_DND_GH_EVT_ERROR    = 0x117a87c4
     593    CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG      = 0x19820126,
     594    CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG_DATA = 0x19850630,
     595    CB_MAGIC_DND_HG_ACK_OP                 = 0xe2100b93,
     596    CB_MAGIC_DND_HG_REQ_DATA               = 0x5cb3faf9,
     597    CB_MAGIC_DND_HG_EVT_PROGRESS           = 0x8c8a6956,
     598    CB_MAGIC_DND_GH_ACK_PENDING            = 0xbe975a14,
     599    CB_MAGIC_DND_GH_SND_DATA               = 0x4eb61bff,
     600    CB_MAGIC_DND_GH_SND_DIR                = 0x411ca754,
     601    CB_MAGIC_DND_GH_SND_FILE_HDR           = 0x65e35eaf,
     602    CB_MAGIC_DND_GH_SND_FILE_DATA          = 0x19840804,
     603    CB_MAGIC_DND_GH_EVT_ERROR              = 0x117a87c4
    462604};
    463605
     
    468610    /** Context ID to identify callback data. */
    469611    uint32_t u32ContextID;
    470 } VBOXDNDCBHEADERDATA;
    471 typedef VBOXDNDCBHEADERDATA *PVBOXDNDCBHEADERDATA;
     612} VBOXDNDCBHEADERDATA, *PVBOXDNDCBHEADERDATA;
     613
     614typedef struct VBOXDNDCBHGGETNEXTHOSTMSG
     615{
     616    /** Callback data header. */
     617    VBOXDNDCBHEADERDATA hdr;
     618    uint32_t uMsg;
     619    uint32_t cParms;
     620} VBOXDNDCBHGGETNEXTHOSTMSG, *PVBOXDNDCBHGGETNEXTHOSTMSG;
     621
     622typedef struct VBOXDNDCBHGGETNEXTHOSTMSGDATA
     623{
     624    /** Callback data header. */
     625    VBOXDNDCBHEADERDATA hdr;
     626    uint32_t uMsg;
     627    uint32_t cParms;
     628    PVBOXHGCMSVCPARM paParms;
     629} VBOXDNDCBHGGETNEXTHOSTMSGDATA, *PVBOXDNDCBHGGETNEXTHOSTMSGDATA;
    472630
    473631typedef struct VBOXDNDCBHGACKOPDATA
     
    476634    VBOXDNDCBHEADERDATA hdr;
    477635    uint32_t uAction;
    478 } VBOXDNDCBHGACKOPDATA;
    479 typedef VBOXDNDCBHGACKOPDATA *PVBOXDNDCBHGACKOPDATA;
     636} VBOXDNDCBHGACKOPDATA, *PVBOXDNDCBHGACKOPDATA;
    480637
    481638typedef struct VBOXDNDCBHGREQDATADATA
     
    484641    VBOXDNDCBHEADERDATA hdr;
    485642    char *pszFormat;
    486 } VBOXDNDCBHGREQDATADATA;
    487 typedef VBOXDNDCBHGREQDATADATA *PVBOXDNDCBHGREQDATADATA;
     643} VBOXDNDCBHGREQDATADATA, *PVBOXDNDCBHGREQDATADATA;
    488644
    489645typedef struct VBOXDNDCBHGEVTPROGRESSDATA
     
    492648    VBOXDNDCBHEADERDATA hdr;
    493649    uint32_t uPercentage;
    494     uint32_t uState;
    495     int rc;
    496 } VBOXDNDCBHGEVTPROGRESSDATA;
    497 typedef VBOXDNDCBHGEVTPROGRESSDATA *PVBOXDNDCBHGEVTPROGRESSDATA;
     650    uint32_t uStatus;
     651    uint32_t rc;
     652} VBOXDNDCBHGEVTPROGRESSDATA, *PVBOXDNDCBHGEVTPROGRESSDATA;
    498653
    499654typedef struct VBOXDNDCBGHACKPENDINGDATA
     
    504659    uint32_t  uAllActions;
    505660    char     *pszFormat;
    506 } VBOXDNDCBGHACKPENDINGDATA;
    507 typedef VBOXDNDCBGHACKPENDINGDATA *PVBOXDNDCBGHACKPENDINGDATA;
     661} VBOXDNDCBGHACKPENDINGDATA, *PVBOXDNDCBGHACKPENDINGDATA;
    508662
    509663typedef struct VBOXDNDCBSNDDATADATA
     
    516670     *  with every message because the size can change. */
    517671    uint32_t  cbTotalSize;
    518 } VBOXDNDCBSNDDATADATA;
    519 typedef VBOXDNDCBSNDDATADATA *PVBOXDNDCBSNDDATADATA;
     672} VBOXDNDCBSNDDATADATA, *PVBOXDNDCBSNDDATADATA;
    520673
    521674typedef struct VBOXDNDCBSNDDIRDATA
     
    526679    uint32_t  cbPath;
    527680    uint32_t  fMode;
    528 } VBOXDNDCBSNDDIRDATA;
    529 typedef VBOXDNDCBSNDDIRDATA *PVBOXDNDCBSNDDIRDATA;
    530 
    531 typedef struct VBOXDNDCBSNDFILEDATA
    532 {
    533     /** Callback data header. */
    534     VBOXDNDCBHEADERDATA hdr;
     681} VBOXDNDCBSNDDIRDATA, *PVBOXDNDCBSNDDIRDATA;
     682
     683/*  Note: Only for protocol version 2 and up (>= VBox 5.0). */
     684typedef struct VBOXDNDCBSNDFILEHDRDATA
     685{
     686    /** Callback data header. */
     687    VBOXDNDCBHEADERDATA hdr;
     688    /** File path (name). */
    535689    char     *pszFilePath;
     690    /** Size (in bytes) of file path. */
    536691    uint32_t  cbFilePath;
     692    /** Total size (in bytes) of this file. */
     693    uint64_t  cbSize;
     694    /** File (creation) mode. */
    537695    uint32_t  fMode;
    538     void     *pvData;
    539     uint32_t  cbData;
    540 } VBOXDNDCBSNDFILEDATA;
    541 typedef VBOXDNDCBSNDFILEDATA *PVBOXDNDCBSNDFILEDATA;
     696    /** Additional flags. Not used at the moment. */
     697    uint32_t  fFlags;
     698} VBOXDNDCBSNDFILEHDRDATA, *PVBOXDNDCBSNDFILEHDRDATA;
     699
     700typedef struct VBOXDNDCBSNDFILEDATADATA
     701{
     702    /** Callback data header. */
     703    VBOXDNDCBHEADERDATA  hdr;
     704    /** Current file data chunk. */
     705    void                *pvData;
     706    /** Size (in bytes) of current data chunk. */
     707    uint32_t             cbData;
     708    union
     709    {
     710        struct
     711        {
     712            /** File path (name). */
     713            char     *pszFilePath;
     714            /** Size (in bytes) of file path. */
     715            uint32_t  cbFilePath;
     716            /** File (creation) mode. */
     717            uint32_t  fMode;
     718        } v1;
     719        /* Note: Protocol version 2 has the file attributes (name, size,
     720                 mode, ...) in the VBOXDNDCBSNDFILEHDRDATA structure. */
     721    } u;
     722} VBOXDNDCBSNDFILEDATADATA, *PVBOXDNDCBSNDFILEDATADATA;
    542723
    543724typedef struct VBOXDNDCBEVTERRORDATA
     
    546727    VBOXDNDCBHEADERDATA hdr;
    547728    int32_t rc;
    548 } VBOXDNDCBEVTERRORDATA;
    549 typedef VBOXDNDCBEVTERRORDATA *PVBOXDNDCBEVTERRORDATA;
     729} VBOXDNDCBEVTERRORDATA, *PVBOXDNDCBEVTERRORDATA;
    550730
    551731} /* namespace DragAndDropSvc */
  • trunk/include/VBox/HostServices/Service.h

    r55353 r55422  
    44
    55/*
    6  * Copyright (C) 2011-2012 Oracle Corporation
     6 * Copyright (C) 2011-2015 Oracle Corporation
    77 *
    88 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    5050        initData(uMsg, cParms, aParms);
    5151    }
    52     ~Message()
     52
     53    virtual ~Message(void)
    5354    {
    5455        cleanup();
     
    9091        return VINF_SUCCESS;
    9192    }
     93
    9294    int getParmU64Info(uint32_t iParm, uint64_t *pu64Info) const
    9395    {
     
    100102        return VINF_SUCCESS;
    101103    }
     104
    102105    int getParmPtrInfo(uint32_t iParm, void **ppvAddr, uint32_t *pcSize) const
    103106    {
     
    113116    }
    114117
    115     int copyParms(uint32_t cParms, PVBOXHGCMSVCPARM paParmsSrc, PVBOXHGCMSVCPARM paParmsDst) const
     118    static int copyParms(uint32_t cParms, PVBOXHGCMSVCPARM paParmsSrc, PVBOXHGCMSVCPARM paParmsDst)
    116119    {
    117120        return copyParmsInternal(cParms, paParmsSrc, paParmsDst, false /* fCreatePtrs */);
     
    119122
    120123private:
     124
    121125    uint32_t m_uMsg;
    122126    uint32_t m_cParms;
     
    149153    }
    150154
    151     int copyParmsInternal(uint32_t cParms, PVBOXHGCMSVCPARM paParmsSrc, PVBOXHGCMSVCPARM paParmsDst, bool fCreatePtrs) const
     155    static int copyParmsInternal(uint32_t cParms, PVBOXHGCMSVCPARM paParmsSrc, PVBOXHGCMSVCPARM paParmsDst, bool fCreatePtrs)
    152156    {
    153157        int rc = VINF_SUCCESS;
     
    188192                        /* No, but we have to check if there is enough room. */
    189193                        if (paParmsDst[i].u.pointer.size < paParmsSrc[i].u.pointer.size)
     194                        {
    190195                            rc = VERR_BUFFER_OVERFLOW;
     196                            break;
     197                        }
    191198                    }
     199
    192200                    if (   paParmsDst[i].u.pointer.addr
    193201                        && paParmsSrc[i].u.pointer.size > 0
    194202                        && paParmsDst[i].u.pointer.size > 0)
     203                    {
    195204                        memcpy(paParmsDst[i].u.pointer.addr,
    196205                               paParmsSrc[i].u.pointer.addr,
    197206                               RT_MIN(paParmsDst[i].u.pointer.size, paParmsSrc[i].u.pointer.size));
     207                    }
    198208                    break;
    199209                }
     
    236246{
    237247public:
    238     Client(uint32_t uClientId, VBOXHGCMCALLHANDLE hHandle, uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[])
     248    Client(uint32_t uClientId, VBOXHGCMCALLHANDLE hHandle = NULL,
     249           uint32_t uMsg = 0, uint32_t cParms = 0, VBOXHGCMSVCPARM aParms[] = NULL)
    239250      : m_uClientId(uClientId)
     251      , m_uProtocol(0)
    240252      , m_hHandle(hHandle)
    241253      , m_uMsg(uMsg)
     
    243255      , m_paParms(aParms) {}
    244256
    245     VBOXHGCMCALLHANDLE handle() const { return m_hHandle; }
    246     uint32_t message() const { return m_uMsg; }
    247     uint32_t clientId() const { return m_uClientId; }
     257public:
     258
     259    VBOXHGCMCALLHANDLE handle(void) const { return m_hHandle; }
     260    uint32_t message(void) const { return m_uMsg; }
     261    uint32_t clientId(void) const { return m_uClientId; }
     262    uint32_t protocol(void) const { return m_uProtocol; }
     263
     264public:
     265
     266    int setProtocol(uint32_t uProtocol) { m_uProtocol = uProtocol; return VINF_SUCCESS; }
     267
     268public:
    248269
    249270    int addMessageInfo(uint32_t uMsg, uint32_t cParms)
     
    259280    int addMessageInfo(const Message *pMessage)
    260281    {
     282        AssertPtrReturn(pMessage, VERR_INVALID_POINTER);
    261283        if (m_cParms != 3)
    262284            return VERR_INVALID_PARAMETER;
     
    269291    int addMessage(const Message *pMessage)
    270292    {
     293        AssertPtrReturn(pMessage, VERR_INVALID_POINTER);
    271294        return pMessage->getData(m_uMsg, m_cParms, m_paParms);
    272295    }
     296
    273297private:
     298
    274299    uint32_t m_uClientId;
     300    /** Optional protocol version the client uses. */
     301    uint32_t m_uProtocol;
    275302    VBOXHGCMCALLHANDLE m_hHandle;
    276303    uint32_t m_uMsg;
  • trunk/include/VBox/VBoxGuestLib.h

    r54010 r55422  
    44
    55/*
    6  * Copyright (C) 2006-2014 Oracle Corporation
     6 * Copyright (C) 2006-2015 Oracle Corporation
    77 *
    88 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    606606 * Structure containing the context required for
    607607 * either retrieving or sending a HGCM guest control
    608  * command from or to the host.
     608 * commands from or to the host.
    609609 *
    610610 * Note: Do not change parameter order without also
     
    713713/** @name Drag and Drop
    714714 * @{ */
     715/**
     716 * Structure containing the context required for
     717 * either retrieving or sending a HGCM guest drag'n drop
     718 * commands from or to the host.
     719 *
     720 * Note: Do not change parameter order without also
     721 *       adapting all structure initializers.
     722 */
     723typedef struct VBGLR3GUESTDNDCMDCTX
     724{
     725    /** @todo This struct could be handy if we want to implement
     726     *        a second communication channel, e.g. via TCP/IP.
     727     *        Use a union for the HGCM stuff then. */
     728
     729    /** IN: HGCM client ID to use for communication. */
     730    uint32_t uClientID;
     731    /** IN: Protocol version to use. */
     732    uint32_t uProtocol;
     733    /** OUT: Number of parameters retrieved. */
     734    uint32_t uNumParms;
     735} VBGLR3GUESTDNDCMDCTX, *PVBGLR3GUESTDNDCMDCTX;
     736
    715737typedef struct VBGLR3DNDHGCMEVENT
    716738{
    717     uint32_t uType;               /** The event type this struct contains */
    718     uint32_t uScreenId;           /** Screen ID this request belongs to */
    719     char    *pszFormats;          /** Format list (\r\n separated) */
    720     uint32_t cbFormats;           /** Size of pszFormats (\0 included) */
     739    uint32_t uType;               /** The event type this struct contains. */
     740    uint32_t uScreenId;           /** Screen ID this request belongs to. */
     741    char    *pszFormats;          /** Format list (\r\n separated). */
     742    uint32_t cbFormats;           /** Size of pszFormats (\0 included). */
    721743    union
    722744    {
    723745        struct
    724746        {
    725             uint32_t uXpos;       /** X position of guest screen */
    726             uint32_t uYpos;       /** Y position of guest screen */
    727             uint32_t uDefAction;  /** Proposed DnD action */
    728             uint32_t uAllActions; /** Allowed DnD actions */
    729         }a; /** Values used in init, move and drop event type */
     747            uint32_t uXpos;       /** X position of guest screen. */
     748            uint32_t uYpos;       /** Y position of guest screen. */
     749            uint32_t uDefAction;  /** Proposed DnD action. */
     750            uint32_t uAllActions; /** Allowed DnD actions. */
     751        } a; /** Values used in init, move and drop event type. */
    730752        struct
    731753        {
    732             void    *pvData;      /** Data request */
    733             size_t   cbData;      /** Size of pvData */
    734         }b; /** Values used in drop data event type */
    735     }u;
     754            void    *pvData;      /** Data request. */
     755            size_t   cbData;      /** Size of pvData. */
     756        } b; /** Values used in drop data event type. */
     757    } u;
    736758} VBGLR3DNDHGCMEVENT;
    737759typedef VBGLR3DNDHGCMEVENT *PVBGLR3DNDHGCMEVENT;
    738760typedef const PVBGLR3DNDHGCMEVENT CPVBGLR3DNDHGCMEVENT;
    739 VBGLR3DECL(int)     VbglR3DnDConnect(uint32_t *pu32ClientId);
    740 VBGLR3DECL(int)     VbglR3DnDDisconnect(uint32_t u32ClientId);
    741 
    742 VBGLR3DECL(int)     VbglR3DnDProcessNextMessage(uint32_t u32ClientId, CPVBGLR3DNDHGCMEVENT pEvent);
    743 
    744 VBGLR3DECL(int)     VbglR3DnDHGAcknowledgeOperation(uint32_t u32ClientId, uint32_t uAction);
    745 VBGLR3DECL(int)     VbglR3DnDHGRequestData(uint32_t u32ClientId, const char* pcszFormat);
     761VBGLR3DECL(int)     VbglR3DnDConnect(PVBGLR3GUESTDNDCMDCTX pCtx);
     762VBGLR3DECL(int)     VbglR3DnDDisconnect(PVBGLR3GUESTDNDCMDCTX pCtx);
     763
     764VBGLR3DECL(int)     VbglR3DnDProcessNextMessage(PVBGLR3GUESTDNDCMDCTX pCtx, CPVBGLR3DNDHGCMEVENT pEvent);
     765
     766VBGLR3DECL(int)     VbglR3DnDHGAcknowledgeOperation(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uAction);
     767VBGLR3DECL(int)     VbglR3DnDHGRequestData(PVBGLR3GUESTDNDCMDCTX pCtx, const char* pcszFormat);
     768VBGLR3DECL(int)     VbglR3DnDHGSetProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr);
    746769#  ifdef VBOX_WITH_DRAG_AND_DROP_GH
    747 VBGLR3DECL(int)     VbglR3DnDGHAcknowledgePending(uint32_t u32ClientId, uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats);
    748 VBGLR3DECL(int)     VbglR3DnDGHSendData(uint32_t u32ClientId, const char *pszFormat, void *pvData, uint32_t cbData);
    749 VBGLR3DECL(int)     VbglR3DnDGHSendError(uint32_t u32ClientId, int rcOp);
     770VBGLR3DECL(int)     VbglR3DnDGHAcknowledgePending(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats);
     771VBGLR3DECL(int)     VbglR3DnDGHSendData(PVBGLR3GUESTDNDCMDCTX pCtx, const char *pszFormat, void *pvData, uint32_t cbData);
     772VBGLR3DECL(int)     VbglR3DnDGHSendError(PVBGLR3GUESTDNDCMDCTX pCtx, int rcOp);
    750773#  endif /* VBOX_WITH_DRAG_AND_DROP_GH */
    751774/** @} */
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp

    r55180 r55422  
    55
    66/*
    7  * Copyright (C) 2013-2014 Oracle Corporation
     7 * Copyright (C) 2013-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    7272      pDropTarget(NULL),
    7373#endif
    74       mClientID(UINT32_MAX),
    7574      mMode(Unknown),
    7675      mState(Uninitialized)
     
    707706int VBoxDnDWnd::OnCreate(void)
    708707{
    709     int rc = VbglR3DnDConnect(&mClientID);
     708    int rc = VbglR3DnDConnect(&mDnDCtx);
    710709    if (RT_FAILURE(rc))
    711710    {
     
    714713    }
    715714
    716     LogFlowThisFunc(("Client ID=%RU32, rc=%Rrc\n", mClientID, rc));
     715    LogFlowThisFunc(("Client ID=%RU32, rc=%Rrc\n", mDnDCtx.uClientID, rc));
    717716    return rc;
    718717}
     
    723722void VBoxDnDWnd::OnDestroy(void)
    724723{
    725     VbglR3DnDDisconnect(mClientID);
     724    VbglR3DnDDisconnect(&mDnDCtx);
    726725    LogFlowThisFuncLeave();
    727726}
     
    853852    if (RT_SUCCESS(rc))
    854853    {
    855         rc = VbglR3DnDHGAcknowledgeOperation(mClientID, uActionNotify);
     854        rc = VbglR3DnDHGAcknowledgeOperation(&mDnDCtx, uActionNotify);
    856855        if (RT_FAILURE(rc))
    857856            LogFlowThisFunc(("Acknowledging operation failed with rc=%Rrc\n", rc));
     
    923922            {
    924923                LogRel(("DnD: Requesting data as '%s' ...\n", mFormatRequested.c_str()));
    925                 rc = VbglR3DnDHGRequestData(mClientID, mFormatRequested.c_str());
     924                rc = VbglR3DnDHGRequestData(&mDnDCtx, mFormatRequested.c_str());
    926925                if (RT_FAILURE(rc))
    927926                    LogFlowThisFunc(("Requesting data failed with rc=%Rrc\n", rc));
    928927            }
     928
    929929        }
    930930        else /* Should never happen. */
     
    976976
    977977/**
    978  * Handles actions required when the host wants to cancel an action
     978 * Handles actions required when the host wants to cancel the current
    979979 * host -> guest operation.
    980980 *
     
    11221122        uAllActions = uDefAction;
    11231123
    1124         rc = VbglR3DnDGHAcknowledgePending(mClientID,
     1124        rc = VbglR3DnDGHAcknowledgePending(&mDnDCtx,
    11251125                                           uDefAction, uAllActions, strFormats.c_str());
    11261126        if (RT_FAILURE(rc))
     
    11991199            Assert(cbData);
    12001200
    1201             rc = VbglR3DnDGHSendData(mClientID, pszFormat, pvData, cbData);
    1202             LogFlowFunc(("Sent pvData=0x%p, cbData=%RU32, rc=%Rrc\n",
    1203                          pvData, cbData, rc));
    1204 
    1205 
     1201            rc = VbglR3DnDGHSendData(&mDnDCtx, pszFormat, pvData, cbData);
     1202            LogFlowFunc(("Sent pvData=0x%p, cbData=%RU32, rc=%Rrc\n", pvData, cbData, rc));
    12061203        }
    12071204    }
     
    12311228    {
    12321229        static int s_iBitchedAboutFailedDnDMessages = 0;
    1233         if (s_iBitchedAboutFailedDnDMessages++ < 10)
     1230        if (s_iBitchedAboutFailedDnDMessages++ < 32)
    12341231        {
    12351232            DWORD dwErr = GetLastError();
     
    16191616    AssertPtr(pCtx);
    16201617
    1621     uint32_t uClientID;
    1622     int rc = VbglR3DnDConnect(&uClientID);
     1618    VBGLR3GUESTDNDCMDCTX ctxDnD; /* The thread's own DnD context. */
     1619
     1620    int rc = VbglR3DnDConnect(&ctxDnD);
    16231621    if (RT_FAILURE(rc))
    16241622        return rc;
     
    16421640        /* Note: pEvent will be free'd by the consumer later. */
    16431641
    1644         rc = VbglR3DnDProcessNextMessage(uClientID, &pEvent->Event);
     1642        rc = VbglR3DnDProcessNextMessage(&ctxDnD, &pEvent->Event);
    16451643        LogFlowFunc(("VbglR3DnDProcessNextMessage returned uType=%RU32, rc=%Rrc\n",
    16461644                     pEvent->Event.uType, rc));
     
    16491647            break;
    16501648
    1651         if (RT_SUCCESS(rc))
     1649        if (   RT_SUCCESS(rc)
     1650            || rc == VERR_CANCELLED)
    16521651        {
    16531652            cMsgSkippedInvalid = 0; /* Reset skipped messages count. */
     
    16581657            if (RT_FAILURE(rc2))
    16591658                LogFlowFunc(("Processing event failed with rc=%Rrc\n", rc2));
    1660         }
    1661         else if (rc == VERR_CANCELLED)
    1662         {
    1663             int rc2 = pWnd->OnHgCancel();
    1664             if (RT_FAILURE(rc2))
    1665                 LogFlowFunc(("Cancelling failed with rc=%Rrc\n", rc2));
    1666             break;
    16671659        }
    16681660        else
     
    16791671            }
    16801672
    1681             int rc2 = VbglR3DnDGHSendError(uClientID, rc);
     1673            int rc2 = VbglR3DnDGHSendError(&ctxDnD, rc);
    16821674            AssertRC(rc2);
    16831675        }
     
    16931685    LogFlowFunc(("Shutting down ...\n"));
    16941686
    1695     VbglR3DnDDisconnect(uClientID);
     1687    VbglR3DnDDisconnect(&ctxDnD);
    16961688
    16971689    LogFlowFuncLeaveRC(rc);
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.h

    r51675 r55422  
    55
    66/*
    7  * Copyright (C) 2013-2014 Oracle Corporation
     7 * Copyright (C) 2013-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    121121protected:
    122122
    123     LONG mRefCount;
    124     VBoxDnDWnd *mpWndParent;
    125     uint32_t mClientID;
    126     DWORD mdwCurEffect;
    127     uint32_t muCurAction;
     123    LONG                  mRefCount;
     124    VBoxDnDWnd           *mpWndParent;
     125    VBGLR3GUESTDNDCMDCTX  mDnDCtx;
     126    DWORD                 mdwCurEffect;
     127    uint32_t              muCurAction;
    128128};
    129129
     
    162162protected:
    163163
    164     LONG mRefCount;
    165     VBoxDnDWnd *mpWndParent;
    166     uint32_t mClientID;
    167     DWORD mdwCurEffect;
     164    LONG                  mRefCount;
     165    VBoxDnDWnd           *mpWndParent;
     166    VBGLR3GUESTDNDCMDCTX  mDnDCtx;
     167    DWORD                 mdwCurEffect;
    168168    /** Copy of the data object's FORMATETC struct.
    169      *  Note: We don't keep the pointer of the
    170      *        DVTARGETDEVICE here! */
    171     FORMATETC mFormatEtc;
    172     RTCString mFormats;
    173     void *mpvData;
    174     uint32_t mcbData;
    175     RTSEMEVENT hEventDrop;
    176     int mDroppedRc;
     169     *  Note: We don't keep the pointer of the DVTARGETDEVICE here! */
     170    FORMATETC             mFormatEtc;
     171    RTCString             mFormats;
     172    void                 *mpvData;
     173    uint32_t              mcbData;
     174    RTSEMEVENT            hEventDrop;
     175    int                   mDroppedRc;
    177176};
    178177
     
    392391#endif /* RT_OS_WINDOWS */
    393392
    394     /** The window's own HGCM client ID. */
    395     uint32_t                   mClientID;
     393    /** The window's own DnD context. */
     394    VBGLR3GUESTDNDCMDCTX       mDnDCtx;
    396395    /** The current operation mode. */
    397396    Mode                       mMode;
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnDDropSource.cpp

    r51476 r55422  
    55
    66/*
    7  * Copyright (C) 2013-2014 Oracle Corporation
     7 * Copyright (C) 2013-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3535    : mRefCount(1),
    3636      mpWndParent(pParent),
    37       mClientID(UINT32_MAX),
    3837      mdwCurEffect(0),
    3938      muCurAction(DND_IGNORE_ACTION)
    4039{
    41     int rc = VbglR3DnDConnect(&mClientID);
     40    int rc = VbglR3DnDConnect(&mDnDCtx);
    4241
    4342    LogFlowFunc(("rc=%Rrc\n", rc));
     
    4645VBoxDnDDropSource::~VBoxDnDDropSource(void)
    4746{
    48     int rc = VbglR3DnDDisconnect(mClientID);
     47    int rc = VbglR3DnDDisconnect(&mDnDCtx);
    4948
    5049    LogFlowFunc(("rc=%Rrc, mRefCount=%RI32\n", rc, mRefCount));
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnDDropTarget.cpp

    r55180 r55422  
    55
    66/*
    7  * Copyright (C) 2014 Oracle Corporation
     7 * Copyright (C) 2014-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3737    : mRefCount(1),
    3838      mpWndParent(pParent),
    39       mClientID(UINT32_MAX),
    4039      mdwCurEffect(0),
    4140      mpvData(NULL),
     
    4342      hEventDrop(NIL_RTSEMEVENT)
    4443{
    45     int rc = VbglR3DnDConnect(&mClientID);
     44    int rc = VbglR3DnDConnect(&mDnDCtx);
    4645    if (RT_SUCCESS(rc))
    4746        rc = RTSemEventCreate(&hEventDrop);
    4847
    49     LogFlowFunc(("clientID=%RU32, rc=%Rrc\n",
    50                  mClientID, rc));
     48    LogFlowFunc(("clientID=%RU32, rc=%Rrc\n", mDnDCtx.uClientID, rc));
    5149}
    5250
     
    5553    reset();
    5654
    57     int rc2 = VbglR3DnDDisconnect(mClientID);
     55    int rc2 = VbglR3DnDDisconnect(&mDnDCtx);
    5856    AssertRC(rc2);
    5957    rc2 = RTSemEventDestroy(hEventDrop);
  • trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp

    r54858 r55422  
    55
    66/*
    7  * Copyright (C) 2011-2013 Oracle Corporation
     7 * Copyright (C) 2011-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    4444#include <VBox/log.h>
    4545
     46#include <VBox/VBoxGuestLib.h>
    4647#include <VBox/GuestHost/DragAndDrop.h>
    4748#include <VBox/HostServices/DragAndDropSvc.h>
     
    6364 ******************************************************************************/
    6465
    65 static int vbglR3DnDQueryNextHostMessageType(uint32_t uClientId, uint32_t *puMsg, uint32_t *pcParms, bool fWait)
    66 {
     66static int vbglR3DnDQueryNextHostMessageType(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t *puMsg, uint32_t *pcParms, bool fWait)
     67{
     68    AssertPtrReturn(pCtx,    VERR_INVALID_POINTER);
    6769    AssertPtrReturn(puMsg,   VERR_INVALID_POINTER);
    6870    AssertPtrReturn(pcParms, VERR_INVALID_POINTER);
     
    7173    RT_ZERO(Msg);
    7274    Msg.hdr.result      = VERR_WRONG_ORDER;
    73     Msg.hdr.u32ClientID = uClientId;
     75    Msg.hdr.u32ClientID = pCtx->uClientID;
    7476    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG;
    7577    Msg.hdr.cParms      = 3;
     
    7779    Msg.msg.SetUInt32(0);
    7880    Msg.num_parms.SetUInt32(0);
    79     Msg.block.SetUInt32(fWait);
     81    Msg.block.SetUInt32(fWait ? 1 : 0);
    8082
    8183    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    9395}
    9496
    95 static int vbglR3DnDHGProcessActionMessage(uint32_t  uClientId,
     97static int vbglR3DnDHGProcessActionMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
    9698                                           uint32_t  uMsg,
    9799                                           uint32_t *puScreenId,
     
    104106                                           uint32_t *pcbFormatsRecv)
    105107{
     108    AssertPtrReturn(pCtx,           VERR_INVALID_POINTER);
    106109    AssertPtrReturn(puScreenId,     VERR_INVALID_POINTER);
    107110    AssertPtrReturn(puX,            VERR_INVALID_POINTER);
     
    115118    DragAndDropSvc::VBOXDNDHGACTIONMSG Msg;
    116119    RT_ZERO(Msg);
    117     Msg.hdr.u32ClientID = uClientId;
     120    Msg.hdr.u32ClientID = pCtx->uClientID;
    118121    Msg.hdr.u32Function = uMsg;
    119122    Msg.hdr.cParms      = 7;
     
    147150}
    148151
    149 static int vbglR3DnDHGProcessLeaveMessage(uint32_t uClientId)
    150 {
     152static int vbglR3DnDHGProcessLeaveMessage(PVBGLR3GUESTDNDCMDCTX pCtx)
     153{
     154    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     155
    151156    DragAndDropSvc::VBOXDNDHGLEAVEMSG Msg;
    152157    RT_ZERO(Msg);
    153     Msg.hdr.u32ClientID = uClientId;
     158    Msg.hdr.u32ClientID = pCtx->uClientID;
    154159    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_LEAVE;
    155160    Msg.hdr.cParms      = 0;
     
    162167}
    163168
    164 static int vbglR3DnDHGProcessCancelMessage(uint32_t uClientId)
    165 {
     169static int vbglR3DnDHGProcessCancelMessage(PVBGLR3GUESTDNDCMDCTX pCtx)
     170{
     171    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     172
    166173    DragAndDropSvc::VBOXDNDHGCANCELMSG Msg;
    167174    RT_ZERO(Msg);
    168     Msg.hdr.u32ClientID = uClientId;
     175    Msg.hdr.u32ClientID = pCtx->uClientID;
    169176    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_CANCEL;
    170177    Msg.hdr.cParms      = 0;
     
    177184}
    178185
    179 static int vbglR3DnDHGProcessSendDirMessage(uint32_t  uClientId,
     186static int vbglR3DnDHGProcessSendDirMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
    180187                                            char     *pszDirname,
    181188                                            uint32_t  cbDirname,
     
    183190                                            uint32_t *pfMode)
    184191{
     192    AssertPtrReturn(pCtx,           VERR_INVALID_POINTER);
    185193    AssertPtrReturn(pszDirname,     VERR_INVALID_POINTER);
    186194    AssertReturn(cbDirname,         VERR_INVALID_PARAMETER);
     
    190198    DragAndDropSvc::VBOXDNDHGSENDDIRMSG Msg;
    191199    RT_ZERO(Msg);
    192     Msg.hdr.u32ClientID = uClientId;
     200    Msg.hdr.u32ClientID = pCtx->uClientID;
    193201    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_DIR;
    194202    Msg.hdr.cParms      = 3;
     
    214222}
    215223
    216 static int vbglR3DnDHGProcessSendFileMessage(uint32_t  uClientId,
     224static int vbglR3DnDHGProcessSendFileMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
    217225                                             char     *pszFilename,
    218226                                             uint32_t  cbFilename,
     
    223231                                             uint32_t *pfMode)
    224232{
     233    AssertPtrReturn(pCtx,            VERR_INVALID_POINTER);
    225234    AssertPtrReturn(pszFilename,     VERR_INVALID_POINTER);
    226235    AssertReturn(cbFilename,         VERR_INVALID_PARAMETER);
     
    231240    AssertPtrReturn(pfMode,          VERR_INVALID_POINTER);
    232241
    233     DragAndDropSvc::VBOXDNDHGSENDFILEMSG Msg;
    234     RT_ZERO(Msg);
    235     Msg.hdr.u32ClientID = uClientId;
    236     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_FILE;
    237     Msg.hdr.cParms      = 5;
    238 
    239     Msg.pvName.SetPtr(pszFilename, cbFilename);
    240     Msg.cbName.SetUInt32(0);
    241     Msg.pvData.SetPtr(pvData, cbData);
    242     Msg.cbData.SetUInt32(0);
    243     Msg.fMode.SetUInt32(0);
     242    DragAndDropSvc::VBOXDNDHGSENDFILEDATAMSG Msg;
     243    RT_ZERO(Msg);
     244    Msg.hdr.u32ClientID = pCtx->uClientID;
     245    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA;
     246
     247    if (pCtx->uProtocol <= 1)
     248    {
     249        Msg.u.v1.pvName.SetPtr(pszFilename, cbFilename);
     250        Msg.u.v1.cbName.SetUInt32(0);
     251        Msg.u.v1.pvData.SetPtr(pvData, cbData);
     252        Msg.u.v1.cbData.SetUInt32(0);
     253        Msg.u.v1.fMode.SetUInt32(0);
     254
     255        Msg.hdr.cParms = 5;
     256    }
     257    else
     258    {
     259        Msg.u.v2.pvData.SetPtr(pvData, cbData);
     260        Msg.u.v2.cbData.SetUInt32(0);
     261
     262        Msg.hdr.cParms = 2;
     263    }
    244264
    245265    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    249269        if (RT_SUCCESS(rc))
    250270        {
    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 
    255             AssertReturn(cbFilename >= *pcbFilenameRecv, VERR_TOO_MUCH_DATA);
    256             AssertReturn(cbData     >= *pcbDataRecv,     VERR_TOO_MUCH_DATA);
    257         }
    258     }
    259 
    260     return rc;
    261 }
    262 
    263 static int vbglR3DnDHGProcessURIMessages(uint32_t   uClientId,
     271            if (pCtx->uProtocol <= 1)
     272            {
     273                rc = Msg.u.v1.cbName.GetUInt32(pcbFilenameRecv); AssertRC(rc);
     274                rc = Msg.u.v1.cbData.GetUInt32(pcbDataRecv);     AssertRC(rc);
     275                rc = Msg.u.v1.fMode.GetUInt32(pfMode);           AssertRC(rc);
     276
     277                AssertReturn(cbFilename >= *pcbFilenameRecv, VERR_TOO_MUCH_DATA);
     278                AssertReturn(cbData     >= *pcbDataRecv,     VERR_TOO_MUCH_DATA);
     279            }
     280            else
     281            {
     282                rc = Msg.u.v2.cbData.GetUInt32(pcbDataRecv);     AssertRC(rc);
     283                AssertReturn(cbData     >= *pcbDataRecv,     VERR_TOO_MUCH_DATA);
     284            }
     285        }
     286    }
     287
     288    return rc;
     289}
     290
     291static int vbglR3DnDHGProcessSendFileHdrMessage(PVBGLR3GUESTDNDCMDCTX  pCtx,
     292                                                char                  *pszFilename,
     293                                                uint32_t               cbFilename,
     294                                                uint32_t              *puFlags,
     295                                                uint32_t              *pfMode,
     296                                                uint64_t              *pcbTotal)
     297{
     298    AssertPtrReturn(pCtx,        VERR_INVALID_POINTER);
     299    AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
     300    AssertReturn(cbFilename,     VERR_INVALID_PARAMETER);
     301    AssertPtrReturn(puFlags,     VERR_INVALID_POINTER);
     302    AssertPtrReturn(pfMode,      VERR_INVALID_POINTER);
     303    AssertReturn(pcbTotal,       VERR_INVALID_POINTER);
     304
     305    DragAndDropSvc::VBOXDNDHGSENDFILEHDRMSG Msg;
     306    RT_ZERO(Msg);
     307    Msg.hdr.u32ClientID = pCtx->uClientID;
     308    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR;
     309
     310    int rc;
     311
     312    if (pCtx->uProtocol <= 1)
     313    {
     314        rc = VERR_NOT_SUPPORTED;
     315    }
     316    else
     317    {
     318        Msg.pvName.SetPtr(pszFilename, cbFilename);
     319        Msg.cbName.SetUInt32(0);
     320        Msg.uContext.SetUInt32(0); /** @todo Not used yet. */
     321        Msg.uFlags.SetUInt32(0);
     322        Msg.fMode.SetUInt32(0);
     323        Msg.cbTotal.SetUInt64(0);
     324
     325        Msg.hdr.cParms = 6;
     326
     327        rc = VINF_SUCCESS;
     328    }
     329
     330    if (RT_SUCCESS(rc))
     331        rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     332    if (RT_SUCCESS(rc))
     333    {
     334        rc = Msg.hdr.result;
     335        if (RT_SUCCESS(rc))
     336        {
     337            /** @todo Get context ID. */
     338            rc = Msg.uFlags.GetUInt32(puFlags);   AssertRC(rc);
     339            rc = Msg.fMode.GetUInt32(pfMode);     AssertRC(rc);
     340            rc = Msg.cbTotal.GetUInt64(pcbTotal); AssertRC(rc);
     341        }
     342    }
     343
     344    return rc;
     345}
     346
     347static int vbglR3DnDHGProcessURIMessages(PVBGLR3GUESTDNDCMDCTX pCtx,
    264348                                         uint32_t  *puScreenId,
    265349                                         char      *pszFormat,
     
    270354                                         size_t    *pcbDataRecv)
    271355{
    272     AssertPtrReturn(ppvData, VERR_INVALID_POINTER);
    273     AssertPtrReturn(cbData, VERR_INVALID_PARAMETER);
     356    AssertPtrReturn(pCtx,        VERR_INVALID_POINTER);
     357    AssertPtrReturn(ppvData,     VERR_INVALID_POINTER);
     358    AssertPtrReturn(cbData,      VERR_INVALID_PARAMETER);
    274359    AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
    275360
    276     if (!*pcbDataRecv)
    277         return VERR_INVALID_PARAMETER;
     361    void    *pvData        = *ppvData;
     362    uint32_t cbDataRecv    = 0;
     363    uint64_t cbDataToRead  = *pcbDataRecv;
     364    uint64_t cbDataWritten = 0;
     365
     366    int rc = VINF_SUCCESS;
    278367
    279368    /* Allocate temp buffer. */
     
    281370    void *pvTmpData = RTMemAlloc(cbTmpData);
    282371    if (!pvTmpData)
    283         return VERR_NO_MEMORY;
     372        rc = VERR_NO_MEMORY;
    284373
    285374    /* Create and query the (unique) drop target directory. */
    286     char pszDropDir[RTPATH_MAX];
    287     int rc = DnDDirCreateDroppedFiles(pszDropDir, sizeof(pszDropDir));
     375    DnDURIList lstURI;
     376    char szDropDir[RTPATH_MAX];
     377    if (RT_SUCCESS(rc))
     378        rc = DnDDirCreateDroppedFiles(szDropDir, sizeof(szDropDir));
     379
    288380    if (RT_FAILURE(rc))
    289381    {
    290         RTMemFree(pvTmpData);
     382        int rc2 = VbglR3DnDHGSetProgress(pCtx, DragAndDropSvc::DND_PROGRESS_ERROR, 100 /* Percent */, rc);
     383        AssertRC(rc2);
     384
     385        if (pvTmpData)
     386            RTMemFree(pvTmpData);
    291387        return rc;
    292388    }
    293389
    294     /* Patch the old drop data with the new drop directory, so the drop target
    295      * can find the files. */
    296     DnDURIList lstURI;
    297     rc = lstURI.RootFromURIData(*ppvData, *pcbDataRecv,
    298                                 0 /* fFlags */);
    299     if (RT_SUCCESS(rc))
    300     {
    301         /* Cleanup the old data and write the new data back to the event. */
    302         RTMemFree(*ppvData);
    303 
    304         RTCString strData = lstURI.RootToString(pszDropDir);
    305         *ppvData = RTStrDupN(strData.c_str(), strData.length());
    306         *pcbDataRecv = strData.length() + 1;
    307     }
    308 
    309     /* Lists for holding created files & directories
    310      * in the case of a rollback. */
     390    /* Lists for holding created files & directories in the case of a rollback. */
    311391    RTCList<RTCString> guestDirList;
    312392    RTCList<RTCString> guestFileList;
    313393
    314     char szPathName[RTPATH_MAX];
     394    DnDURIObject objFile(DnDURIObject::File);
     395
     396    char szPathName[RTPATH_MAX] = { 0 };
    315397    uint32_t cbPathName = 0;
    316 
    317     bool fLoop = RT_SUCCESS(rc); /* No error occurred yet? */
    318     while (fLoop)
     398    uint32_t fFlags = 0;
     399    uint32_t fMode = 0;
     400
     401    while (RT_SUCCESS(rc))
    319402    {
    320403        uint32_t uNextMsg;
    321404        uint32_t cNextParms;
    322         rc = vbglR3DnDQueryNextHostMessageType(uClientId, &uNextMsg, &cNextParms, false /* fWait */);
     405        LogFlowFunc(("Waiting for new message ...\n"));
     406        rc = vbglR3DnDQueryNextHostMessageType(pCtx, &uNextMsg, &cNextParms, false /* fWait */);
    323407        if (RT_SUCCESS(rc))
    324408        {
     409            LogFlowFunc(("uNextMsg=%RU32, cNextParms=%RU32\n", uNextMsg, cNextParms));
     410
    325411            switch (uNextMsg)
    326412            {
    327413                case DragAndDropSvc::HOST_DND_HG_SND_DIR:
    328414                {
    329                     uint32_t fMode = 0;
    330                     rc = vbglR3DnDHGProcessSendDirMessage(uClientId,
     415                    rc = vbglR3DnDHGProcessSendDirMessage(pCtx,
    331416                                                          szPathName,
    332417                                                          sizeof(szPathName),
    333418                                                          &cbPathName,
    334419                                                          &fMode);
    335 #ifdef DEBUG_andy
    336420                    LogFlowFunc(("HOST_DND_HG_SND_DIR pszPathName=%s, cbPathName=%RU32, fMode=0x%x, rc=%Rrc\n",
    337421                                 szPathName, cbPathName, fMode, rc));
    338 #endif
     422
     423                    /*
     424                     * Important: HOST_DND_HG_SND_DIR sends the path (directory) name without URI specifications, that is,
     425                     *            only the pure name! To match the accounting though we have to translate the pure name into
     426                     *            a valid URI again.
     427                     *
     428                     ** @todo     Fix this URI translation!
     429                     */
     430                    RTCString strPath(szPathName);
    339431                    if (RT_SUCCESS(rc))
    340                         rc = DnDPathSanitize(szPathName, sizeof(szPathName));
     432                        rc = objFile.RebaseURIPath(strPath);
    341433                    if (RT_SUCCESS(rc))
    342434                    {
    343                         char *pszNewDir = RTPathJoinA(pszDropDir, szPathName);
     435                        rc = DnDPathSanitize(szPathName, sizeof(szPathName));
     436                        char *pszNewDir = RTPathJoinA(szDropDir, szPathName);
    344437                        if (pszNewDir)
    345438                        {
    346439                            rc = RTDirCreate(pszNewDir, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRWXU, 0);
    347                             if (!guestDirList.contains(pszNewDir))
    348                                 guestDirList.append(pszNewDir);
    349 
    350440                            RTStrFree(pszNewDir);
    351441                        }
    352442                        else
    353443                            rc = VERR_NO_MEMORY;
     444
     445                        if (RT_SUCCESS(rc))
     446                        {
     447                            if (!guestDirList.contains(strPath))
     448                                guestDirList.append(strPath);
     449                        }
    354450                    }
    355451                    break;
    356452                }
    357                 case DragAndDropSvc::HOST_DND_HG_SND_FILE:
     453                case DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR:
    358454                {
    359                     uint32_t cbDataRecv;
    360                     uint32_t fMode = 0;
    361                     rc = vbglR3DnDHGProcessSendFileMessage(uClientId,
     455                    rc = vbglR3DnDHGProcessSendFileHdrMessage(pCtx,
     456                                                              szPathName,
     457                                                              sizeof(szPathName),
     458                                                              &fFlags,
     459                                                              &fMode,
     460                                                              &cbDataToRead);
     461                    LogFlowFunc(("HOST_DND_HG_SND_FILE_HDR pszPathName=%s, fFlags=0x%x, fMode=0x%x, cbDataToRead=%RU64, rc=%Rrc\n",
     462                                 szPathName, fFlags, fMode, cbDataToRead, rc));
     463
     464                    cbDataWritten = 0;
     465                    break;
     466                }
     467                case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA:
     468                {
     469                    rc = vbglR3DnDHGProcessSendFileMessage(pCtx,
    362470                                                           szPathName,
    363471                                                           sizeof(szPathName),
     
    367475                                                           &cbDataRecv,
    368476                                                           &fMode);
    369 #ifdef DEBUG_andy
    370477                    LogFlowFunc(("HOST_DND_HG_SND_FILE pszPathName=%s, cbPathName=%RU32, pvData=0x%p, cbDataRecv=%RU32, fMode=0x%x, rc=%Rrc\n",
    371478                                 szPathName, cbPathName, pvTmpData, cbDataRecv, fMode, rc));
    372 #endif
     479
     480                    /*
     481                     * Important: HOST_DND_HG_SND_FILE sends the path (directory) name without URI specifications, that is,
     482                     *            only the pure name! To match the accounting though we have to translate the pure name into
     483                     *            a valid URI again.
     484                     *
     485                     ** @todo     Fix this URI translation!
     486                     */
     487                    RTCString strPath(szPathName);
    373488                    if (RT_SUCCESS(rc))
    374                         rc = DnDPathSanitize(szPathName, sizeof(szPathName));
     489                        rc = objFile.RebaseURIPath(strPath);
    375490                    if (RT_SUCCESS(rc))
    376491                    {
    377                         char *pszPathAbs = RTPathJoinA(pszDropDir, szPathName);
    378                         if (pszPathAbs)
     492                        rc = DnDPathSanitize(szPathName, sizeof(szPathName));
     493                        if (RT_SUCCESS(rc))
    379494                        {
    380                             RTFILE hFile;
    381                             /** @todo r=andy Keep the file open and locked during the actual file transfer. Otherwise this will
    382                              *               create all sorts of funny races because we don't know if the guest has
    383                              *               modified the file in between the file data send calls. */
    384                             rc = RTFileOpen(&hFile, pszPathAbs,
    385                                             RTFILE_O_WRITE | RTFILE_O_APPEND | RTFILE_O_DENY_ALL | RTFILE_O_OPEN_CREATE);
    386                             if (RT_SUCCESS(rc))
     495                            char *pszPathAbs = RTPathJoinA(szDropDir, szPathName);
     496                            if (pszPathAbs)
    387497                            {
    388                                 /** @todo r=andy Not very safe to assume that we were last appending to the current file. */
    389                                 rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, NULL);
     498                                RTFILE hFile;
     499                                /** @todo r=andy Keep the file open and locked during the actual file transfer. Otherwise this will
     500                                 *               create all sorts of funny races because we don't know if the guest has
     501                                 *               modified the file in between the file data send calls.
     502                                 *
     503                                 *               See HOST_DND_HG_SND_FILE_HDR for a good place to do this. */
     504                                rc = RTFileOpen(&hFile, pszPathAbs,
     505                                                RTFILE_O_WRITE | RTFILE_O_APPEND | RTFILE_O_DENY_ALL | RTFILE_O_OPEN_CREATE);
    390506                                if (RT_SUCCESS(rc))
    391507                                {
    392                                     rc = RTFileWrite(hFile, pvTmpData, cbDataRecv, 0);
    393                                     /* Valid UNIX mode? */
    394                                     if (   RT_SUCCESS(rc)
    395                                         && (fMode & RTFS_UNIX_MASK))
    396                                         rc = RTFileSetMode(hFile, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR);
     508                                    /** @todo r=andy Not very safe to assume that we were last appending to the current file. */
     509                                    rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, NULL);
     510                                    if (RT_SUCCESS(rc))
     511                                    {
     512                                        rc = RTFileWrite(hFile, pvTmpData, cbDataRecv, 0);
     513                                        if (RT_SUCCESS(rc))
     514                                        {
     515                                            if (fMode & RTFS_UNIX_MASK) /* Valid UNIX mode? */
     516                                                rc = RTFileSetMode(hFile, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR);
     517
     518                                            cbDataWritten += cbDataRecv;
     519                                            Assert(cbDataWritten <= cbDataToRead);
     520                                        }
     521                                    }
     522
     523                                    RTFileClose(hFile);
     524
     525                                    if (!guestFileList.contains(pszPathAbs)) /* Add the file to (rollback) list. */
     526                                        guestFileList.append(pszPathAbs);
    397527                                }
    398 
    399                                 RTFileClose(hFile);
    400 
    401                                 if (!guestFileList.contains(pszPathAbs))
    402                                     guestFileList.append(pszPathAbs);
     528                                else
     529                                    LogFlowFunc(("Opening file failed with rc=%Rrc\n", rc));
     530
     531                                RTStrFree(pszPathAbs);
    403532                            }
    404 #ifdef DEBUG
    405533                            else
    406                                 LogFlowFunc(("Opening file failed with rc=%Rrc\n", rc));
    407 #endif
    408                             RTStrFree(pszPathAbs);
     534                                rc = VERR_NO_MEMORY;
    409535                        }
    410                         else
    411                             rc = VERR_NO_MEMORY;
    412536                    }
    413537                    break;
     
    415539                case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
    416540                {
    417                     rc = vbglR3DnDHGProcessCancelMessage(uClientId);
     541                    rc = vbglR3DnDHGProcessCancelMessage(pCtx);
    418542                    if (RT_SUCCESS(rc))
    419543                        rc = VERR_CANCELLED;
    420                     /* Break out of the loop. */
     544                    break;
    421545                }
    422546                default:
    423                     fLoop = false;
     547                    LogFlowFunc(("Message %RU32 not supported\n", uNextMsg));
     548                    rc = VERR_NOT_SUPPORTED;
    424549                    break;
    425550            }
     551
     552#if 0
     553            if (pCtx->uProtocol >= XXX)
     554            {
     555                /*
     556                 * Send the progress back to the host.
     557                 */
     558                uint32_t uStatus;
     559                int guestRc;
     560                uint8_t uPercent;
     561                switch (rc)
     562                {
     563                    case VINF_SUCCESS:
     564                    {
     565                        if (!cbData)
     566                            cbData = 1;
     567                        uPercent = cbDataWritten * 100 / (cbDataToRead ? cbDataToRead : 1);
     568                        uStatus  = uPercent >= 100 ?
     569                                   DragAndDropSvc::DND_PROGRESS_COMPLETE : DragAndDropSvc::DND_PROGRESS_RUNNING;
     570                        guestRc  = VINF_SUCCESS;
     571                        break;
     572                    }
     573
     574                    case VERR_CANCELLED:
     575                    {
     576                        uStatus  = DragAndDropSvc::DND_PROGRESS_CANCELLED;
     577                        uPercent = 100;
     578                        guestRc  = VINF_SUCCESS;
     579                        break;
     580                    }
     581
     582                    default:
     583                    {
     584                        uStatus  = DragAndDropSvc::DND_PROGRESS_ERROR;
     585                        uPercent = 100;
     586                        guestRc  = rc;
     587                        break;
     588                    }
     589                }
     590
     591                int rc2 = VbglR3DnDHGSetProgress(pCtx, uStatus, uPercent, guestRc);
     592                LogFlowFunc(("cbDataWritten=%RU64 / cbDataToRead=%RU64 => %RU8%% (uStatus=%ld, %Rrc), rc=%Rrc\n", cbDataWritten, cbDataToRead,
     593                              uPercent, uStatus, guestRc, rc2));
     594                if (RT_SUCCESS(rc))
     595                    rc = rc2;
     596
     597                /* All data transferred? */
     598                if (   RT_SUCCESS(rc)
     599                    && uPercent == 100)
     600                {
     601                    rc = VINF_EOF;
     602                    break;
     603                }
     604            }
     605#endif
    426606        }
    427607        else
    428608        {
     609            /* All URI data processed? */
    429610            if (rc == VERR_NO_DATA)
    430611                rc = VINF_SUCCESS;
     
    437618    } /* while */
    438619
     620    LogFlowFunc(("Loop ended with %Rrc\n", rc));
     621
    439622    if (pvTmpData)
    440623        RTMemFree(pvTmpData);
    441624
    442     /* Cleanup on failure or if the user has canceled. */
     625    /* Cleanup on failure or if the user has canceled the operation. */
    443626    if (RT_FAILURE(rc))
    444627    {
    445         /* Remove any stuff created. */
     628        LogFlowFunc(("Rolling back ...\n"));
     629
     630        /* Rollback by removing any stuff created. */
    446631        for (size_t i = 0; i < guestFileList.size(); ++i)
    447632            RTFileDelete(guestFileList.at(i).c_str());
    448633        for (size_t i = 0; i < guestDirList.size(); ++i)
    449634            RTDirRemove(guestDirList.at(i).c_str());
    450         RTDirRemove(pszDropDir);
    451 
    452         LogFlowFunc(("Failed with rc=%Rrc\n", rc));
    453     }
    454 
    455     return rc;
    456 }
    457 
    458 static int vbglR3DnDHGProcessDataMessageInternal(uint32_t  uClientId,
     635    }
     636    else
     637    {
     638        /*
     639         * Patch the old drop data with the new drop directory, so the drop target can find the files.
     640         */
     641        rc = lstURI.RootFromURIData(pvData, cbDataToRead, 0 /* fFlags */);
     642        if (RT_SUCCESS(rc))
     643        {
     644            /* Cleanup the old data and write the new data back to the event. */
     645            RTMemFree(pvData);
     646
     647            RTCString strData = lstURI.RootToString(szDropDir);
     648            LogFlowFunc(("cbDataToRead: %zu -> %zu\n", cbDataToRead, strData.length() + 1));
     649
     650            pvData       = RTStrDupN(strData.c_str(), strData.length());
     651            cbDataToRead = strData.length() + 1;
     652        }
     653
     654        if (RT_SUCCESS(rc))
     655        {
     656            *ppvData     = pvData;
     657            *pcbDataRecv = cbDataToRead;
     658        }
     659
     660        /** @todo Compare the URI list with the dirs/files we really transferred. */
     661    }
     662
     663    /* Try removing the (empty) drop directory in any case. */
     664    int rc2 = RTDirRemove(szDropDir);
     665    if (RT_FAILURE(rc2))
     666        LogFunc(("Warning: Unable to remove drop directory \"%s\": %Rrc\n", szDropDir, rc2));
     667
     668    LogFlowFuncLeaveRC(rc);
     669    return rc;
     670}
     671
     672static int vbglR3DnDHGProcessDataMessageInternal(PVBGLR3GUESTDNDCMDCTX pCtx,
    459673                                                 uint32_t *puScreenId,
    460674                                                 char     *pszFormat,
     
    465679                                                 uint32_t *pcbDataTotal)
    466680{
     681    AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
    467682    AssertPtrReturn(puScreenId,    VERR_INVALID_POINTER);
    468683    AssertPtrReturn(pszFormat,     VERR_INVALID_POINTER);
     
    475690    DragAndDropSvc::VBOXDNDHGSENDDATAMSG Msg;
    476691    RT_ZERO(Msg);
    477     Msg.hdr.u32ClientID = uClientId;
     692    Msg.hdr.u32ClientID = pCtx->uClientID;
    478693    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_DATA;
    479694    Msg.hdr.cParms      = 5;
     
    493708        {
    494709            rc = Msg.uScreenId.GetUInt32(puScreenId);  AssertRC(rc);
     710
     711            /*
     712             * In case of VERR_BUFFER_OVERFLOW get the data sizes required
     713             * for the format + data blocks.
     714             */
    495715            rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
    496             rc = Msg.cbData.GetUInt32(pcbDataTotal);   AssertRC(rc);
     716            rc = Msg.cbData.GetUInt32(pcbDataTotal); AssertRC(rc);
    497717
    498718            AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
    499             AssertReturn(cbData   >= *pcbDataTotal,  VERR_TOO_MUCH_DATA);
    500         }
    501     }
    502 
    503     return rc;
    504 }
    505 
    506 static int vbglR3DnDHGProcessMoreDataMessageInternal(uint32_t  uClientId,
     719            AssertReturn(cbData   >= *pcbDataTotal, VERR_TOO_MUCH_DATA);
     720        }
     721    }
     722
     723    return rc;
     724}
     725
     726static int vbglR3DnDHGProcessMoreDataMessageInternal(PVBGLR3GUESTDNDCMDCTX pCtx,
    507727                                                     void     *pvData,
    508728                                                     uint32_t  cbData,
    509                                                      uint32_t *pcbDataRecv)
    510 {
    511     AssertPtrReturn(pvData,      VERR_INVALID_POINTER);
    512     AssertReturn(cbData,         VERR_INVALID_PARAMETER);
    513     AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
     729                                                     uint32_t *pcbDataTotal)
     730{
     731    AssertPtrReturn(pCtx,         VERR_INVALID_POINTER);
     732    AssertPtrReturn(pvData,       VERR_INVALID_POINTER);
     733    AssertReturn(cbData,          VERR_INVALID_PARAMETER);
     734    AssertPtrReturn(pcbDataTotal, VERR_INVALID_POINTER);
    514735
    515736    DragAndDropSvc::VBOXDNDHGSENDMOREDATAMSG Msg;
    516737    RT_ZERO(Msg);
    517     Msg.hdr.u32ClientID = uClientId;
     738    Msg.hdr.u32ClientID = pCtx->uClientID;
    518739    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA;
    519740    Msg.hdr.cParms      = 2;
     
    529750            || rc == VERR_BUFFER_OVERFLOW)
    530751        {
    531             rc = Msg.cbData.GetUInt32(pcbDataRecv); AssertRC(rc);
    532             AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA);
    533         }
    534     }
    535     return rc;
    536 }
    537 
    538 static int vbglR3DnDHGProcessSendDataMessageLoop(uint32_t  uClientId,
     752            rc = Msg.cbData.GetUInt32(pcbDataTotal); AssertRC(rc);
     753            AssertReturn(cbData >= *pcbDataTotal, VERR_TOO_MUCH_DATA);
     754        }
     755    }
     756    return rc;
     757}
     758
     759static int vbglR3DnDHGProcessSendDataMessageLoop(PVBGLR3GUESTDNDCMDCTX pCtx,
    539760                                                 uint32_t *puScreenId,
    540761                                                 char     *pszFormat,
     
    545766                                                 size_t   *pcbDataRecv)
    546767{
    547     uint32_t cbDataRecv = 0;
    548     int rc = vbglR3DnDHGProcessDataMessageInternal(uClientId,
     768    AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
     769    AssertPtrReturn(puScreenId,    VERR_INVALID_POINTER);
     770    AssertPtrReturn(pszFormat,     VERR_INVALID_POINTER);
     771    AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
     772    AssertPtrReturn(ppvData,       VERR_INVALID_POINTER);
     773    /* pcbDataRecv is optional. */
     774
     775    uint32_t cbDataReq = 0;
     776    int rc = vbglR3DnDHGProcessDataMessageInternal(pCtx,
    549777                                                   puScreenId,
    550778                                                   pszFormat,
     
    553781                                                   *ppvData,
    554782                                                   cbData,
    555                                                    &cbDataRecv);
    556     uint32_t cbAllDataRecv = cbDataRecv;
     783                                                   &cbDataReq);
     784    uint32_t cbDataTotal = cbDataReq;
     785    void *pvData = *ppvData;
     786
     787    LogFlowFunc(("HOST_DND_HG_SND_DATA cbDataReq=%RU32, rc=%Rrc\n", cbDataTotal, rc));
     788
    557789    while (rc == VERR_BUFFER_OVERFLOW)
    558790    {
    559791        uint32_t uNextMsg;
    560792        uint32_t cNextParms;
    561         rc = vbglR3DnDQueryNextHostMessageType(uClientId, &uNextMsg, &cNextParms, false);
     793        rc = vbglR3DnDQueryNextHostMessageType(pCtx, &uNextMsg, &cNextParms, false);
    562794        if (RT_SUCCESS(rc))
    563795        {
     
    566798                case DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA:
    567799                {
    568                     *ppvData = RTMemRealloc(*ppvData, cbAllDataRecv + cbData);
    569                     if (!*ppvData)
     800                    /** @todo r=andy Don't use reallocate here; can go wrong with *really* big URI lists.
     801                     *               Instead send as many URI entries as possible per chunk and add those entries
     802                     *               to our to-process list for immediata processing. Repeat the step after processing then. */
     803                    LogFlowFunc(("HOST_DND_HG_SND_MORE_DATA cbDataTotal: %RU32 -> %RU32\n", cbDataReq, cbDataReq + cbData));
     804                    pvData = RTMemRealloc(*ppvData, cbDataTotal + cbData);
     805                    if (!pvData)
    570806                    {
    571807                        rc = VERR_NO_MEMORY;
    572808                        break;
    573809                    }
    574                     rc = vbglR3DnDHGProcessMoreDataMessageInternal(uClientId,
    575                                                                    &((char*)*ppvData)[cbAllDataRecv],
     810                    rc = vbglR3DnDHGProcessMoreDataMessageInternal(pCtx,
     811                                                                   &((char *)pvData)[cbDataTotal],
    576812                                                                   cbData,
    577                                                                    &cbDataRecv);
    578                     cbAllDataRecv += cbDataRecv;
     813                                                                   &cbDataReq);
     814                    cbDataTotal += cbDataReq;
    579815                    break;
    580816                }
     
    582818                default:
    583819                {
    584                     rc = vbglR3DnDHGProcessCancelMessage(uClientId);
     820                    rc = vbglR3DnDHGProcessCancelMessage(pCtx);
    585821                    if (RT_SUCCESS(rc))
    586822                        rc = VERR_CANCELLED;
     
    590826        }
    591827    }
    592     if (RT_SUCCESS(rc))
    593         *pcbDataRecv = cbAllDataRecv;
    594 
    595     return rc;
    596 }
    597 
    598 static int vbglR3DnDHGProcessSendDataMessage(uint32_t   uClientId,
     828
     829    if (RT_SUCCESS(rc))
     830    {
     831        *ppvData         = pvData;
     832        if (pcbDataRecv)
     833            *pcbDataRecv = cbDataTotal;
     834    }
     835
     836    return rc;
     837}
     838
     839static int vbglR3DnDHGProcessSendDataMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
    599840                                             uint32_t  *puScreenId,
    600841                                             char      *pszFormat,
     
    605846                                             size_t    *pcbDataRecv)
    606847{
    607     int rc = vbglR3DnDHGProcessSendDataMessageLoop(uClientId,
     848    AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
     849    AssertPtrReturn(puScreenId,    VERR_INVALID_POINTER);
     850    AssertPtrReturn(pszFormat,     VERR_INVALID_POINTER);
     851    AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
     852    AssertPtrReturn(ppvData,       VERR_INVALID_POINTER);
     853
     854    int rc = vbglR3DnDHGProcessSendDataMessageLoop(pCtx,
    608855                                                   puScreenId,
    609856                                                   pszFormat,
     
    623870        AssertPtr(pcbFormatRecv);
    624871        if (DnDMIMEHasFileURLs(pszFormat, *pcbFormatRecv))
    625             rc = vbglR3DnDHGProcessURIMessages(uClientId,
     872            rc = vbglR3DnDHGProcessURIMessages(pCtx,
    626873                                               puScreenId,
    627874                                               pszFormat,
     
    631878                                               cbData,
    632879                                               pcbDataRecv);
    633     }
    634 
    635     return rc;
    636 }
    637 
    638 static int vbglR3DnDGHProcessRequestPendingMessage(uint32_t  uClientId,
     880        else
     881            rc = VERR_NOT_SUPPORTED;
     882    }
     883
     884    return rc;
     885}
     886
     887static int vbglR3DnDGHProcessRequestPendingMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
    639888                                                   uint32_t *puScreenId)
    640889{
     890    AssertPtrReturn(pCtx,       VERR_INVALID_POINTER);
    641891    AssertPtrReturn(puScreenId, VERR_INVALID_POINTER);
    642892
    643893    DragAndDropSvc::VBOXDNDGHREQPENDINGMSG Msg;
    644894    RT_ZERO(Msg);
    645     Msg.hdr.u32ClientID = uClientId;
     895    Msg.hdr.u32ClientID = pCtx->uClientID;
    646896    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_REQ_PENDING;
    647897    Msg.hdr.cParms      = 1;
     
    662912}
    663913
    664 static int vbglR3DnDGHProcessDroppedMessage(uint32_t  uClientId,
     914static int vbglR3DnDGHProcessDroppedMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
    665915                                            char     *pszFormat,
    666916                                            uint32_t  cbFormat,
     
    668918                                            uint32_t *puAction)
    669919{
     920    AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
    670921    AssertPtrReturn(pszFormat,     VERR_INVALID_POINTER);
    671922    AssertReturn(cbFormat,         VERR_INVALID_PARAMETER);
     
    675926    DragAndDropSvc::VBOXDNDGHDROPPEDMSG Msg;
    676927    RT_ZERO(Msg);
    677     Msg.hdr.u32ClientID = uClientId;
     928    Msg.hdr.u32ClientID = pCtx->uClientID;
    678929    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_EVT_DROPPED;
    679930    Msg.hdr.cParms      = 3;
     
    703954 ******************************************************************************/
    704955
    705 VBGLR3DECL(int) VbglR3DnDConnect(uint32_t *pu32ClientId)
    706 {
    707     AssertPtrReturn(pu32ClientId, VERR_INVALID_POINTER);
     956VBGLR3DECL(int) VbglR3DnDConnect(PVBGLR3GUESTDNDCMDCTX pCtx)
     957{
     958    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    708959
    709960    /* Initialize header */
     
    712963    Info.result      = VERR_WRONG_ORDER;
    713964    Info.u32ClientID = UINT32_MAX;  /* try make valgrind shut up. */
    714     /* Initialize parameter */
    715965    Info.Loc.type    = VMMDevHGCMLoc_LocalHost_Existing;
     966
    716967    int rc = RTStrCopy(Info.Loc.u.host.achName, sizeof(Info.Loc.u.host.achName), "VBoxDragAndDropSvc");
    717     if (RT_FAILURE(rc)) return rc;
    718     /* Do request */
     968    if (RT_FAILURE(rc))
     969        return rc;
     970
    719971    rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CONNECT, &Info, sizeof(Info));
    720972    if (RT_SUCCESS(rc))
    721973    {
    722974        rc = Info.result;
    723         if (RT_SUCCESS(rc))
    724             *pu32ClientId = Info.u32ClientID;
    725     }
    726     if (rc == VERR_HGCM_SERVICE_NOT_FOUND)
    727         rc = VINF_PERMISSION_DENIED;
    728     return rc;
    729 }
    730 
    731 VBGLR3DECL(int) VbglR3DnDDisconnect(uint32_t u32ClientId)
    732 {
     975        if (rc == VERR_HGCM_SERVICE_NOT_FOUND)
     976            rc = VINF_PERMISSION_DENIED;
     977
     978        /* Set the protocol version to use. */
     979        pCtx->uProtocol = 2;
     980
     981        Assert(Info.u32ClientID);
     982        pCtx->uClientID = Info.u32ClientID;
     983    }
     984
     985    if (RT_SUCCESS(rc))
     986    {
     987        /*
     988         * Try sending the connect message to tell the protocol version to use.
     989         * Note: This might fail when the Guest Additions run on an older VBox host (< VBox 5.0) which
     990         *       does not implement this command.
     991         */
     992        DragAndDropSvc::VBOXDNDCONNECTPMSG Msg;
     993        RT_ZERO(Msg);
     994        Msg.hdr.result      = VERR_WRONG_ORDER;
     995        Msg.hdr.u32ClientID = pCtx->uClientID;
     996        Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_CONNECT;
     997        Msg.hdr.cParms      = 2;
     998
     999        Msg.uProtocol.SetUInt32(pCtx->uProtocol);
     1000        Msg.uFlags.SetUInt32(0); /* Unused at the moment. */
     1001
     1002        int rc2 = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     1003        if (RT_SUCCESS(rc2))
     1004            rc2 = Msg.hdr.result; /* Not fatal. */
     1005
     1006        LogFlowFunc(("Connection request ended with rc=%Rrc\n", rc2));
     1007    }
     1008
     1009    LogFlowFunc(("uClient=%RU32, uProtocol=%RU32, rc=%Rrc\n", pCtx->uClientID, pCtx->uProtocol, rc));
     1010    return rc;
     1011}
     1012
     1013VBGLR3DECL(int) VbglR3DnDDisconnect(PVBGLR3GUESTDNDCMDCTX pCtx)
     1014{
     1015    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     1016
    7331017    VBoxGuestHGCMDisconnectInfo Info;
    7341018    Info.result      = VERR_WRONG_ORDER;
    735     Info.u32ClientID = u32ClientId;
    736 
    737     /* Do request */
     1019    Info.u32ClientID = pCtx->uClientID;
     1020
    7381021    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_DISCONNECT, &Info, sizeof(Info));
    7391022    if (RT_SUCCESS(rc))
     
    7431026}
    7441027
    745 VBGLR3DECL(int) VbglR3DnDProcessNextMessage(uint32_t u32ClientId, CPVBGLR3DNDHGCMEVENT pEvent)
    746 {
     1028VBGLR3DECL(int) VbglR3DnDProcessNextMessage(PVBGLR3GUESTDNDCMDCTX pCtx, CPVBGLR3DNDHGCMEVENT pEvent)
     1029{
     1030    AssertPtrReturn(pCtx,   VERR_INVALID_POINTER);
    7471031    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
    7481032
     
    7511035    const uint32_t ccbFormats = _64K;
    7521036    const uint32_t ccbData    = _64K;
    753     int rc = vbglR3DnDQueryNextHostMessageType(u32ClientId, &uMsg, &uNumParms,
     1037    int rc = vbglR3DnDQueryNextHostMessageType(pCtx, &uMsg, &uNumParms,
    7541038                                               true /* fWait */);
    7551039    if (RT_SUCCESS(rc))
    7561040    {
     1041        pEvent->uType = uMsg;
     1042
    7571043        switch(uMsg)
    7581044        {
     
    7611047            case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
    7621048            {
    763                 pEvent->uType = uMsg;
    7641049                pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
    7651050                if (!pEvent->pszFormats)
     
    7671052
    7681053                if (RT_SUCCESS(rc))
    769                     rc = vbglR3DnDHGProcessActionMessage(u32ClientId,
     1054                    rc = vbglR3DnDHGProcessActionMessage(pCtx,
    7701055                                                         uMsg,
    7711056                                                         &pEvent->uScreenId,
     
    7811066            case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE:
    7821067            {
    783                 pEvent->uType = uMsg;
    784                 rc = vbglR3DnDHGProcessLeaveMessage(u32ClientId);
     1068                rc = vbglR3DnDHGProcessLeaveMessage(pCtx);
    7851069                break;
    7861070            }
    7871071            case DragAndDropSvc::HOST_DND_HG_SND_DATA:
    7881072            {
    789                 pEvent->uType = uMsg;
    7901073                pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
    7911074                if (!pEvent->pszFormats)
     
    7991082                        RTMemFree(pEvent->pszFormats);
    8001083                        pEvent->pszFormats = NULL;
     1084
    8011085                        rc = VERR_NO_MEMORY;
    8021086                    }
     
    8041088
    8051089                if (RT_SUCCESS(rc))
    806                     rc = vbglR3DnDHGProcessSendDataMessage(u32ClientId,
     1090                    rc = vbglR3DnDHGProcessSendDataMessage(pCtx,
    8071091                                                           &pEvent->uScreenId,
    8081092                                                           pEvent->pszFormats,
     
    8161100            case DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA:
    8171101            case DragAndDropSvc::HOST_DND_HG_SND_DIR:
    818             case DragAndDropSvc::HOST_DND_HG_SND_FILE:
     1102            case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA:
    8191103            {
    820                 pEvent->uType = uMsg;
    821 
    822                 /* All messages in this case are handled internally
     1104                /*
     1105                 * All messages in this case are handled internally
    8231106                 * by vbglR3DnDHGProcessSendDataMessage() and must
    824                  * be specified by a preceding HOST_DND_HG_SND_DATA call. */
     1107                 * be specified by a preceding HOST_DND_HG_SND_DATA call.
     1108                 */
    8251109                rc = VERR_WRONG_ORDER;
    8261110                break;
     
    8281112            case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
    8291113            {
    830                 pEvent->uType = uMsg;
    831                 rc = vbglR3DnDHGProcessCancelMessage(u32ClientId);
     1114                rc = vbglR3DnDHGProcessCancelMessage(pCtx);
    8321115                break;
    8331116            }
     
    8351118            case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
    8361119            {
    837                 pEvent->uType = uMsg;
    838                 rc = vbglR3DnDGHProcessRequestPendingMessage(u32ClientId,
    839                                                              &pEvent->uScreenId);
     1120                rc = vbglR3DnDGHProcessRequestPendingMessage(pCtx, &pEvent->uScreenId);
    8401121                break;
    8411122            }
    8421123            case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
    8431124            {
    844                 pEvent->uType = uMsg;
    8451125                pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
    8461126                if (!pEvent->pszFormats)
     
    8481128
    8491129                if (RT_SUCCESS(rc))
    850                     rc = vbglR3DnDGHProcessDroppedMessage(u32ClientId,
     1130                    rc = vbglR3DnDGHProcessDroppedMessage(pCtx,
    8511131                                                          pEvent->pszFormats,
    8521132                                                          ccbFormats,
     
    8581138            default:
    8591139            {
    860                 pEvent->uType = uMsg;
    861 
    8621140                rc = VERR_NOT_SUPPORTED;
    8631141                break;
     
    8691147}
    8701148
    871 VBGLR3DECL(int) VbglR3DnDHGAcknowledgeOperation(uint32_t u32ClientId, uint32_t uAction)
    872 {
     1149VBGLR3DECL(int) VbglR3DnDHGAcknowledgeOperation(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uAction)
     1150{
     1151    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     1152
    8731153    DragAndDropSvc::VBOXDNDHGACKOPMSG Msg;
    8741154    RT_ZERO(Msg);
    8751155    Msg.hdr.result      = VERR_WRONG_ORDER;
    876     Msg.hdr.u32ClientID = u32ClientId;
     1156    Msg.hdr.u32ClientID = pCtx->uClientID;
    8771157    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_ACK_OP;
    8781158    Msg.hdr.cParms      = 1;
     
    8871167}
    8881168
    889 VBGLR3DECL(int) VbglR3DnDHGRequestData(uint32_t u32ClientId, const char* pcszFormat)
    890 {
    891     AssertPtrReturn(pcszFormat, VERR_INVALID_PARAMETER);
     1169VBGLR3DECL(int) VbglR3DnDHGRequestData(PVBGLR3GUESTDNDCMDCTX pCtx, const char* pcszFormat)
     1170{
     1171    AssertPtrReturn(pCtx,       VERR_INVALID_POINTER);
     1172    AssertPtrReturn(pcszFormat, VERR_INVALID_POINTER);
    8921173
    8931174    DragAndDropSvc::VBOXDNDHGREQDATAMSG Msg;
    8941175    RT_ZERO(Msg);
    8951176    Msg.hdr.result      = VERR_WRONG_ORDER;
    896     Msg.hdr.u32ClientID = u32ClientId;
     1177    Msg.hdr.u32ClientID = pCtx->uClientID;
    8971178    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_REQ_DATA;
    8981179    Msg.hdr.cParms      = 1;
     
    9071188}
    9081189
     1190VBGLR3DECL(int) VbglR3DnDHGSetProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr)
     1191{
     1192    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     1193
     1194    DragAndDropSvc::VBOXDNDHGEVTPROGRESSMSG Msg;
     1195    RT_ZERO(Msg);
     1196    Msg.hdr.result      = VERR_WRONG_ORDER;
     1197    Msg.hdr.u32ClientID = pCtx->uClientID;
     1198    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS;
     1199    Msg.hdr.cParms      = 3;
     1200
     1201    Msg.uStatus.SetUInt32(uStatus);
     1202    Msg.uPercent.SetUInt32(uPercent);
     1203    Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
     1204
     1205    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     1206    if (RT_SUCCESS(rc))
     1207        rc = Msg.hdr.result;
     1208
     1209    return rc;
     1210}
     1211
    9091212#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    910 VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending(uint32_t u32ClientId,
    911                                               uint32_t uDefAction, uint32_t uAllActions,
    912                                               const char* pcszFormats)
    913 {
     1213VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending(PVBGLR3GUESTDNDCMDCTX pCtx,
     1214                                              uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats)
     1215{
     1216    AssertPtrReturn(pCtx,        VERR_INVALID_POINTER);
    9141217    AssertPtrReturn(pcszFormats, VERR_INVALID_POINTER);
    9151218
     
    9171220    RT_ZERO(Msg);
    9181221    Msg.hdr.result      = VERR_WRONG_ORDER;
    919     Msg.hdr.u32ClientID = u32ClientId;
     1222    Msg.hdr.u32ClientID = pCtx->uClientID;
    9201223    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_ACK_PENDING;
    9211224    Msg.hdr.cParms      = 3;
     
    9321235}
    9331236
    934 static int vbglR3DnDGHSendDataInternal(uint32_t u32ClientId,
    935                                        void *pvData, uint32_t cbData,
    936                                        uint32_t cbAdditionalData)
    937 {
     1237static int vbglR3DnDGHSendDataInternal(PVBGLR3GUESTDNDCMDCTX pCtx,
     1238                                       void *pvData, uint32_t cbData, uint32_t cbAdditionalData)
     1239{
     1240    AssertPtrReturn(pCtx,   VERR_INVALID_POINTER);
    9381241    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
    939     AssertReturn(cbData, VERR_INVALID_PARAMETER);
     1242    AssertReturn(cbData,    VERR_INVALID_PARAMETER);
     1243    /* cbAdditionalData is optional. */
    9401244
    9411245    DragAndDropSvc::VBOXDNDGHSENDDATAMSG Msg;
    9421246    RT_ZERO(Msg);
    9431247    Msg.hdr.result      = VERR_WRONG_ORDER;
    944     Msg.hdr.u32ClientID = u32ClientId;
     1248    Msg.hdr.u32ClientID = pCtx->uClientID;
    9451249    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DATA;
    9461250    Msg.hdr.cParms      = 2;
     
    9491253    Msg.cbTotalBytes.SetUInt32(cbData + cbAdditionalData);
    9501254
    951     int rc;
    952 
     1255    int rc = VINF_SUCCESS;
     1256
     1257    uint32_t cbCurChunk;
    9531258    uint32_t cbMaxChunk = _64K; /** @todo Transfer max. 64K chunks per message. Configurable? */
    9541259    uint32_t cbSent     = 0;
     
    9561261    while (cbSent < cbData)
    9571262    {
    958         uint32_t cbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk);
    959         Msg.pvData.SetPtr(static_cast<uint8_t*>(pvData) + cbSent, cbCurChunk);
     1263        cbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk);
     1264        Msg.pvData.SetPtr(static_cast<uint8_t *>(pvData) + cbSent, cbCurChunk);
    9601265
    9611266        rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    9771282}
    9781283
    979 static int vbglR3DnDGHSendDir(uint32_t u32ClientId, DnDURIObject &obj)
    980 {
     1284static int vbglR3DnDGHSendDir(PVBGLR3GUESTDNDCMDCTX pCtx, DnDURIObject &obj)
     1285{
     1286    AssertPtrReturn(pCtx,                                  VERR_INVALID_POINTER);
    9811287    AssertReturn(obj.GetType() == DnDURIObject::Directory, VERR_INVALID_PARAMETER);
    9821288
     
    9841290    RT_ZERO(Msg);
    9851291    Msg.hdr.result      = VERR_WRONG_ORDER;
    986     Msg.hdr.u32ClientID = u32ClientId;
     1292    Msg.hdr.u32ClientID = pCtx->uClientID;
    9871293    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DIR;
    9881294    Msg.hdr.cParms      = 3;
     
    10041310}
    10051311
    1006 static int vbglR3DnDGHSendFile(uint32_t u32ClientId, DnDURIObject &obj)
    1007 {
     1312static int vbglR3DnDGHSendFile(PVBGLR3GUESTDNDCMDCTX pCtx, DnDURIObject &obj)
     1313{
     1314    AssertPtrReturn(pCtx,                             VERR_INVALID_POINTER);
    10081315    AssertReturn(obj.GetType() == DnDURIObject::File, VERR_INVALID_PARAMETER);
    10091316
     
    10131320        return VERR_NO_MEMORY;
    10141321
    1015     DragAndDropSvc::VBOXDNDGHSENDFILEMSG Msg;
    1016     RT_ZERO(Msg);
    1017     Msg.hdr.result      = VERR_WRONG_ORDER;
    1018     Msg.hdr.u32ClientID = u32ClientId;
    1019     Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_FILE;
    1020     Msg.hdr.cParms      = 5;
    1021 
    10221322    RTCString strPath = obj.GetDestPath();
    1023     LogFlowFunc(("strFile=%s (%zu), fMode=0x%x\n",
    1024                  strPath.c_str(), strPath.length(), obj.GetMode()));
    1025 
    1026     Msg.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
    1027     Msg.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
    1028     Msg.fMode.SetUInt32(obj.GetMode());
    1029 
    1030     int rc = VINF_SUCCESS;
    1031     uint32_t cbData = obj.GetSize();
    1032 
    1033     do
    1034     {
    1035         uint32_t cbToRead = RT_MIN(cbData, cbBuf);
    1036         uint32_t cbRead   = 0;
    1037         if (cbToRead)
    1038             rc = obj.Read(pvBuf, cbToRead, &cbRead);
     1323    LogFlowFunc(("strFile=%s (%zu), fMode=0x%x\n", strPath.c_str(), strPath.length(), obj.GetMode()));
     1324
     1325    int rc = obj.Open(DnDURIObject::Source, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
     1326    if (RT_FAILURE(rc))
     1327    {
     1328        LogFunc(("Opening file \"%s\" failed with rc=%Rrc\n", obj.GetSourcePath().c_str(), rc));
     1329        return rc;
     1330    }
     1331
     1332    LogFlowFunc(("cbSize=%RU64, uProtocol=%RU32, uClientID=%RU32\n", obj.GetSize(), pCtx->uProtocol, pCtx->uClientID));
     1333
     1334    if (pCtx->uProtocol >= 2) /* Protocol version 2 and up sends a file header first. */
     1335    {
     1336        DragAndDropSvc::VBOXDNDGHSENDFILEHDRMSG MsgHdr;
     1337        RT_ZERO(MsgHdr);
     1338        MsgHdr.hdr.result      = VERR_WRONG_ORDER;
     1339        MsgHdr.hdr.u32ClientID = pCtx->uClientID;
     1340        MsgHdr.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR;
     1341        MsgHdr.hdr.cParms      = 6;
     1342
     1343        MsgHdr.uContext.SetUInt32(0); /* Context ID; unused at the moment. */
     1344        MsgHdr.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
     1345        MsgHdr.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
     1346        MsgHdr.uFlags.SetUInt32(0);   /* Flags; unused at the moment. */
     1347        MsgHdr.fMode.SetUInt32(obj.GetMode());
     1348        MsgHdr.cbTotal.SetUInt64(obj.GetSize());
     1349
     1350        rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(MsgHdr)), &MsgHdr, sizeof(MsgHdr));
    10391351        if (RT_SUCCESS(rc))
    1040         {
    1041              Msg.cbData.SetUInt32(cbRead);
    1042              Msg.pvData.SetPtr(pvBuf, cbRead);
    1043 
    1044              rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    1045              if (RT_SUCCESS(rc))
    1046                  rc = Msg.hdr.result;
    1047         }
    1048 
    1049         if (RT_FAILURE(rc))
     1352            rc = MsgHdr.hdr.result;
     1353
     1354        LogFlowFunc(("Sending file header resulted in %Rrc\n", rc));
     1355    }
     1356    else
     1357        rc = VINF_SUCCESS;
     1358
     1359    if (RT_SUCCESS(rc))
     1360    {
     1361        /*
     1362         * Send the actual file data, chunk by chunk.
     1363         */
     1364        DragAndDropSvc::VBOXDNDGHSENDFILEDATAMSG Msg;
     1365        RT_ZERO(Msg);
     1366        Msg.hdr.result      = VERR_WRONG_ORDER;
     1367        Msg.hdr.u32ClientID = pCtx->uClientID;
     1368        Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA;
     1369
     1370        if (pCtx->uProtocol <= 1)
     1371        {
     1372            Msg.hdr.cParms  = 5;
     1373
     1374            Msg.u.v1.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
     1375            Msg.u.v1.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
     1376            Msg.u.v1.fMode.SetUInt32(obj.GetMode());
     1377        }
     1378        else
     1379        {
     1380            /* Only send context ID, file chunk + chunk size. */
     1381            Msg.hdr.cParms  = 3;
     1382
     1383            Msg.u.v2.uContext.SetUInt32(0); /** @todo Set context ID. */
     1384        }
     1385
     1386        uint64_t cbToReadTotal  = obj.GetSize();
     1387        uint64_t cbWrittenTotal = 0;
     1388        while (cbToReadTotal)
     1389        {
     1390            uint32_t cbToRead = RT_MIN(cbToReadTotal, cbBuf);
     1391            uint32_t cbRead   = 0;
     1392            if (cbToRead)
     1393                rc = obj.Read(pvBuf, cbToRead, &cbRead);
     1394
     1395            LogFlowFunc(("cbToReadTotal=%RU64, cbToRead=%RU32, cbRead=%RU32, rc=%Rrc\n",
     1396                         cbToReadTotal, cbToRead, cbRead, rc));
     1397
     1398            if (   RT_SUCCESS(rc)
     1399                && cbRead)
     1400            {
     1401                if (pCtx->uProtocol <= 1)
     1402                {
     1403                    Msg.u.v1.pvData.SetPtr(pvBuf, cbRead);
     1404                    Msg.u.v1.cbData.SetUInt32(cbRead);
     1405                }
     1406                else
     1407                {
     1408                    Msg.u.v2.pvData.SetPtr(pvBuf, cbRead);
     1409                    Msg.u.v2.cbData.SetUInt32(cbRead);
     1410                }
     1411
     1412                rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     1413                if (RT_SUCCESS(rc))
     1414                    rc = Msg.hdr.result;
     1415            }
     1416
     1417            if (RT_FAILURE(rc))
     1418            {
     1419                LogFlowFunc(("Reading failed with rc=%Rrc\n", rc));
     1420                break;
     1421            }
     1422
     1423            Assert(cbRead  <= cbToReadTotal);
     1424            cbToReadTotal  -= cbRead;
     1425            cbWrittenTotal += cbRead;
     1426
     1427            LogFlowFunc(("%RU64/%RU64 -- %RU8%%\n", cbWrittenTotal, obj.GetSize(), cbWrittenTotal * 100 / obj.GetSize()));
     1428        };
     1429    }
     1430
     1431    RTMemFree(pvBuf);
     1432
     1433    LogFlowFuncLeaveRC(rc);
     1434    return rc;
     1435}
     1436
     1437static int vbglR3DnDGHSendURIObject(PVBGLR3GUESTDNDCMDCTX pCtx, DnDURIObject &obj)
     1438{
     1439    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     1440
     1441    int rc;
     1442
     1443    switch (obj.GetType())
     1444    {
     1445        case DnDURIObject::Directory:
     1446            rc = vbglR3DnDGHSendDir(pCtx, obj);
    10501447            break;
    10511448
    1052         Assert(cbRead <= cbData);
    1053         cbData -= cbRead;
    1054 
    1055     } while (cbData);
    1056 
    1057     RTMemFree(pvBuf);
    1058 
    1059     LogFlowFuncLeaveRC(rc);
    1060     return rc;
    1061 }
    1062 
    1063 static int vbglR3DnDGHSendURIObject(uint32_t u32ClientId, DnDURIObject &obj)
    1064 {
    1065     int rc;
    1066 
    1067     switch (obj.GetType())
    1068     {
    1069         case DnDURIObject::Directory:
    1070             rc = vbglR3DnDGHSendDir(u32ClientId, obj);
     1449        case DnDURIObject::File:
     1450            rc = vbglR3DnDGHSendFile(pCtx, obj);
    10711451            break;
    10721452
    1073         case DnDURIObject::File:
    1074             rc = vbglR3DnDGHSendFile(u32ClientId, obj);
    1075             break;
    1076 
    10771453        default:
    1078             AssertMsgFailed(("Type %ld not implemented\n",
    1079                              obj.GetType()));
     1454            AssertMsgFailed(("URI type %ld not implemented\n", obj.GetType()));
    10801455            rc = VERR_NOT_IMPLEMENTED;
    10811456            break;
     
    10851460}
    10861461
    1087 static int vbglR3DnDGHProcessURIMessages(uint32_t u32ClientId,
     1462static int vbglR3DnDGHProcessURIMessages(PVBGLR3GUESTDNDCMDCTX pCtx,
    10881463                                         const void *pvData, uint32_t cbData)
    10891464{
     1465    AssertPtrReturn(pCtx,   VERR_INVALID_POINTER);
    10901466    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
    1091     AssertReturn(cbData, VERR_INVALID_PARAMETER);
     1467    AssertReturn(cbData,    VERR_INVALID_PARAMETER);
    10921468
    10931469    RTCList<RTCString> lstPaths =
     
    11061482        uint32_t cbToSend = (uint32_t)strRootDest.length() + 1;
    11071483
    1108         rc = vbglR3DnDGHSendDataInternal(u32ClientId, pvToSend, cbToSend,
     1484        rc = vbglR3DnDGHSendDataInternal(pCtx, pvToSend, cbToSend,
    11091485                                         /* Include total bytes of all file paths,
    11101486                                          * file sizes etc. */
     
    11181494            DnDURIObject &nextObj = lstURI.First();
    11191495
    1120             rc = vbglR3DnDGHSendURIObject(u32ClientId, nextObj);
     1496            rc = vbglR3DnDGHSendURIObject(pCtx, nextObj);
    11211497            if (RT_FAILURE(rc))
    11221498                break;
     
    11291505}
    11301506
    1131 VBGLR3DECL(int) VbglR3DnDGHSendData(uint32_t u32ClientId,
    1132                                     const char *pszFormat,
    1133                                     void *pvData, uint32_t cbData)
    1134 {
     1507VBGLR3DECL(int) VbglR3DnDGHSendData(PVBGLR3GUESTDNDCMDCTX pCtx, const char *pszFormat, void *pvData, uint32_t cbData)
     1508{
     1509    AssertPtrReturn(pCtx,      VERR_INVALID_POINTER);
    11351510    AssertPtrReturn(pszFormat, VERR_INVALID_POINTER);
    1136     AssertPtrReturn(pvData, VERR_INVALID_POINTER);
    1137     AssertReturn(cbData, VERR_INVALID_PARAMETER);
     1511    AssertPtrReturn(pvData,    VERR_INVALID_POINTER);
     1512    AssertReturn(cbData,       VERR_INVALID_PARAMETER);
     1513
     1514    LogFlowFunc(("pszFormat=%s, pvData=%p, cbData=%RU32\n", pszFormat, pvData, cbData));
    11381515
    11391516    int rc;
    11401517    if (DnDMIMEHasFileURLs(pszFormat, strlen(pszFormat)))
    11411518    {
    1142         rc = vbglR3DnDGHProcessURIMessages(u32ClientId, pvData, cbData);
     1519        rc = vbglR3DnDGHProcessURIMessages(pCtx, pvData, cbData);
    11431520    }
    11441521    else
    1145         rc = vbglR3DnDGHSendDataInternal(u32ClientId, pvData, cbData,
    1146                                          0 /* cbAdditionalData */);
     1522    {
     1523        rc = vbglR3DnDGHSendDataInternal(pCtx, pvData, cbData, 0 /* cbAdditionalData */);
     1524    }
     1525
    11471526    if (RT_FAILURE(rc))
    11481527    {
    1149         int rc2 = VbglR3DnDGHSendError(u32ClientId, rc);
    1150         AssertRC(rc2);
    1151     }
    1152 
    1153     return rc;
    1154 }
    1155 
    1156 VBGLR3DECL(int) VbglR3DnDGHSendError(uint32_t u32ClientId, int rcErr)
    1157 {
     1528        int rc2 = VbglR3DnDGHSendError(pCtx, rc);
     1529        if (RT_FAILURE(rc2))
     1530            LogFlowFunc(("Unable to send error (%Rrc) to host, rc=%Rrc\n", rc, rc2));
     1531    }
     1532
     1533    return rc;
     1534}
     1535
     1536VBGLR3DECL(int) VbglR3DnDGHSendError(PVBGLR3GUESTDNDCMDCTX pCtx, int rcErr)
     1537{
     1538    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     1539
    11581540    DragAndDropSvc::VBOXDNDGHEVTERRORMSG Msg;
    11591541    RT_ZERO(Msg);
    11601542    Msg.hdr.result      = VERR_WRONG_ORDER;
    1161     Msg.hdr.u32ClientID = u32ClientId;
     1543    Msg.hdr.u32ClientID = pCtx->uClientID;
    11621544    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_EVT_ERROR;
    11631545    Msg.hdr.cParms      = 1;
    11641546
    1165     Msg.uRC.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
     1547    Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
    11661548
    11671549    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    11731555}
    11741556#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
     1557
  • trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp

    r55401 r55422  
    55
    66/*
    7  * Copyright (C) 2011-2014 Oracle Corporation
     7 * Copyright (C) 2011-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    406406protected:
    407407
    408     uint32_t            m_uClientID;
    409     DragAndDropService *m_pParent;
    410     Display            *m_pDisplay;
    411     int                 m_screenId;
    412     Screen             *m_pScreen;
    413     Window              m_wndRoot;
    414     Window              m_wndProxy;
    415     Window              m_wndCur;
    416     long                m_curVer;
    417     RTCList<Atom>       m_formats;
    418     RTCList<Atom>       m_actions;
     408    /** The instance's own DnD context. */
     409    VBGLR3GUESTDNDCMDCTX        m_dndCtx;
     410    DragAndDropService         *m_pParent;
     411    Display                    *m_pDisplay;
     412    int                         m_screenId;
     413    Screen                     *m_pScreen;
     414    Window                      m_wndRoot;
     415    Window                      m_wndProxy;
     416    Window                      m_wndCur;
     417    long                        m_curVer;
     418    RTCList<Atom>               m_formats;
     419    RTCList<Atom>               m_actions;
    419420    /** Deferred host to guest selection event for sending to the
    420421     *  target window as soon as data from the host arrived. */
    421     XEvent              m_eventHgSelection;
     422    XEvent                      m_eventHgSelection;
    422423    /** Current operation mode. */
    423     Mode                m_mode;
     424    Mode                        m_mode;
    424425    /** Current state of operation mode. */
    425     State               m_state;
     426    State                       m_state;
    426427    /** The instance's own X event queue. */
    427     RTCMTList<XEvent>   m_eventQueue;
     428    RTCMTList<XEvent>           m_eventQueue;
    428429    /** Critical section for providing serialized access to list
    429430     *  event queue's contents. */
    430     RTCRITSECT          m_eventQueueCS;
     431    RTCRITSECT                  m_eventQueueCS;
    431432    /** Event for notifying this instance in case of a new
    432433     *  event. */
    433     RTSEMEVENT          m_hEventSem;
     434    RTSEMEVENT                  m_hEventSem;
    434435    /** List of allowed formats. */
    435     RTCList<RTCString>  m_lstAllowedFormats;
     436    RTCList<RTCString>          m_lstAllowedFormats;
    436437};
    437438
     
    507508
    508509DragInstance::DragInstance(Display *pDisplay, DragAndDropService *pParent)
    509   : m_uClientID(0)
    510   , m_pParent(pParent)
    511   , m_pDisplay(pDisplay)
    512   , m_pScreen(0)
    513   , m_wndRoot(0)
    514   , m_wndProxy(0)
    515   , m_wndCur(0)
    516   , m_curVer(-1)
    517   , m_mode(Unknown)
    518   , m_state(Uninitialized)
     510    : m_pParent(pParent)
     511    , m_pDisplay(pDisplay)
     512    , m_pScreen(0)
     513    , m_wndRoot(0)
     514    , m_wndProxy(0)
     515    , m_wndCur(0)
     516    , m_curVer(-1)
     517    , m_mode(Unknown)
     518    , m_state(Uninitialized)
    519519{
    520520    uninit();
     
    527527        XDestroyWindow(m_pDisplay, m_wndProxy);
    528528
    529     if (m_uClientID)
    530     {
    531         VbglR3DnDDisconnect(m_uClientID);
    532         m_uClientID = 0;
    533     }
     529    VbglR3DnDDisconnect(&m_dndCtx);
    534530
    535531    m_state    = Uninitialized;
     
    571567        uninit();
    572568
    573         rc = VbglR3DnDConnect(&m_uClientID);
     569        rc = VbglR3DnDConnect(&m_dndCtx);
    574570        if (RT_FAILURE(rc))
    575571            break;
     
    692688                    uAction = toHGCMAction(static_cast<Atom>(e.xclient.data.l[4]));
    693689
    694                 rc = VbglR3DnDHGAcknowledgeOperation(m_uClientID, uAction);
     690                rc = VbglR3DnDHGAcknowledgeOperation(&m_dndCtx, uAction);
    695691            }
    696692            else if (e.xclient.message_type == xAtom(XA_XdndFinished))
     
    859855                    RTCString strFormat = xAtomToString(e.xselectionrequest.target);
    860856                    Assert(strFormat.isNotEmpty());
    861                     rc = VbglR3DnDHGRequestData(m_uClientID, strFormat.c_str());
     857                    rc = VbglR3DnDHGRequestData(&m_dndCtx, strFormat.c_str());
    862858                    LogFlowThisFunc(("Requesting data from host as \"%s\", rc=%Rrc\n",
    863859                                     strFormat.c_str(), rc));
     
    12211217    {
    12221218        /* No window to process, so send a ignore ack event to the host. */
    1223         rc = VbglR3DnDHGAcknowledgeOperation(m_uClientID, DND_IGNORE_ACTION);
     1219        rc = VbglR3DnDHGAcknowledgeOperation(&m_dndCtx, DND_IGNORE_ACTION);
    12241220    }
    12251221
     
    14761472            uint32_t uAllActions = toHGCMActions(m_actions);
    14771473
    1478             rc = VbglR3DnDGHAcknowledgePending(m_uClientID, uDefAction, uAllActions, strFormats.c_str());
     1474            rc = VbglR3DnDGHAcknowledgePending(&m_dndCtx, uDefAction, uAllActions, strFormats.c_str());
    14791475            LogFlowThisFunc(("Acknowledging m_uClientID=%RU32, allActions=0x%x, strFormats=%s, rc=%Rrc\n",
    1480                              m_uClientID, uAllActions, strFormats.c_str(), rc));
     1476                             m_dndCtx.uClientID, uAllActions, strFormats.c_str(), rc));
    14811477        }
    14821478    }
     
    15871583                            pvDataTmp[cbData++] = '\0';
    15881584
    1589                             rc = VbglR3DnDGHSendData(m_uClientID, strFormat.c_str(),
    1590                                                      pvDataTmp, cbData);
     1585                            rc = VbglR3DnDGHSendData(&m_dndCtx, strFormat.c_str(), pvDataTmp, cbData);
    15911586                            RTMemFree(pvDataTmp);
    15921587                        }
     
    15971592                    {
    15981593                        /* Send the raw data to the host. */
    1599                         rc = VbglR3DnDGHSendData(m_uClientID, strFormat.c_str(),
    1600                                                  pcData, cbData);
     1594                        rc = VbglR3DnDGHSendData(&m_dndCtx, strFormat.c_str(), pcData, cbData);
    16011595                    }
    16021596
    1603                     LogFlowThisFunc(("Sent strFormat=%s with rc=%Rrc\n",
    1604                                      strFormat.c_str(), rc));
     1597                    LogFlowThisFunc(("Sent strFormat=%s, rc=%Rrc\n", strFormat.c_str(), rc));
    16051598
    16061599                    if (RT_SUCCESS(rc))
     
    16791672    if (RT_FAILURE(rc))
    16801673    {
    1681         int rc2 = VbglR3DnDGHSendError(m_uClientID, rc);
     1674        int rc2 = VbglR3DnDGHSendError(&m_dndCtx, rc);
    16821675        AssertRC(rc2);
    16831676    }
     
    22532246    AssertPtr(pThis);
    22542247
    2255     uint32_t uClientID;
    2256     int rc = VbglR3DnDConnect(&uClientID);
     2248    /* This thread has an own DnD context, e.g. an own client ID. */
     2249    VBGLR3GUESTDNDCMDCTX dndCtx;
     2250
     2251    int rc = VbglR3DnDConnect(&dndCtx);
    22572252    if (RT_FAILURE(rc))
    22582253        LogRel(("DnD: Unable to connect to drag and drop service, rc=%Rrc\n", rc));
     
    22712266
    22722267        /* Wait for new events. */
    2273         rc = VbglR3DnDProcessNextMessage(uClientID, &e.hgcm);
    2274         if (RT_SUCCESS(rc))
     2268        rc = VbglR3DnDProcessNextMessage(&dndCtx, &e.hgcm);
     2269        if (   RT_SUCCESS(rc)
     2270            || rc == VERR_CANCELLED)
    22752271        {
    22762272            cMsgSkippedInvalid = 0; /* Reset skipped messages count. */
     
    22852281        else
    22862282        {
     2283            LogFlowFunc(("Processing next message failed with rc=%Rrc\n", rc));
     2284
    22872285            /* Old(er) hosts either are broken regarding DnD support or otherwise
    22882286             * don't support the stuff we do on the guest side, so make sure we
     
    22992297    } while (!ASMAtomicReadBool(&pThis->m_fSrvStopping));
    23002298
    2301     VbglR3DnDDisconnect(uClientID);
     2299    VbglR3DnDDisconnect(&dndCtx);
    23022300
    23032301    LogFlowFuncLeaveRC(rc);
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.cpp

    r55305 r55422  
    55
    66/*
    7  * Copyright (C) 2006-2014 Oracle Corporation
     7 * Copyright (C) 2006-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    7373# ifdef VBOX_WITH_DRAG_AND_DROP
    7474#  include "CGuest.h"
     75#  include "CDnDTarget.h"
    7576# endif /* VBOX_WITH_DRAG_AND_DROP */
    7677
     
    23942395{
    23952396    error(pParent, MessageType_Error,
    2396           tr("Failed to drop data."),
     2397          tr("Drag and drop operation failed."),
    23972398          formatErrorInfo(guest));
    23982399}
     
    24012402{
    24022403    error(pParent, MessageType_Error,
    2403           tr("Failed to drop data."),
     2404          tr("Failed while dropping data."),
    24042405          formatErrorInfo(progress));
     2406}
     2407
     2408void UIMessageCenter::cannotCancelDrop(const CDnDTarget &dndTarget, QWidget *pParent /* = 0*/) const
     2409{
     2410    error(pParent, MessageType_Error,
     2411          tr("Unable to cancel drag and drop operation."),
     2412          formatErrorInfo(dndTarget));
    24052413}
    24062414#endif /* VBOX_WITH_DRAG_AND_DROP */
  • trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.h

    r55401 r55422  
    351351    void cannotDropData(const CGuest &guest, QWidget *pParent = 0) const;
    352352    void cannotDropData(const CProgress &progress, QWidget *pParent = 0) const;
     353    void cannotCancelDrop(const CDnDTarget &dndTarget, QWidget *pParent = 0) const;
    353354#endif /* VBOX_WITH_DRAG_AND_DROP */
    354355
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.cpp

    r52730 r55422  
    55
    66/*
    7  * Copyright (C) 2011-2014 Oracle Corporation
     7 * Copyright (C) 2011-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    4343#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
    4444
    45 #undef LOG_GROUP
     45#ifdef LOG_GROUP
     46 #undef LOG_GROUP
     47#endif
    4648#define LOG_GROUP LOG_GROUP_GUEST_DND
    4749#include <VBox/log.h>
    48 
    4950
    5051
     
    127128            && !format.isEmpty())
    128129        {
    129             /* Convert the actual MIME data to a vector (needed
    130              * for the COM wrapper). */
     130            /* Convert the actual MIME data to a vector (needed for the COM wrapper). */
    131131            QVector<uint8_t> dv(d.size());
    132132            memcpy(dv.data(), d.constData(), d.size());
    133133
    134134            CProgress progress = dndTarget.SendData(screenId, format, dv);
    135             if (guest.isOk())
     135
     136            if (progress.isOk())
    136137            {
     138                LogFlowFunc(("Transferring data to guest ...\n"));
     139
    137140                msgCenter().showModalProgressDialog(progress,
    138141                                                    tr("Dropping data ..."), ":/progress_dnd_hg_90px.png",
    139142                                                    pParent);
    140                 if (   !progress.GetCanceled()
     143
     144                LogFlowFunc(("Transfer fCompleted=%RTbool, fCanceled=%RTbool, hr=%Rhrc\n",
     145                             progress.GetCompleted(), progress.GetCanceled(), progress.GetResultCode()));
     146
     147                BOOL fCanceled = progress.GetCanceled();
     148
     149                /* Some error occurred? */
     150                if (   !fCanceled
    141151                    && (   !progress.isOk()
    142152                        ||  progress.GetResultCode() != 0))
     
    145155                    result = KDnDAction_Ignore;
    146156                }
     157                #if 0
     158                else if (fCanceled) /* Operation canceled by user? */
     159                {
     160                    Assert(progress.isOk());
     161                    Assert(progress.GetResultCode() == 0);
     162
     163                    /* Tell the guest. */
     164                    BOOL fVeto = dndTarget.Cancel();
     165                    if (fVeto) /* Cancelling vetoed by the target? Tell the user why. */
     166                        msgCenter().cannotCancelDrop(dndTarget, pParent);
     167                }
     168                #endif
    147169            }
    148170            else
  • trunk/src/VBox/GuestHost/DragAndDrop/DnDURIList.cpp

    r50830 r55422  
    55
    66/*
    7  * Copyright (C) 2014 Oracle Corporation
     7 * Copyright (C) 2014-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3333
    3434#include <VBox/GuestHost/DragAndDrop.h>
    35 
    36 DnDURIObject::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 
    50 DnDURIObject::~DnDURIObject(void)
    51 {
    52     closeInternal();
    53 }
    54 
    55 void 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 
    67 bool 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? */
    95 int 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 
    149 int 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 (   m_cbProcessed == m_cbSize
    186                         || RT_FAILURE(rc))
    187                     {
    188                         closeInternal();
    189                     }
    190                 }
    191             }
    192 
    193             break;
    194         }
    195 
    196         case Directory:
    197         {
    198             rc = VINF_SUCCESS;
    199             break;
    200         }
    201 
    202         default:
    203             rc = VERR_NOT_IMPLEMENTED;
    204             break;
    205     }
    206 
    207     LogFlowFunc(("Returning strSourcePath=%s, rc=%Rrc\n",
    208                  m_strSrcPath.c_str(), rc));
    209     return rc;
    210 }
    211 
    212 /*** */
    21335
    21436DnDURIList::DnDURIList(void)
     
    439261                             pszFilePath, pszFileName, pszRoot));
    440262#endif
    441                 rc = appendPathRecursive(pszFilePath, cbBase,
    442                                          fFlags);
     263                rc = appendPathRecursive(pszFilePath, cbBase, fFlags);
    443264            }
    444265            else
     
    496317void DnDURIList::RemoveFirst(void)
    497318{
     319    if (m_lstTree.isEmpty())
     320        return;
     321
    498322    DnDURIObject &curPath = m_lstTree.first();
    499323
  • trunk/src/VBox/GuestHost/DragAndDrop/Makefile.kmk

    r50468 r55422  
    11# $Id$
    22## @file
    3 # Sub-Makefile for the shared DnD code for both host and guest.
     3# Sub-Makefile for the shared DnD code for both, host and guest.
    44#
    55
    66#
    7 # Copyright (C) 2014 Oracle Corporation
     7# Copyright (C) 2014-2015 Oracle Corporation
    88#
    99# This file is part of VirtualBox Open Source Edition (OSE), as
     
    2323        DnDMIME.cpp \
    2424        DnDPath.cpp \
    25         DnDURIList.cpp
     25        DnDURIList.cpp \
     26        DnDURIObject.cpp
    2627
    2728#
  • trunk/src/VBox/HostServices/DragAndDrop/dndmanager.cpp

    r50561 r55422  
    11/* $Id$ */
    22/** @file
    3  * Drag and Drop manager.
     3 * Drag and Drop manager: Handling of DnD messages on the host side.
    44 */
    55
    66/*
    7  * Copyright (C) 2011-2014 Oracle Corporation
     7 * Copyright (C) 2011-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3434
    3535/******************************************************************************
    36  *   Private declarations                                                     *
    37  ******************************************************************************/
    38 
    39 typedef DECLCALLBACK(int) FNDNDPRIVATEPROGRESS(size_t cbDone, void *pvUser);
    40 typedef FNDNDPRIVATEPROGRESS *PFNDNDPRIVATEPROGRESS;
    41 
    42 /**
    43  * Internal DnD message class for informing the
    44  * guest about a new directory.
    45  *
    46  * @see DnDHGSendDataMessage
    47  */
    48 class DnDHGSendDirPrivate: public DnDMessage
    49 {
    50 public:
    51 
    52     DnDHGSendDirPrivate(DnDURIObject URIObject,
    53                         PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser)
    54         : m_URIObject(URIObject)
    55         , m_pfnProgressCallback(pfnProgressCallback)
    56         , m_pvProgressUser(pvProgressUser)
    57     {
    58         RTCString strPath = m_URIObject.GetDestPath();
    59         LogFlowFunc(("strPath=%s (%zu)\n", strPath.c_str(), strPath.length()));
    60 
    61         VBOXHGCMSVCPARM paTmpParms[3];
    62         paTmpParms[0].setString(strPath.c_str());
    63         paTmpParms[1].setUInt32((uint32_t)(strPath.length() + 1));
    64         paTmpParms[2].setUInt32(m_URIObject.GetMode());
    65 
    66         m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_DIR, 3, paTmpParms);
    67     }
    68 
    69 public:
    70 
    71     int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    72     {
    73         int rc = DnDMessage::currentMessage(uMsg, cParms, paParms);
    74         /* Advance progress info */
    75         if (   RT_SUCCESS(rc)
    76             && m_pfnProgressCallback)
    77             rc = m_pfnProgressCallback(m_URIObject.GetSize(), m_pvProgressUser);
    78 
    79         return rc;
    80     }
    81 
    82 protected:
    83 
    84     DnDURIObject           m_URIObject;
    85 
    86     /* Progress stuff. */
    87     PFNDNDPRIVATEPROGRESS  m_pfnProgressCallback;
    88     void                  *m_pvProgressUser;
    89 };
    90 
    91 /**
    92  * Internal DnD message class for informing the guest about a new file.
    93  *
    94  * @see DnDHGSendDataMessage
    95  */
    96 class DnDHGSendFilePrivate: public DnDMessage
    97 {
    98 public:
    99 
    100     DnDHGSendFilePrivate(DnDURIObject URIObject,
    101                          PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser);
    102     virtual ~DnDHGSendFilePrivate(void);
    103 
    104 public:
    105 
    106     int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    107 
    108 protected:
    109 
    110     DnDURIObject           m_URIObject;
    111     /** Skeleton parameters for the next upcoming message in case
    112      *  the file data didn't fit completely into the first one. */
    113     VBOXHGCMSVCPARM        m_aSkelParms[5];
    114 
    115     /* Progress stuff. */
    116     PFNDNDPRIVATEPROGRESS  m_pfnProgressCallback;
    117     void                  *m_pvProgressUser;
    118 };
    119 
    120 /**
    121  * Internal DnD message class for informing the guest about new drag & drop
    122  * data.
    123  *
    124  * @see DnDHGSendDataMessage
    125  */
    126 class DnDHGSendDataMessagePrivate: public DnDMessage
    127 {
    128 public:
    129 
    130     DnDHGSendDataMessagePrivate(uint32_t uMsg, uint32_t cParms,
    131                                 VBOXHGCMSVCPARM paParms[],
    132                                 PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser);
    133     int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    134 
    135 protected:
    136     size_t                 m_cbSize;
    137     size_t                 m_cbDone;
    138 
    139     /* Progress stuff. */
    140     PFNDNDPRIVATEPROGRESS  m_pfnProgressCallback;
    141     void                  *m_pvProgressUser;
    142 };
    143 
    144 /******************************************************************************
    145  *   Implementation                                                           *
    146  ******************************************************************************/
    147 
    148 /******************************************************************************
    149  *   DnDHGSendFilePrivate                                                     *
    150  ******************************************************************************/
    151 
    152 DnDHGSendFilePrivate::DnDHGSendFilePrivate(DnDURIObject URIObject,
    153                                            PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser)
    154     : m_URIObject(URIObject)
    155     , m_pfnProgressCallback(pfnProgressCallback)
    156     , m_pvProgressUser(pvProgressUser)
    157 {
    158     LogFlowFunc(("strPath=%s (%zu)\n",
    159                  m_URIObject.GetDestPath().c_str(), m_URIObject.GetDestPath().length()));
    160 
    161     m_aSkelParms[0].setString(m_URIObject.GetDestPath().c_str()); /* pvName */
    162     m_aSkelParms[1].setUInt32((uint32_t)(m_URIObject.GetDestPath().length() + 1)); /* cbName */
    163     m_aSkelParms[2].setPointer(NULL, 0); /* pvData */
    164     m_aSkelParms[3].setUInt32(0); /* cbData */
    165     m_aSkelParms[4].setUInt32(m_URIObject.GetMode()); /* fMode */
    166 
    167     m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_FILE, 5, m_aSkelParms);
    168 }
    169 
    170 DnDHGSendFilePrivate::~DnDHGSendFilePrivate(void)
    171 {
    172 }
    173 
    174 int DnDHGSendFilePrivate::currentMessage(uint32_t uMsg, uint32_t cParms,
    175                                          VBOXHGCMSVCPARM paParms[])
    176 {
    177     if (!m_pNextMsg)
    178         return VERR_NO_DATA;
    179 
    180     int rc = m_pNextMsg->getData(uMsg, cParms, paParms);
    181     clearNextMsg();
    182     if (RT_FAILURE(rc))
    183         return rc;
    184 
    185     uint32_t cbRead;
    186     if (RT_SUCCESS(rc))
    187     {
    188         /* Get buffer size + pointer to buffer from guest side. */
    189         uint32_t cbToRead = paParms[2].u.pointer.size; /* cbData */
    190         Assert(cbToRead);
    191         void *pvBuf = paParms[2].u.pointer.addr; /* pvData */
    192         AssertPtr(pvBuf);
    193 
    194         rc = m_URIObject.Read(pvBuf, cbToRead, &cbRead);
    195         LogFlowFunc(("Read %RU32 bytes (%RU32 bytes buffer) for \"%s\", rc=%Rrc\n",
    196                      cbRead, cbToRead, m_URIObject.GetDestPath().c_str(), rc));
    197 
    198         if (RT_LIKELY(RT_SUCCESS(rc)))
    199         {
    200             /* Tell the guest the actual size read. */
    201             paParms[3].setUInt32((uint32_t)cbRead); /* cbData */
    202         }
    203     }
    204 
    205     if (RT_SUCCESS(rc))
    206     {
    207         if (!m_URIObject.IsComplete())
    208         {
    209             try
    210             {
    211                 /* More data needed to send over. Prepare the next message. */
    212                 m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_FILE, 5 /* cParms */,
    213                                                m_aSkelParms);
    214             }
    215             catch(std::bad_alloc &)
    216             {
    217                 rc = VERR_NO_MEMORY;
    218             }
    219         }
    220 
    221         /* Advance progress info. */
    222         if (   RT_SUCCESS(rc)
    223             && m_pfnProgressCallback)
    224         {
    225             rc = m_pfnProgressCallback(cbRead, m_pvProgressUser);
    226         }
    227     }
    228 
    229     return rc;
    230 }
    231 
    232 /******************************************************************************
    233  *   DnDHGSendDataMessagePrivate                                                *
    234  ******************************************************************************/
    235 
    236 DnDHGSendDataMessagePrivate::DnDHGSendDataMessagePrivate(uint32_t uMsg, uint32_t cParms,
    237                                                          VBOXHGCMSVCPARM paParms[],
    238                                                          PFNDNDPRIVATEPROGRESS pfnProgressCallback,
    239                                                          void *pvProgressUser)
    240     : m_cbSize(paParms[4].u.uint32)
    241     , m_cbDone(0)
    242     , m_pfnProgressCallback(pfnProgressCallback)
    243     , m_pvProgressUser(pvProgressUser)
    244 {
    245     /* Create the initial data message. This might throw
    246      * a bad_alloc exception. */
    247     m_pNextMsg = new HGCM::Message(uMsg, cParms, paParms);
    248 }
    249 
    250 int DnDHGSendDataMessagePrivate::currentMessage(uint32_t uMsg, uint32_t cParms,
    251                                                 VBOXHGCMSVCPARM paParms[])
    252 {
    253     /** @todo Don't copy the data parts ... just move the data pointer in
    254      *        the original data ptr. */
    255     if (!m_pNextMsg)
    256         return VERR_NO_DATA;
    257 
    258     int rc = VINF_SUCCESS;
    259 
    260     HGCM::Message *pCurMsg = m_pNextMsg;
    261     AssertPtr(pCurMsg);
    262 
    263     m_pNextMsg = 0;
    264     rc = pCurMsg->getData(uMsg, cParms, paParms);
    265 
    266     /* Depending on the current message, the data pointer is on a
    267      * different position (HOST_DND_HG_SND_DATA=3;
    268      * HOST_DND_HG_SND_MORE_DATA=0). */
    269     int iPos = uMsg == DragAndDropSvc::HOST_DND_HG_SND_DATA ? 3 : 0;
    270     m_cbDone += paParms[iPos + 1].u.uint32;
    271 
    272     /* Info + data send already? */
    273     if (rc == VERR_BUFFER_OVERFLOW)
    274     {
    275         paParms[iPos + 1].u.uint32 = paParms[iPos].u.pointer.size;
    276         VBOXHGCMSVCPARM paTmpParms[2];
    277         void     *pvOldData;
    278         uint32_t  cOldData;
    279         pCurMsg->getParmPtrInfo(iPos, &pvOldData, &cOldData);
    280         paTmpParms[0].setPointer(static_cast<uint8_t*>(pvOldData) + paParms[iPos].u.pointer.size, cOldData - paParms[iPos].u.pointer.size);
    281         paTmpParms[1].setUInt32(cOldData - paParms[iPos].u.pointer.size);
    282 
    283         try
    284         {
    285             m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA, 2, paTmpParms);
    286         }
    287         catch(std::bad_alloc &)
    288         {
    289             rc = VERR_NO_MEMORY;
    290         }
    291     }
    292 
    293     if (pCurMsg)
    294         delete pCurMsg;
    295 
    296     /* Advance progress info. */
    297     if (   RT_SUCCESS(rc)
    298         && m_pfnProgressCallback)
    299     {
    300         rc = m_pfnProgressCallback(m_cbDone, m_pvProgressUser);
    301     }
    302 
    303     return rc;
    304 }
    305 
    306 /******************************************************************************
    307  *   DnDHGSendDataMessage                                                       *
    308  ******************************************************************************/
    309 
    310 /*
    311  * This class is a meta message class. It doesn't consist of any own message
    312  * data, but handle the meta info, the data itself as well as any files or
    313  * directories which have to be transfered to the guest.
    314  */
    315 DnDHGSendDataMessage::DnDHGSendDataMessage(uint32_t uMsg, uint32_t cParms,
    316                                            VBOXHGCMSVCPARM paParms[],
    317                                            PFNDNDPROGRESS pfnProgressCallback,
    318                                            void *pvProgressUser)
    319     : m_cbTotal(0)
    320     , m_cbTransfered(0)
    321     , m_pfnProgressCallback(pfnProgressCallback)
    322     , m_pvProgressUser(pvProgressUser)
    323 {
    324     if (cParms < 5) /* Paranoia. */
    325         return;
    326 
    327     const char *pszFormat = static_cast<const char*>(paParms[1].u.pointer.addr);
    328     uint32_t cbFormat = paParms[1].u.pointer.size;
    329 
    330     int rc = VINF_SUCCESS;
    331     RTCString strNewURIs;
    332 
    333     /* Do we need to build up a file tree? */
    334     if (DnDMIMEHasFileURLs(pszFormat, cbFormat))
    335     {
    336         const char *pszList = static_cast<const char*>(paParms[3].u.pointer.addr);
    337         AssertPtr(pszList);
    338         uint32_t cbList = paParms[3].u.pointer.size;
    339         Assert(cbList);
    340 
    341         LogFlowFunc(("Old data (%RU32 bytes): '%s'\n", cbList, pszList));
    342 
    343         /* The list is separated by newline (even if only one file is listed). */
    344         RTCList<RTCString> lstURIOrg
    345             = RTCString(pszList, cbList).split("\r\n");
    346         if (!lstURIOrg.isEmpty())
    347         {
    348             rc = m_lstURI.AppendURIPathsFromList(lstURIOrg, 0 /* fFlags */);
    349             if (RT_SUCCESS(rc))
    350             {
    351                 /* Add the total size of all meta data + files transferred to
    352                  * the message's total byte count. */
    353                 m_cbTotal += m_lstURI.TotalBytes();
    354 
    355                 /* We have to change the actual DnD data. Remove any host paths and
    356                  * just decode the filename into the new data. The Guest Additions will
    357                  * add the correct path again before sending the DnD drop event to
    358                  * some window. */
    359                 strNewURIs = m_lstURI.RootToString();
    360 
    361                 /* Note: We don't delete the old pointer here, cause this is done
    362                  *       by the caller. We just use the RTString data, which has the
    363                  *       scope of this ctor. This is enough cause the data is copied in
    364                  *       the DnDHGSendDataMessagePrivate anyway. */
    365                 paParms[3].u.pointer.addr = (void *)strNewURIs.c_str();
    366                 paParms[3].u.pointer.size = (uint32_t)(strNewURIs.length() + 1);
    367                 paParms[4].u.uint32       = (uint32_t)(strNewURIs.length() + 1);
    368 
    369                 LogFlowFunc(("Set new data (%RU32 bytes): '%s'\n",
    370                             paParms[3].u.pointer.size,
    371                             (const char*)paParms[3].u.pointer.addr));
    372             }
    373         }
    374     }
    375 
    376     /* Add the size of the data to the todo list. */
    377     m_cbTotal += paParms[4].u.uint32;
    378     LogFlowFunc(("cbTotal=%zu\n", m_cbTotal));
    379 
    380     /* The first message is the meta info for the data and the data itself. */
    381     m_pNextPathMsg = new DnDHGSendDataMessagePrivate(uMsg, cParms, paParms,
    382                                                      &DnDHGSendDataMessage::progressCallback, this);
    383 }
    384 
    385 DnDHGSendDataMessage::~DnDHGSendDataMessage(void)
    386 {
    387     if (m_pNextPathMsg)
    388         delete m_pNextPathMsg;
    389 }
    390 
    391 HGCM::Message* DnDHGSendDataMessage::nextHGCMMessage(void)
    392 {
    393     if (!m_pNextPathMsg)
    394         return NULL;
    395 
    396     return m_pNextPathMsg->nextHGCMMessage();
    397 }
    398 
    399 int DnDHGSendDataMessage::currentMessageInfo(uint32_t *puMsg, uint32_t *pcParms)
    400 {
    401     if (!m_pNextPathMsg)
    402         return VERR_NO_DATA;
    403 
    404     return m_pNextPathMsg->currentMessageInfo(puMsg, pcParms);
    405 }
    406 
    407 int DnDHGSendDataMessage::currentMessage(uint32_t uMsg,
    408                                          uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    409 {
    410     if (!m_pNextPathMsg)
    411         return VERR_NO_DATA;
    412 
    413     /* Fill the data out of our current queued message. */
    414     int rc = m_pNextPathMsg->currentMessage(uMsg, cParms, paParms);
    415     /* Has this message more data to deliver? */
    416     if (!m_pNextPathMsg->isMessageWaiting())
    417     {
    418         delete m_pNextPathMsg;
    419         m_pNextPathMsg = NULL;
    420     }
    421 
    422     /* File/directory data to send? */
    423     if (!m_pNextPathMsg)
    424     {
    425         if (m_lstURI.IsEmpty())
    426             return rc;
    427 
    428         /* Create new messages based on our internal path list. Currently
    429          * this could be directories or regular files. */
    430         const DnDURIObject &nextObj = m_lstURI.First();
    431         try
    432         {
    433             uint32_t fMode = nextObj.GetMode();
    434             LogFlowFunc(("Processing srcPath=%s, dstPath=%s, fMode=0x%x, cbSize=%RU32, fIsDir=%RTbool, fIsFile=%RTbool\n",
    435                          nextObj.GetSourcePath().c_str(), nextObj.GetDestPath().c_str(),
    436                          fMode, nextObj.GetSize(),
    437                          RTFS_IS_DIRECTORY(fMode), RTFS_IS_FILE(fMode)));
    438 
    439             if (RTFS_IS_DIRECTORY(fMode))
    440                 m_pNextPathMsg = new DnDHGSendDirPrivate(nextObj,
    441                                                          &DnDHGSendDataMessage::progressCallback /* pfnProgressCallback */,
    442                                                          this /* pvProgressUser */);
    443             else if (RTFS_IS_FILE(fMode))
    444                 m_pNextPathMsg = new DnDHGSendFilePrivate(nextObj,
    445                                                           &DnDHGSendDataMessage::progressCallback /* pfnProgressCallback */,
    446                                                           this /* pvProgressUser */);
    447             else
    448                 AssertMsgFailedReturn(("fMode=0x%x is not supported for srcPath=%s, dstPath=%s\n",
    449                                        fMode, nextObj.GetSourcePath().c_str(), nextObj.GetDestPath().c_str()),
    450                                        VERR_NO_DATA);
    451 
    452             m_lstURI.RemoveFirst();
    453         }
    454         catch(std::bad_alloc &)
    455         {
    456             rc = VERR_NO_MEMORY;
    457         }
    458     }
    459 
    460     return rc;
    461 }
    462 
    463 int DnDHGSendDataMessage::progressCallback(size_t cbDone, void *pvUser)
    464 {
    465     AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
    466 
    467     DnDHGSendDataMessage *pSelf = static_cast<DnDHGSendDataMessage *>(pvUser);
    468     AssertPtr(pSelf);
    469 
    470     /* How many bytes are transfered already. */
    471     pSelf->m_cbTransfered += cbDone;
    472 
    473     /* Advance progress info. */
    474     int rc = VINF_SUCCESS;
    475     if (   pSelf->m_pfnProgressCallback
    476         && pSelf->m_cbTotal)
    477     {
    478         AssertMsg(pSelf->m_cbTransfered <= pSelf->m_cbTotal,
    479                   ("More bytes transferred (%zu) than expected (%zu), cbDone=%zu\n",
    480                    pSelf->m_cbTransfered, pSelf->m_cbTotal, cbDone));
    481 
    482         unsigned uPercentage = (unsigned)((uint64_t)pSelf->m_cbTransfered * 100 / pSelf->m_cbTotal);
    483         rc = pSelf->m_pfnProgressCallback(RT_MIN(uPercentage, 100),
    484                                           DragAndDropSvc::DND_PROGRESS_RUNNING,
    485                                           VINF_SUCCESS /* rc */, pSelf->m_pvProgressUser);
    486     }
    487 
    488     return rc;
    489 }
    490 
    491 /******************************************************************************
    49236 *   DnDManager                                                               *
    49337 ******************************************************************************/
    49438
    495 int DnDManager::addMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     39int DnDManager::addMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool fAppend /* = true */)
    49640{
    49741    int rc = VINF_SUCCESS;
    49842
     43    LogFlowFunc(("uMsg=%RU32, cParms=%RU32, fAppend=%RTbool\n", uMsg, cParms, fAppend));
     44
    49945    try
    50046    {
     47        DnDMessage *pMessage = NULL;
     48
    50149        switch (uMsg)
    50250        {
     
    50553                clear();
    50654                LogFlowFunc(("HOST_DND_HG_EVT_ENTER\n"));
    507 
    508                 /* Verify parameter count and types. */
    509                 if (   cParms != 7
    510                     || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */
    511                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* x-pos */
    512                     || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* y-pos */
    513                     || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* default action */
    514                     || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* allowed actions */
    515                     || paParms[5].type != VBOX_HGCM_SVC_PARM_PTR   /* data */
    516                     || paParms[6].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
    517                     rc = VERR_INVALID_PARAMETER;
    518                 else
    519                 {
    520                     m_fOpInProcess = true;
    521                     DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
    522                     m_dndMessageQueue.append(pMessage);
    523                 }
    52455                break;
    52556            }
     
    52859            {
    52960                LogFlowFunc(("HOST_DND_HG_EVT_MOVE\n"));
    530 
    531                 /* Verify parameter count and types. */
    532                 if (   cParms != 7
    533                     || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */
    534                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* x-pos */
    535                     || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* y-pos */
    536                     || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* default action */
    537                     || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* allowed actions */
    538                     || paParms[5].type != VBOX_HGCM_SVC_PARM_PTR   /* data */
    539                     || paParms[6].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
    540                 {
    541                     rc = VERR_INVALID_PARAMETER;
    542                 }
    543                 else
    544                 {
    545                     m_fOpInProcess = true;
    546                     DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
    547                     m_dndMessageQueue.append(pMessage);
    548                 }
    54961                break;
    55062            }
     
    55365            {
    55466                LogFlowFunc(("HOST_DND_HG_EVT_LEAVE\n"));
    555 
    556                 /* Verify parameter count and types. */
    557                 if (cParms != 0)
    558                     rc = VERR_INVALID_PARAMETER;
    559                 else
    560                 {
    561                     DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
    562                     m_dndMessageQueue.append(pMessage);
    563                 }
    564 
    565                 m_fOpInProcess = false;
    56667                break;
    56768            }
     
    57071            {
    57172                LogFlowFunc(("HOST_DND_HG_EVT_DROPPED\n"));
    572 
    573                 /* Verify parameter count and types. */
    574                 if (   cParms != 7
    575                     || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */
    576                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* x-pos */
    577                     || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* y-pos */
    578                     || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* default action */
    579                     || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* allowed actions */
    580                     || paParms[5].type != VBOX_HGCM_SVC_PARM_PTR   /* data */
    581                     || paParms[6].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
    582                 {
    583                     rc = VERR_INVALID_PARAMETER;
    584                 }
    585                 else
    586                 {
    587                     DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
    588                     m_dndMessageQueue.append(pMessage);
    589                 }
     73                break;
     74            }
     75
     76            case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
     77            {
     78                LogFlowFunc(("HOST_DND_HG_EVT_CANCEL\n"));
     79
     80                pMessage = new DnDHGCancelMessage();
    59081                break;
    59182            }
     
    59485            {
    59586                LogFlowFunc(("HOST_DND_HG_SND_DATA\n"));
    596 
    597                 /* Verify parameter count and types. */
    598                 if (   cParms != 5
    599                     || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */
    600                     || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR   /* format */
    601                     || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* format size */
    602                     || paParms[3].type != VBOX_HGCM_SVC_PARM_PTR   /* data */
    603                     || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* data size */)
    604                 {
    605                     rc = VERR_INVALID_PARAMETER;
    606                 }
    607                 else
    608                 {
    609                     DnDHGSendDataMessage *pMessage =
    610                         new DnDHGSendDataMessage(uMsg, cParms, paParms,
    611                                                  m_pfnProgressCallback, m_pvProgressUser);
    612                     m_dndMessageQueue.append(pMessage);
    613                 }
     87                break;
     88            }
     89
     90            case DragAndDropSvc::HOST_DND_HG_SND_DIR:
     91            {
     92                LogFlowFunc(("HOST_DND_HG_SND_DIR\n"));
     93                break;
     94            }
     95
     96            /* New since protocol version 2 (VBox 5.0). */
     97            case DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR:
     98            {
     99                LogFlowFunc(("HOST_DND_HG_SND_FILE_HDR\n"));
     100                break;
     101            }
     102
     103            case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA:
     104            {
     105                LogFlowFunc(("HOST_DND_HG_SND_FILE\n"));
     106
     107                /* No parameter verification here as, depending on the protocol version
     108                 * being used, the parameter count + types might change. */
    614109                break;
    615110            }
     
    625120                {
    626121                    rc = VERR_INVALID_PARAMETER;
    627                 }
    628                 else
    629                 {
    630                     DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
    631                     m_dndMessageQueue.append(pMessage);
    632122                }
    633123                break;
     
    646136                    rc = VERR_INVALID_PARAMETER;
    647137                }
    648                 else
    649                 {
    650                     try
    651                     {
    652                         DnDGenericMessage *pMessage
    653                             = new DnDGenericMessage(uMsg, cParms, paParms);
    654                         m_dndMessageQueue.append(pMessage);
    655                     }
    656                     catch(std::bad_alloc &)
    657                     {
    658                         rc = VERR_NO_MEMORY;
    659                     }
    660                 }
    661138                break;
    662139            }
     
    667144                break;
    668145        }
     146
     147        if (!pMessage) /* Generic message needed? */
     148            pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
     149
     150        if (fAppend)
     151            m_dndMessageQueue.append(pMessage);
     152        else
     153            m_dndMessageQueue.prepend(pMessage);
    669154    }
    670155    catch(std::bad_alloc &)
     
    692177    AssertPtrReturn(pcParms, VERR_INVALID_POINTER);
    693178
    694     int rc = VINF_SUCCESS;
    695 
     179    int rc;
    696180    if (m_pCurMsg)
    697181        rc = m_pCurMsg->currentMessageInfo(puMsg, pcParms);
     
    699183    {
    700184        if (m_dndMessageQueue.isEmpty())
    701         {
    702185            rc = VERR_NO_DATA;
    703 //            if (m_pfnProgressCallback)
    704 //                m_pfnProgressCallback(100.0, DragAndDropSvc::DND_OP_CANCELLED, m_pvProgressUser);
    705         }
    706186        else
    707187            rc = m_dndMessageQueue.first()->currentMessageInfo(puMsg, pcParms);
     
    743223     * callback about our exit.
    744224     */
    745     if (   RT_FAILURE(rc)
    746         && m_pfnProgressCallback)
     225    if (RT_FAILURE(rc))
    747226    {
    748227        /* Clear any pending messages. */
     
    754233        try
    755234        {
     235            if (rc == VERR_CANCELLED)
     236                LogFlowFunc(("Operation was cancelled\n"));
     237
    756238            Assert(!m_pCurMsg);
    757239            m_pCurMsg = new DnDHGCancelMessage();
    758             m_pfnProgressCallback(100 /* Percent */,
    759                                     rc == VERR_CANCELLED
    760                                   ? DragAndDropSvc::DND_PROGRESS_CANCELLED
    761                                   : DragAndDropSvc::DND_PROGRESS_ERROR, rc, m_pvProgressUser);
     240
     241            if (m_pfnProgressCallback)
     242            {
     243                LogFlowFunc(("Notifying host about aborting operation (%Rrc) ...\n", rc));
     244                m_pfnProgressCallback(  rc == VERR_CANCELLED
     245                                      ? DragAndDropSvc::DND_PROGRESS_CANCELLED
     246                                      : DragAndDropSvc::DND_PROGRESS_ERROR,
     247                                      100 /* Percent */, rc,
     248                                      m_pvProgressUser);
     249            }
    762250        }
    763251        catch(std::bad_alloc &)
     
    776264    {
    777265        delete m_pCurMsg;
    778         m_pCurMsg = 0;
     266        m_pCurMsg = NULL;
    779267    }
    780268
     
    786274}
    787275
     276/**
     277 * Triggers a rescheduling of the manager's message queue by setting the first
     278 * message available in the queue as the current one to process.
     279 *
     280 * @return  IPRT status code. VERR_NO_DATA if not message to process is available at
     281 *          the time of calling.
     282 */
     283int DnDManager::doReschedule(void)
     284{
     285    LogFlowFunc(("Rescheduling ...\n"));
     286
     287    if (!m_dndMessageQueue.isEmpty())
     288    {
     289        m_pCurMsg = m_dndMessageQueue.first();
     290        m_dndMessageQueue.removeFirst();
     291
     292        return VINF_SUCCESS;
     293    }
     294
     295    return VERR_NO_DATA;
     296}
     297
  • trunk/src/VBox/HostServices/DragAndDrop/dndmanager.h

    r50460 r55422  
    44
    55/*
    6  * Copyright (C) 2011-2014 Oracle Corporation
     6 * Copyright (C) 2011-2015 Oracle Corporation
    77 *
    88 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2525#include <iprt/cpp/list.h>
    2626
    27 typedef DECLCALLBACK(int) FNDNDPROGRESS(unsigned uPercentage, uint32_t uState, int rc, void *pvUser);
     27typedef DECLCALLBACK(int) FNDNDPROGRESS(uint32_t uState, uint32_t uPercentage, int rc, void *pvUser);
    2828typedef FNDNDPROGRESS *PFNDNDPROGRESS;
    2929
     
    108108
    109109/**
    110  * DnD message class for informing the guest about a new drop data event.
    111  */
    112 class DnDHGSendDataMessage: public DnDMessage
    113 {
    114 public:
    115 
    116     DnDHGSendDataMessage(uint32_t uMsg, uint32_t cParms,
    117                          VBOXHGCMSVCPARM paParms[],
    118                          PFNDNDPROGRESS pfnProgressCallback, void *pvProgressUser);
    119 
    120     virtual ~DnDHGSendDataMessage(void);
    121 
    122     HGCM::Message* nextHGCMMessage(void);
    123     int currentMessageInfo(uint32_t *puMsg, uint32_t *pcParms);
    124     int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    125 
    126     bool isMessageWaiting(void) const { return !!m_pNextPathMsg; }
    127 
    128 protected:
    129 
    130     static DECLCALLBACK(int) progressCallback(size_t cbDone, void *pvUser);
    131 
    132     DnDMessage         *m_pNextPathMsg;
    133 
    134     DnDURIList          m_lstURI;
    135     /* Total message size (in bytes). */
    136     size_t              m_cbTotal;
    137     /* Transferred message size (in bytes). */
    138     size_t              m_cbTransfered;
    139 
    140     PFNDNDPROGRESS      m_pfnProgressCallback;
    141     void               *m_pvProgressUser;
    142 };
    143 
    144 /**
    145  * DnD message class for informing the guest to cancel any currently and
    146  * pending activities.
     110 * DnD message class for informing the guest to cancel any current (and pending) activities.
    147111 */
    148112class DnDHGCancelMessage: public DnDMessage
     
    167131
    168132    DnDManager(PFNDNDPROGRESS pfnProgressCallback, void *pvProgressUser)
    169         : m_pCurMsg(0)
    170         , m_fOpInProcess(false)
     133        : m_pCurMsg(NULL)
    171134        , m_pfnProgressCallback(pfnProgressCallback)
    172135        , m_pvProgressUser(pvProgressUser)
     
    178141    }
    179142
    180     int addMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     143    int addMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool fAppend = true);
    181144
    182145    HGCM::Message *nextHGCMMessage(void);
     
    185148
    186149    void clear(void);
    187 
    188     bool hasActiveOperation(void) const { return m_fOpInProcess; }
     150    int doReschedule(void);
    189151
    190152private:
    191153    DnDMessage           *m_pCurMsg;
    192154    RTCList<DnDMessage*>  m_dndMessageQueue;
    193 
    194     bool                  m_fOpInProcess;
    195155
    196156    /* Progress stuff */
  • trunk/src/VBox/HostServices/DragAndDrop/service.cpp

    r50724 r55422  
    55
    66/*
    7  * Copyright (C) 2011-2014 Oracle Corporation
     7 * Copyright (C) 2011-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    6060#define LOG_GROUP LOG_GROUP_GUEST_DND
    6161
     62#include <map>
     63
    6264#include "dndmanager.h"
    6365
     
    6668 ******************************************************************************/
    6769
     70/** Map holding pointers to HGCM clients. Key is the (unique) HGCM client ID. */
     71typedef std::map<uint32_t, HGCM::Client*> DnDClientMap;
     72
    6873/**
    6974 * Specialized drag & drop service class.
    7075 */
    71 class DragAndDropService: public HGCM::AbstractService<DragAndDropService>
     76class DragAndDropService : public HGCM::AbstractService<DragAndDropService>
    7277{
    7378public:
     
    7580    explicit DragAndDropService(PVBOXHGCMSVCHELPERS pHelpers)
    7681        : HGCM::AbstractService<DragAndDropService>(pHelpers)
    77         , m_pManager(0)
    78         , m_cClients(0)
    79     {}
     82        , m_pManager(NULL) {}
    8083
    8184protected:
    82     /* HGCM service implementation */
     85
    8386    int  init(VBOXHGCMSVCFNTABLE *pTable);
    84     int  uninit();
     87    int  uninit(void);
    8588    int  clientConnect(uint32_t u32ClientID, void *pvClient);
    8689    int  clientDisconnect(uint32_t u32ClientID, void *pvClient);
     
    8891    int  hostCall(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    8992
    90     static DECLCALLBACK(int) progressCallback(uint32_t uPercentage, uint32_t uState, int rc, void *pvUser);
    9193    int modeSet(uint32_t u32Mode);
    9294    inline uint32_t modeGet() { return m_u32Mode; };
    9395
     96protected:
     97
     98    static DECLCALLBACK(int) progressCallback(uint32_t uStatus, uint32_t uPercentage, int rc, void *pvUser);
     99
     100protected:
     101
    94102    DnDManager             *m_pManager;
    95 
    96     uint32_t                m_cClients;
     103    /** Map of all connected clients. */
     104    DnDClientMap            m_clientMap;
     105    /** List of all clients which are queued up (deferred return) and ready
     106     *  to process new commands. */
    97107    RTCList<HGCM::Client*>  m_clientQueue;
    98108    uint32_t                m_u32Mode;
     
    114124    modeSet(VBOX_DRAG_AND_DROP_MODE_OFF);
    115125
    116     m_pManager = new DnDManager(&DragAndDropService::progressCallback, this);
     126    int rc = VINF_SUCCESS;
     127
     128    try
     129    {
     130        m_pManager = new DnDManager(&DragAndDropService::progressCallback, this);
     131    }
     132    catch(std::bad_alloc &)
     133    {
     134        rc = VERR_NO_MEMORY;
     135    }
     136
     137    LogFlowFuncLeaveRC(rc);
     138    return rc;
     139}
     140
     141int DragAndDropService::uninit(void)
     142{
     143    if (m_pManager)
     144    {
     145        delete m_pManager;
     146        m_pManager = NULL;
     147    }
    117148
    118149    return VINF_SUCCESS;
    119150}
    120151
    121 int DragAndDropService::uninit(void)
    122 {
    123     delete m_pManager;
    124 
    125     return VINF_SUCCESS;
     152int DragAndDropService::clientConnect(uint32_t u32ClientID, void *pvClient)
     153{
     154    if (m_clientMap.size() >= UINT8_MAX) /* Don't allow too much clients at the same time. */
     155    {
     156        AssertMsgFailed(("Maximum number of clients reached\n"));
     157        return VERR_BUFFER_OVERFLOW;
     158    }
     159
     160    int rc = VINF_SUCCESS;
     161
     162    /*
     163     * Add client to our client map.
     164     */
     165    if (m_clientMap.find(u32ClientID) != m_clientMap.end())
     166        rc = VERR_ALREADY_EXISTS;
     167
     168    if (RT_SUCCESS(rc))
     169    {
     170        try
     171        {
     172            m_clientMap[u32ClientID] = new HGCM::Client(u32ClientID);
     173        }
     174        catch(std::bad_alloc &)
     175        {
     176            rc = VERR_NO_MEMORY;
     177        }
     178
     179        if (RT_SUCCESS(rc))
     180        {
     181            /*
     182             * Clear the message queue as soon as a new clients connect
     183             * to ensure that every client has the same state.
     184             */
     185            if (m_pManager)
     186                m_pManager->clear();
     187        }
     188    }
     189
     190    LogFlowFunc(("Client %RU32 connected, rc=%Rrc\n", u32ClientID, rc));
     191    return rc;
    126192}
    127193
    128 int DragAndDropService::clientConnect(uint32_t u32ClientID, void *pvClient)
    129 {
    130     LogFlowFunc(("New client (%RU32) connected\n", u32ClientID));
    131     if (m_cClients < UINT32_MAX)
    132         m_cClients++;
    133     else
    134         AssertMsgFailed(("Maximum number of clients reached\n"));
     194int DragAndDropService::clientDisconnect(uint32_t u32ClientID, void *pvClient)
     195{
     196    /* Client not found? Bail out early. */
     197    DnDClientMap::iterator itClient =  m_clientMap.find(u32ClientID);
     198    if (itClient == m_clientMap.end())
     199        return VERR_NOT_FOUND;
    135200
    136201    /*
    137      * Clear the message queue as soon as a new clients connect
    138      * to ensure that every client has the same state.
     202     * Remove from waiters queue.
    139203     */
    140     if (m_pManager)
    141         m_pManager->clear();
    142 
    143     return VINF_SUCCESS;
    144 }
    145 
    146 int DragAndDropService::clientDisconnect(uint32_t u32ClientID, void *pvClient)
    147 {
    148     /* Remove all waiters with this u32ClientID. */
    149     for (size_t i = 0; i < m_clientQueue.size(); )
     204    for (size_t i = 0; i < m_clientQueue.size(); i++)
    150205    {
    151206        HGCM::Client *pClient = m_clientQueue.at(i);
     
    157212            m_clientQueue.removeAt(i);
    158213            delete pClient;
    159         }
    160         else
    161             i++;
    162     }
    163 
     214
     215            break;
     216        }
     217    }
     218
     219    /*
     220     * Remove from client map and deallocate.
     221     */
     222    AssertPtr(itClient->second);
     223    delete itClient->second;
     224
     225    m_clientMap.erase(itClient);
     226
     227    LogFlowFunc(("Client %RU32 disconnected\n", u32ClientID));
    164228    return VINF_SUCCESS;
    165229}
     
    197261    {
    198262        case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
     263        {
    199264            if (modeGet() != VBOX_DRAG_AND_DROP_MODE_OFF)
    200265            {
     
    207272            }
    208273            break;
     274        }
     275
     276        /* Note: New since protocol version 2. */
     277        case DragAndDropSvc::GUEST_DND_CONNECT:
     278            /* Fall through is intentional. */
    209279        case DragAndDropSvc::GUEST_DND_HG_ACK_OP:
    210280        case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
     281        case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS:
     282        {
    211283            if (   modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
    212284                || modeGet() == VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST)
     
    217289                LogFlowFunc(("Host -> Guest DnD mode disabled, ignoring request\n"));
    218290            break;
     291        }
     292
    219293        case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
    220294        case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
    221295        case DragAndDropSvc::GUEST_DND_GH_SND_DIR:
    222         case DragAndDropSvc::GUEST_DND_GH_SND_FILE:
     296        case DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR:
     297        case DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA:
    223298        case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
     299        {
    224300#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    225301            if (   modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
     
    232308                LogFlowFunc(("Guest -> Host DnD mode disabled, ignoring request\n"));
    233309            break;
     310        }
     311
    234312        default:
    235313            /* Reach through to DnD manager. */
     
    244322    if (rc == VINF_SUCCESS) /* Note: rc might be VINF_HGCM_ASYNC_EXECUTE! */
    245323    {
     324        DnDClientMap::iterator itClient =  m_clientMap.find(u32ClientID);
     325        Assert(itClient != m_clientMap.end());
     326
     327        HGCM::Client *pClient = itClient->second;
     328        AssertPtr(pClient);
     329
    246330        switch (u32Function)
    247331        {
    248             /* Note: Older VBox versions with enabled DnD guest->host support (< 4.4)
     332            /*
     333             * Note: Older VBox versions with enabled DnD guest->host support (< 5.0)
    249334             *       used the same message ID (300) for GUEST_DND_GET_NEXT_HOST_MSG and
    250335             *       HOST_DND_GH_REQ_PENDING, which led this service returning
    251336             *       VERR_INVALID_PARAMETER when the guest wanted to actually
    252              *       handle HOST_DND_GH_REQ_PENDING. */
     337             *       handle HOST_DND_GH_REQ_PENDING.
     338             */
    253339            case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
    254340            {
     
    258344                    || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* parameter count */
    259345                    || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* blocking */)
    260                     rc = VERR_INVALID_PARAMETER;
    261                 else
    262                 {
    263                     rc = m_pManager->nextMessageInfo(&paParms[0].u.uint32, &paParms[1].u.uint32);
    264                     if (   RT_FAILURE(rc)
    265                         && paParms[2].u.uint32) /* Blocking? */
     346                {
     347                    rc = VERR_INVALID_PARAMETER;
     348                }
     349                else
     350                {
     351                    rc = m_pManager->nextMessageInfo(&paParms[0].u.uint32 /* uMsg */, &paParms[1].u.uint32 /* cParms */);
     352                    if (RT_FAILURE(rc)) /* No queued messages available? */
    266353                    {
    267                         /* Defer client returning. */
    268                         rc = VINF_HGCM_ASYNC_EXECUTE;
     354                        if (m_pfnHostCallback) /* Try asking the host. */
     355                        {
     356                            DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSG data;
     357                            data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG;
     358                            rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
     359                            if (RT_SUCCESS(rc))
     360                            {
     361                                paParms[0].u.uint32 = data.uMsg;   /* uMsg */
     362                                paParms[1].u.uint32 = data.cParms; /* cParms */
     363                                /* Note: paParms[2] was set by the guest as blocking flag. */
     364                            }
     365                        }
     366                        else
     367                            rc = VERR_NOT_FOUND;
     368
     369                        if (RT_FAILURE(rc))
     370                            rc = m_pManager->nextMessage(u32Function, cParms, paParms);
     371
     372                        /* Some error occurred? */
     373                        if (   RT_FAILURE(rc)
     374                            && paParms[2].u.uint32) /* Blocking flag set? */
     375                        {
     376                            /* Defer client returning. */
     377                            rc = VINF_HGCM_ASYNC_EXECUTE;
     378                        }
    269379                    }
     380                }
     381                break;
     382            }
     383            case DragAndDropSvc::GUEST_DND_CONNECT:
     384            {
     385                LogFlowFunc(("GUEST_DND_CONNECT\n"));
     386                if (   cParms != 2
     387                    || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* protocol version */
     388                    || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* additional connection flags */)
     389                    rc = VERR_INVALID_PARAMETER;
     390                else
     391                {
     392                    uint32_t uProtocol;
     393                    paParms[0].getUInt32(&uProtocol); /* Get protocol version. */
     394
     395                    rc = pClient->setProtocol(uProtocol);
     396                    if (RT_SUCCESS(rc))
     397                    {
     398                        /** @todo Handle connection flags (paParms[1]). */
     399                    }
     400
     401                    /* Note: Does not reach the host; the client's protocol version
     402                     *       is only kept in this service. */
    270403                }
    271404                break;
     
    304437                break;
    305438            }
     439            case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS:
     440            {
     441                LogFlowFunc(("GUEST_DND_HG_EVT_PROGRESS\n"));
     442                if (   cParms != 3
     443                    || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* status */
     444                    || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* percent */
     445                    || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* rc */)
     446                    rc = VERR_INVALID_PARAMETER;
     447                else
     448                {
     449                    DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA data;
     450                    data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS;
     451                    paParms[0].getUInt32(&data.uStatus);
     452                    paParms[1].getUInt32(&data.uPercentage);
     453                    paParms[2].getUInt32(&data.rc);
     454                    if (m_pfnHostCallback)
     455                        rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
     456                }
     457                break;
     458            }
    306459#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    307460            case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
     
    310463                if (   cParms != 3
    311464                    || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* defaction */
    312                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* allactions */
     465                    || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* alloctions */
    313466                    || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR   /* format */)
    314467                    rc = VERR_INVALID_PARAMETER;
     
    360513                    paParms[1].getUInt32(&data.cbPath);
    361514                    paParms[2].getUInt32(&data.fMode);
    362 #ifdef DEBUG_andy
    363                     LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x\n",
    364                                  data.pszPath, data.cbPath, data.fMode));
    365 #endif
     515
     516                    LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x\n", data.pszPath, data.cbPath, data.fMode));
    366517                    if (m_pfnHostCallback)
    367518                        rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
     
    369520                break;
    370521            }
    371             case DragAndDropSvc::GUEST_DND_GH_SND_FILE:
    372             {
    373                 LogFlowFunc(("GUEST_DND_GH_SND_FILE\n"));
    374                 if (   cParms != 5
    375                     || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR   /* file path */
    376                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* file path length */
    377                     || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR   /* file data */
    378                     || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* file data length */
    379                     || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* creation mode */)
    380                     rc = VERR_INVALID_PARAMETER;
    381                 else
    382                 {
    383                     DragAndDropSvc::VBOXDNDCBSNDFILEDATA data;
    384                     data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE;
     522            /* Note: Since protocol v2 (>= VBox 5.0). */
     523            case DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR:
     524            {
     525                LogFlowFunc(("GUEST_DND_GH_SND_FILE_HDR\n"));
     526                if (   cParms != 6
     527                    || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* context ID */
     528                    || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR   /* file path */
     529                    || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* file path length  */
     530                    || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* flags */
     531                    || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* file mode */
     532                    || paParms[5].type != VBOX_HGCM_SVC_PARM_64BIT /* file size */)
     533                    rc = VERR_INVALID_PARAMETER;
     534                else
     535                {
     536                    DragAndDropSvc::VBOXDNDCBSNDFILEHDRDATA data;
     537                    data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_HDR;
    385538                    uint32_t cTmp;
    386                     paParms[0].getPointer((void**)&data.pszFilePath, &cTmp);
    387                     paParms[1].getUInt32(&data.cbFilePath);
    388                     paParms[2].getPointer((void**)&data.pvData, &data.cbData);
    389                     /* paParms[3] is cbData. */
     539                    /* paParms[0] is context ID; unused yet. */
     540                    paParms[1].getPointer((void**)&data.pszFilePath, &cTmp);
     541                    paParms[2].getUInt32(&data.cbFilePath);
     542                    paParms[3].getUInt32(&data.fFlags);
    390543                    paParms[4].getUInt32(&data.fMode);
    391 #ifdef DEBUG_andy
    392                     LogFlowFunc(("pszFilePath=%s, cbData=%RU32, pvData=0x%p, fMode=0x%x\n",
    393                                  data.pszFilePath, data.cbData, data.pvData, data.fMode));
    394 #endif
     544                    paParms[5].getUInt64(&data.cbSize);
     545
     546                    LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x, cbSize=%RU64\n",
     547                                 data.pszFilePath, data.cbFilePath, data.fMode, data.cbSize));
     548
    395549                    if (m_pfnHostCallback)
    396550                        rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
     551                }
     552                break;
     553            }
     554            case DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA:
     555            {
     556                LogFlowFunc(("GUEST_DND_GH_SND_FILE_DATA\n"));
     557
     558                switch (pClient->protocol())
     559                {
     560                    case 2: /* Protocol version 2 only sends the next data chunks to reduce traffic. */
     561                    {
     562                        if (   cParms != 3
     563                            /* paParms[0] is context ID; unused yet. */
     564                            || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR   /* file data */
     565                            || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* file data length */)
     566                        {
     567                            rc = VERR_INVALID_PARAMETER;
     568                        }
     569                        else
     570                        {
     571                            DragAndDropSvc::VBOXDNDCBSNDFILEDATADATA data;
     572                            data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_DATA;
     573                            /* paParms[0] is context ID; unused yet. */
     574                            paParms[1].getPointer((void**)&data.pvData, &data.cbData);
     575                            paParms[2].getUInt32(&data.cbData);
     576
     577                            LogFlowFunc(("cbData=%RU32, pvData=0x%p\n", data.cbData, data.pvData));
     578
     579                            if (m_pfnHostCallback)
     580                                rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
     581                        }
     582                        break;
     583                    }
     584                    default:
     585                    {
     586                        if (   cParms != 5
     587                            || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR   /* file path */
     588                            || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* file path length */
     589                            || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR   /* file data */
     590                            || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* file data length */
     591                            || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* creation mode */)
     592                        {
     593                            rc = VERR_INVALID_PARAMETER;
     594                        }
     595                        else
     596                        {
     597                            DragAndDropSvc::VBOXDNDCBSNDFILEDATADATA data;
     598                            data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_DATA;
     599                            uint32_t cTmp;
     600                            paParms[0].getPointer((void**)&data.u.v1.pszFilePath, &cTmp);
     601                            paParms[1].getUInt32(&data.u.v1.cbFilePath);
     602                            paParms[2].getPointer((void**)&data.pvData, &cTmp);
     603                            paParms[3].getUInt32(&data.cbData);
     604                            paParms[4].getUInt32(&data.u.v1.fMode);
     605
     606                            LogFlowFunc(("pszFilePath=%s, cbData=%RU32, pvData=0x%p, fMode=0x%x\n",
     607                                         data.u.v1.pszFilePath, data.cbData, data.pvData, data.u.v1.fMode));
     608
     609                            if (m_pfnHostCallback)
     610                                rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
     611                        }
     612                        break;
     613                    }
    397614                }
    398615                break;
     
    423640                /* All other messages are handled by the DnD manager. */
    424641                rc = m_pManager->nextMessage(u32Function, cParms, paParms);
    425                 break;
    426             }
    427         }
    428     }
    429 
    430     /* If async execution is requested, we didn't notify the guest yet about
     642                if (rc == VERR_NO_DATA) /* Manager has no new messsages? Try asking the host. */
     643                {
     644                    if (m_pfnHostCallback)
     645                    {
     646                        DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSGDATA data;
     647                        data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG_DATA;
     648                        data.uMsg    = u32Function;
     649                        data.cParms  = cParms;
     650                        data.paParms = paParms;
     651
     652                        rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
     653                        if (RT_SUCCESS(rc))
     654                        {
     655                            cParms  = data.cParms;
     656                            paParms = data.paParms;
     657                        }
     658                    }
     659                }
     660                break;
     661            }
     662        }
     663    }
     664
     665    /*
     666     * If async execution is requested, we didn't notify the guest yet about
    431667     * completion. The client is queued into the waiters list and will be
    432      * notified as soon as a new event is available. */
     668     * notified as soon as a new event is available.
     669     */
    433670    if (rc == VINF_HGCM_ASYNC_EXECUTE)
    434671    {
     
    449686                                 uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    450687{
    451     LogFlowFunc(("u32Function=%RU32, cParms=%RU32\n", u32Function, cParms));
     688    LogFlowFunc(("u32Function=%RU32, cParms=%RU32, cClients=%zu, cQueue=%zu\n",
     689                 u32Function, cParms, m_clientMap.size(), m_clientQueue.size()));
    452690
    453691    int rc;
     
    463701    else if (modeGet() != VBOX_DRAG_AND_DROP_MODE_OFF)
    464702    {
    465         if (!m_clientQueue.isEmpty()) /* At least one client on the guest connected? */
    466         {
    467             rc = m_pManager->addMessage(u32Function, cParms, paParms);
     703        if (m_clientMap.size()) /* At least one client on the guest connected? */
     704        {
     705            /*
     706             * Did the host call something which needs immediate processing?
     707             * Prepend the message instead of appending to the command queue then.
     708             */
     709            bool fAppend;
     710            switch (u32Function)
     711            {
     712                /* Cancelling the drag'n drop operation has higher priority than
     713                 * processing already buffered messages. */
     714                case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
     715                    fAppend = false;
     716                    break;
     717
     718                default:
     719                    fAppend = true;
     720                    break;
     721            }
     722
     723            /*
     724             * If we prepending the message (instead of appending) this mean we need
     725             * to re-schedule the message queue in order to get the new command executed as
     726             * soon as possible.
     727             */
     728            bool fReschedule = !fAppend;
     729
     730            rc = m_pManager->addMessage(u32Function, cParms, paParms, fAppend);
     731            if (   RT_SUCCESS(rc)
     732                && fReschedule)
     733            {
     734                rc = m_pManager->doReschedule();
     735            }
     736
    468737            if (RT_SUCCESS(rc))
    469738            {
    470                 HGCM::Client *pClient = m_clientQueue.first();
    471                 AssertPtr(pClient);
    472 
    473                 /* Check if this was a request for getting the next host
    474                  * message. If so, return the message id and the parameter
    475                  * count. The message itself has to be queued. */
    476                 uint32_t uMsg = pClient->message();
    477                 if (uMsg == DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG)
    478                 {
    479                     LogFlowFunc(("Client %RU32 is waiting for next host msg\n", pClient->clientId()));
    480 
    481                     uint32_t uMsg1;
    482                     uint32_t cParms1;
    483                     rc = m_pManager->nextMessageInfo(&uMsg1, &cParms1);
    484                     if (RT_SUCCESS(rc))
     739                if (m_clientQueue.size()) /* Any clients in our queue ready for processing the next command? */
     740                {
     741                    HGCM::Client *pClient = m_clientQueue.first();
     742                    AssertPtr(pClient);
     743
     744                    /*
     745                     * Check if this was a request for getting the next host
     746                     * message. If so, return the message ID and the parameter
     747                     * count. The message itself has to be queued.
     748                     */
     749                    uint32_t uMsg = pClient->message();
     750                    if (uMsg == DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG)
    485751                    {
    486                         pClient->addMessageInfo(uMsg1, cParms1);
    487                         if (m_pHelpers)
    488                             m_pHelpers->pfnCallComplete(pClient->handle(), rc);
    489 
    490                         m_clientQueue.removeFirst();
    491                         delete pClient;
     752                        LogFlowFunc(("Client %RU32 is waiting for next host msg\n", pClient->clientId()));
     753
     754                        uint32_t uMsg1;
     755                        uint32_t cParms1;
     756                        rc = m_pManager->nextMessageInfo(&uMsg1, &cParms1);
     757                        if (RT_SUCCESS(rc))
     758                        {
     759                            pClient->addMessageInfo(uMsg1, cParms1);
     760                            if (   m_pHelpers
     761                                && m_pHelpers->pfnCallComplete)
     762                            {
     763                                m_pHelpers->pfnCallComplete(pClient->handle(), rc);
     764                            }
     765
     766                            m_clientQueue.removeFirst();
     767
     768                            delete pClient;
     769                            pClient = NULL;
     770                        }
     771                        else
     772                            AssertMsgFailed(("m_pManager::nextMessageInfo failed with rc=%Rrc\n", rc));
    492773                    }
    493774                    else
    494                         AssertMsgFailed(("m_pManager::nextMessageInfo failed with rc=%Rrc\n", rc));
    495                 }
    496                 else
    497                     AssertMsgFailed(("Client ID=%RU32 in wrong state with uMsg=%RU32\n",
    498                                      pClient->clientId(), uMsg));
     775                        AssertMsgFailed(("Client ID=%RU32 in wrong state with uMsg=%RU32\n",
     776                                         pClient->clientId(), uMsg));
     777                }
     778                else
     779                    LogFlowFunc(("All clients busy; delaying execution\n"));
    499780            }
    500781            else
     
    504785        else
    505786        {
    506             /* Tell the host that the guest does not support drag'n drop.
     787            /*
     788             * Tell the host that the guest does not support drag'n drop.
    507789             * This might happen due to not installed Guest Additions or
    508              * not running VBoxTray/VBoxClient. */
     790             * not running VBoxTray/VBoxClient.
     791             */
    509792            rc = VERR_NOT_SUPPORTED;
    510793        }
     
    516799    }
    517800
    518     LogFlowFunc(("rc=%Rrc\n", rc));
     801    LogFlowFuncLeaveRC(rc);
    519802    return rc;
    520803}
    521804
    522 DECLCALLBACK(int) DragAndDropService::progressCallback(uint32_t uPercentage, uint32_t uState, int rc, void *pvUser)
     805DECLCALLBACK(int) DragAndDropService::progressCallback(uint32_t uStatus, uint32_t uPercentage, int rc, void *pvUser)
    523806{
    524807    AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
     
    529812    if (pSelf->m_pfnHostCallback)
    530813    {
    531         LogFlowFunc(("GUEST_DND_HG_EVT_PROGRESS: uPercentage=%RU32, uState=%RU32, rc=%Rrc\n",
    532                      uPercentage, uState, rc));
     814        LogFlowFunc(("GUEST_DND_HG_EVT_PROGRESS: uStatus=%RU32, uPercentage=%RU32, rc=%Rrc\n",
     815                     uStatus, uPercentage, rc));
     816
    533817        DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA data;
    534818        data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS;
    535819        data.uPercentage  = RT_MIN(uPercentage, 100);
    536         data.uState       = uState;
    537         data.rc           = rc;
     820        data.uStatus      = uStatus;
     821        data.rc           = rc; /** @todo uin32_t vs. int. */
    538822
    539823        return pSelf->m_pfnHostCallback(pSelf->m_pvHostData,
  • trunk/src/VBox/Main/Makefile.kmk

    r55314 r55422  
    55
    66#
    7 # Copyright (C) 2004-2014 Oracle Corporation
     7# Copyright (C) 2004-2015 Oracle Corporation
    88#
    99# This file is part of VirtualBox Open Source Edition (OSE), as
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r55405 r55422  
    23532353            in one of the formats supported by VirtualBox (see
    23542354            <link to="ISystemProperties::mediumFormats" />).
    2355             After the storage unit is successfully created and this method succeeds, 
     2355            After the storage unit is successfully created and this method succeeds,
    23562356            if the medium is a base medium, it
    23572357            will be added to the <link to="#hardDisks"/> array attribute. </li>
     
    1046010460  <interface
    1046110461    name="IDnDBase" extends="$unknown"
    10462     uuid="b15cf9ca-4078-4786-a1be-af773a36e19f"
     10462    uuid="a9630a67-7238-4b0e-9a58-364b1dd3d032"
    1046310463    wsmap="managed"
    1046410464    >
    1046510465    <desc>Base abstract interface for drag'n drop.</desc>
     10466
     10467    <attribute name="formats" type="wstring" safearray="yes" readonly="yes">
     10468      <desc>Returns all supported drag'n drop formats.</desc>
     10469    </attribute>
     10470
     10471    <attribute name="protocolVersion" type="unsigned long" readonly="yes">
     10472      <desc>Returns the protocol version which is used to communicate
     10473       with the guest.</desc>
     10474    </attribute>
    1046610475
    1046710476    <method name="isFormatSupported" >
     
    1049410503      </param>
    1049510504    </method>
    10496 
    10497     <attribute name="formats" type="wstring" safearray="yes" readonly="yes">
    10498       <desc>Returns all supported drag'n drop formats.</desc>
    10499     </attribute>
    1050010505
    1050110506  </interface>
     
    1058310588  <interface
    1058410589    name="IDnDTarget" extends="IDnDBase"
    10585     uuid="2366c45c-4633-41a1-9fa6-0ef9f244434c"
     10590    uuid="25ac16fa-316d-4934-9a7f-fe02f6739bef"
    1058610591    wsmap="managed"
    1058710592    >
     
    1070010705    <method name="sendData">
    1070110706      <desc>
    10702         Sends data to the target.
     10707        Initiates sending data to the target.
    1070310708
    1070410709        <result name="VBOX_E_VM_ERROR">
     
    1071810723      <param name="progress" type="IProgress" dir="return">
    1071910724        <desc>Progress object to track the operation completion.</desc>
     10725      </param>
     10726    </method>
     10727
     10728    <method name="cancel">
     10729      <desc>
     10730        Requests cancelling the current operation. The target can veto
     10731        the request in case the operation is not cancelable at the moment.
     10732
     10733        <result name="VBOX_E_VM_ERROR">
     10734          VMM device is not available.
     10735        </result>
     10736
     10737      </desc>
     10738
     10739      <param name="veto" type="boolean" dir="return">
     10740        <desc>Whether the target has vetoed cancelling the operation.</desc>
    1072010741      </param>
    1072110742    </method>
  • trunk/src/VBox/Main/include/GuestDnDPrivate.h

    r51556 r55422  
    66
    77/*
    8  * Copyright (C) 2011-2014 Oracle Corporation
     8 * Copyright (C) 2011-2015 Oracle Corporation
    99 *
    1010 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2121
    2222#include "VBox/hgcmsvc.h" /* For PVBOXHGCMSVCPARM. */
    23 
    24 /* Forward prototype declarations. */
     23#include "VBox/GuestHost/DragAndDrop.h"
     24
     25/**
     26 * Forward prototype declarations.
     27 */
    2528class Guest;
     29class GuestDnDBase;
     30class GuestDnDResponse;
     31class GuestDnDSource;
     32class GuestDnDTarget;
    2633class Progress;
    2734
    28 /**
    29  * Class for handling drag'n drop responses from
    30  * the guest side.
    31  */
     35/** Array (vector) of guest DnD data. This might be an URI list, according
     36 *  to the format being set. */
     37typedef std::vector<BYTE> GuestDnDData;
     38
     39/**
     40 * Context structure for sending data to the guest.
     41 */
     42typedef struct SENDDATACTX
     43{
     44    /** Pointer to guest target class this context belongs to. */
     45    GuestDnDTarget                     *mpTarget;
     46    /** Pointer to guest response class this context belongs to. */
     47    GuestDnDResponse                   *mpResp;
     48    /** Flag indicating whether a file transfer is active and
     49     *  initiated by the host. */
     50    bool                                mIsActive;
     51    /** Target (VM) screen ID. */
     52    uint32_t                            mScreenID;
     53    /** Drag'n drop format to send. */
     54    com::Utf8Str                        mFormat;
     55    /** Drag'n drop data to send.
     56     *  This can be arbitrary data or an URI list. */
     57    GuestDnDData                        mData;
     58    /** Struct for keeping data required for URI list processing. */
     59    struct
     60    {
     61        /** List of all URI objects to send. */
     62        DnDURIList                      lstURI;
     63        /** Event semaphore to notify in case of callback completion. */
     64        RTSEMEVENT                      SemEvent;
     65        /** Overall size (in bytes) of data to send. */
     66        uint64_t                        cbToProcess;
     67        /** Overall number of processed URI objects. */
     68        uint32_t                        cProcessed;
     69        /** Overall size (in bytes) of processed file data. */
     70        uint64_t                        cbProcessed;
     71        /** Pointer to scratch buffer to use for
     72         *  doing the actual chunk transfers. */
     73        void                           *pvScratchBuf;
     74        /** Size (in bytes) of scratch buffer. */
     75        size_t                          cbScratchBuf;
     76    } mURI;
     77
     78} SENDDATACTX, *PSENDDATACTX;
     79
     80/**
     81 * Context structure for receiving data from the guest.
     82 */
     83typedef struct RECVDATACTX
     84{
     85    /** Pointer to guest source class this context belongs to. */
     86    GuestDnDSource                     *mpSource;
     87    /** Pointer to guest response class this context belongs to. */
     88    GuestDnDResponse                   *mpResp;
     89    /** Flag indicating whether a file transfer is active and
     90     *  initiated by the host. */
     91    bool                                mIsActive;
     92    /** Drag'n drop format to send. */
     93    com::Utf8Str                        mFormat;
     94    /** Desired drop action to perform on the host.
     95     *  Needed to tell the guest if data has to be
     96     *  deleted e.g. when moving instead of copying. */
     97    uint32_t                            mAction;
     98    /** Drag'n drop received from the guest.
     99     *  This can be arbitrary data or an URI list. */
     100    GuestDnDData                        mData;
     101    /** Event semaphore to notify in case of callback completion. */
     102    RTSEMEVENT                          SemEvent;
     103    /** Struct for keeping data required for URI list processing. */
     104    struct
     105    {
     106        /** Temporary drop directory on the host where to
     107         *  put the files sent from the guest. */
     108        com::Utf8Str                    strDropDir;
     109        /** (Non-recursive) List of root URI objects to receive. */
     110        DnDURIList                      lstURI;
     111        /** Current object to receive. */
     112        DnDURIObject                    objURI;
     113        /** Overall size (in bytes) of data to send. */
     114        uint64_t                        cbToProcess;
     115        /** Overall number of processed URI objects. */
     116        uint32_t                        cProcessed;
     117        /** Overall size (in bytes) of processed file data. */
     118        uint64_t                        cbProcessed;
     119        /** List for holding created directories in the case of a rollback. */
     120        RTCList<RTCString>              lstDirs;
     121        /** List for holding created files in the case of a rollback. */
     122        RTCList<RTCString>              lstFiles;
     123
     124    } mURI;
     125
     126} RECVDATACTX, *PRECVDATACTX;
     127
     128/**
     129 * Simple structure for a buffered guest DnD message.
     130 */
     131class GuestDnDMsg
     132{
     133public:
     134
     135    GuestDnDMsg(void)
     136        : uMsg(0)
     137        , cParms(0)
     138        , cParmsAlloc(0)
     139        , paParms(NULL) { }
     140
     141    virtual ~GuestDnDMsg(void)
     142    {
     143        if (paParms)
     144        {
     145            /* Remove deep copies. */
     146            for (uint32_t i = 0; i < cParms; i++)
     147            {
     148                if (   paParms[i].type == VBOX_HGCM_SVC_PARM_PTR
     149                    && paParms[i].u.pointer.addr)
     150                {
     151                    RTMemFree(paParms[i].u.pointer.addr);
     152                }
     153            }
     154
     155            delete paParms;
     156        }
     157    }
     158
     159public:
     160
     161    PVBOXHGCMSVCPARM getNextParam(void)
     162    {
     163        if (cParms >= cParmsAlloc)
     164        {
     165            paParms = (PVBOXHGCMSVCPARM)RTMemRealloc(paParms, (cParmsAlloc + 4) * sizeof(VBOXHGCMSVCPARM));
     166            if (!paParms)
     167                throw VERR_NO_MEMORY;
     168            RT_BZERO(&paParms[cParmsAlloc], 4 * sizeof(VBOXHGCMSVCPARM));
     169            cParmsAlloc += 4;
     170        }
     171
     172        return &paParms[cParms++];
     173    }
     174
     175    uint32_t getCount(void) const { return cParms; }
     176    PVBOXHGCMSVCPARM getParms(void) const { return paParms; }
     177    uint32_t getType(void) const { return uMsg; }
     178
     179    int setNextPointer(void *pvBuf, uint32_t cbBuf)
     180    {
     181        AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
     182        AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
     183
     184        PVBOXHGCMSVCPARM pParm = getNextParam();
     185        if (!pParm)
     186            return VERR_NO_MEMORY;
     187
     188        void *pvTmp = RTMemDup(pvBuf, cbBuf);
     189        if (!pvTmp)
     190        {
     191            RTMemFree(pParm);
     192            return VERR_NO_MEMORY;
     193        }
     194
     195        pParm->setPointer(pvTmp, cbBuf);
     196        return VINF_SUCCESS;
     197    }
     198
     199    int setNextString(const char *pszString)
     200    {
     201        PVBOXHGCMSVCPARM pParm = getNextParam();
     202        if (!pParm)
     203            return VERR_NO_MEMORY;
     204
     205        char *pszTemp = RTStrDup(pszString);
     206        if (!pszTemp)
     207        {
     208            RTMemFree(pParm);
     209            return VERR_NO_MEMORY;
     210        }
     211
     212        pParm->setString(pszTemp);
     213        return VINF_SUCCESS;
     214    }
     215
     216    int setNextUInt32(uint32_t u32Val)
     217    {
     218        PVBOXHGCMSVCPARM pParm = getNextParam();
     219        if (!pParm)
     220            return VERR_NO_MEMORY;
     221
     222        pParm->setUInt32(u32Val);
     223        return VINF_SUCCESS;
     224    }
     225
     226    int setNextUInt64(uint64_t u64Val)
     227    {
     228        PVBOXHGCMSVCPARM pParm = getNextParam();
     229        if (!pParm)
     230            return VERR_NO_MEMORY;
     231
     232        pParm->setUInt64(u64Val);
     233        return VINF_SUCCESS;
     234    }
     235
     236    void setType(uint32_t uMsgType) { uMsg = uMsgType; }
     237
     238protected:
     239
     240    /** Message type. */
     241    uint32_t                    uMsg;
     242    /** Message parameters. */
     243    uint32_t                    cParms;
     244    /** Size of array. */
     245    uint32_t                    cParmsAlloc;
     246    /** Array of HGCM parameters */
     247    PVBOXHGCMSVCPARM            paParms;
     248};
     249
     250/** Guest DnD callback function definition. */
     251typedef DECLCALLBACKPTR(int, PFNGUESTDNDCALLBACK) (uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser);
     252
     253/**
     254 * Structure for keeping a guest DnD callback.
     255 * Each callback can handle one HGCM message, however, multiple HGCM messages can be registered
     256 * to the same callback (function).
     257 */
     258typedef struct GuestDnDCallback
     259{
     260    GuestDnDCallback(void)
     261        : uMessgage(0)
     262        , pfnCallback(NULL)
     263        , pvUser(NULL) { }
     264
     265    GuestDnDCallback(PFNGUESTDNDCALLBACK pvCB, uint32_t uMsg, void *pvUsr = NULL)
     266        : uMessgage(uMsg)
     267        , pfnCallback(pvCB)
     268        , pvUser(pvUsr) { }
     269
     270    /** The HGCM message ID to handle. */
     271    uint32_t             uMessgage;
     272    /** Pointer to callback function. */
     273    PFNGUESTDNDCALLBACK  pfnCallback;
     274    /** Pointer to user-supplied data. */
     275    void                *pvUser;
     276
     277} GuestDnDCallback;
     278
     279/** Contains registered callback pointers for specific HGCM message types. */
     280typedef std::map<uint32_t, GuestDnDCallback> GuestDnDCallbackMap;
     281
    32282class GuestDnDResponse
    33283{
     
    36286
    37287    GuestDnDResponse(const ComObjPtr<Guest>& pGuest);
    38 
    39288    virtual ~GuestDnDResponse(void);
    40289
    41290public:
    42291
    43     int notifyAboutGuestResponse(void);
    44     int waitForGuestResponse(RTMSINTERVAL msTimeout = 500);
     292    int notifyAboutGuestResponse(void) const;
     293    int waitForGuestResponse(RTMSINTERVAL msTimeout = 500) const;
     294
     295    void setAllActions(uint32_t a) { m_allActions = a; }
     296    uint32_t allActions(void) const { return m_allActions; }
    45297
    46298    void setDefAction(uint32_t a) { m_defAction = a; }
    47299    uint32_t defAction(void) const { return m_defAction; }
    48300
    49     void setAllActions(uint32_t a) { m_allActions = a; }
    50     uint32_t allActions() const { return m_allActions; }
     301    void setDropDir(const Utf8Str &strDropDir) { m_strDropDir = strDropDir; }
     302    Utf8Str dropDir(void) const { return m_strDropDir; }
    51303
    52304    void setFormat(const Utf8Str &strFormat) { m_strFormat = strFormat; }
    53305    Utf8Str format(void) const { return m_strFormat; }
    54306
    55     void setDropDir(const Utf8Str &strDropDir) { m_strDropDir = strDropDir; }
    56     Utf8Str dropDir(void) const { return m_strDropDir; }
    57 
    58307    int dataAdd(const void *pvData, uint32_t cbData, uint32_t *pcbCurSize);
    59308    int dataSetStatus(size_t cbDataAdd, size_t cbDataTotal = 0);
    60     void reset(void);
    61309    const void *data(void) { return m_pvData; }
    62310    size_t size(void) const { return m_cbData; }
    63311
     312    void reset(void);
     313
     314    bool isProgressCanceled(void) const;
     315    int setCallback(uint32_t uMsg, PFNGUESTDNDCALLBACK pfnCallback, void *pvUser = NULL);
    64316    int setProgress(unsigned uPercentage, uint32_t uState, int rcOp = VINF_SUCCESS);
    65317    HRESULT resetProgress(const ComObjPtr<Guest>& pParent);
    66318    HRESULT queryProgressTo(IProgress **ppProgress);
    67319
    68     int writeToFile(const char *pszPath, size_t cbPath, void *pvData, size_t cbData, uint32_t fMode);
     320public:
     321
     322    /** @name HGCM callback handling.
     323       @{ */
     324    int onDispatch(uint32_t u32Function, void *pvParms, uint32_t cbParms);
     325    /** @}  */
    69326
    70327public:
     
    72329    Utf8Str errorToString(const ComObjPtr<Guest>& pGuest, int guestRc);
    73330
    74 private:
    75     RTSEMEVENT           m_EventSem;
    76     uint32_t             m_defAction;
    77     uint32_t             m_allActions;
    78     Utf8Str              m_strFormat;
     331protected:
     332
     333    /** Pointer to context this class is tied to. */
     334    void                 *m_pvCtx;
     335    RTSEMEVENT            m_EventSem;
     336    uint32_t              m_defAction;
     337    uint32_t              m_allActions;
     338    Utf8Str               m_strFormat;
    79339
    80340    /** The actual MIME data.*/
    81     void                *m_pvData;
     341    void                 *m_pvData;
    82342    /** Size (in bytes) of MIME data. */
    83     uint32_t             m_cbData;
    84 
    85     size_t               m_cbDataCurrent;
    86     size_t               m_cbDataTotal;
     343    uint32_t              m_cbData;
     344
     345    size_t                m_cbDataCurrent;
     346    size_t                m_cbDataTotal;
    87347    /** Dropped files directory on the host. */
    88     Utf8Str              m_strDropDir;
    89     /** The handle of the currently opened file being written to
    90      *  or read from. */
    91     RTFILE               m_hFile;
    92     Utf8Str              m_strFile;
    93 
    94     ComObjPtr<Guest>     m_parent;
    95     ComObjPtr<Progress>  m_progress;
     348    Utf8Str               m_strDropDir;
     349    /** URI object to use for reading/writing from/to files
     350     *  and handling directories. */
     351    DnDURIObject          m_URIObj;
     352    /** Pointer to IGuest parent object. */
     353    ComObjPtr<Guest>      m_parent;
     354    /** Pointer to associated progress object. Optional. */
     355    ComObjPtr<Progress>   m_progress;
     356    /** Callback map. */
     357    GuestDnDCallbackMap   m_mapCallbacks;
    96358};
    97359
     
    172434    /** @}  */
    173435
    174 protected:
    175 
    176 #ifdef VBOX_WITH_DRAG_AND_DROP_GH
    177     /** @name Dispatch handlers for the HGCM callbacks.
    178      * @{ */
    179     int onGHSendData(GuestDnDResponse *pResp, const void *pvData, size_t cbData, size_t cbTotalSize);
    180     int onGHSendDir(GuestDnDResponse *pResp, const char *pszPath, size_t cbPath, uint32_t fMode);
    181     int onGHSendFile(GuestDnDResponse *pResp, const char *pszPath, size_t cbPath, void *pvData, size_t cbData, uint32_t fMode);
    182     /** @}  */
    183 #endif /* VBOX_WITH_DRAG_AND_DROP_GH */
    184 
    185436private:
    186437
     
    192443#define GuestDnDInst() GuestDnD::getInstance()
    193444
     445/** List of pointers to guest DnD Messages. */
     446typedef std::list<GuestDnDMsg *> GuestDnDMsgList;
     447
    194448/**
    195449 * IDnDBase class implementation for sharing code between
     
    204458protected:
    205459
    206     /** Shared IDnDBase method implementations.
    207      * @{ */
    208     HRESULT isFormatSupported(const com::Utf8Str &aFormat, BOOL *aSupported);
    209     HRESULT getFormats(std::vector<com::Utf8Str> &aFormats);
    210     HRESULT addFormats(const std::vector<com::Utf8Str> &aFormats);
    211     HRESULT removeFormats(const std::vector<com::Utf8Str> &aFormats);
     460    /** Shared (internal) IDnDBase method implementations.
     461     * @{ */
     462    HRESULT i_isFormatSupported(const com::Utf8Str &aFormat, BOOL *aSupported);
     463    HRESULT i_getFormats(std::vector<com::Utf8Str> &aFormats);
     464    HRESULT i_addFormats(const std::vector<com::Utf8Str> &aFormats);
     465    HRESULT i_removeFormats(const std::vector<com::Utf8Str> &aFormats);
     466
     467    HRESULT i_getProtocolVersion(ULONG *puVersion);
     468    /** @}  */
     469
     470protected:
     471
     472    int getProtocolVersion(uint32_t *puVersion);
     473
     474    int addMsg(GuestDnDMsg *pMsg)
     475    {
     476        mData.m_lstOutgoing.push_back(pMsg);
     477        return VINF_SUCCESS;
     478    }
     479
     480    GuestDnDMsg *nextMsg(void)
     481    {
     482        if (mData.m_lstOutgoing.empty())
     483            return NULL;
     484        return mData.m_lstOutgoing.front();
     485    }
     486
     487    void removeNext(void)
     488    {
     489        if (!mData.m_lstOutgoing.empty())
     490        {
     491            GuestDnDMsg *pMsg = mData.m_lstOutgoing.front();
     492            if (pMsg)
     493                delete pMsg;
     494            mData.m_lstOutgoing.pop_front();
     495        }
     496    }
     497
     498    /** Static callbacks.
     499     * @{ */
     500    //static DECLCALLBACK(int) i_getNextMsgCallback(GuestDnDBase *pThis, uint32_t *puMsg, uint32_t *pcParms, PVBOXHGCMSVCPARM paParms);
    212501    /** @}  */
    213502
     
    217506     * @{ */
    218507    /** Pointer to guest implementation. */
    219     const ComObjPtr<Guest>     m_pGuest;
     508    const ComObjPtr<Guest>          m_pGuest;
    220509    /** List of supported MIME/Content-type formats. */
    221     std::vector<com::Utf8Str>  m_strFormats;
    222     /** @}  */
     510    std::vector<com::Utf8Str>       m_strFormats;
     511    /** @}  */
     512
     513    struct
     514    {
     515        /** The DnD protocol version to use, depending on the
     516         *  installed Guest Additions. */
     517        uint32_t                    mProtocolVersion;
     518        /** Outgoing message queue. */
     519        GuestDnDMsgList             m_lstOutgoing;
     520    } mData;
    223521};
    224522
  • trunk/src/VBox/Main/include/GuestDnDSourceImpl.h

    r51556 r55422  
    55
    66/*
    7  * Copyright (C) 2014 Oracle Corporation
     7 * Copyright (C) 2014-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2222#include "GuestDnDPrivate.h"
    2323
     24struct RECVDATACTX;
     25typedef struct RECVDATACTX *PRECVDATACTX;
     26
    2427class ATL_NO_VTABLE GuestDnDSource :
    2528    public GuestDnDSourceWrap,
    26     protected GuestDnDBase
     29    public GuestDnDBase
    2730{
    2831public:
     
    4649    HRESULT addFormats(const std::vector<com::Utf8Str> &aFormats);
    4750    HRESULT removeFormats(const std::vector<com::Utf8Str> &aFormats);
     51
     52    HRESULT getProtocolVersion(ULONG *aProtocolVersion);
    4853    /** @}  */
    4954
     
    5762protected:
    5863
    59     /** @name Attributes.
     64#ifdef VBOX_WITH_DRAG_AND_DROP_GH
     65    /** @name Dispatch handlers for the HGCM callbacks.
    6066     * @{ */
    61     /** Pointer to guest implementation. */
    62     const ComObjPtr<Guest>     m_pGuest;
     67    int i_onReceiveData(PRECVDATACTX pCtx, const void *pvData, uint32_t cbData, uint64_t cbTotalSize);
     68    int i_onReceiveDir(PRECVDATACTX pCtx, const char *pszPath, uint32_t cbPath, uint32_t fMode);
     69    int i_onReceiveFileHdr(PRECVDATACTX pCtx, const char *pszPath, uint32_t cbPath, uint64_t cbSize, uint32_t fMode, uint32_t fFlags);
     70    int i_onReceiveFileData(PRECVDATACTX pCtx, const void *pvData, uint32_t cbData);
    6371    /** @}  */
     72#endif
     73
     74protected:
     75
     76    static DECLCALLBACK(int) i_receiveDataThread(RTTHREAD Thread, void *pvUser);
     77
     78    /** @name Callbacks for dispatch handler.
     79     * @{ */
     80    static DECLCALLBACK(int) i_receiveRawDataCallback(uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser);
     81    static DECLCALLBACK(int) i_receiveURIDataCallback(uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser);
     82    /** @}  */
     83
     84protected:
     85
     86    int i_receiveData(PRECVDATACTX pCtx);
     87    int i_receiveRawData(PRECVDATACTX pCtx);
     88    int i_receiveURIData(PRECVDATACTX pCtx);
    6489};
    6590
  • trunk/src/VBox/Main/include/GuestDnDTargetImpl.h

    r51556 r55422  
    55
    66/*
    7  * Copyright (C) 2014 Oracle Corporation
     7 * Copyright (C) 2014-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2222#include "GuestDnDPrivate.h"
    2323
     24#include <VBox/GuestHost/DragAndDrop.h>
     25#include <VBox/HostServices/DragAndDropSvc.h>
     26
     27struct SENDDATACTX;
     28typedef struct SENDDATACTX *PSENDDATACTX;
     29
    2430class ATL_NO_VTABLE GuestDnDTarget :
    2531    public GuestDnDTargetWrap,
    26     protected GuestDnDBase
     32    public GuestDnDBase
    2733{
    2834public:
     
    4652    HRESULT addFormats(const std::vector<com::Utf8Str> &aFormats);
    4753    HRESULT removeFormats(const std::vector<com::Utf8Str> &aFormats);
     54
     55    HRESULT getProtocolVersion(ULONG *aProtocolVersion);
    4856    /** @}  */
    4957
     
    5563    HRESULT drop(ULONG aScreenId, ULONG aX, ULONG aY, DnDAction_T aDefaultAction, const std::vector<DnDAction_T> &aAllowedActions, const std::vector<com::Utf8Str> &aFormats, com::Utf8Str &aFormat, DnDAction_T *aResultAction);
    5664    HRESULT sendData(ULONG aScreenId, const com::Utf8Str &aFormat, const std::vector<BYTE> &aData, ComPtr<IProgress> &aProgress);
     65    HRESULT cancel(BOOL *aVeto);
    5766    /** @}  */
     67
     68protected:
     69
     70    static DECLCALLBACK(int) i_sendDataThread(RTTHREAD Thread, void *pvUser);
     71    static DECLCALLBACK(int) i_sendURIDataCallback(uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser);
     72
     73protected:
     74
     75    int i_cancelOperation(void);
     76    int i_sendData(PSENDDATACTX pCtx);
     77    int i_sendDirectory(PSENDDATACTX pCtx, GuestDnDMsg *pMsg, DnDURIObject &aDirectory);
     78    int i_sendFile(PSENDDATACTX pCtx, GuestDnDMsg *pMsg, DnDURIObject &aFile);
     79    int i_sendFileData(PSENDDATACTX pCtx, GuestDnDMsg *pMsg, DnDURIObject &aFile);
     80    int i_sendURIData(PSENDDATACTX pCtx);
     81    int i_sendURIDataLoop(PSENDDATACTX pCtx, GuestDnDMsg *pMsg);
    5882
    5983protected:
     
    6185    /** @name Attributes.
    6286     * @{ */
    63     /** Pointer to guest implementation. */
    64     const ComObjPtr<Guest>     m_pGuest;
     87    /** Maximum data block size (in bytes) the target can handle. */
     88    uint32_t                   m_cbBlockSize;
    6589    /** @}  */
    6690};
  • trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp

    r55244 r55422  
    66
    77/*
    8  * Copyright (C) 2011-2014 Oracle Corporation
     8 * Copyright (C) 2011-2015 Oracle Corporation
    99 *
    1010 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3737# include <VBox/GuestHost/DragAndDrop.h>
    3838# include <VBox/HostServices/DragAndDropSvc.h>
     39# include <VBox/version.h>
    3940
    4041# ifdef LOG_GROUP
     
    167168    , m_cbDataCurrent(0)
    168169    , m_cbDataTotal(0)
    169     , m_hFile(NIL_RTFILE)
    170170    , m_parent(pGuest)
    171171{
    172172    int rc = RTSemEventCreate(&m_EventSem);
    173     AssertRC(rc);
     173    if (RT_FAILURE(rc))
     174        throw rc;
    174175}
    175176
     
    242243}
    243244
    244 int GuestDnDResponse::notifyAboutGuestResponse(void)
     245int GuestDnDResponse::notifyAboutGuestResponse(void) const
    245246{
    246247    return RTSemEventSignal(m_EventSem);
     
    262263        m_pvData = NULL;
    263264    }
    264     m_cbData = 0;
     265
     266    m_cbData        = 0;
    265267    m_cbDataCurrent = 0;
    266     m_cbDataTotal = 0;
    267 
    268     if (m_hFile != NIL_RTFILE)
    269     {
    270         RTFileClose(m_hFile);
    271         m_hFile = NIL_RTFILE;
    272     }
    273     m_strFile = "";
     268    m_cbDataTotal   = 0;
    274269}
    275270
     
    280275    if (SUCCEEDED(rc))
    281276    {
    282         rc = m_progress->init(static_cast<IGuest*>(pParent),
     277        rc = m_progress->init(static_cast<IGuest *>(pParent),
    283278                              Bstr(pParent->tr("Dropping data")).raw(),
    284                               FALSE /* fCancelable */);
     279                              TRUE /* aCancelable */);
    285280    }
    286281    return rc;
    287282}
    288283
     284bool GuestDnDResponse::isProgressCanceled(void) const
     285{
     286    BOOL fCanceled;
     287    if (!m_progress.isNull())
     288    {
     289        HRESULT hr = m_progress->COMGETTER(Canceled)(&fCanceled);
     290        AssertComRC(hr);
     291    }
     292    else fCanceled = TRUE;
     293
     294    return RT_BOOL(fCanceled);
     295}
     296
     297int GuestDnDResponse::setCallback(uint32_t uMsg, PFNGUESTDNDCALLBACK pfnCallback, void *pvUser /* = NULL */)
     298{
     299    GuestDnDCallbackMap::const_iterator it = m_mapCallbacks.find(uMsg);
     300
     301    /* Add. */
     302    if (pfnCallback)
     303    {
     304        if (it == m_mapCallbacks.end())
     305        {
     306            m_mapCallbacks[uMsg] = GuestDnDCallback(pfnCallback, uMsg, pvUser);
     307            return VINF_SUCCESS;
     308        }
     309
     310        AssertMsgFailed(("Callback for message %RU32 already registered\n", uMsg));
     311        return VERR_ALREADY_EXISTS;
     312    }
     313
     314    /* Remove. */
     315    if (it != m_mapCallbacks.end())
     316        m_mapCallbacks.erase(it);
     317
     318    return VINF_SUCCESS;
     319}
     320
    289321int GuestDnDResponse::setProgress(unsigned uPercentage,
    290                                   uint32_t uState, int rcOp /* = VINF_SUCCESS */)
    291 {
    292     LogFlowFunc(("uPercentage=%RU32, uState=%RU32, rcOp=%Rrc\n",
    293                  uPercentage, uState, rcOp));
     322                                  uint32_t uStatus, int rcOp /* = VINF_SUCCESS */)
     323{
     324    LogFlowFunc(("uStatus=%RU32, uPercentage=%RU32, rcOp=%Rrc\n",
     325                 uStatus, uPercentage, rcOp));
    294326
    295327    int vrc = VINF_SUCCESS;
     
    298330        BOOL fCompleted;
    299331        HRESULT hr = m_progress->COMGETTER(Completed)(&fCompleted);
     332        AssertComRC(hr);
     333
     334        BOOL fCanceled;
     335        hr = m_progress->COMGETTER(Canceled)(&fCanceled);
     336        AssertComRC(hr);
     337
     338        LogFlowFunc(("fCompleted=%RTbool, fCanceled=%RTbool\n", fCompleted, fCanceled));
     339
    300340        if (!fCompleted)
    301341        {
    302             if (uState == DragAndDropSvc::DND_PROGRESS_ERROR)
     342            switch (uStatus)
    303343            {
    304                 hr = m_progress->i_notifyComplete(VBOX_E_IPRT_ERROR,
    305                                                   COM_IIDOF(IGuest),
    306                                                   m_parent->getComponentName(),
    307                                                   GuestDnDResponse::errorToString(m_parent, rcOp).c_str());
    308                 reset();
    309             }
    310             else if (uState == DragAndDropSvc::DND_PROGRESS_CANCELLED)
    311             {
    312                 hr = m_progress->Cancel();
    313                 if (SUCCEEDED(hr))
    314                     vrc = VERR_CANCELLED;
    315 
    316                 reset();
    317             }
    318             else /* uState == DragAndDropSvc::DND_PROGRESS_RUNNING */
    319             {
    320                 hr = m_progress->SetCurrentOperationProgress(uPercentage);
    321                 AssertComRC(hr);
    322                 if (   uState      == DragAndDropSvc::DND_PROGRESS_COMPLETE
    323                     || uPercentage >= 100)
     344                case DragAndDropSvc::DND_PROGRESS_ERROR:
     345                {
     346                    hr = m_progress->i_notifyComplete(VBOX_E_IPRT_ERROR,
     347                                                      COM_IIDOF(IGuest),
     348                                                      m_parent->getComponentName(),
     349                                                      GuestDnDResponse::errorToString(m_parent, rcOp).c_str());
     350                    reset();
     351                    break;
     352                }
     353
     354                case DragAndDropSvc::DND_PROGRESS_CANCELLED:
     355                {
    324356                    hr = m_progress->i_notifyComplete(S_OK);
     357                    AssertComRC(hr);
     358
     359                    reset();
     360                    break;
     361                }
     362
     363                case DragAndDropSvc::DND_PROGRESS_RUNNING:
     364                case DragAndDropSvc::DND_PROGRESS_COMPLETE:
     365                {
     366                    if (!fCanceled)
     367                    {
     368                        hr = m_progress->SetCurrentOperationProgress(uPercentage);
     369                        AssertComRC(hr);
     370                        if (   uStatus     == DragAndDropSvc::DND_PROGRESS_COMPLETE
     371                            || uPercentage >= 100)
     372                        {
     373                            hr = m_progress->i_notifyComplete(S_OK);
     374                            AssertComRC(hr);
     375                        }
     376                    }
     377                    break;
     378                }
     379
     380                default:
     381                    break;
    325382            }
    326383        }
    327384    }
    328385
     386    LogFlowFuncLeaveRC(vrc);
    329387    return vrc;
    330388}
     
    348406    /** @todo Don't use anonymous enums (uint32_t). */
    349407    uint32_t uStatus = DragAndDropSvc::DND_PROGRESS_RUNNING;
    350     if (m_cbDataCurrent >= m_cbDataTotal)
    351         uStatus = DragAndDropSvc::DND_PROGRESS_COMPLETE;
    352 
    353 #ifdef DEBUG_andy
    354     LogFlowFunc(("Updating transfer status (%zu/%zu), status=%ld\n",
    355                  m_cbDataCurrent, m_cbDataTotal, uStatus));
    356 #else
     408    Assert(m_cbDataCurrent <= m_cbDataTotal);
     409    if (m_cbDataCurrent >= m_cbDataTotal) uStatus = DragAndDropSvc::DND_PROGRESS_COMPLETE;
     410
     411    LogFlowFunc(("Updating transfer status (%zu/%zu), status=%ld\n", m_cbDataCurrent, m_cbDataTotal, uStatus));
    357412    AssertMsg(m_cbDataCurrent <= m_cbDataTotal,
    358413              ("More data transferred (%zu) than initially announced (%zu), cbDataAdd=%zu\n",
    359               m_cbDataCurrent, m_cbDataTotal, cbDataAdd));
    360 #endif
     414               m_cbDataCurrent, m_cbDataTotal, cbDataAdd));
     415
    361416    int rc = setProgress(cPercentage, uStatus);
    362417
     
    364419     *        guest should first clean up stuff itself and than really confirm
    365420     *        the cancel request by an extra message. */
    366     if (rc == VERR_CANCELLED)
    367         rc = setProgress(100, DragAndDropSvc::DND_PROGRESS_CANCELLED);
     421    if (rc == VERR_CANCELLED) rc = setProgress(100, DragAndDropSvc::DND_PROGRESS_CANCELLED);
    368422
    369423    LogFlowFuncLeaveRC(rc);
     
    371425}
    372426
     427int GuestDnDResponse::onDispatch(uint32_t u32Function, void *pvParms, uint32_t cbParms)
     428{
     429    LogFlowFunc(("u32Function=%RU32, pvParms=%p, cbParms=%RU32\n", u32Function, pvParms, cbParms));
     430
     431    int rc = VERR_WRONG_ORDER; /* Play safe. */
     432    bool fTryCallbacks = false;
     433
     434    switch (u32Function)
     435    {
     436        case DragAndDropSvc::GUEST_DND_HG_ACK_OP:
     437        {
     438            DragAndDropSvc::PVBOXDNDCBHGACKOPDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGACKOPDATA>(pvParms);
     439            AssertPtr(pCBData);
     440            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGACKOPDATA) == cbParms, VERR_INVALID_PARAMETER);
     441            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_ACK_OP == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     442
     443            setDefAction(pCBData->uAction);
     444            rc = notifyAboutGuestResponse();
     445            break;
     446        }
     447
     448        case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
     449        {
     450            DragAndDropSvc::PVBOXDNDCBHGREQDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGREQDATADATA>(pvParms);
     451            AssertPtr(pCBData);
     452            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGREQDATADATA) == cbParms, VERR_INVALID_PARAMETER);
     453            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_REQ_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     454
     455            setFormat(pCBData->pszFormat);
     456            rc = notifyAboutGuestResponse();
     457            break;
     458        }
     459
     460        case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS:
     461        {
     462            DragAndDropSvc::PVBOXDNDCBHGEVTPROGRESSDATA pCBData =
     463               reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGEVTPROGRESSDATA>(pvParms);
     464            AssertPtr(pCBData);
     465            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA) == cbParms, VERR_INVALID_PARAMETER);
     466            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     467
     468            rc = setProgress(pCBData->uPercentage, pCBData->uStatus, pCBData->rc);
     469            if (RT_SUCCESS(rc))
     470                rc = notifyAboutGuestResponse();
     471            break;
     472        }
     473#ifdef VBOX_WITH_DRAG_AND_DROP_GH
     474        case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
     475        {
     476            DragAndDropSvc::PVBOXDNDCBGHACKPENDINGDATA pCBData =
     477               reinterpret_cast<DragAndDropSvc::PVBOXDNDCBGHACKPENDINGDATA>(pvParms);
     478            AssertPtr(pCBData);
     479            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBGHACKPENDINGDATA) == cbParms, VERR_INVALID_PARAMETER);
     480            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_ACK_PENDING == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     481
     482            setFormat    (pCBData->pszFormat);
     483            setDefAction (pCBData->uDefAction);
     484            setAllActions(pCBData->uAllActions);
     485
     486            rc = notifyAboutGuestResponse();
     487            break;
     488        }
     489#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
     490        default:
     491            /* * Try if the event is covered by a registered callback. */
     492            fTryCallbacks = true;
     493            break;
     494    }
     495
     496    /*
     497     * Try the host's installed callbacks (if any).
     498     */
     499    if (fTryCallbacks)
     500    {
     501        GuestDnDCallbackMap::const_iterator it = m_mapCallbacks.find(u32Function);
     502        if (it != m_mapCallbacks.end())
     503        {
     504            AssertPtr(it->second.pfnCallback);
     505            rc = it->second.pfnCallback(u32Function, pvParms, cbParms, it->second.pvUser);
     506        }
     507        else
     508            rc = VERR_NO_DATA; /* Tell the guest. */
     509    }
     510
     511    LogFlowFunc(("Returning rc=%Rrc\n", rc));
     512    return rc;
     513}
     514
    373515HRESULT GuestDnDResponse::queryProgressTo(IProgress **ppProgress)
    374516{
     
    376518}
    377519
    378 int GuestDnDResponse::waitForGuestResponse(RTMSINTERVAL msTimeout /*= 500 */)
     520int GuestDnDResponse::waitForGuestResponse(RTMSINTERVAL msTimeout /*= 500 */) const
    379521{
    380522    int rc = RTSemEventWait(m_EventSem, msTimeout);
     
    382524    LogFlowFunc(("msTimeout=%RU32, rc=%Rrc\n", msTimeout, rc));
    383525#endif
    384     return rc;
    385 }
    386 
    387 int GuestDnDResponse::writeToFile(const char *pszPath, size_t cbPath,
    388                                   void *pvData, size_t cbData, uint32_t fMode)
    389 {
    390     /** @todo Support locking more than one file at a time! We
    391      *        might want to have a table in DnDGuestImpl which
    392      *        keeps those file pointers around, or extend the
    393      *        actual protocol for explicit open calls.
    394      *
    395      *        For now we only keep one file open at a time, so if
    396      *        a client does alternating writes to different files
    397      *        this function will close the old and re-open the new
    398      *        file on every call. */
    399     int rc;
    400     if (   m_hFile == NIL_RTFILE
    401         || m_strFile != pszPath)
    402     {
    403         char *pszFile = RTPathJoinA(m_strDropDir.c_str(), pszPath);
    404         if (pszFile)
    405         {
    406             RTFILE hFile;
    407             /** @todo Respect fMode!  */
    408             rc = RTFileOpen(&hFile, pszFile,
    409                               RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE
    410                             | RTFILE_O_WRITE | RTFILE_O_APPEND);
    411             if (RT_SUCCESS(rc))
    412             {
    413                 LogFlowFunc(("Opening \"%s\" (fMode=0x%x) for writing ...\n",
    414                              pszFile, fMode));
    415 
    416                 m_hFile = hFile;
    417                 m_strFile = pszPath;
    418             }
    419 
    420             RTStrFree(pszFile);
    421         }
    422         else
    423             rc = VERR_NO_MEMORY;
    424     }
    425     else
    426         rc = VINF_SUCCESS;
    427 
    428     if (RT_SUCCESS(rc))
    429     {
    430         rc = RTFileWrite(m_hFile, pvData, cbData,
    431                          NULL /* No partial writes */);
    432 
    433         if (RT_SUCCESS(rc))
    434             rc = dataSetStatus(cbData);
    435     }
    436 
    437526    return rc;
    438527}
     
    507596        return VERR_COM_OBJECT_NOT_FOUND;
    508597
    509     int rc = pVMMDev->hgcmHostCall("VBoxDragAndDropSvc", u32Function,
    510                                    cParms, paParms);
    511     LogFlowFunc(("uMsg=%RU32, cParms=%RU32, rc=%Rrc\n",
    512                  u32Function, cParms, rc));
     598    int rc = pVMMDev->hgcmHostCall("VBoxDragAndDropSvc", u32Function, cParms, paParms);
     599    LogFlowFunc(("uMsg=%RU32, cParms=%RU32, rc=%Rrc\n", u32Function, cParms, rc));
    513600    return rc;
    514601}
     602
     603/* static */
     604DECLCALLBACK(int) GuestDnD::notifyDnDDispatcher(void *pvExtension, uint32_t u32Function,
     605                                                void *pvParms, uint32_t cbParms)
     606{
     607    LogFlowFunc(("pvExtension=%p, u32Function=%RU32, pvParms=%p, cbParms=%RU32\n",
     608                 pvExtension, u32Function, pvParms, cbParms));
     609
     610    GuestDnD *pGuestDnD = reinterpret_cast<GuestDnD*>(pvExtension);
     611    AssertPtrReturn(pGuestDnD, VERR_INVALID_POINTER);
     612
     613    /** @todo In case we need to handle multiple guest DnD responses at a time this
     614     *        would be the place to lookup and dispatch to those. For the moment we
     615     *        only have one response -- simple. */
     616    GuestDnDResponse *pResp = pGuestDnD->m_pResponse;
     617    if (pResp)
     618        return pResp->onDispatch(u32Function, pvParms, cbParms);
     619
     620    return VERR_NOT_SUPPORTED;
     621}
     622
    515623
    516624/* static */
     
    637745}
    638746
    639 /* static */
    640 DECLCALLBACK(int) GuestDnD::notifyDnDDispatcher(void *pvExtension, uint32_t u32Function,
    641                                                 void *pvParms, uint32_t cbParms)
    642 {
    643     LogFlowFunc(("pvExtension=%p, u32Function=%RU32, pvParms=%p, cbParms=%RU32\n",
    644                  pvExtension, u32Function, pvParms, cbParms));
    645 
    646     GuestDnD *pGuestDnD = reinterpret_cast<GuestDnD*>(pvExtension);
    647     AssertPtrReturn(pGuestDnD, VERR_INVALID_POINTER);
    648 
    649     GuestDnDResponse *pResp = pGuestDnD->m_pResponse;
    650     AssertPtrReturn(pResp, VERR_INVALID_POINTER);
    651 
    652     int rc;
    653     switch (u32Function)
    654     {
    655         case DragAndDropSvc::GUEST_DND_HG_ACK_OP:
    656         {
    657             DragAndDropSvc::PVBOXDNDCBHGACKOPDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGACKOPDATA>(pvParms);
    658             AssertPtr(pCBData);
    659             AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGACKOPDATA) == cbParms, VERR_INVALID_PARAMETER);
    660             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_ACK_OP == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    661 
    662             pResp->setDefAction(pCBData->uAction);
    663 
    664             rc = pResp->notifyAboutGuestResponse();
    665             break;
    666         }
    667 
    668         case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
    669         {
    670             DragAndDropSvc::PVBOXDNDCBHGREQDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGREQDATADATA>(pvParms);
    671             AssertPtr(pCBData);
    672             AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGREQDATADATA) == cbParms, VERR_INVALID_PARAMETER);
    673             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_REQ_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    674 
    675             pResp->setFormat(pCBData->pszFormat);
    676 
    677             rc = pResp->notifyAboutGuestResponse();
    678             break;
    679         }
    680 
    681         case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS:
    682         {
    683             DragAndDropSvc::PVBOXDNDCBHGEVTPROGRESSDATA pCBData =
    684                 reinterpret_cast <DragAndDropSvc::PVBOXDNDCBHGEVTPROGRESSDATA>(pvParms);
    685             AssertPtr(pCBData);
    686             AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA) == cbParms, VERR_INVALID_PARAMETER);
    687             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    688 
    689             rc = pResp->setProgress(pCBData->uPercentage, pCBData->uState, pCBData->rc);
    690             break;
    691         }
    692 
    693 # ifdef VBOX_WITH_DRAG_AND_DROP_GH
    694         case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
    695         {
    696             DragAndDropSvc::PVBOXDNDCBGHACKPENDINGDATA pCBData =
    697                 reinterpret_cast <DragAndDropSvc::PVBOXDNDCBGHACKPENDINGDATA>(pvParms);
    698             AssertPtr(pCBData);
    699             AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBGHACKPENDINGDATA) == cbParms, VERR_INVALID_PARAMETER);
    700             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_ACK_PENDING == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    701 
    702             pResp->setFormat(pCBData->pszFormat);
    703             pResp->setDefAction(pCBData->uDefAction);
    704             pResp->setAllActions(pCBData->uAllActions);
    705 
    706             rc = pResp->notifyAboutGuestResponse();
    707             break;
    708         }
    709 
    710         case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
    711         {
    712             DragAndDropSvc::PVBOXDNDCBSNDDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDDATADATA>(pvParms);
    713             AssertPtr(pCBData);
    714             AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDDATADATA) == cbParms, VERR_INVALID_PARAMETER);
    715             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    716 
    717             rc = pGuestDnD->onGHSendData(pResp, pCBData->pvData, pCBData->cbData,
    718                                          pCBData->cbTotalSize);
    719             break;
    720         }
    721 
    722         case DragAndDropSvc::GUEST_DND_GH_SND_DIR:
    723         {
    724             DragAndDropSvc::PVBOXDNDCBSNDDIRDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDDIRDATA>(pvParms);
    725             AssertPtr(pCBData);
    726             AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDDIRDATA) == cbParms, VERR_INVALID_PARAMETER);
    727             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DIR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    728 
    729             rc = pGuestDnD->onGHSendDir(pResp, pCBData->pszPath, pCBData->cbPath, pCBData->fMode);
    730             break;
    731         }
    732 
    733         case DragAndDropSvc::GUEST_DND_GH_SND_FILE:
    734         {
    735             DragAndDropSvc::PVBOXDNDCBSNDFILEDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDFILEDATA>(pvParms);
    736             AssertPtr(pCBData);
    737             AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDFILEDATA) == cbParms, VERR_INVALID_PARAMETER);
    738             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    739 
    740             rc = pGuestDnD->onGHSendFile(pResp, pCBData->pszFilePath, pCBData->cbFilePath,
    741                                          pCBData->pvData, pCBData->cbData, pCBData->fMode);
    742             break;
    743         }
    744 
    745         case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
    746         {
    747             DragAndDropSvc::PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBEVTERRORDATA>(pvParms);
    748             AssertPtr(pCBData);
    749             AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER);
    750             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    751 
    752             /* Cleanup. */
    753             pResp->reset();
    754             rc = pResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, pCBData->rc);
    755             break;
    756         }
    757 # endif /* VBOX_WITH_DRAG_AND_DROP_GH */
    758         default:
    759             rc = VERR_NOT_SUPPORTED; /* Tell the guest. */
    760             break;
    761     }
    762 
    763     LogFlowFunc(("Returning rc=%Rrc\n", rc));
    764     return rc;
    765 }
    766 
    767 # ifdef VBOX_WITH_DRAG_AND_DROP_GH
    768 int GuestDnD::onGHSendData(GuestDnDResponse *pResp,
    769                            const void *pvData, size_t cbData, size_t cbTotalSize)
    770 {
    771     AssertPtrReturn(pResp, VERR_INVALID_POINTER);
    772     AssertPtrReturn(pvData, VERR_INVALID_POINTER);
    773     AssertReturn(cbData, VERR_INVALID_PARAMETER);
    774     AssertReturn(cbTotalSize, VERR_INVALID_PARAMETER);
    775 
    776     int rc = pResp->dataAdd(pvData, cbData, NULL /* Current size */);
    777     if (RT_SUCCESS(rc))
    778         rc = pResp->dataSetStatus(cbData, cbTotalSize);
    779 
    780     LogFlowFuncLeaveRC(rc);
    781     return rc;
    782 }
    783 
    784 int GuestDnD::onGHSendDir(GuestDnDResponse *pResp,
    785                           const char *pszPath, size_t cbPath, uint32_t fMode)
    786 {
    787     AssertPtrReturn(pResp, VERR_INVALID_POINTER);
    788     AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
    789     AssertReturn(cbPath, VERR_INVALID_PARAMETER);
    790 
    791     LogFlowFunc(("pszPath=%s, cbPath=%zu, fMode=0x%x\n",
    792                  pszPath, cbPath, fMode));
    793 
    794     int rc;
    795     char *pszDir = RTPathJoinA(pResp->dropDir().c_str(), pszPath);
    796     if (pszDir)
    797     {
    798         rc = RTDirCreateFullPath(pszDir, fMode);
    799         RTStrFree(pszDir);
    800     }
    801     else
    802         rc = VERR_NO_MEMORY;
    803 
    804     if (RT_SUCCESS(rc))
    805         rc = pResp->dataSetStatus(cbPath);
    806 
    807     LogFlowFuncLeaveRC(rc);
    808     return rc;
    809 }
    810 
    811 int GuestDnD::onGHSendFile(GuestDnDResponse *pResp,
    812                            const char *pszPath, size_t cbPath,
    813                            void *pvData, size_t cbData, uint32_t fMode)
    814 {
    815     AssertPtrReturn(pResp, VERR_INVALID_POINTER);
    816     AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
    817     AssertReturn(cbPath, VERR_INVALID_PARAMETER);
    818 
    819     LogFlowFunc(("pszPath=%s, cbPath=%zu, fMode=0x%x\n",
    820                  pszPath, cbPath, fMode));
    821 
    822     int rc = pResp->writeToFile(pszPath, cbPath,
    823                                 pvData, cbData, fMode);
    824     LogFlowFuncLeaveRC(rc);
    825     return rc;
    826 }
    827 # endif /* VBOX_WITH_DRAG_AND_DROP_GH */
    828 
    829747///////////////////////////////////////////////////////////////////////////////
    830748
     
    834752}
    835753
    836 HRESULT GuestDnDBase::isFormatSupported(const com::Utf8Str &aFormat, BOOL *aSupported)
     754HRESULT GuestDnDBase::i_isFormatSupported(const com::Utf8Str &aFormat, BOOL *aSupported)
    837755{
    838756    *aSupported = std::find(m_strFormats.begin(),
     
    842760}
    843761
    844 HRESULT GuestDnDBase::getFormats(std::vector<com::Utf8Str> &aFormats)
     762HRESULT GuestDnDBase::i_getFormats(std::vector<com::Utf8Str> &aFormats)
    845763{
    846764    aFormats = m_strFormats;
     
    849767}
    850768
    851 HRESULT GuestDnDBase::addFormats(const std::vector<com::Utf8Str> &aFormats)
     769HRESULT GuestDnDBase::i_addFormats(const std::vector<com::Utf8Str> &aFormats)
    852770{
    853771    for (size_t i = 0; i < aFormats.size(); ++i)
     
    864782}
    865783
    866 HRESULT GuestDnDBase::removeFormats(const std::vector<com::Utf8Str> &aFormats)
     784HRESULT GuestDnDBase::i_removeFormats(const std::vector<com::Utf8Str> &aFormats)
    867785{
    868786    for (size_t i = 0; i < aFormats.size(); ++i)
     
    878796}
    879797
     798HRESULT GuestDnDBase::i_getProtocolVersion(ULONG *puVersion)
     799{
     800    int rc = getProtocolVersion((uint32_t *)puVersion);
     801    return RT_SUCCESS(rc) ? S_OK : E_FAIL;
     802}
     803
     804int GuestDnDBase::getProtocolVersion(uint32_t *puVersion)
     805{
     806    AssertPtrReturn(puVersion, VERR_INVALID_POINTER);
     807
     808    int rc;
     809
     810    uint32_t uVer, uVerAdditions = 0;
     811    if (   m_pGuest
     812        && (uVerAdditions = m_pGuest->i_getAdditionsVersion()) > 0)
     813    {
     814        uint32_t uVBoxMajor = VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions);
     815        uint32_t uVBoxMinor = VBOX_FULL_VERSION_GET_MINOR(uVerAdditions);
     816
     817#if 0 /*def DEBUG_andy*/
     818        /* Hardcode the to-used protocol version; nice for testing side effects. */
     819        uVer = 2;
     820#else
     821        uVer = (  uVBoxMajor  >= 5)
     822             ? 2  /* VBox 5.0 and up: Protocol version 2. */
     823             : 1; /* VBox <= 4.3:     Protocol version 1. */
     824        /* Build revision is ignored. */
     825#endif
     826
     827        LogFlowThisFunc(("uVerAdditions=%RU32 (%RU32.%RU32)\n", uVerAdditions, uVBoxMajor, uVBoxMinor));
     828        rc = VINF_SUCCESS;
     829    }
     830    else
     831    {
     832        uVer = 1; /* Fallback. */
     833        rc = VERR_NOT_FOUND;
     834    }
     835
     836    LogFlowThisFunc(("uVer=%RU32, uVerAdditions=%RU32, rc=%Rrc\n", uVer, uVerAdditions, rc));
     837
     838    *puVersion = uVer;
     839    return rc;
     840}
     841
     842#if 0
     843/**
     844 * Returns back information (message type + parameter count) of the current message in
     845 * the local outgoing message queue.
     846 *
     847 * @return  IPRT status code.
     848 * @param   pThis
     849 * @param   puMsg
     850 * @param   pcParms
     851 * @param   paParms
     852 */
     853/* static */
     854DECLCALLBACK(int) GuestDnDBase::i_getNextMsgCallback(GuestDnDBase *pThis, uint32_t *puMsg,
     855                                                     uint32_t *pcParms, PVBOXHGCMSVCPARM paParms)
     856{
     857    AssertPtrReturn(pThis,   VERR_INVALID_POINTER);
     858    AssertPtrReturn(puMsg,   VERR_INVALID_POINTER);
     859    AssertPtrReturn(pcParms, VERR_INVALID_POINTER);
     860    AssertPtrReturn(paParms, VERR_INVALID_POINTER);
     861
     862    if (pThis->mData.m_lstOutgoing.empty())
     863        return VERR_NO_DATA;
     864
     865    GuestDnDMsg *pMsg = pThis->mData.m_lstOutgoing.front();
     866    AssertPtr(pMsg);
     867
     868    *puMsg   = pMsg->uMsg;
     869    *pcParms = pMsg->cParms;
     870
     871    return VINF_SUCCESS;
     872}
     873#endif
    880874#endif /* VBOX_WITH_DRAG_AND_DROP */
    881875
  • trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp

    r55180 r55422  
    55
    66/*
    7  * Copyright (C) 2014 Oracle Corporation
     7 * Copyright (C) 2014-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2727#include "AutoCaller.h"
    2828
     29#include <memory>    /* For unique_ptr, seee #7179. */
     30
     31#include <iprt/dir.h>
     32#include <iprt/file.h>
     33#include <iprt/path.h>
     34
    2935#include <iprt/cpp/utils.h> /* For unconst(). */
    3036
     
    3945#include <VBox/log.h>
    4046
     47/**
     48 * Base class for a source task.
     49 */
     50class GuestDnDSourceTask
     51{
     52public:
     53
     54    GuestDnDSourceTask(GuestDnDSource *pSource)
     55        : mSource(pSource),
     56          mRC(VINF_SUCCESS) { }
     57
     58    virtual ~GuestDnDSourceTask(void) { }
     59
     60    int getRC(void) const { return mRC; }
     61    bool isOk(void) const { return RT_SUCCESS(mRC); }
     62    const ComObjPtr<GuestDnDSource> &getSource(void) const { return mSource; }
     63
     64protected:
     65
     66    const ComObjPtr<GuestDnDSource>     mSource;
     67    int                                 mRC;
     68};
     69
     70/**
     71 * Task structure for receiving data from a source using
     72 * a worker thread.
     73 */
     74class RecvDataTask : public GuestDnDSourceTask
     75{
     76public:
     77
     78    RecvDataTask(GuestDnDSource *pSource, PRECVDATACTX pCtx)
     79        : GuestDnDSourceTask(pSource)
     80        , mpCtx(pCtx) { }
     81
     82    virtual ~RecvDataTask(void)
     83    {
     84        if (mpCtx)
     85        {
     86            delete mpCtx;
     87            mpCtx = NULL;
     88        }
     89    }
     90
     91    PRECVDATACTX getCtx(void) { return mpCtx; }
     92
     93protected:
     94
     95    /** Pointer to receive data context. */
     96    PRECVDATACTX mpCtx;
     97};
    4198
    4299// constructor / destructor
     
    95152/////////////////////////////////////////////////////////////////////////////
    96153
    97 HRESULT GuestDnDSource::isFormatSupported(const com::Utf8Str &aFormat,
    98                                           BOOL *aSupported)
     154HRESULT GuestDnDSource::isFormatSupported(const com::Utf8Str &aFormat, BOOL *aSupported)
    99155{
    100156#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
     
    107163    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    108164
    109     return GuestDnDBase::isFormatSupported(aFormat, aSupported);
     165    return GuestDnDBase::i_isFormatSupported(aFormat, aSupported);
    110166#endif /* VBOX_WITH_DRAG_AND_DROP */
    111167}
     
    122178    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    123179
    124     return GuestDnDBase::getFormats(aFormats);
     180    return GuestDnDBase::i_getFormats(aFormats);
    125181#endif /* VBOX_WITH_DRAG_AND_DROP */
    126182}
     
    137193    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    138194
    139     return GuestDnDBase::addFormats(aFormats);
     195    return GuestDnDBase::i_addFormats(aFormats);
    140196#endif /* VBOX_WITH_DRAG_AND_DROP */
    141197}
     
    152208    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    153209
    154     return GuestDnDBase::removeFormats(aFormats);
     210    return GuestDnDBase::i_removeFormats(aFormats);
     211#endif /* VBOX_WITH_DRAG_AND_DROP */
     212}
     213
     214HRESULT GuestDnDSource::getProtocolVersion(ULONG *aProtocolVersion)
     215{
     216#if !defined(VBOX_WITH_DRAG_AND_DROP)
     217    ReturnComNotImplemented();
     218#else /* VBOX_WITH_DRAG_AND_DROP */
     219
     220    AutoCaller autoCaller(this);
     221    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     222
     223    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     224
     225    return GuestDnDBase::i_getProtocolVersion(aProtocolVersion);
    155226#endif /* VBOX_WITH_DRAG_AND_DROP */
    156227}
     
    171242    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    172243
     244    /* Determine guest DnD protocol to use. */
     245    GuestDnDBase::getProtocolVersion(&mData.mProtocolVersion);
     246
    173247    /* Default is ignoring the action. */
    174248    DnDAction_T defaultAction = DnDAction_Ignore;
     
    180254    paParms[i++].setUInt32(uScreenId);
    181255
    182     int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_GH_REQ_PENDING,
    183                                       i, paParms);
     256    int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_GH_REQ_PENDING, i, paParms);
    184257    if (RT_SUCCESS(rc))
    185258    {
     
    210283    if (RT_FAILURE(rc))
    211284        hr = setError(VBOX_E_IPRT_ERROR,
    212                       tr("Unable to retrieve pending status (%Rrc)\n"), rc);
     285                      tr("Unable to retrieve drag'n drop pending status (%Rrc)\n"), rc);
    213286
    214287    LogFlowFunc(("hr=%Rhrc, defaultAction=0x%x\n", hr, defaultAction));
     
    238311    HRESULT hr = S_OK;
    239312
    240     const char *pcszFormat = aFormat.c_str();
    241     bool fNeedsDropDir = DnDMIMENeedsDropDir(pcszFormat, strlen(pcszFormat));
    242     LogFlowFunc(("strFormat=%s, uAction=0x%x, fNeedsDropDir=%RTbool\n",
    243                  pcszFormat, uAction, fNeedsDropDir));
    244 
     313    /* Note: At the moment we only support one response at a time. */
    245314    GuestDnDResponse *pResp = GuestDnDInst()->response();
    246315    if (pResp)
    247316    {
    248         /* Reset any old data. */
    249         pResp->reset();
    250317        pResp->resetProgress(m_pGuest);
    251318
    252         /* Set the format we are going to retrieve to have it around
    253          * when retrieving the data later. */
    254         pResp->setFormat(aFormat);
    255 
    256         if (fNeedsDropDir)
    257         {
    258             char szDropDir[RTPATH_MAX];
    259             int rc = DnDDirCreateDroppedFiles(szDropDir, sizeof(szDropDir));
    260             LogFlowFunc(("rc=%Rrc, szDropDir=%s\n", rc, szDropDir));
    261             if (RT_FAILURE(rc))
    262                 return setError(VBOX_E_IPRT_ERROR,
    263                                 tr("Unable to create the temporary drag and drop directory \"%s\" (%Rrc)\n"),
    264                                 szDropDir, rc);
    265 
    266             pResp->setDropDir(szDropDir);
    267         }
    268 
    269         VBOXHGCMSVCPARM paParms[4];
    270         int i = 0;
    271         paParms[i++].setPointer((void*)aFormat.c_str(), (uint32_t)aFormat.length() + 1);
    272         paParms[i++].setUInt32((uint32_t)aFormat.length() + 1);
    273         paParms[i++].setUInt32(uAction);
    274 
    275         int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_GH_EVT_DROPPED,
    276                                           i, paParms);
    277         if (RT_SUCCESS(rc))
    278         {
    279             /* Query the progress object to the caller. */
    280             pResp->queryProgressTo(aProgress.asOutParam());
    281         }
    282         else
    283             hr = setError(VBOX_E_IPRT_ERROR,
    284                           tr("Error signalling to drop data (%Rrc)\n"), rc);
    285     }
     319        int rc;
     320
     321        try
     322        {
     323            PRECVDATACTX pRecvCtx = new RECVDATACTX;
     324            RT_BZERO(pRecvCtx, sizeof(RECVDATACTX));
     325
     326            pRecvCtx->mpSource  = this;
     327            pRecvCtx->mpResp    = pResp;
     328            pRecvCtx->mFormat   = aFormat;
     329
     330            std::unique_ptr <RecvDataTask> pTask(new RecvDataTask(this, pRecvCtx));
     331            AssertReturn(pTask->isOk(), pTask->getRC());
     332
     333            rc = RTThreadCreate(NULL, GuestDnDSource::i_receiveDataThread,
     334                                (void *)pTask.get(), 0, RTTHREADTYPE_MAIN_WORKER, 0, "dndSrcRcvData");
     335            if (RT_SUCCESS(rc))
     336            {
     337                hr = pResp->queryProgressTo(aProgress.asOutParam());
     338                ComAssertComRC(hr);
     339
     340                /* pTask is now owned by i_receiveDataThread(), so release it. */
     341                pTask.release();
     342            }
     343            else if (pRecvCtx)
     344                delete pRecvCtx;
     345        }
     346        catch(std::bad_alloc &)
     347        {
     348            rc = VERR_NO_MEMORY;
     349        }
     350
     351        /*if (RT_FAILURE(vrc)) @todo SetError(...) */
     352    }
     353    /** @todo SetError(...) */
    286354
    287355    LogFlowFunc(("Returning hr=%Rhrc\n", hr));
     
    313381
    314382            Utf8Str strFormat = pResp->format();
    315             LogFlowFunc(("strFormat=%s, cbData=%zu, pvData=0x%p\n",
    316                          strFormat.c_str(), cbData, pvData));
     383            LogFlowFunc(("strFormat=%s, cbData=%zu, pvData=0x%p\n", strFormat.c_str(), cbData, pvData));
    317384
    318385            try
     
    329396                        size_t cbURIs = strURIs.length();
    330397
    331                         LogFlowFunc(("Found %zu root URIs (%zu bytes)\n",
    332                                      lstURI.RootCount(), cbURIs));
     398                        LogFlowFunc(("Found %zu root URIs (%zu bytes)\n", lstURI.RootCount(), cbURIs));
    333399
    334400                        aData.resize(cbURIs + 1 /* Include termination */);
     
    362428}
    363429
     430// implementation of internal methods.
     431/////////////////////////////////////////////////////////////////////////////
     432
     433#ifdef VBOX_WITH_DRAG_AND_DROP_GH
     434int GuestDnDSource::i_onReceiveData(PRECVDATACTX pCtx, const void *pvData, uint32_t cbData, uint64_t cbTotalSize)
     435{
     436    AssertPtrReturn(pCtx,     VERR_INVALID_POINTER);
     437    AssertPtrReturn(pvData,   VERR_INVALID_POINTER);
     438    AssertReturn(cbData,      VERR_INVALID_PARAMETER);
     439    AssertReturn(cbTotalSize, VERR_INVALID_PARAMETER);
     440
     441    LogFlowFunc(("cbData=%RU32, cbTotalSize=%RU64\n", cbData, cbTotalSize));
     442
     443    int rc = VINF_SUCCESS;
     444
     445    try
     446    {
     447        if (   cbData > cbTotalSize
     448            || cbData > _64K) /** @todo Make this configurable? */
     449        {
     450            LogFlowFunc(("Data sizes invalid: cbData=%RU32, cbTotalSize=%RU64\n", cbData, cbTotalSize));
     451            rc = VERR_INVALID_PARAMETER;
     452        }
     453        else if (cbData < pCtx->mData.size())
     454        {
     455            AssertMsgFailed(("New size (%RU64) is smaller than current size (%zu)\n", cbTotalSize, pCtx->mData.size()));
     456            rc = VERR_INVALID_PARAMETER;
     457        }
     458
     459        if (RT_SUCCESS(rc))
     460        {
     461            pCtx->mData.insert(pCtx->mData.begin(), (BYTE *)pvData, (BYTE *)pvData + cbData);
     462
     463            LogFlowFunc(("mDataSize=%zu\n", pCtx->mData.size()));
     464
     465            /* Data transfer complete? */
     466            Assert(cbData <= pCtx->mData.size());
     467            if (cbData == pCtx->mData.size())
     468            {
     469                bool fHasURIList = DnDMIMENeedsDropDir(pCtx->mFormat.c_str(), pCtx->mFormat.length());
     470                if (fHasURIList)
     471                {
     472                    LogFlowFunc(("Parsing URI data ...\n"));
     473
     474                    /* Try parsing the data as URI list. */
     475                    rc = pCtx->mURI.lstURI.RootFromURIData(&pCtx->mData[0], pCtx->mData.size(), 0 /* uFlags */);
     476                    if (RT_SUCCESS(rc))
     477                    {
     478                        pCtx->mURI.cbProcessed = 0;
     479                        pCtx->mURI.cbToProcess = cbTotalSize;
     480                    }
     481                }
     482            }
     483        }
     484    }
     485    catch (std::bad_alloc &)
     486    {
     487        rc = VERR_NO_MEMORY;
     488    }
     489
     490    LogFlowFuncLeaveRC(rc);
     491    return rc;
     492}
     493
     494int GuestDnDSource::i_onReceiveDir(PRECVDATACTX pCtx, const char *pszPath, uint32_t cbPath, uint32_t fMode)
     495{
     496    AssertPtrReturn(pCtx,    VERR_INVALID_POINTER);
     497    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
     498    AssertReturn(cbPath,     VERR_INVALID_PARAMETER);
     499
     500    LogFlowFunc(("pszPath=%s, cbPath=%zu, fMode=0x%x\n", pszPath, cbPath, fMode));
     501
     502    int rc;
     503    char *pszDir = RTPathJoinA(pCtx->mURI.strDropDir.c_str(), pszPath);
     504    if (pszDir)
     505    {
     506        rc = RTDirCreateFullPath(pszDir, fMode);
     507        RTStrFree(pszDir);
     508    }
     509    else
     510         rc = VERR_NO_MEMORY;
     511
     512    LogFlowFuncLeaveRC(rc);
     513    return rc;
     514}
     515
     516int GuestDnDSource::i_onReceiveFileHdr(PRECVDATACTX pCtx, const char *pszPath, uint32_t cbPath,
     517                                       uint64_t cbSize, uint32_t fMode, uint32_t fFlags)
     518{
     519    AssertPtrReturn(pCtx,    VERR_INVALID_POINTER);
     520    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
     521    AssertReturn(cbPath,     VERR_INVALID_PARAMETER);
     522    AssertReturn(fMode,      VERR_INVALID_PARAMETER);
     523    /* fFlags are optional. */
     524
     525    LogFlowFunc(("pszPath=%s, cbPath=%RU32, cbSize=%RU64, fMode=0x%x, fFlags=0x%x\n", pszPath, cbPath, cbSize, fMode, fFlags));
     526
     527    int rc = VINF_SUCCESS;
     528
     529    do
     530    {
     531        if (!pCtx->mURI.objURI.IsComplete())
     532        {
     533            LogFlowFunc(("Warning: Object \"%s\" not complete yet\n", pCtx->mURI.objURI.GetDestPath().c_str()));
     534            rc = VERR_INVALID_PARAMETER;
     535            break;
     536        }
     537
     538        if (pCtx->mURI.objURI.IsOpen()) /* File already opened? */
     539        {
     540            LogFlowFunc(("Warning: Current opened object is \"%s\"\n", pCtx->mURI.objURI.GetDestPath().c_str()));
     541            rc = VERR_WRONG_ORDER;
     542            break;
     543        }
     544
     545        char pszPathAbs[RTPATH_MAX];
     546        rc = RTPathJoin(pszPathAbs, sizeof(pszPathAbs), pCtx->mURI.strDropDir.c_str(), pszPath);
     547        if (RT_FAILURE(rc))
     548        {
     549            LogFlowFunc(("Warning: Rebasing current file failed with rc=%Rrc\n", rc));
     550            break;
     551        }
     552
     553        rc = DnDPathSanitize(pszPathAbs, sizeof(pszPathAbs));
     554        if (RT_FAILURE(rc))
     555        {
     556            LogFlowFunc(("Warning: Rebasing current file failed with rc=%Rrc\n", rc));
     557            break;
     558        }
     559
     560        LogFunc(("Rebased to: %s\n", pszPathAbs));
     561
     562        /** @todo Add sparse file support based on fFlags? (Use Open(..., fFlags | SPARSE). */
     563        /** @todo Add fMode to opening flags. */
     564        rc = pCtx->mURI.objURI.OpenEx(pszPathAbs, DnDURIObject::File, DnDURIObject::Target,
     565                                      RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
     566        if (RT_SUCCESS(rc))
     567        {
     568            /** @todo Unescpae path before printing. */
     569            LogRel2(("DnD: Transferring file to host: %s\n", pCtx->mURI.objURI.GetDestPath().c_str()));
     570
     571            /* Note: Protocol v1 does not send any file sizes, so always 0. */
     572            if (mData.mProtocolVersion >= 2)
     573                rc = pCtx->mURI.objURI.SetSize(cbSize);
     574        }
     575
     576    } while (0);
     577
     578    LogFlowFuncLeaveRC(rc);
     579    return rc;
     580}
     581
     582int GuestDnDSource::i_onReceiveFileData(PRECVDATACTX pCtx, const void *pvData, uint32_t cbData)
     583{
     584    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     585    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     586    AssertReturn(cbData, VERR_INVALID_PARAMETER);
     587
     588    int rc = VINF_SUCCESS;
     589
     590    do
     591    {
     592        if (pCtx->mURI.objURI.IsComplete())
     593        {
     594            LogFlowFunc(("Warning: Object \"%s\" already completed\n", pCtx->mURI.objURI.GetDestPath().c_str()));
     595            rc = VERR_WRONG_ORDER;
     596            break;
     597        }
     598
     599        if (!pCtx->mURI.objURI.IsOpen()) /* File opened on host? */
     600        {
     601            LogFlowFunc(("Warning: Object \"%s\" not opened\n", pCtx->mURI.objURI.GetDestPath().c_str()));
     602            rc = VERR_WRONG_ORDER;
     603            break;
     604        }
     605
     606        uint32_t cbWritten;
     607        rc = pCtx->mURI.objURI.Write(pvData, cbData, &cbWritten);
     608        if (RT_SUCCESS(rc))
     609        {
     610            Assert(cbWritten <= cbData);
     611            if (cbWritten < cbData)
     612            {
     613                /** @todo What to do when the host's disk is full? */
     614                rc = VERR_DISK_FULL;
     615            }
     616        }
     617
     618        if (RT_SUCCESS(rc))
     619        {
     620            if (pCtx->mURI.objURI.IsComplete())
     621            {
     622                LogRel2(("DnD: File transfer to host complete: %s", pCtx->mURI.objURI.GetDestPath().c_str()));
     623                rc = VINF_EOF;
     624            }
     625        }
     626        else
     627            LogRel(("DnD: Error: Can't write guest file to host to \"%s\": %Rrc\n", pCtx->mURI.objURI.GetDestPath().c_str(), rc));
     628
     629    } while (0);
     630
     631    LogFlowFuncLeaveRC(rc);
     632    return rc;
     633}
     634#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
     635
     636int GuestDnDSource::i_receiveData(PRECVDATACTX pCtx)
     637{
     638    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     639
     640    int rc;
     641
     642    GuestDnD *pInst = GuestDnDInst();
     643    if (!pInst)
     644        return VERR_INVALID_POINTER;
     645
     646    GuestDnDResponse *pResp = pCtx->mpResp;
     647    AssertPtr(pCtx->mpResp);
     648
     649    ASMAtomicWriteBool(&pCtx->mIsActive, true);
     650
     651    /* Create event semaphore. */
     652    pCtx->SemEvent = NIL_RTSEMEVENT;
     653    rc = RTSemEventCreate(&pCtx->SemEvent);
     654    if (RT_FAILURE(rc))
     655        return rc;
     656
     657    pCtx->mURI.cbToProcess = 0;
     658    pCtx->mURI.cbProcessed = 0;
     659    pCtx->mURI.cProcessed  = 0;
     660
     661    do
     662    {
     663        /* Reset any old data. */
     664        pResp->reset();
     665        pResp->resetProgress(m_pGuest);
     666
     667        /* Set the format we are going to retrieve to have it around
     668         * when retrieving the data later. */
     669        pResp->setFormat(pCtx->mFormat);
     670
     671        bool fHasURIList = DnDMIMENeedsDropDir(pCtx->mFormat.c_str(), pCtx->mFormat.length());
     672        LogFlowFunc(("strFormat=%s, uAction=0x%x, fHasURIList=%RTbool\n", pCtx->mFormat.c_str(), pCtx->mAction, fHasURIList));
     673
     674        if (fHasURIList)
     675        {
     676            rc = i_receiveURIData(pCtx);
     677        }
     678        else
     679        {
     680            rc = i_receiveRawData(pCtx);
     681        }
     682
     683    } while (0);
     684
     685    if (pCtx->SemEvent != NIL_RTSEMEVENT)
     686    {
     687        RTSemEventDestroy(pCtx->SemEvent);
     688        pCtx->SemEvent = NIL_RTSEMEVENT;
     689    }
     690
     691    ASMAtomicWriteBool(&pCtx->mIsActive, false);
     692
     693    LogFlowFuncLeaveRC(rc);
     694    return rc;
     695}
     696
     697/* static */
     698DECLCALLBACK(int) GuestDnDSource::i_receiveDataThread(RTTHREAD Thread, void *pvUser)
     699{
     700    LogFlowFunc(("pvUser=%p\n", pvUser));
     701
     702    std::unique_ptr<RecvDataTask> pTask(static_cast<RecvDataTask*>(pvUser));
     703    AssertPtr(pTask.get());
     704
     705    const ComObjPtr<GuestDnDSource> pTarget(pTask->getSource());
     706    Assert(!pTarget.isNull());
     707
     708    AutoCaller autoCaller(pTarget);
     709    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     710
     711    int rc = pTarget->i_receiveData(pTask->getCtx());
     712    /* Nothing to do here anymore. */
     713
     714    LogFlowFunc(("pSource=%p returning rc=%Rrc\n", (GuestDnDSource *)pTarget, rc));
     715    return rc;
     716}
     717
     718int GuestDnDSource::i_receiveRawData(PRECVDATACTX pCtx)
     719{
     720    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     721
     722    int rc;
     723
     724    GuestDnDResponse *pResp = pCtx->mpResp;
     725    AssertPtr(pCtx->mpResp);
     726
     727    GuestDnD *pInst = GuestDnDInst();
     728    if (!pInst)
     729        return VERR_INVALID_POINTER;
     730
     731#define REGISTER_CALLBACK(x) \
     732    rc = pResp->setCallback(x, i_receiveRawDataCallback, pCtx); \
     733    if (RT_FAILURE(rc)) \
     734        return rc;
     735
     736#define UNREGISTER_CALLBACK(x) \
     737    rc = pCtx->mpResp->setCallback(x, NULL); \
     738    AssertRC(rc);
     739
     740    /*
     741     * Register callbacks.
     742     */
     743    /* Guest callbacks. */
     744    REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DATA);
     745
     746    do
     747    {
     748        /*
     749         * Receive the raw data.
     750         */
     751        GuestDnDMsg Msg;
     752        Msg.setType(DragAndDropSvc::HOST_DND_GH_EVT_DROPPED);
     753        Msg.setNextPointer((void*)pCtx->mFormat.c_str(), (uint32_t)pCtx->mFormat.length() + 1);
     754        Msg.setNextUInt32((uint32_t)pCtx->mFormat.length() + 1);
     755        Msg.setNextUInt32(pCtx->mAction);
     756
     757        /* Make the initial call to the guest by telling that we initiated the "dropped" event on
     758         * the host and therefore now waiting for the actual raw data. */
     759        rc = pInst->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
     760        if (RT_SUCCESS(rc))
     761        {
     762            /*
     763             * Wait until our callback i_receiveRawDataCallback triggered the
     764             * wait event.
     765             */
     766            LogFlowFunc(("Waiting for raw data callback ...\n"));
     767            rc = RTSemEventWait(pCtx->SemEvent, RT_INDEFINITE_WAIT);
     768            LogFlowFunc(("Raw data callback done\n"));
     769        }
     770
     771    } while (0);
     772
     773    /*
     774     * Unregister callbacks.
     775     */
     776    UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DATA);
     777
     778#undef REGISTER_CALLBACK
     779#undef UNREGISTER_CALLBACK
     780
     781    LogFlowFuncLeaveRC(rc);
     782    return rc;
     783}
     784
     785int GuestDnDSource::i_receiveURIData(PRECVDATACTX pCtx)
     786{
     787    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     788
     789    int rc;
     790
     791    GuestDnDResponse *pResp = pCtx->mpResp;
     792    AssertPtr(pCtx->mpResp);
     793
     794    GuestDnD *pInst = GuestDnDInst();
     795    if (!pInst)
     796        return VERR_INVALID_POINTER;
     797
     798#define REGISTER_CALLBACK(x) \
     799    rc = pResp->setCallback(x, i_receiveURIDataCallback, pCtx); \
     800    if (RT_FAILURE(rc)) \
     801        return rc;
     802
     803#define UNREGISTER_CALLBACK(x) \
     804    rc = pResp->setCallback(x, NULL); \
     805    AssertRC(rc);
     806
     807    /*
     808     * Register callbacks.
     809     */
     810    /* Guest callbacks. */
     811    REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DATA);
     812    REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DIR);
     813    if (mData.mProtocolVersion >= 2)
     814        REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR);
     815    REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA);
     816
     817    do
     818    {
     819        char szDropDir[RTPATH_MAX];
     820        rc = DnDDirCreateDroppedFiles(szDropDir, sizeof(szDropDir));
     821        LogFlowFunc(("rc=%Rrc, szDropDir=%s\n", rc, szDropDir));
     822        if (RT_FAILURE(rc))
     823            break;
     824
     825        pCtx->mURI.strDropDir = szDropDir; /** @todo Keep directory handle open? */
     826        pResp->setDropDir(szDropDir);
     827
     828        /*
     829         * Receive the URI list.
     830         */
     831        GuestDnDMsg Msg;
     832        Msg.setType(DragAndDropSvc::HOST_DND_GH_EVT_DROPPED);
     833        Msg.setNextPointer((void*)pCtx->mFormat.c_str(), (uint32_t)pCtx->mFormat.length() + 1);
     834        Msg.setNextUInt32((uint32_t)pCtx->mFormat.length() + 1);
     835        Msg.setNextUInt32(pCtx->mAction);
     836
     837        /* Make the initial call to the guest by telling that we initiated the "dropped" event on
     838         * the host and therefore now waiting for the actual URI actual data. */
     839        rc = pInst->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
     840        if (RT_SUCCESS(rc))
     841        {
     842            /*
     843             * Wait until our callback i_receiveURIDataCallback triggered the
     844             * wait event.
     845             */
     846            LogFlowFunc(("Waiting for URI callback ...\n"));
     847            rc = RTSemEventWait(pCtx->SemEvent, RT_INDEFINITE_WAIT);
     848            LogFlowFunc(("URI callback done, rc=%Rrc\n", rc));
     849        }
     850
     851    } while (0);
     852
     853    /*
     854     * Unregister callbacks.
     855     */
     856    UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DATA);
     857    UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DIR);
     858    if (mData.mProtocolVersion >= 2)
     859        UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR);
     860    UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA);
     861
     862#undef REGISTER_CALLBACK
     863#undef UNREGISTER_CALLBACK
     864
     865    if (RT_FAILURE(rc))
     866    {
     867        LogFlowFunc(("Rolling back ...\n"));
     868
     869        /* Rollback by removing any stuff created. */
     870        for (size_t i = 0; i < pCtx->mURI.lstFiles.size(); ++i)
     871            RTFileDelete(pCtx->mURI.lstFiles.at(i).c_str());
     872        for (size_t i = 0; i < pCtx->mURI.lstDirs.size(); ++i)
     873            RTDirRemove(pCtx->mURI.lstDirs.at(i).c_str());
     874    }
     875
     876    /* Try removing (hopefully) empty drop directory in any case. */
     877    if (pCtx->mURI.strDropDir.isNotEmpty())
     878        RTDirRemove(pCtx->mURI.strDropDir.c_str());
     879
     880    LogFlowFuncLeaveRC(rc);
     881    return rc;
     882}
     883
     884/* static */
     885DECLCALLBACK(int) GuestDnDSource::i_receiveRawDataCallback(uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser)
     886{
     887    PRECVDATACTX pCtx = (PRECVDATACTX)pvUser;
     888    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     889
     890    GuestDnDSource *pThis = pCtx->mpSource;
     891    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
     892
     893    LogFlowFunc(("pThis=%p, uMsg=%RU32\n", pThis, uMsg));
     894
     895    int rc = VINF_SUCCESS;
     896
     897    switch (uMsg)
     898    {
     899        case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
     900        {
     901            DragAndDropSvc::PVBOXDNDCBSNDDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDDATADATA>(pvParms);
     902            AssertPtr(pCBData);
     903            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDDATADATA) == cbParms, VERR_INVALID_PARAMETER);
     904            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     905
     906            rc = pThis->i_onReceiveData(pCtx, pCBData->pvData, pCBData->cbData, pCBData->cbTotalSize);
     907            break;
     908        }
     909        case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
     910        {
     911            DragAndDropSvc::PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBEVTERRORDATA>(pvParms);
     912            AssertPtr(pCBData);
     913            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER);
     914            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     915
     916            /* Cleanup. */
     917            pCtx->mpResp->reset();
     918            rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, pCBData->rc);
     919            break;
     920        }
     921        default:
     922            rc = VERR_NOT_SUPPORTED;
     923            break;
     924    }
     925
     926    if (RT_FAILURE(rc))
     927    {
     928        if (pCtx->SemEvent != NIL_RTSEMEVENT)
     929        {
     930            LogFlowFunc(("Signalling ...\n"));
     931            int rc2 = RTSemEventSignal(pCtx->SemEvent);
     932            AssertRC(rc2);
     933        }
     934    }
     935
     936    LogFlowFuncLeaveRC(rc);
     937    return rc; /* Tell the guest. */
     938}
     939
     940/* static */
     941DECLCALLBACK(int) GuestDnDSource::i_receiveURIDataCallback(uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser)
     942{
     943    PRECVDATACTX pCtx = (PRECVDATACTX)pvUser;
     944    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     945
     946    GuestDnDSource *pThis = pCtx->mpSource;
     947    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
     948
     949    LogFlowFunc(("pThis=%p, uMsg=%RU32\n", pThis, uMsg));
     950
     951    int rc = VINF_SUCCESS;
     952
     953    switch (uMsg)
     954    {
     955        case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
     956        {
     957            DragAndDropSvc::PVBOXDNDCBSNDDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDDATADATA>(pvParms);
     958            AssertPtr(pCBData);
     959            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDDATADATA) == cbParms, VERR_INVALID_PARAMETER);
     960            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     961
     962            rc = pThis->i_onReceiveData(pCtx, pCBData->pvData, pCBData->cbData, pCBData->cbTotalSize);
     963            break;
     964        }
     965        case DragAndDropSvc::GUEST_DND_GH_SND_DIR:
     966        {
     967            DragAndDropSvc::PVBOXDNDCBSNDDIRDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDDIRDATA>(pvParms);
     968            AssertPtr(pCBData);
     969            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDDIRDATA) == cbParms, VERR_INVALID_PARAMETER);
     970            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DIR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     971
     972            rc = pThis->i_onReceiveDir(pCtx, pCBData->pszPath, pCBData->cbPath, pCBData->fMode);
     973            break;
     974        }
     975        case DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR:
     976        {
     977            DragAndDropSvc::PVBOXDNDCBSNDFILEHDRDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDFILEHDRDATA>(pvParms);
     978            AssertPtr(pCBData);
     979            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDFILEHDRDATA) == cbParms, VERR_INVALID_PARAMETER);
     980            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_HDR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     981
     982            rc = pThis->i_onReceiveFileHdr(pCtx, pCBData->pszFilePath, pCBData->cbFilePath,
     983                                           pCBData->cbSize, pCBData->fMode, pCBData->fFlags);
     984            break;
     985        }
     986        case DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA:
     987        {
     988            DragAndDropSvc::PVBOXDNDCBSNDFILEDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDFILEDATADATA>(pvParms);
     989            AssertPtr(pCBData);
     990            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDFILEDATADATA) == cbParms, VERR_INVALID_PARAMETER);
     991            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     992
     993            if (pThis->mData.mProtocolVersion <= 1)
     994            {
     995                /**
     996                 * Notes for protocol v1 (< VBox 5.0):
     997                 * - Every time this command is being sent it includes the file header,
     998                 *   so just process both calls here.
     999                 * - There was no information whatsoever about the total file size; the old code only
     1000                 *   appended data to the desired file. So just pass 0 as cbSize.
     1001                 */
     1002                rc = pThis->i_onReceiveFileHdr(pCtx,
     1003                                               pCBData->u.v1.pszFilePath, pCBData->u.v1.cbFilePath,
     1004                                               0 /* cbSize */, pCBData->u.v1.fMode, 0 /* fFlags */);
     1005                if (RT_SUCCESS(rc))
     1006                    rc = pThis->i_onReceiveFileData(pCtx, pCBData->pvData, pCBData->cbData);
     1007            }
     1008            else /* Protocol v2 and up. */
     1009                rc = pThis->i_onReceiveFileData(pCtx, pCBData->pvData, pCBData->cbData);
     1010
     1011            /* Current file done? */
     1012            if (rc == VINF_EOF)
     1013            {
     1014                /* Remove it from the list. */
     1015                pCtx->mURI.lstURI.RemoveFirst();
     1016
     1017                if (pCtx->mURI.lstURI.IsEmpty()) /* Current file processed? Check if there's more. */
     1018                {
     1019                    /* Let waiters know. */
     1020                    if (pCtx->SemEvent != NIL_RTSEMEVENT)
     1021                    {
     1022                        LogFlowFunc(("Signalling ...\n"));
     1023                        int rc2 = RTSemEventSignal(pCtx->SemEvent);
     1024                        AssertRC(rc2);
     1025                    }
     1026                }
     1027            }
     1028            break;
     1029        }
     1030        case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
     1031        {
     1032            DragAndDropSvc::PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBEVTERRORDATA>(pvParms);
     1033            AssertPtr(pCBData);
     1034            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER);
     1035            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1036
     1037            /* Cleanup. */
     1038            pCtx->mpResp->reset();
     1039            rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, pCBData->rc);
     1040            break;
     1041        }
     1042        default:
     1043            rc = VERR_NOT_SUPPORTED;
     1044            break;
     1045    }
     1046
     1047    if (RT_FAILURE(rc))
     1048    {
     1049        if (pCtx->SemEvent != NIL_RTSEMEVENT)
     1050        {
     1051            LogFlowFunc(("Signalling ...\n"));
     1052            int rc2 = RTSemEventSignal(pCtx->SemEvent);
     1053            AssertRC(rc2);
     1054        }
     1055    }
     1056
     1057    LogFlowFuncLeaveRC(rc);
     1058    return rc; /* Tell the guest. */
     1059}
     1060
  • trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp

    r55244 r55422  
    55
    66/*
    7  * Copyright (C) 2014 Oracle Corporation
     7 * Copyright (C) 2014-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2222#include "GuestImpl.h"
    2323#include "GuestDnDTargetImpl.h"
     24#include "VirtualBoxErrorInfoImpl.h"
    2425
    2526#include "Global.h"
     
    2728
    2829#include <algorithm> /* For std::find(). */
     30#include <memory>    /* For unique_ptr, see #7179. */
     31
     32#include <iprt/file.h>
     33#include <iprt/dir.h>
     34#include <iprt/path.h>
     35#include <iprt/uri.h>
    2936#include <iprt/cpp/utils.h> /* For unconst(). */
    3037
    3138#include <VBox/com/array.h>
    32 #include <VBox/HostServices/DragAndDropSvc.h>
     39
     40#include <VBox/GuestHost/DragAndDrop.h>
     41#include <VBox/HostServices/Service.h>
    3342
    3443#ifdef LOG_GROUP
     
    3948
    4049
     50/**
     51 * Base class for a target task.
     52 */
     53class GuestDnDTargetTask
     54{
     55public:
     56
     57    GuestDnDTargetTask(GuestDnDTarget *pTarget)
     58        : mTarget(pTarget),
     59          mRC(VINF_SUCCESS) { }
     60
     61    virtual ~GuestDnDTargetTask(void) { }
     62
     63    int getRC(void) const { return mRC; }
     64    bool isOk(void) const { return RT_SUCCESS(mRC); }
     65    const ComObjPtr<GuestDnDTarget> &getTarget(void) const { return mTarget; }
     66
     67protected:
     68
     69    const ComObjPtr<GuestDnDTarget>     mTarget;
     70    int                                 mRC;
     71};
     72
     73/**
     74 * Task structure for sending data to a target using
     75 * a worker thread.
     76 */
     77class SendDataTask : public GuestDnDTargetTask
     78{
     79public:
     80
     81    SendDataTask(GuestDnDTarget *pTarget, PSENDDATACTX pCtx)
     82        : GuestDnDTargetTask(pTarget),
     83          mpCtx(pCtx) { }
     84
     85    virtual ~SendDataTask(void)
     86    {
     87        if (mpCtx)
     88        {
     89            delete mpCtx;
     90            mpCtx = NULL;
     91        }
     92    }
     93
     94
     95    PSENDDATACTX getCtx(void) { return mpCtx; }
     96
     97protected:
     98
     99    /** Pointer to send data context. */
     100    PSENDDATACTX mpCtx;
     101};
     102
    41103// constructor / destructor
    42104/////////////////////////////////////////////////////////////////////////////
     
    46108HRESULT GuestDnDTarget::FinalConstruct(void)
    47109{
     110    /* Set the maximum block size our guests can handle to 64K. This always has
     111     * been hardcoded until now. */
     112    /* Note: Never ever rely on information from the guest; the host dictates what and
     113     *       how to do something, so try to negogiate a sensible value here later. */
     114    m_cbBlockSize = _32K; /** @todo Make this configurable. */
     115
    48116    LogFlowThisFunc(("\n"));
    49117    return BaseFinalConstruct();
     
    94162/////////////////////////////////////////////////////////////////////////////
    95163
    96 HRESULT GuestDnDTarget::isFormatSupported(const com::Utf8Str &aFormat,
    97                                           BOOL *aSupported)
    98 {
    99 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
     164HRESULT GuestDnDTarget::isFormatSupported(const com::Utf8Str &aFormat, BOOL *aSupported)
     165{
     166#if !defined(VBOX_WITH_DRAG_AND_DROP)
    100167    ReturnComNotImplemented();
    101168#else /* VBOX_WITH_DRAG_AND_DROP */
     
    106173    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    107174
    108     return GuestDnDBase::isFormatSupported(aFormat, aSupported);
     175    return GuestDnDBase::i_isFormatSupported(aFormat, aSupported);
    109176#endif /* VBOX_WITH_DRAG_AND_DROP */
    110177}
     
    112179HRESULT GuestDnDTarget::getFormats(std::vector<com::Utf8Str> &aFormats)
    113180{
    114 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
     181#if !defined(VBOX_WITH_DRAG_AND_DROP)
    115182    ReturnComNotImplemented();
    116183#else /* VBOX_WITH_DRAG_AND_DROP */
     
    121188    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    122189
    123     return GuestDnDBase::getFormats(aFormats);
     190    return GuestDnDBase::i_getFormats(aFormats);
    124191#endif /* VBOX_WITH_DRAG_AND_DROP */
    125192}
     
    127194HRESULT GuestDnDTarget::addFormats(const std::vector<com::Utf8Str> &aFormats)
    128195{
    129 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
     196#if !defined(VBOX_WITH_DRAG_AND_DROP)
    130197    ReturnComNotImplemented();
    131198#else /* VBOX_WITH_DRAG_AND_DROP */
     
    136203    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    137204
    138     return GuestDnDBase::addFormats(aFormats);
     205    return GuestDnDBase::i_addFormats(aFormats);
    139206#endif /* VBOX_WITH_DRAG_AND_DROP */
    140207}
     
    142209HRESULT GuestDnDTarget::removeFormats(const std::vector<com::Utf8Str> &aFormats)
    143210{
    144 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
     211#if !defined(VBOX_WITH_DRAG_AND_DROP)
    145212    ReturnComNotImplemented();
    146213#else /* VBOX_WITH_DRAG_AND_DROP */
     
    151218    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    152219
    153     return GuestDnDBase::removeFormats(aFormats);
     220    return GuestDnDBase::i_removeFormats(aFormats);
     221#endif /* VBOX_WITH_DRAG_AND_DROP */
     222}
     223
     224HRESULT GuestDnDTarget::getProtocolVersion(ULONG *aProtocolVersion)
     225{
     226#if !defined(VBOX_WITH_DRAG_AND_DROP)
     227    ReturnComNotImplemented();
     228#else /* VBOX_WITH_DRAG_AND_DROP */
     229
     230    AutoCaller autoCaller(this);
     231    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     232
     233    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     234
     235    return GuestDnDBase::i_getProtocolVersion(aProtocolVersion);
    154236#endif /* VBOX_WITH_DRAG_AND_DROP */
    155237}
     
    164246                              DnDAction_T *aResultAction)
    165247{
    166 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
     248#if !defined(VBOX_WITH_DRAG_AND_DROP)
    167249    ReturnComNotImplemented();
    168250#else /* VBOX_WITH_DRAG_AND_DROP */
     
    178260    AutoCaller autoCaller(this);
    179261    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     262
     263    /* Determine guest DnD protocol to use. */
     264    GuestDnDBase::getProtocolVersion(&mData.mProtocolVersion);
    180265
    181266    /* Default action is ignoring. */
     
    237322                             DnDAction_T *aResultAction)
    238323{
    239 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
     324#if !defined(VBOX_WITH_DRAG_AND_DROP)
    240325    ReturnComNotImplemented();
    241326#else /* VBOX_WITH_DRAG_AND_DROP */
     
    299384HRESULT GuestDnDTarget::leave(ULONG uScreenId)
    300385{
    301 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
     386#if !defined(VBOX_WITH_DRAG_AND_DROP)
    302387    ReturnComNotImplemented();
    303388#else /* VBOX_WITH_DRAG_AND_DROP */
     
    327412                             com::Utf8Str &aFormat, DnDAction_T *aResultAction)
    328413{
    329 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
     414#if !defined(VBOX_WITH_DRAG_AND_DROP)
    330415    ReturnComNotImplemented();
    331416#else /* VBOX_WITH_DRAG_AND_DROP */
     
    395480}
    396481
    397 HRESULT GuestDnDTarget::sendData(ULONG aScreenId,
    398                                  const com::Utf8Str &aFormat,
    399                                  const std::vector<BYTE> &aData,
     482/* static */
     483DECLCALLBACK(int) GuestDnDTarget::i_sendDataThread(RTTHREAD Thread, void *pvUser)
     484{
     485    LogFlowFunc(("pvUser=%p\n", pvUser));
     486
     487    std::unique_ptr<SendDataTask> pTask(static_cast<SendDataTask*>(pvUser));
     488    AssertPtr(pTask.get());
     489
     490    const ComObjPtr<GuestDnDTarget> pTarget(pTask->getTarget());
     491    Assert(!pTarget.isNull());
     492
     493    AutoCaller autoCaller(pTarget);
     494    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     495
     496    int rc = pTarget->i_sendData(pTask->getCtx());
     497    /* Nothing to do here anymore. */
     498
     499    LogFlowFunc(("pTarget=%p returning rc=%Rrc\n", (GuestDnDTarget *)pTarget, rc));
     500    return rc;
     501}
     502
     503/**
     504 * Initiates a data transfer from the host to the guest. The source is the host whereas the target is the
     505 * guest in this case.
     506 *
     507 * @return  HRESULT
     508 * @param   aScreenId
     509 * @param   aFormat
     510 * @param   aData
     511 * @param   aProgress
     512 */
     513HRESULT GuestDnDTarget::sendData(ULONG aScreenId, const com::Utf8Str &aFormat, const std::vector<BYTE> &aData,
    400514                                 ComPtr<IProgress> &aProgress)
    401515{
    402 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
     516#if !defined(VBOX_WITH_DRAG_AND_DROP)
    403517    ReturnComNotImplemented();
    404518#else /* VBOX_WITH_DRAG_AND_DROP */
    405519
    406     /* Input validation */
    407 
     520    /** @todo Add input validation. */
     521    /** @todo Check if another sendData() call currently is being processed. */
    408522
    409523    AutoCaller autoCaller(this);
    410524    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    411525
    412     HRESULT hr = S_OK;
    413 
    414     VBOXHGCMSVCPARM paParms[8];
    415     int i = 0;
    416     paParms[i++].setUInt32(aScreenId);
    417     paParms[i++].setPointer((void *)aFormat.c_str(), (uint32_t)aFormat.length() + 1);
    418     paParms[i++].setUInt32((uint32_t)aFormat.length() + 1);
    419     paParms[i++].setPointer((void*)&aData.front(), (uint32_t)aData.size());
    420     paParms[i++].setUInt32((uint32_t)aData.size());
    421 
     526    HRESULT hr;
     527    int vrc;
     528
     529    /* Note: At the moment we only support one response at a time. */
    422530    GuestDnDResponse *pResp = GuestDnDInst()->response();
    423531    if (pResp)
    424532    {
    425         /* Reset any old progress status. */
    426533        pResp->resetProgress(m_pGuest);
    427534
    428         /* Note: The actual data transfer of files/directoies is performed by the
    429          *       DnD host service. */
    430         int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_HG_SND_DATA,
    431                                           i, paParms);
    432         if (RT_SUCCESS(rc))
    433         {
    434             hr = pResp->queryProgressTo(aProgress.asOutParam());
    435             ComAssertComRC(hr);
    436         }
    437     }
     535        try
     536        {
     537            PSENDDATACTX pSendCtx = new SENDDATACTX;
     538            RT_BZERO(pSendCtx, sizeof(SENDDATACTX));
     539
     540            pSendCtx->mpTarget  = this;
     541            pSendCtx->mpResp    = pResp;
     542            pSendCtx->mScreenID = aScreenId;
     543            pSendCtx->mFormat   = aFormat;
     544            pSendCtx->mData     = aData;
     545
     546            std::unique_ptr<SendDataTask> pTask(new SendDataTask(this, pSendCtx));
     547            AssertReturn(pTask->isOk(), pTask->getRC());
     548
     549            vrc = RTThreadCreate(NULL, GuestDnDTarget::i_sendDataThread,
     550                                 (void *)pTask.get(), 0, RTTHREADTYPE_MAIN_WORKER, 0, "dndTgtSndData");
     551            if (RT_SUCCESS(vrc))
     552            {
     553                hr = pResp->queryProgressTo(aProgress.asOutParam());
     554                ComAssertComRC(hr);
     555
     556                /* pTask is now owned by i_sendDataThread(), so release it. */
     557                pTask.release();
     558            }
     559            else if (pSendCtx)
     560                delete pSendCtx;
     561        }
     562        catch(std::bad_alloc &)
     563        {
     564            vrc = VERR_NO_MEMORY;
     565        }
     566
     567        /*if (RT_FAILURE(vrc)) ** @todo SetError(...) */
     568    }
     569    /** @todo SetError(...) */
    438570
    439571    return hr;
     
    441573}
    442574
     575int GuestDnDTarget::i_cancelOperation(void)
     576{
     577    /** @todo Check for pending cancel requests. */
     578
     579#if 0 /** @todo Later. */
     580    /* Cancel any outstanding waits for guest responses first. */
     581    if (pResp)
     582        pResp->notifyAboutGuestResponse();
     583#endif
     584
     585    LogFlowFunc(("Cancelling operation, telling guest ...\n"));
     586    return GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_HG_EVT_CANCEL, 0 /* cParms */, NULL /*paParms*/);
     587}
     588
     589int GuestDnDTarget::i_sendData(PSENDDATACTX pCtx)
     590{
     591    AssertPtrReturn(pCtx,  VERR_INVALID_POINTER);
     592
     593#define DATA_IS_VALID_BREAK(x) \
     594    if (!x) \
     595    { \
     596        LogFlowFunc(("Invalid URI data value for \"" #x "\"\n")); \
     597        rc = VERR_INVALID_PARAMETER; \
     598        break; \
     599    }
     600
     601    GuestDnD *pInst = GuestDnDInst();
     602    if (!pInst)
     603        return VERR_INVALID_POINTER;
     604
     605    int rc;
     606
     607    ASMAtomicWriteBool(&pCtx->mIsActive, true);
     608
     609    do
     610    {
     611        const char *pszFormat = pCtx->mFormat.c_str();
     612        DATA_IS_VALID_BREAK(pszFormat);
     613        uint32_t cbFormat = pCtx->mFormat.length() + 1;
     614
     615        /* Do we need to build up a file tree? */
     616        bool fHasURIList = DnDMIMEHasFileURLs(pszFormat, cbFormat);
     617        if (fHasURIList)
     618        {
     619            rc = i_sendURIData(pCtx);
     620        }
     621        else
     622        {
     623            GuestDnDMsg Msg;
     624
     625            size_t cbDataTotal = pCtx->mData.size();
     626            DATA_IS_VALID_BREAK(cbDataTotal);
     627
     628            /* Just copy over the raw data. */
     629            Msg.setType(DragAndDropSvc::HOST_DND_HG_SND_DATA);
     630            Msg.setNextUInt32(pCtx->mScreenID);
     631            Msg.setNextPointer((void *)pCtx->mFormat.c_str(), (uint32_t)pCtx->mFormat.length() + 1);
     632            Msg.setNextUInt32((uint32_t)pCtx->mFormat.length() + 1);
     633            Msg.setNextPointer((void*)&pCtx->mData.front(), (uint32_t)cbDataTotal);
     634            Msg.setNextUInt32(cbDataTotal);
     635
     636            LogFlowFunc(("%zu total bytes of raw data to transfer\n", cbDataTotal));
     637
     638            /* Make the initial call to the guest by sending the actual data. This might
     639             * be an URI list which in turn can lead to more data to send afterwards. */
     640            rc = pInst->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
     641            if (RT_FAILURE(rc))
     642                break;
     643        }
     644
     645    } while (0);
     646
     647    ASMAtomicWriteBool(&pCtx->mIsActive, false);
     648
     649#undef DATA_IS_VALID_BREAK
     650
     651    LogFlowFuncLeaveRC(rc);
     652    return rc;
     653}
     654
     655int GuestDnDTarget::i_sendDirectory(PSENDDATACTX pCtx, GuestDnDMsg *pMsg, DnDURIObject &aDirectory)
     656{
     657    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     658
     659    RTCString strPath = aDirectory.GetDestPath();
     660    if (strPath.isEmpty())
     661        return VERR_INVALID_PARAMETER;
     662    if (strPath.length() >= RTPATH_MAX) /* Note: Maximum is RTPATH_MAX on guest side. */
     663        return VERR_BUFFER_OVERFLOW;
     664
     665    LogFlowFunc(("Sending directory \"%s\" using protocol v%RU32 ...\n", strPath.c_str(), mData.mProtocolVersion));
     666
     667    pMsg->setType(DragAndDropSvc::HOST_DND_HG_SND_DIR);
     668    pMsg->setNextString(strPath.c_str());                  /* path */
     669    pMsg->setNextUInt32((uint32_t)(strPath.length() + 1)); /* path length - note: Maximum is RTPATH_MAX on guest side. */
     670    pMsg->setNextUInt32(aDirectory.GetMode());             /* mode */
     671
     672    return VINF_SUCCESS;
     673}
     674
     675int GuestDnDTarget::i_sendFile(PSENDDATACTX pCtx, GuestDnDMsg *pMsg, DnDURIObject &aFile)
     676{
     677    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     678
     679    RTCString strPath = aFile.GetDestPath();
     680    if (strPath.isEmpty())
     681        return VERR_INVALID_PARAMETER;
     682
     683    int rc = VINF_SUCCESS;
     684
     685    LogFlowFunc(("Sending \"%s\" (%RU32 bytes buffer) using protocol v%RU32 ...\n",
     686                 aFile.GetDestPath().c_str(), m_cbBlockSize, mData.mProtocolVersion));
     687
     688    bool fSendFileData = false;
     689    if (mData.mProtocolVersion >= 2)
     690    {
     691        if (!aFile.IsOpen())
     692        {
     693            rc = aFile.OpenEx(aFile.GetSourcePath(), DnDURIObject::Type::File, DnDURIObject::Dest::Source,
     694                              RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE, 0 /* fFlags */);
     695            if (RT_SUCCESS(rc))
     696            {
     697                /*
     698                 * Since protocol v2 the file header and the actual file contents are
     699                 * separate messages, so send the file header first.
     700                 * The just registered callback will be called by the guest afterwards.
     701                 */
     702                pMsg->setType(DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR);
     703                pMsg->setNextUInt32(0);                                /* context ID */
     704                pMsg->setNextString(strPath.c_str());                  /* pvName */
     705                pMsg->setNextUInt32((uint32_t)(strPath.length() + 1)); /* cbName */
     706                pMsg->setNextUInt32(0);                                /* uFlags */
     707                pMsg->setNextUInt32(aFile.GetMode());                  /* fMode */
     708                pMsg->setNextUInt64(aFile.GetSize());                  /* uSize */
     709
     710                LogFlowFunc(("Sending file header ...\n"));
     711            }
     712        }
     713        else
     714        {
     715            /* File header was sent, so only send the actual file data. */
     716            fSendFileData = true;
     717        }
     718    }
     719    else /* Protocol v1. */
     720    {
     721        /* Always send the file data, every time. */
     722        fSendFileData = true;
     723    }
     724
     725    if (   RT_SUCCESS(rc)
     726        && fSendFileData)
     727    {
     728        rc = i_sendFileData(pCtx, pMsg, aFile);
     729    }
     730
     731    LogFlowFuncLeaveRC(rc);
     732    return rc;
     733}
     734
     735int GuestDnDTarget::i_sendFileData(PSENDDATACTX pCtx, GuestDnDMsg *pMsg, DnDURIObject &aFile)
     736{
     737    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     738    AssertPtrReturn(pMsg, VERR_INVALID_POINTER);
     739
     740    GuestDnDResponse *pResp = pCtx->mpResp;
     741    AssertPtr(pResp);
     742
     743    /** @todo Don't allow concurrent reads per context! */
     744
     745    /* Something to transfer? */
     746    if (   pCtx->mURI.lstURI.IsEmpty()
     747        || !pCtx->mIsActive)
     748    {
     749        return VERR_WRONG_ORDER;
     750    }
     751
     752    /*
     753     * Start sending stuff.
     754     */
     755
     756    /* Set the message type. */
     757    pMsg->setType(DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA);
     758
     759    /* Protocol version 1 sends the file path *every* time with a new file chunk.
     760     * In protocol version 2 we only do this once with HOST_DND_HG_SND_FILE_HDR. */
     761    if (mData.mProtocolVersion <= 1)
     762    {
     763        pMsg->setNextUInt32(0);                                              /* context ID */
     764        pMsg->setNextString(aFile.GetSourcePath().c_str());                  /* pvName */
     765        pMsg->setNextUInt32((uint32_t)(aFile.GetSourcePath().length() + 1)); /* cbName */
     766    }
     767
     768    uint32_t cbRead = 0;
     769
     770    int rc = aFile.Read(pCtx->mURI.pvScratchBuf, pCtx->mURI.cbScratchBuf, &cbRead);
     771    if (RT_SUCCESS(rc))
     772    {
     773        pCtx->mURI.cbProcessed += cbRead;
     774
     775        if (mData.mProtocolVersion <= 1)
     776        {
     777            pMsg->setNextPointer(pCtx->mURI.pvScratchBuf, cbRead);  /* pvData */
     778            pMsg->setNextUInt32(cbRead);                            /* cbData */
     779            pMsg->setNextUInt32(aFile.GetMode());                   /* fMode */
     780        }
     781        else
     782        {
     783            pMsg->setNextPointer(pCtx->mURI.pvScratchBuf, cbRead); /* pvData */
     784            pMsg->setNextUInt32(cbRead);                           /* cbData */
     785        }
     786
     787        if (aFile.IsComplete()) /* Done reading? */
     788        {
     789            LogFlowFunc(("File \"%s\" complete\n", aFile.GetSourcePath().c_str()));
     790            rc = VINF_EOF;
     791        }
     792    }
     793
     794    LogFlowFuncLeaveRC(rc);
     795    return rc;
     796}
     797
     798/* static */
     799DECLCALLBACK(int) GuestDnDTarget::i_sendURIDataCallback(uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser)
     800{
     801    PSENDDATACTX pCtx = (PSENDDATACTX)pvUser;
     802    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     803
     804    GuestDnDTarget *pThis = pCtx->mpTarget;
     805    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
     806
     807    LogFlowFunc(("pThis=%p, uMsg=%RU32\n", pThis, uMsg));
     808
     809    int rc = VINF_SUCCESS;
     810
     811    switch (uMsg)
     812    {
     813        case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
     814        {
     815            DragAndDropSvc::PVBOXDNDCBHGGETNEXTHOSTMSG pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGGETNEXTHOSTMSG>(pvParms);
     816            AssertPtr(pCBData);
     817            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSG) == cbParms, VERR_INVALID_PARAMETER);
     818            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     819
     820            GuestDnDMsg *pMsg;
     821            try
     822            {
     823                pMsg = new GuestDnDMsg();
     824                rc = pThis->i_sendURIDataLoop(pCtx, pMsg);
     825                if (RT_SUCCESS(rc))
     826                {
     827                    rc = pThis->addMsg(pMsg);
     828                    if (RT_SUCCESS(rc)) /* Return message type & required parameter count to the guest. */
     829                    {
     830                        LogFlowFunc(("GUEST_DND_GET_NEXT_HOST_MSG -> %RU32 (%RU32 params)\n", pMsg->getType(), pMsg->getCount()));
     831                        pCBData->uMsg   = pMsg->getType();
     832                        pCBData->cParms = pMsg->getCount();
     833                    }
     834                }
     835
     836                if (RT_FAILURE(rc))
     837                {
     838                    if (rc == VERR_NO_DATA) /* All URI objects processed? */
     839                    {
     840                        /* Unregister this callback. */
     841                        AssertPtr(pCtx->mpResp);
     842                        int rc2 = pCtx->mpResp->setCallback(uMsg, NULL /* PFNGUESTDNDCALLBACK */);
     843                        if (RT_FAILURE(rc2))
     844                            LogFlowFunc(("Error: Unable to unregister callback for message %RU32, rc=%Rrc\n", uMsg, rc2));
     845                    }
     846
     847                    delete pMsg;
     848                }
     849            }
     850            catch(std::bad_alloc & /*e*/)
     851            {
     852                rc = VERR_NO_MEMORY;
     853            }
     854            break;
     855        }
     856        case DragAndDropSvc::HOST_DND_HG_SND_DIR:
     857        case DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR:
     858        case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA:
     859        {
     860            DragAndDropSvc::PVBOXDNDCBHGGETNEXTHOSTMSGDATA pCBData
     861                = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGGETNEXTHOSTMSGDATA>(pvParms);
     862            AssertPtr(pCBData);
     863            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSGDATA) == cbParms, VERR_INVALID_PARAMETER);
     864            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     865
     866            GuestDnDMsg *pMsg = pThis->nextMsg();
     867            if (pMsg)
     868            {
     869                /*
     870                 * Sanity checks.
     871                 */
     872                if (   pCBData->uMsg    != uMsg
     873                    || pCBData->paParms == NULL
     874                    || pCBData->cParms  != pMsg->getCount())
     875                {
     876                    rc = VERR_INVALID_PARAMETER;
     877                }
     878
     879                if (RT_SUCCESS(rc))
     880                {
     881                    LogFlowFunc(("Sending uMsg=%RU32, cParms=%RU32 ...\n", uMsg, pCBData->cParms));
     882                    rc = HGCM::Message::copyParms(pMsg->getCount(), pMsg->getParms(), pCBData->paParms);
     883                    if (RT_SUCCESS(rc))
     884                    {
     885                        pCBData->cParms = pMsg->getCount();
     886                        pThis->removeNext();
     887                    }
     888                }
     889            }
     890            else
     891                rc = VERR_NO_DATA;
     892
     893            LogFlowFunc(("Returning msg %RU32, rc=%Rrc\n", uMsg, rc));
     894            break;
     895        }
     896        default:
     897            rc = VERR_NOT_SUPPORTED;
     898            break;
     899    }
     900
     901    if (RT_FAILURE(rc))
     902    {
     903        if (pCtx->mURI.SemEvent != NIL_RTSEMEVENT)
     904        {
     905            LogFlowFunc(("Signalling ...\n"));
     906            int rc2 = RTSemEventSignal(pCtx->mURI.SemEvent);
     907            AssertRC(rc2);
     908        }
     909    }
     910
     911    LogFlowFuncLeaveRC(rc);
     912    return rc; /* Tell the guest. */
     913}
     914
     915int GuestDnDTarget::i_sendURIData(PSENDDATACTX pCtx)
     916{
     917    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     918    AssertPtr(pCtx->mpResp);
     919
     920#define URI_DATA_IS_VALID_BREAK(x) \
     921    if (!x) \
     922    { \
     923        LogFlowFunc(("Invalid URI data value for \"" #x "\"\n")); \
     924        rc = VERR_INVALID_PARAMETER; \
     925        break; \
     926    }
     927
     928    void *pvBuf = RTMemAlloc(m_cbBlockSize);
     929    if (!pvBuf)
     930        return VERR_NO_MEMORY;
     931
     932    int rc;
     933
     934#define REGISTER_CALLBACK(x) \
     935    rc = pCtx->mpResp->setCallback(x, i_sendURIDataCallback, pCtx); \
     936    if (RT_FAILURE(rc)) \
     937        return rc;
     938
     939#define UNREGISTER_CALLBACK(x) \
     940    rc = pCtx->mpResp->setCallback(x, NULL); \
     941    AssertRC(rc);
     942
     943    /*
     944     * Register callbacks.
     945     */
     946    /* Generic callbacks. */
     947    REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG);
     948    /* Host callbacks. */
     949    REGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_DIR);
     950    if (mData.mProtocolVersion >= 2)
     951        REGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR);
     952    REGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA);
     953
     954    do
     955    {
     956        /*
     957         * Set our scratch buffer.
     958         */
     959        pCtx->mURI.pvScratchBuf = pvBuf;
     960        pCtx->mURI.cbScratchBuf = m_cbBlockSize;
     961
     962        /* Create event semaphore. */
     963        pCtx->mURI.SemEvent = NIL_RTSEMEVENT;
     964        rc = RTSemEventCreate(&pCtx->mURI.SemEvent);
     965        if (RT_FAILURE(rc))
     966            break;
     967
     968        /*
     969         * Extract URI list from byte data.
     970         */
     971        DnDURIList &lstURI = pCtx->mURI.lstURI; /* Use the URI list from the context. */
     972
     973        const char *pszList = (const char *)&pCtx->mData.front();
     974        URI_DATA_IS_VALID_BREAK(pszList);
     975
     976        uint32_t cbList = pCtx->mData.size();
     977        URI_DATA_IS_VALID_BREAK(cbList);
     978
     979        RTCList<RTCString> lstURIOrg = RTCString(pszList, cbList).split("\r\n");
     980        URI_DATA_IS_VALID_BREAK(!lstURIOrg.isEmpty());
     981
     982        rc = lstURI.AppendURIPathsFromList(lstURIOrg, 0 /* fFlags */);
     983        if (RT_SUCCESS(rc))
     984            LogFlowFunc(("URI root objects: %zu, total bytes (raw data to transfer): %zu\n",
     985                         lstURI.RootCount(), lstURI.TotalBytes()));
     986        else
     987            break;
     988
     989        /*
     990         * The first message always is the meta info for the data. The meta
     991         * info *only* contains the root elements of an URI list.
     992         *
     993         * After the meta data we generate the messages required to send the data itself.
     994         */
     995        Assert(!lstURI.IsEmpty());
     996        RTCString strData = lstURI.RootToString().c_str();
     997        size_t    cbData  = strData.length() + 1; /* Include terminating zero. */
     998
     999        GuestDnDMsg Msg;
     1000        Msg.setType(DragAndDropSvc::HOST_DND_HG_SND_DATA);
     1001        Msg.setNextUInt32(pCtx->mScreenID);
     1002        Msg.setNextPointer((void *)pCtx->mFormat.c_str(), (uint32_t)pCtx->mFormat.length() + 1);
     1003        Msg.setNextUInt32((uint32_t)pCtx->mFormat.length() + 1);
     1004        Msg.setNextPointer((void*)strData.c_str(), (uint32_t)cbData);
     1005        Msg.setNextUInt32((uint32_t)cbData);
     1006
     1007        rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
     1008        if (RT_SUCCESS(rc))
     1009        {
     1010            /*
     1011             * Wait until our callback i_sendURIDataCallback triggered the
     1012             * wait event.
     1013             */
     1014            LogFlowFunc(("Waiting for URI callback ...\n"));
     1015            rc = RTSemEventWait(pCtx->mURI.SemEvent, RT_INDEFINITE_WAIT);
     1016            LogFlowFunc(("URI callback done\n"));
     1017        }
     1018
     1019    } while (0);
     1020
     1021     if (pCtx->mURI.SemEvent != NIL_RTSEMEVENT)
     1022     {
     1023         RTSemEventDestroy(pCtx->mURI.SemEvent);
     1024         pCtx->mURI.SemEvent = NIL_RTSEMEVENT;
     1025     }
     1026
     1027    /*
     1028     * Unregister callbacksagain.
     1029     */
     1030    /* Guest callbacks. */
     1031    UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG);
     1032    /* Host callbacks. */
     1033    UNREGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_DIR);
     1034    if (mData.mProtocolVersion >= 2)
     1035        UNREGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR);
     1036    UNREGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA);
     1037
     1038#undef REGISTER_CALLBACK
     1039#undef UNREGISTER_CALLBACK
     1040
     1041    if (pvBuf)
     1042        RTMemFree(pvBuf);
     1043
     1044#undef URI_DATA_IS_VALID_BREAK
     1045
     1046    LogFlowFuncLeaveRC(rc);
     1047    return rc;
     1048}
     1049
     1050int GuestDnDTarget::i_sendURIDataLoop(PSENDDATACTX pCtx, GuestDnDMsg *pMsg)
     1051{
     1052    AssertPtrReturn(pCtx,  VERR_INVALID_POINTER);
     1053
     1054    DnDURIList &lstURI = pCtx->mURI.lstURI;
     1055
     1056    int rc;
     1057
     1058    uint64_t cbTotal = pCtx->mURI.lstURI.TotalBytes();
     1059    uint8_t uPercent = pCtx->mURI.cbProcessed * 100 / (cbTotal ? cbTotal : 1);
     1060    Assert(uPercent <= 100);
     1061
     1062    LogFlowFunc(("%RU64 / %RU64 -- %RU8%%\n", pCtx->mURI.cbProcessed, cbTotal, uPercent));
     1063
     1064    bool fComplete = (uPercent >= 100) || lstURI.IsEmpty();
     1065
     1066    if (pCtx->mpResp)
     1067    {
     1068        int rc2 = pCtx->mpResp->setProgress(uPercent,
     1069                                              fComplete
     1070                                            ? DragAndDropSvc::DND_PROGRESS_COMPLETE
     1071                                            : DragAndDropSvc::DND_PROGRESS_RUNNING);
     1072        AssertRC(rc2);
     1073    }
     1074
     1075    if (fComplete)
     1076    {
     1077        LogFlowFunc(("Last URI item processed, bailing out\n"));
     1078        return VERR_NO_DATA;
     1079    }
     1080
     1081    Assert(!lstURI.IsEmpty());
     1082    DnDURIObject &curObj = lstURI.First();
     1083
     1084    uint32_t fMode = curObj.GetMode();
     1085    LogFlowFunc(("Processing srcPath=%s, dstPath=%s, fMode=0x%x, cbSize=%RU32, fIsDir=%RTbool, fIsFile=%RTbool\n",
     1086                 curObj.GetSourcePath().c_str(), curObj.GetDestPath().c_str(),
     1087                 fMode, curObj.GetSize(),
     1088                 RTFS_IS_DIRECTORY(fMode), RTFS_IS_FILE(fMode)));
     1089
     1090    if (RTFS_IS_DIRECTORY(fMode))
     1091    {
     1092        rc = i_sendDirectory(pCtx, pMsg, curObj);
     1093    }
     1094    else if (RTFS_IS_FILE(fMode))
     1095    {
     1096        rc = i_sendFile(pCtx, pMsg, curObj);
     1097    }
     1098    else
     1099    {
     1100        AssertMsgFailed(("fMode=0x%x is not supported for srcPath=%s, dstPath=%s\n",
     1101                         fMode, curObj.GetSourcePath().c_str(), curObj.GetDestPath().c_str()));
     1102        rc = VERR_NOT_SUPPORTED;
     1103    }
     1104
     1105    bool fRemove = false; /* Remove current entry? */
     1106    if (   curObj.IsComplete()
     1107        || RT_FAILURE(rc))
     1108    {
     1109        fRemove = true;
     1110    }
     1111
     1112    if (fRemove)
     1113    {
     1114        LogFlowFunc(("Removing \"%s\" from list, rc=%Rrc\n", curObj.GetSourcePath().c_str(), rc));
     1115        lstURI.RemoveFirst();
     1116    }
     1117
     1118    if (   pCtx->mpResp
     1119        && pCtx->mpResp->isProgressCanceled())
     1120    {
     1121        LogFlowFunc(("Cancelling ...\n"));
     1122
     1123        rc = i_cancelOperation();
     1124        if (RT_SUCCESS(rc))
     1125            rc = VERR_CANCELLED;
     1126    }
     1127
     1128    LogFlowFuncLeaveRC(rc);
     1129    return rc;
     1130}
     1131
     1132HRESULT GuestDnDTarget::cancel(BOOL *aVeto)
     1133{
     1134#if !defined(VBOX_WITH_DRAG_AND_DROP)
     1135    ReturnComNotImplemented();
     1136#else /* VBOX_WITH_DRAG_AND_DROP */
     1137
     1138    int rc = i_cancelOperation();
     1139
     1140    if (aVeto)
     1141        *aVeto = FALSE; /** @todo */
     1142
     1143    return RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
     1144#endif /* VBOX_WITH_DRAG_AND_DROP */
     1145}
     1146
Note: See TracChangeset for help on using the changeset viewer.

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