VirtualBox

Changeset 58212 in vbox


Ignore:
Timestamp:
Oct 13, 2015 11:49:33 AM (10 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
103344
Message:

DnD: Updates.

  • Introduced protocol changelog in DragAndDropSvc.h.
  • Implemented protocol v3 with HOST_DND_HG_SND_DATA_HDR message for doing proper object accounting, among other parameters like checksumming and compression flags.
  • Encapsulated a lot of functionality in class hierarchies.
  • Renamed a lot of functions to make the usage more clear.
  • Various other bugfixes.
Location:
trunk
Files:
24 edited

Legend:

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

    r57776 r58212  
    5959    int AddFile(const char *pszFile);
    6060    int AddDir(const char *pszDir);
     61    int Close(void);
    6162    bool IsOpen(void) const;
    6263    int OpenEx(const char *pszPath, uint32_t fFlags);
    6364    int OpenTemp(uint32_t fFlags);
    6465    const char *GetDirAbs(void) const;
     66    int Reopen(void);
    6567    int Reset(bool fDeleteContent);
    6668    int Rollback(void);
     
    6870protected:
    6971
     72    int closeInternal(void);
     73
     74protected:
     75
     76    /** Open flags. */
     77    uint32_t                     fOpen;
    7078    /** Directory handle for drop directory. */
    7179    PRTDIR                       hDir;
    72     /** Flag indicating whether the drop directory
    73      *  has been opened for processing or not. */
    74     bool                         fOpen;
    7580    /** Absolute path to drop directory. */
    7681    RTCString                    strPathAbs;
     
    197202    void RemoveFirst(void);
    198203    int RootFromURIData(const void *pvData, size_t cbData, uint32_t fFlags);
    199     RTCString RootToString(const RTCString &strPathBase = "", const RTCString &strSeparator = "\r\n");
     204    RTCString RootToString(const RTCString &strPathBase = "", const RTCString &strSeparator = "\r\n") const;
    200205    size_t RootCount(void) const { return m_lstRoot.size(); }
    201206    uint32_t TotalCount(void) const { return m_cTotal; }
  • trunk/include/VBox/HostServices/DragAndDropSvc.h

    r57500 r58212  
    2222 * You may elect to license modified versions of this file under the
    2323 * terms and conditions of either the GPL or the CDDL or both.
     24 */
     25
     26/**
     27 * Protocol handling and notes:
     28 *     All client/server components should be backwards compatible.
     29 *
     30 ******************************************************************************
     31 *
     32 * Protocol changelog:
     33 *
     34 *     Protocol v1 (VBox < 5.0):
     35 *         - Initial implementation which only implemented host to guest transfers.
     36 *         - For file transfers all file information such as the file name and file size were
     37 *           transferred with every file data chunk being sent.
     38 *
     39 *     Protocol v2 (VBox 5.0):
     40 *         - Added support for guest to host transfers.
     41 *         - Added protocol version support through VBOXDNDCONNECTMSG. The host takes the installed
     42 *           Guest Additions version as indicator which protocol to use for communicating with the guest.
     43 *           The guest itself uses VBOXDNDCONNECTMSG to report its supported protocol version to the DnD service.
     44 *
     45 *     Protocol v3 (VBox 5.0+):
     46 *         - Added VBOXDNDSNDDATAHDR and VBOXDNDCBSNDDATAHDRDATA to support (simple) accounting of objects
     47 *           being transferred, along with supplying separate meta data size (which is part of the total size being sent).
     48 *         - Added new HOST_DND_HG_SND_DATA_HDR + GUEST_DND_GH_SND_DATA_HDR commands which now allow specifying an optional
     49 *           compression type and defining a checksum for the overall data transfer.
     50 *         - Enhannced VBOXDNDGHSENDDATAMSG to support (rolling) checksums for the supplied data block.
     51 *         - VBOXDNDHGSENDFILEDATAMSG and VBOXDNDGHSENDFILEDATAMSG are now sharing the same HGCM mesasge.
     52 *         - VBOXDNDHGSENDDATAMSG and VBOXDNDGHSENDDATAMSG can now contain an optional checksum for the current data block.
     53 *         - Removed unused HOST_DND_GH_RECV_DIR, HOST_DND_GH_RECV_FILE_DATA and HOST_DND_GH_RECV_FILE_HDR commands.
    2454 */
    2555
     
    106136    /** The host requested to cancel the current DnD operation. */
    107137    HOST_DND_HG_EVT_CANCEL             = 204,
    108     /** Gets the actual MIME data, based on
    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. */
     138    /** Sends the data header at the beginning of a (new)
     139     *  data transfer. */
     140    HOST_DND_HG_SND_DATA_HDR           = 210,
     141    /**
     142     * Sends the actual meta data, based on
     143     * the format(s) specified by HOST_DND_HG_EVT_ENTER.
     144     *
     145     * Protocol v1/v2: If the guest supplied buffer too small to send
     146     *                 the actual data, the host will send a HOST_DND_HG_SND_MORE_DATA
     147     *                 message as follow-up.
     148     * Protocol v3+:   The incoming meta data size is specified upfront in the
     149     *                 HOST_DND_HG_SND_DATA_HDR message and must be handled accordingly.
     150     */
    112151    HOST_DND_HG_SND_DATA               = 205,
    113     /** Sent when the actual buffer for HOST_DND_HG_SND_DATA
    114      *  was too small, issued by the DnD host service. */
     152    /** Sent when the actual buffer for HOST_DND_HG_SND_DATA was too small. */
     153    /** @todo Deprecated function; do not use anymore. */
    115154    HOST_DND_HG_SND_MORE_DATA          = 206,
    116155    /** Directory entry to be sent to the guest. */
     
    133172     *  a specific MIME type. */
    134173    HOST_DND_GH_EVT_DROPPED            = 601,
    135     /** Creates a directory on the guest. */
    136     HOST_DND_GH_RECV_DIR               = 650,
    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,
    142174    /** Blow the type up to 32-bit. */
    143175    HOST_DND_32BIT_HACK                = 0x7fffffff
     
    185217     */
    186218    GUEST_DND_GH_ACK_PENDING           = 500,
     219    /** Sends the data header at the beginning of a (new)
     220     *  data transfer. */
     221    GUEST_DND_GH_SND_DATA_HDR          = 503,
    187222    /**
    188223     * Sends data of the requested format to the host. There can
     
    227262 */
    228263
     264/**
     265 * Action message for telling the guest about the currently ongoing
     266 * drag and drop action when entering the guest's area, moving around in it
     267 * and dropping content into it from the host.
     268 *
     269 * Used by:
     270 * HOST_DND_HG_EVT_ENTER
     271 * HOST_DND_HG_EVT_MOVE
     272 * HOST_DND_HG_EVT_DROPPED
     273 */
    229274typedef struct VBOXDNDHGACTIONMSG
    230275{
    231276    VBoxGuestHGCMCallInfo hdr;
    232277
    233     /**
    234      * HG Action event.
    235      *
    236      * Used by:
    237      * HOST_DND_HG_EVT_ENTER
    238      * HOST_DND_HG_EVT_MOVE
    239      * HOST_DND_HG_EVT_DROPPED
    240      */
    241278    HGCMFunctionParameter uScreenId;    /* OUT uint32_t */
    242279    HGCMFunctionParameter uX;           /* OUT uint32_t */
     
    248285} VBOXDNDHGACTIONMSG;
    249286
     287/**
     288 * Tells the guest that the host has left its drag and drop area on the guest.
     289 *
     290 * Used by:
     291 * HOST_DND_HG_EVT_LEAVE
     292 */
    250293typedef struct VBOXDNDHGLEAVEMSG
    251294{
    252295    VBoxGuestHGCMCallInfo hdr;
     296} VBOXDNDHGLEAVEMSG;
     297
     298
     299/**
     300 * Tells the guest that the host wants to cancel the current drag and drop operation.
     301 *
     302 * Used by:
     303 * HOST_DND_HG_EVT_CANCEL
     304 */
     305typedef struct VBOXDNDHGCANCELMSG
     306{
     307    VBoxGuestHGCMCallInfo hdr;
     308} VBOXDNDHGCANCELMSG;
     309
     310/**
     311 * Sends the header of an incoming (meta) data block.
     312 *
     313 * Used by:
     314 * HOST_DND_HG_SND_DATA_HDR
     315 * GUEST_DND_GH_SND_DATA_HDR
     316 *
     317 * New since protocol v3.
     318 */
     319typedef struct VBOXDNDHGSENDDATAHDRMSG
     320{
     321    VBoxGuestHGCMCallInfo hdr;
     322
     323    /** Context ID. Unused at the moment. */
     324    HGCMFunctionParameter uContext;        /* OUT uint32_t */
     325    /** Data transfer flags. Not yet used and must be 0. */
     326    HGCMFunctionParameter uFlags;          /* OUT uint32_t */
     327    /** Screen ID where the data originates from. */
     328    HGCMFunctionParameter uScreenId;       /* OUT uint32_t */
     329    /** Total size (in bytes) to transfer. */
     330    HGCMFunctionParameter cbTotal;         /* OUT uint64_t */
    253331    /**
    254      * HG Leave event.
     332     * Total meta data size (in bytes) to transfer.
     333     * This size also is part of cbTotal already, so:
    255334     *
    256      * Used by:
    257      * HOST_DND_HG_EVT_LEAVE
     335     * cbTotal = cbMeta + additional size for files etc.
    258336     */
    259 } VBOXDNDHGLEAVEMSG;
    260 
    261 typedef struct VBOXDNDHGCANCELMSG
    262 {
    263     VBoxGuestHGCMCallInfo hdr;
    264 
    265     /**
    266      * HG Cancel return event.
    267      *
    268      * Used by:
    269      * HOST_DND_HG_EVT_CANCEL
    270      */
    271 } VBOXDNDHGCANCELMSG;
    272 
     337    HGCMFunctionParameter cbMeta;          /* OUT uint64_t */
     338    /** Meta data format. */
     339    HGCMFunctionParameter pvMetaFmt;       /* OUT ptr */
     340    /** Size (in bytes) of meta data format. */
     341    HGCMFunctionParameter cbMetaFmt;       /* OUT uint32_t */
     342    /* Number of objects (files/directories) to transfer. */
     343    HGCMFunctionParameter cObjects;        /* OUT uint64_t */
     344    /** Compression type. */
     345    HGCMFunctionParameter enmCompression;  /* OUT uint32_t */
     346    /** Checksum type. */
     347    HGCMFunctionParameter enmChecksumType; /* OUT uint32_t */
     348    /** Checksum buffer for the entire data to be transferred. */
     349    HGCMFunctionParameter pvChecksum;      /* OUT ptr */
     350    /** Size (in bytes) of checksum. */
     351    HGCMFunctionParameter cbChecksum;      /* OUT uint32_t */
     352} VBOXDNDHGSENDDATAHDRMSG;
     353
     354/**
     355 * Sends a (meta) data block to the guest.
     356 *
     357 * Used by:
     358 * HOST_DND_HG_SND_DATA
     359 */
    273360typedef struct VBOXDNDHGSENDDATAMSG
    274361{
    275362    VBoxGuestHGCMCallInfo hdr;
    276363
    277     /**
    278      * HG Send Data event.
    279      *
    280      * Used by:
    281      * HOST_DND_HG_SND_DATA
    282      */
    283     HGCMFunctionParameter uScreenId;    /* OUT uint32_t */
    284     HGCMFunctionParameter pvFormat;     /* OUT ptr */
    285     HGCMFunctionParameter cFormat;      /* OUT uint32_t */
    286     HGCMFunctionParameter pvData;       /* OUT ptr */
    287     HGCMFunctionParameter cbData;       /* OUT uint32_t */
     364    union
     365    {
     366        struct
     367        {
     368            HGCMFunctionParameter uScreenId;    /* OUT uint32_t */
     369            HGCMFunctionParameter pvFormat;     /* OUT ptr */
     370            HGCMFunctionParameter cbFormat;     /* OUT uint32_t */
     371            HGCMFunctionParameter pvData;       /* OUT ptr */
     372            HGCMFunctionParameter cbData;       /* OUT uint32_t */
     373        } v1;
     374        /* No changes in v2. */
     375        struct
     376        {
     377            /** Context ID. Unused at the moment. */
     378            HGCMFunctionParameter uContext;     /* OUT uint32_t */
     379            /** Data block to send. */
     380            HGCMFunctionParameter pvData;       /* OUT ptr */
     381            /** Size (in bytes) of data block to send. */
     382            HGCMFunctionParameter cbData;       /* OUT uint32_t */
     383            /** Checksum of data block, based on the checksum
     384             *  type in the data header. Optional. */
     385            HGCMFunctionParameter pvChecksum;   /* OUT ptr */
     386            /** Size (in bytes) of checksum to send. */
     387            HGCMFunctionParameter cbChecksum;   /* OUT uint32_t */
     388        } v3;
     389    } u;
    288390} VBOXDNDHGSENDDATAMSG;
    289391
     392/**
     393 * Sends more (meta) data in case the data didn't fit
     394 * into the current XXX_DND_HG_SND_DATA message.
     395 *
     396 ** @todo Deprecated since protocol v3. Don't use! Will be removed.
     397 *
     398 * Used by:
     399 * HOST_DND_HG_SND_MORE_DATA
     400 */
    290401typedef struct VBOXDNDHGSENDMOREDATAMSG
    291402{
    292403    VBoxGuestHGCMCallInfo hdr;
    293404
    294     /**
    295      * HG Send More Data event.
    296      *
    297      * Used by:
    298      * HOST_DND_HG_SND_MORE_DATA
    299      */
    300405    HGCMFunctionParameter pvData;       /* OUT ptr */
    301406    HGCMFunctionParameter cbData;       /* OUT uint32_t */
    302407} VBOXDNDHGSENDMOREDATAMSG;
    303408
     409/**
     410 * Directory entry event.
     411 *
     412 * Used by:
     413 * HOST_DND_HG_SND_DIR
     414 * GUEST_DND_GH_SND_DIR
     415 */
    304416typedef struct VBOXDNDHGSENDDIRMSG
    305417{
    306418    VBoxGuestHGCMCallInfo hdr;
    307419
    308     /**
    309      * HG Directory event.
    310      *
    311      * Used by:
    312      * HOST_DND_HG_SND_DIR
    313      */
     420    /** Directory name. */
    314421    HGCMFunctionParameter pvName;       /* OUT ptr */
     422    /** Size (in bytes) of directory name. */
    315423    HGCMFunctionParameter cbName;       /* OUT uint32_t */
     424    /** Directory mode. */
    316425    HGCMFunctionParameter fMode;        /* OUT uint32_t */
    317426} VBOXDNDHGSENDDIRMSG;
    318427
    319428/**
    320  * File header event.
     429 * File header message, marking the start of transferring a new file.
    321430 * Note: Only for protocol version 2 and up.
    322431 *
    323432 * Used by:
    324433 * HOST_DND_HG_SND_FILE_HDR
    325  * HOST_DND_GH_SND_FILE_HDR
     434 * GUEST_DND_GH_SND_FILE_HDR
    326435 */
    327436typedef struct VBOXDNDHGSENDFILEHDRMSG
     
    341450    /** Total size (in bytes). */
    342451    HGCMFunctionParameter cbTotal;      /* OUT uint64_t */
    343 
    344452} VBOXDNDHGSENDFILEHDRMSG;
    345453
     
    360468        struct
    361469        {
     470            /** File name. */
    362471            HGCMFunctionParameter pvName;       /* OUT ptr */
     472            /** Size (in bytes) of file name. */
    363473            HGCMFunctionParameter cbName;       /* OUT uint32_t */
     474            /** Current data chunk. */
    364475            HGCMFunctionParameter pvData;       /* OUT ptr */
     476            /** Size (in bytes) of current data chunk. */
    365477            HGCMFunctionParameter cbData;       /* OUT uint32_t */
     478            /** File mode. */
    366479            HGCMFunctionParameter fMode;        /* OUT uint32_t */
    367480        } v1;
     
    372485            /** Context ID. Unused at the moment. */
    373486            HGCMFunctionParameter uContext;     /* OUT uint32_t */
     487            /** Current data chunk. */
    374488            HGCMFunctionParameter pvData;       /* OUT ptr */
     489            /** Size (in bytes) of current data chunk. */
    375490            HGCMFunctionParameter cbData;       /* OUT uint32_t */
    376491            /** Note: fMode is now part of the VBOXDNDHGSENDFILEHDRMSG message. */
    377492        } v2;
     493        struct
     494        {
     495            /** Context ID. Unused at the moment. */
     496            HGCMFunctionParameter uContext;     /* OUT uint32_t */
     497            /** Current data chunk. */
     498            HGCMFunctionParameter pvData;       /* OUT ptr */
     499            /** Size (in bytes) of current data chunk. */
     500            HGCMFunctionParameter cbData;       /* OUT uint32_t */
     501            /** Checksum of data block, based on the checksum
     502             *  type in the data header. Optional. */
     503            HGCMFunctionParameter pvChecksum;   /* OUT ptr */
     504            /** Size (in bytes) of curren data chunk checksum. */
     505            HGCMFunctionParameter cbChecksum;   /* OUT uint32_t */
     506        } v3;
    378507    } u;
    379 
    380508} VBOXDNDHGSENDFILEDATAMSG;
    381509
     510/**
     511 * Asks the guest if a guest->host DnD operation is in progress.
     512 *
     513 * Used by:
     514 * HOST_DND_GH_REQ_PENDING
     515 */
    382516typedef struct VBOXDNDGHREQPENDINGMSG
    383517{
    384518    VBoxGuestHGCMCallInfo hdr;
    385519
    386     /**
    387      * GH Request Pending event.
    388      *
    389      * Used by:
    390      * HOST_DND_GH_REQ_PENDING
    391      */
     520    /** Screen ID. */
    392521    HGCMFunctionParameter uScreenId;    /* OUT uint32_t */
    393522} VBOXDNDGHREQPENDINGMSG;
    394523
     524/**
     525 * Tells the guest that the host has dropped the ongoing guest->host
     526 * DnD operation on a valid target on the host.
     527 *
     528 * Used by:
     529 * HOST_DND_GH_EVT_DROPPED
     530 */
    395531typedef struct VBOXDNDGHDROPPEDMSG
    396532{
    397533    VBoxGuestHGCMCallInfo hdr;
    398534
    399     /**
    400      * GH Dropped event.
    401      *
    402      * Used by:
    403      * HOST_DND_GH_EVT_DROPPED
    404      */
     535    /** Requested format for sending the data. */
    405536    HGCMFunctionParameter pvFormat;     /* OUT ptr */
    406     HGCMFunctionParameter cFormat;      /* OUT uint32_t */
     537    /** Size (in bytes) of requested format. */
     538    HGCMFunctionParameter cbFormat;     /* OUT uint32_t */
     539    /** Drop action peformed on the host. */
    407540    HGCMFunctionParameter uAction;      /* OUT uint32_t */
    408541} VBOXDNDGHDROPPEDMSG;
     
    423556    VBoxGuestHGCMCallInfo hdr;
    424557
    425     HGCMFunctionParameter msg;          /* OUT uint32_t */
     558    /** Message ID. */
     559    HGCMFunctionParameter uMsg;      /* OUT uint32_t */
    426560    /** Number of parameters the message needs. */
    427     HGCMFunctionParameter num_parms;    /* OUT uint32_t */
     561    HGCMFunctionParameter cParms;    /* OUT uint32_t */
    428562    /** Whether or not to block (wait) for a
    429563     *  new message to arrive. */
    430     HGCMFunctionParameter block;        /* OUT uint32_t */
    431 
     564    HGCMFunctionParameter fBlock;    /* OUT uint32_t */
    432565} VBOXDNDNEXTMSGMSG;
    433566
    434567/**
    435  * Connection request. Used to tell the DnD protocol
     568 * Guest connection request. Used to tell the DnD protocol
    436569 * version to the (host) service.
    437570 *
     
    447580    /** Connection flags. Optional. */
    448581    HGCMFunctionParameter uFlags;        /* OUT uint32_t */
    449 
    450582} VBOXDNDCONNECTMSG;
    451583
     
    486618
    487619/**
    488  * GH Acknowledge Pending event.
     620 * Acknowledges a pending drag and drop event
     621 * to the host.
    489622 *
    490623 * Used by:
     
    501634
    502635/**
    503  * GH Send Data event.
     636 * Sends the header of an incoming data block
     637 * to the host.
     638 *
     639 * Used by:
     640 * GUEST_DND_GH_SND_DATA_HDR
     641 *
     642 * New since protocol v3.
     643 */
     644typedef struct VBOXDNDHGSENDDATAHDRMSG VBOXDNDGHSENDDATAHDRMSG;
     645
     646/**
     647 * Sends a (meta) data block to the host.
    504648 *
    505649 * Used by:
     
    507651 */
    508652typedef struct VBOXDNDGHSENDDATAMSG
    509 {
    510     VBoxGuestHGCMCallInfo hdr;
    511 
    512     HGCMFunctionParameter pvData;       /* OUT ptr */
    513     /** Total bytes to send. This can be more than
    514      *  the data block specified in pvData above, e.g.
    515      *  when sending over file objects afterwards. */
    516     HGCMFunctionParameter cbTotalBytes; /* OUT uint32_t */
    517 } VBOXDNDGHSENDDATAMSG;
    518 
    519 /**
    520  * GH Directory event.
    521  *
    522  * Used by:
    523  * GUEST_DND_GH_SND_DIR
    524  */
    525 typedef struct VBOXDNDGHSENDDIRMSG
    526 {
    527     VBoxGuestHGCMCallInfo hdr;
    528 
    529     HGCMFunctionParameter pvName;       /* OUT ptr */
    530     HGCMFunctionParameter cbName;       /* OUT uint32_t */
    531     HGCMFunctionParameter fMode;        /* OUT uint32_t */
    532 } VBOXDNDGHSENDDIRMSG;
    533 
    534 /**
    535  * GH File header event.
    536  * Note: Only for protocol version 2 and up.
    537  *
    538  * Used by:
    539  * HOST_DND_GH_SND_FILE_HDR
    540  */
    541 typedef struct VBOXDNDHGSENDFILEHDRMSG VBOXDNDGHSENDFILEHDRMSG;
    542 
    543 /**
    544  * GH File data event.
    545  *
    546  * Used by:
    547  * GUEST_DND_HG_SND_FILE_DATA
    548  */
    549 typedef struct VBOXDNDGHSENDFILEDATAMSG
    550653{
    551654    VBoxGuestHGCMCallInfo hdr;
     
    553656    union
    554657    {
    555         /* Note: Protocol v1 sends the file name + file mode
    556          *       every time a file data chunk is being sent. */
    557         struct
    558         {
    559             HGCMFunctionParameter pvName;   /* OUT ptr */
    560             HGCMFunctionParameter cbName;   /* OUT uint32_t */
    561             HGCMFunctionParameter fMode;    /* OUT uint32_t */
    562             HGCMFunctionParameter pvData;   /* OUT ptr */
    563             HGCMFunctionParameter cbData;   /* OUT uint32_t */
     658        struct
     659        {
     660            HGCMFunctionParameter pvData;       /* OUT ptr */
     661            /** Total bytes to send. This can be more than
     662             * the data block specified in pvData above, e.g.
     663             * when sending over file objects afterwards. */
     664            HGCMFunctionParameter cbTotalBytes; /* OUT uint32_t */
    564665        } v1;
    565666        struct
    566667        {
    567             /** Note: pvName is now part of the VBOXDNDHGSENDFILEHDRMSG message. */
    568             /** Note: cbName is now part of the VBOXDNDHGSENDFILEHDRMSG message. */
    569668            /** Context ID. Unused at the moment. */
    570             HGCMFunctionParameter uContext; /* OUT uint32_t */
    571             HGCMFunctionParameter pvData;   /* OUT ptr */
    572             HGCMFunctionParameter cbData;   /* OUT uint32_t */
    573             /** Note: fMode is now part of the VBOXDNDHGSENDFILEHDRMSG message. */
    574         } v2;
     669            HGCMFunctionParameter uContext;     /* OUT uint32_t */
     670            /** Data block to send. */
     671            HGCMFunctionParameter pvData;       /* OUT ptr */
     672            /** Size (in bytes) of data block to send. */
     673            HGCMFunctionParameter cbData;       /* OUT uint32_t */
     674            /** (Rolling) Checksum, based on checksum type in data header. */
     675            HGCMFunctionParameter pvChecksum;   /* OUT ptr */
     676            /** Size (in bytes) of checksum. */
     677            HGCMFunctionParameter cbChecksum;   /* OUT uint32_t */
     678        } v3;
    575679    } u;
    576 
    577 } VBOXDNDGHSENDFILEDATAMSG;
    578 
    579 /**
    580  * GH Error event.
     680} VBOXDNDGHSENDDATAMSG;
     681
     682/**
     683 * Sends a directory entry to the host.
     684 *
     685 * Used by:
     686 * GUEST_DND_GH_SND_DIR
     687 */
     688typedef struct VBOXDNDHGSENDDIRMSG VBOXDNDGHSENDDIRMSG;
     689
     690/**
     691 * Sends a file header to the host.
     692 *
     693 * Used by:
     694 * GUEST_DND_GH_SND_FILE_HDR
     695 *
     696 * New since protocol v2.
     697 */
     698typedef struct VBOXDNDHGSENDFILEHDRMSG VBOXDNDGHSENDFILEHDRMSG;
     699
     700/**
     701 * Sends file data to the host.
     702 *
     703 * Used by:
     704 * GUEST_DND_GH_SND_FILE_DATA
     705 */
     706typedef struct VBOXDNDHGSENDFILEDATAMSG VBOXDNDGHSENDFILEDATAMSG;
     707
     708/**
     709 * Sends a guest error event to the host.
    581710 *
    582711 * Used by:
     
    604733    CB_MAGIC_DND_GH_ACK_PENDING            = 0xbe975a14,
    605734    CB_MAGIC_DND_GH_SND_DATA               = 0x4eb61bff,
     735    CB_MAGIC_DND_GH_SND_DATA_HDR           = 0x4631ee4f,
    606736    CB_MAGIC_DND_GH_SND_DIR                = 0x411ca754,
    607737    CB_MAGIC_DND_GH_SND_FILE_HDR           = 0x65e35eaf,
     
    669799} VBOXDNDCBGHACKPENDINGDATA, *PVBOXDNDCBGHACKPENDINGDATA;
    670800
     801/**
     802 * Data header.
     803 * New since protocol v3.
     804 */
     805typedef struct VBOXDNDDATAHDR
     806{
     807    /** Data transfer flags. Not yet used and must be 0. */
     808    uint32_t                    uFlags;
     809    /** Screen ID where the data originates from. */
     810    uint32_t                    uScreenId;
     811    /** Total size (in bytes) to transfer. */
     812    uint64_t                    cbTotal;
     813    /** Meta data size (in bytes) to transfer.
     814     *  This size also is part of cbTotal already. */
     815    uint32_t                    cbMeta;
     816    /** Meta format buffer. */
     817    void                       *pvMetaFmt;
     818    /** Size (in bytes) of meta format buffer. */
     819    uint32_t                    cbMetaFmt;
     820    /** Number of objects (files/directories) to transfer. */
     821    uint64_t                    cObjects;
     822    /** Compression type. Currently unused, so specify 0.
     823     **@todo Add IPRT compression type enumeration as soon as it's available. */
     824    uint32_t                    enmCompression;
     825    /** Checksum type. Currently unused, so specify RTDIGESTTYPE_INVALID. */
     826    RTDIGESTTYPE                enmChecksumType;
     827    /** The actual checksum buffer for the entire data to be transferred,
     828     *  based on enmChksumType. If RTDIGESTTYPE_INVALID is specified,
     829     *  no checksum is being used and pvChecksum will be NULL. */
     830    void                       *pvChecksum;
     831    /** Size (in bytes) of checksum. */
     832    uint32_t                    cbChecksum;
     833} VBOXDNDDATAHDR, *PVBOXDNDSNDDATAHDR;
     834
     835/* New since protocol v3. */
     836typedef struct VBOXDNDCBSNDDATAHDRDATA
     837{
     838    /** Callback data header. */
     839    VBOXDNDCBHEADERDATA         hdr;
     840    /** Actual header data. */
     841    VBOXDNDDATAHDR              data;
     842} VBOXDNDCBSNDDATAHDRDATA, *PVBOXDNDCBSNDDATAHDRDATA;
     843
     844typedef struct VBOXDNDSNDDATA
     845{
     846    union
     847    {
     848        struct
     849        {
     850            /** Data block buffer. */
     851            void                       *pvData;
     852            /** Size (in bytes) of data block. */
     853            uint32_t                    cbData;
     854            /** Total metadata size (in bytes). This is transmitted
     855             *  with every message because the size can change. */
     856            uint32_t                    cbTotalSize;
     857        } v1;
     858        /* Protocol v2: No changes. */
     859        struct
     860        {
     861            /** Data block buffer. */
     862            void                       *pvData;
     863            /** Size (in bytes) of data block. */
     864            uint32_t                    cbData;
     865            /** (Rolling) Checksum. Not yet implemented. */
     866            void                       *pvChecksum;
     867            /** Size (in bytes) of checksum. Not yet implemented. */
     868            uint32_t                    cbChecksum;
     869        } v3;
     870    } u;
     871} VBOXDNDSNDDATA, *PVBOXDNDSNDDATA;
     872
    671873typedef struct VBOXDNDCBSNDDATADATA
    672874{
    673875    /** Callback data header. */
    674876    VBOXDNDCBHEADERDATA         hdr;
    675     void                       *pvData;
    676     uint32_t                    cbData;
    677     /** Total metadata size (in bytes). This is transmitted
    678      *  with every message because the size can change. */
    679     uint32_t                    cbTotalSize;
     877    /** Actual data. */
     878    VBOXDNDSNDDATA              data;
    680879} VBOXDNDCBSNDDATADATA, *PVBOXDNDCBSNDDATADATA;
    681880
     
    684883    /** Callback data header. */
    685884    VBOXDNDCBHEADERDATA         hdr;
     885    /** Directory path. */
    686886    char                       *pszPath;
     887    /** Size (in bytes) of path. */
    687888    uint32_t                    cbPath;
     889    /** Directory creation mode. */
    688890    uint32_t                    fMode;
    689891} VBOXDNDCBSNDDIRDATA, *PVBOXDNDCBSNDDIRDATA;
    690892
    691 /*  Note: Only for protocol version 2 and up (>= VBox 5.0). */
     893/* Note: Only for protocol version 2 and up (>= VBox 5.0). */
    692894typedef struct VBOXDNDCBSNDFILEHDRDATA
    693895{
     
    725927            uint32_t            fMode;
    726928        } v1;
    727         /* Note: Protocol version 2 has the file attributes (name, size,
    728                  mode, ...) in the VBOXDNDCBSNDFILEHDRDATA structure. */
     929        /* Protocol v2 + v3: Have the file attributes (name, size, mode, ...)
     930                             in the VBOXDNDCBSNDFILEHDRDATA structure. */
     931        struct
     932        {
     933            /** Checksum for current file data chunk. */
     934            void               *pvChecksum;
     935            /** Size (in bytes) of current data chunk. */
     936            uint32_t            cbChecksum;
     937        } v3;
    729938    } u;
    730939} VBOXDNDCBSNDFILEDATADATA, *PVBOXDNDCBSNDFILEDATADATA;
  • trunk/include/VBox/VBoxGuestLib.h

    r58204 r58212  
    125125 * The library termination function.
    126126 */
    127 DECLVBGL(void) VbglTerminate(void);
     127DECLVBGL(void) VbglTerminate (void);
    128128
    129129
     
    149149 * @return VBox status code.
    150150 */
    151 DECLVBGL(int) VbglGRPerform(VMMDevRequestHeader *pReq);
     151DECLVBGL(int) VbglGRPerform (VMMDevRequestHeader *pReq);
    152152
    153153/**
     
    158158 * @return VBox status code.
    159159 */
    160 DECLVBGL(void) VbglGRFree(VMMDevRequestHeader *pReq);
     160DECLVBGL(void) VbglGRFree (VMMDevRequestHeader *pReq);
    161161
    162162/**
     
    170170 * @return VBox status code.
    171171 */
    172 DECLVBGL(int) VbglGRVerify(const VMMDevRequestHeader *pReq, size_t cbReq);
     172DECLVBGL(int) VbglGRVerify (const VMMDevRequestHeader *pReq, size_t cbReq);
    173173/** @} */
    174174
     
    205205 */
    206206
    207 DECLR0VBGL(int) VbglR0HGCMInternalConnect(VBoxGuestHGCMConnectInfo *pConnectInfo,
    208                                           PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData);
     207DECLR0VBGL(int) VbglR0HGCMInternalConnect (VBoxGuestHGCMConnectInfo *pConnectInfo,
     208                                           PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData);
    209209
    210210
     
    226226 */
    227227
    228 DECLR0VBGL(int) VbglR0HGCMInternalDisconnect(VBoxGuestHGCMDisconnectInfo *pDisconnectInfo,
    229                                              PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData);
     228DECLR0VBGL(int) VbglR0HGCMInternalDisconnect (VBoxGuestHGCMDisconnectInfo *pDisconnectInfo,
     229                                              PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData);
    230230
    231231/** Call a HGCM service.
     
    243243 * @return VBox status code.
    244244 */
    245 DECLR0VBGL(int) VbglR0HGCMInternalCall(VBoxGuestHGCMCallInfo *pCallInfo, uint32_t cbCallInfo, uint32_t fFlags,
    246                                        PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData);
     245DECLR0VBGL(int) VbglR0HGCMInternalCall (VBoxGuestHGCMCallInfo *pCallInfo, uint32_t cbCallInfo, uint32_t fFlags,
     246                                        PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData);
    247247
    248248/** Call a HGCM service. (32 bits packet structure in a 64 bits guest)
     
    260260 * @return  VBox status code.
    261261 */
    262 DECLR0VBGL(int) VbglR0HGCMInternalCall32(VBoxGuestHGCMCallInfo *pCallInfo, uint32_t cbCallInfo, uint32_t fFlags,
    263                                          PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData);
     262DECLR0VBGL(int) VbglR0HGCMInternalCall32 (VBoxGuestHGCMCallInfo *pCallInfo, uint32_t cbCallInfo, uint32_t fFlags,
     263                                          PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData);
    264264
    265265/** @name VbglR0HGCMInternalCall flags
     
    296296 * @return VBox status code.
    297297 */
    298 DECLVBGL(int) VbglHGCMConnect(VBGLHGCMHANDLE *pHandle, VBoxGuestHGCMConnectInfo *pData);
     298DECLVBGL(int) VbglHGCMConnect (VBGLHGCMHANDLE *pHandle, VBoxGuestHGCMConnectInfo *pData);
    299299
    300300/**
     
    306306 * @return VBox status code.
    307307 */
    308 DECLVBGL(int) VbglHGCMDisconnect(VBGLHGCMHANDLE handle, VBoxGuestHGCMDisconnectInfo *pData);
     308DECLVBGL(int) VbglHGCMDisconnect (VBGLHGCMHANDLE handle, VBoxGuestHGCMDisconnectInfo *pData);
    309309
    310310/**
     
    317317 * @return VBox status code.
    318318 */
    319 DECLVBGL(int) VbglHGCMCall(VBGLHGCMHANDLE handle, VBoxGuestHGCMCallInfo *pData, uint32_t cbData);
     319DECLVBGL(int) VbglHGCMCall (VBGLHGCMHANDLE handle, VBoxGuestHGCMCallInfo *pData, uint32_t cbData);
    320320
    321321/**
     
    329329 * @return VBox status code.
    330330 */
    331 DECLVBGL(int) VbglHGCMCallUserData(VBGLHGCMHANDLE handle, VBoxGuestHGCMCallInfo *pData, uint32_t cbData);
     331DECLVBGL(int) VbglHGCMCallUserData (VBGLHGCMHANDLE handle, VBoxGuestHGCMCallInfo *pData, uint32_t cbData);
    332332
    333333/**
     
    365365 * @returns VBox status code.
    366366 */
    367 DECLVBGL(int) VbglPhysHeapInit(void);
     367DECLVBGL(int) VbglPhysHeapInit (void);
    368368
    369369/**
    370370 * Shutdown the heap.
    371371 */
    372 DECLVBGL(void) VbglPhysHeapTerminate(void);
     372DECLVBGL(void) VbglPhysHeapTerminate (void);
    373373
    374374/**
     
    376376 *
    377377 * @returns Virtual address of the allocated memory block.
    378  * @param   cbSize    Size of block to be allocated.
    379  */
    380 DECLVBGL(void *) VbglPhysHeapAlloc(uint32_t cbSize);
     378 * @param cbSize    Size of block to be allocated.
     379 */
     380DECLVBGL(void *) VbglPhysHeapAlloc (uint32_t cbSize);
    381381
    382382/**
     
    401401DECLVBGL(void)      VbglPhysHeapFree(void *pv);
    402402
    403 DECLVBGL(int)       VbglQueryVMMDevMemory(VMMDevMemory **ppVMMDevMemory);
    404 DECLR0VBGL(bool)    VbglR0CanUsePhysPageList(void);
     403DECLVBGL(int) VbglQueryVMMDevMemory (VMMDevMemory **ppVMMDevMemory);
     404DECLR0VBGL(bool) VbglR0CanUsePhysPageList(void);
    405405
    406406# ifndef VBOX_GUEST
    407407/** @name Mouse
    408408 * @{ */
    409 DECLVBGL(int)       VbglSetMouseNotifyCallback(PFNVBOXGUESTMOUSENOTIFY pfnNotify, void *pvUser);
    410 DECLVBGL(int)       VbglGetMouseStatus(uint32_t *pfFeatures, uint32_t *px, uint32_t *py);
    411 DECLVBGL(int)       VbglSetMouseStatus(uint32_t fFeatures);
     409DECLVBGL(int)     VbglSetMouseNotifyCallback(PFNVBOXGUESTMOUSENOTIFY pfnNotify, void *pvUser);
     410DECLVBGL(int)     VbglGetMouseStatus(uint32_t *pfFeatures, uint32_t *px, uint32_t *py);
     411DECLVBGL(int)     VbglSetMouseStatus(uint32_t fFeatures);
    412412/** @}  */
    413413# endif /* VBOX_GUEST */
     
    492492/** The folder for the video mode hint unix domain socket on Unix-like guests.
    493493 * @note This can be safely changed as all users are rebuilt in lock-step. */
    494 #define VBGLR3HOSTDISPSOCKETPATH    "/tmp/.VBoxService"
     494#define VBGLR3HOSTDISPSOCKETPATH "/tmp/.VBoxService"
    495495/** The path to the video mode hint unix domain socket on Unix-like guests. */
    496496#define VBGLR3HOSTDISPSOCKET        VBGLR3VIDEOMODEHINTSOCKETPATH "/VideoModeHint"
     
    758758     *        Use a union for the HGCM stuff then. */
    759759
    760     /** IN: HGCM client ID to use for communication. */
     760    /** IN:  HGCM client ID to use for communication. */
    761761    uint32_t uClientID;
    762     /** IN: Protocol version to use. */
     762    /** IN:  Protocol version to use. */
    763763    uint32_t uProtocol;
    764764    /** OUT: Number of parameters retrieved. */
    765765    uint32_t uNumParms;
     766    /** IN:  Max chunk size (in bytes) for data transfers. */
     767    uint32_t cbMaxChunkSize;
    766768} VBGLR3GUESTDNDCMDCTX, *PVBGLR3GUESTDNDCMDCTX;
    767769
     
    771773    uint32_t uScreenId;           /** Screen ID this request belongs to. */
    772774    char    *pszFormats;          /** Format list (\r\n separated). */
    773     uint32_t cbFormats;           /** Size of pszFormats (\0 included). */
     775    uint32_t cbFormats;           /** Size (in bytes) of pszFormats (\0 included). */
    774776    union
    775777    {
     
    784786        {
    785787            void    *pvData;      /** Data request. */
    786             size_t   cbData;      /** Size of pvData. */
     788            uint32_t cbData;      /** Size (in bytes) of pvData. */
    787789        } b; /** Values used in drop data event type. */
    788790    } u;
     
    793795VBGLR3DECL(int)     VbglR3DnDDisconnect(PVBGLR3GUESTDNDCMDCTX pCtx);
    794796
    795 VBGLR3DECL(int)     VbglR3DnDProcessNextMessage(PVBGLR3GUESTDNDCMDCTX pCtx, CPVBGLR3DNDHGCMEVENT pEvent);
    796 
    797 VBGLR3DECL(int)     VbglR3DnDHGAcknowledgeOperation(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uAction);
    798 VBGLR3DECL(int)     VbglR3DnDHGRequestData(PVBGLR3GUESTDNDCMDCTX pCtx, const char *pszFormat);
    799 VBGLR3DECL(int)     VbglR3DnDHGSetProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr);
     797VBGLR3DECL(int)     VbglR3DnDRecvNextMsg(PVBGLR3GUESTDNDCMDCTX pCtx, CPVBGLR3DNDHGCMEVENT pEvent);
     798
     799VBGLR3DECL(int)     VbglR3DnDHGSendAckOp(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uAction);
     800VBGLR3DECL(int)     VbglR3DnDHGSendReqData(PVBGLR3GUESTDNDCMDCTX pCtx, const char *pcszFormat);
     801VBGLR3DECL(int)     VbglR3DnDHGSendProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr);
    800802#  ifdef VBOX_WITH_DRAG_AND_DROP_GH
    801 VBGLR3DECL(int)     VbglR3DnDGHAcknowledgePending(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uDefAction,
    802                                                   uint32_t uAllActions, const char *pszFormats);
     803VBGLR3DECL(int)     VbglR3DnDGHSendAckPending(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats, uint32_t cbFormats);
    803804VBGLR3DECL(int)     VbglR3DnDGHSendData(PVBGLR3GUESTDNDCMDCTX pCtx, const char *pszFormat, void *pvData, uint32_t cbData);
    804805VBGLR3DECL(int)     VbglR3DnDGHSendError(PVBGLR3GUESTDNDCMDCTX pCtx, int rcOp);
  • trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp

    r58157 r58212  
    2222#include <VBox/VBoxGuestLib.h>
    2323#include "VBox/HostServices/DragAndDropSvc.h"
     24
     25using namespace DragAndDropSvc;
    2426
    2527#include <iprt/asm.h>
     
    520522            switch (pEvent->Event.uType)
    521523            {
    522                 case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
     524                case HOST_DND_HG_EVT_ENTER:
    523525                {
    524526                    LogFlowThisFunc(("HOST_DND_HG_EVT_ENTER\n"));
     
    540542                }
    541543
    542                 case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
     544                case HOST_DND_HG_EVT_MOVE:
    543545                {
    544546                    LogFlowThisFunc(("HOST_DND_HG_EVT_MOVE: %d,%d\n",
     
    550552                }
    551553
    552                 case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE:
     554                case HOST_DND_HG_EVT_LEAVE:
    553555                {
    554556                    LogFlowThisFunc(("HOST_DND_HG_EVT_LEAVE\n"));
     
    558560                }
    559561
    560                 case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
     562                case HOST_DND_HG_EVT_DROPPED:
    561563                {
    562564                    LogFlowThisFunc(("HOST_DND_HG_EVT_DROPPED\n"));
     
    566568                }
    567569
    568                 case DragAndDropSvc::HOST_DND_HG_SND_DATA:
     570                case HOST_DND_HG_SND_DATA:
     571                    /* Protocol v1 + v2: Also contains the header data.
     572                    /* Note: Fall through is intentional. */
     573                case HOST_DND_HG_SND_DATA_HDR:
    569574                {
    570575                    LogFlowThisFunc(("HOST_DND_HG_SND_DATA\n"));
     
    575580                }
    576581
    577                 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
     582                case HOST_DND_HG_EVT_CANCEL:
    578583                {
    579584                    LogFlowThisFunc(("HOST_DND_HG_EVT_CANCEL\n"));
     
    583588                }
    584589
    585                 case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
     590                case HOST_DND_GH_REQ_PENDING:
    586591                {
    587592                    LogFlowThisFunc(("HOST_DND_GH_REQ_PENDING\n"));
     
    595600                }
    596601
    597                 case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
     602                case HOST_DND_GH_EVT_DROPPED:
    598603                {
    599604                    LogFlowThisFunc(("HOST_DND_GH_EVT_DROPPED\n"));
     
    616621            switch (pEvent->Event.uType)
    617622            {
    618                 case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
    619                 case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
    620                 case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
     623                case HOST_DND_HG_EVT_ENTER:
     624                case HOST_DND_HG_EVT_MOVE:
     625                case HOST_DND_HG_EVT_DROPPED:
    621626#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    622                 case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
     627                case HOST_DND_GH_EVT_DROPPED:
    623628#endif
    624629                {
     
    628633                }
    629634
    630                 case DragAndDropSvc::HOST_DND_HG_SND_DATA:
     635                case HOST_DND_HG_SND_DATA:
     636                case HOST_DND_HG_SND_DATA_HDR:
    631637                {
    632638                    if (pEvent->Event.pszFormats)
     
    945951    if (RT_SUCCESS(rc))
    946952    {
    947         rc = VbglR3DnDHGAcknowledgeOperation(&mDnDCtx, uActionNotify);
     953        rc = VbglR3DnDHGSendAckOp(&mDnDCtx, uActionNotify);
    948954        if (RT_FAILURE(rc))
    949955            LogFlowThisFunc(("Acknowledging operation failed with rc=%Rrc\n", rc));
     
    10151021            {
    10161022                LogRel(("DnD: Requesting data as '%s' ...\n", mFormatRequested.c_str()));
    1017                 rc = VbglR3DnDHGRequestData(&mDnDCtx, mFormatRequested.c_str());
     1023                rc = VbglR3DnDHGSendReqData(&mDnDCtx, mFormatRequested.c_str());
    10181024                if (RT_FAILURE(rc))
    10191025                    LogFlowThisFunc(("Requesting data failed with rc=%Rrc\n", rc));
     
    12151221        uAllActions = uDefAction;
    12161222
    1217         rc = VbglR3DnDGHAcknowledgePending(&mDnDCtx,
    1218                                            uDefAction, uAllActions, strFormats.c_str());
     1223        rc = VbglR3DnDGHSendAckPending(&mDnDCtx,
     1224                                       uDefAction, uAllActions,
     1225                                       strFormats.c_str(), strFormats.length() + 1 /* Include termination */);
    12191226        if (RT_FAILURE(rc))
    12201227        {
     
    17611768        /* Note: pEvent will be free'd by the consumer later. */
    17621769
    1763         rc = VbglR3DnDProcessNextMessage(&pCtx->cmdCtx, &pEvent->Event);
    1764         LogFlowFunc(("VbglR3DnDProcessNextMessage returned uType=%RU32, rc=%Rrc\n",
    1765                      pEvent->Event.uType, rc));
     1770        rc = VbglR3DnDRecvNextMsg(&pCtx->cmdCtx, &pEvent->Event);
     1771        LogFlowFunc(("VbglR3DnDRecvNextMsg: uType=%RU32, rc=%Rrc\n", pEvent->Event.uType, rc));
    17661772
    17671773        if (   RT_SUCCESS(rc)
  • trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp

    r58183 r58212  
    4848#include <VBox/HostServices/DragAndDropSvc.h>
    4949
     50using namespace DragAndDropSvc;
     51
    5052#include "VBGLR3Internal.h"
    5153
    52 /* Here all the communication with the host over HGCM is handled platform
    53  * neutral. Also the receiving of URIs content (directory trees and files) is
    54  * done here. So the platform code of the guests, should not take care of that.
    55  *
    56  * Todo:
    57  * - Sending dirs/files in the G->H case
    58  * - Maybe the EOL converting of text MIME types (not fully sure, eventually
    59  *   better done on the host side)
    60  */
    61 
    62 
    6354/*********************************************************************************************************************************
    64 *   Private internal functions                                                                                                   *
     55*    Forward declarations                                                                                                        *
    6556*********************************************************************************************************************************/
    6657
    67 static int vbglR3DnDQueryNextHostMessageType(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t *puMsg, uint32_t *pcParms, bool fWait)
     58VBGLR3DECL(int) VbglR3DnDHGSendProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr);
     59
     60/*********************************************************************************************************************************
     61*    Private internal functions                                                                                                  *
     62*********************************************************************************************************************************/
     63
     64static int vbglR3DnDGetNextMsgType(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t *puMsg, uint32_t *pcParms, bool fWait)
    6865{
    6966    AssertPtrReturn(pCtx,    VERR_INVALID_POINTER);
     
    7168    AssertPtrReturn(pcParms, VERR_INVALID_POINTER);
    7269
    73     DragAndDropSvc::VBOXDNDNEXTMSGMSG Msg;
     70    VBOXDNDNEXTMSGMSG Msg;
    7471    RT_ZERO(Msg);
    7572    Msg.hdr.result      = VERR_WRONG_ORDER;
    7673    Msg.hdr.u32ClientID = pCtx->uClientID;
    77     Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG;
     74    Msg.hdr.u32Function = GUEST_DND_GET_NEXT_HOST_MSG;
    7875    Msg.hdr.cParms      = 3;
    7976
    80     Msg.msg.SetUInt32(0);
    81     Msg.num_parms.SetUInt32(0);
    82     Msg.block.SetUInt32(fWait ? 1 : 0);
     77    Msg.uMsg.SetUInt32(0);
     78    Msg.cParms.SetUInt32(0);
     79    Msg.fBlock.SetUInt32(fWait ? 1 : 0);
    8380
    8481    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    8885        if (RT_SUCCESS(rc))
    8986        {
    90             rc = Msg.msg.GetUInt32(puMsg);         AssertRC(rc);
    91             rc = Msg.num_parms.GetUInt32(pcParms); AssertRC(rc);
    92         }
    93     }
    94 
    95     return rc;
    96 }
    97 
    98 static int vbglR3DnDHGProcessActionMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
    99                                            uint32_t  uMsg,
    100                                            uint32_t *puScreenId,
    101                                            uint32_t *puX,
    102                                            uint32_t *puY,
    103                                            uint32_t *puDefAction,
    104                                            uint32_t *puAllActions,
    105                                            char     *pszFormats,
    106                                            uint32_t  cbFormats,
    107                                            uint32_t *pcbFormatsRecv)
     87            rc = Msg.uMsg.GetUInt32(puMsg);         AssertRC(rc);
     88            rc = Msg.cParms.GetUInt32(pcParms); AssertRC(rc);
     89        }
     90    }
     91
     92    return rc;
     93}
     94
     95/** @todo r=andy Clean up the parameter list. */
     96static int vbglR3DnDHGRecvAction(PVBGLR3GUESTDNDCMDCTX pCtx,
     97                                 uint32_t  uMsg,
     98                                 uint32_t *puScreenId,
     99                                 uint32_t *puX,
     100                                 uint32_t *puY,
     101                                 uint32_t *puDefAction,
     102                                 uint32_t *puAllActions,
     103                                 char     *pszFormats,
     104                                 uint32_t  cbFormats,
     105                                 uint32_t *pcbFormatsRecv)
    108106{
    109107    AssertPtrReturn(pCtx,           VERR_INVALID_POINTER);
     
    117115    AssertPtrReturn(pcbFormatsRecv, VERR_INVALID_POINTER);
    118116
    119     DragAndDropSvc::VBOXDNDHGACTIONMSG Msg;
     117    VBOXDNDHGACTIONMSG Msg;
    120118    RT_ZERO(Msg);
     119    Msg.hdr.result      = VERR_WRONG_ORDER;
    121120    Msg.hdr.u32ClientID = pCtx->uClientID;
    122121    Msg.hdr.u32Function = uMsg;
     
    151150}
    152151
    153 static int vbglR3DnDHGProcessLeaveMessage(PVBGLR3GUESTDNDCMDCTX pCtx)
     152static int vbglR3DnDHGRecvLeave(PVBGLR3GUESTDNDCMDCTX pCtx)
    154153{
    155154    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    156155
    157     DragAndDropSvc::VBOXDNDHGLEAVEMSG Msg;
     156    VBOXDNDHGLEAVEMSG Msg;
    158157    RT_ZERO(Msg);
    159158    Msg.hdr.u32ClientID = pCtx->uClientID;
    160     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_LEAVE;
     159    Msg.hdr.u32Function = HOST_DND_HG_EVT_LEAVE;
    161160    Msg.hdr.cParms      = 0;
    162161
     
    168167}
    169168
    170 static int vbglR3DnDHGProcessCancelMessage(PVBGLR3GUESTDNDCMDCTX pCtx)
     169static int vbglR3DnDHGRecvCancel(PVBGLR3GUESTDNDCMDCTX pCtx)
    171170{
    172171    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    173172
    174     DragAndDropSvc::VBOXDNDHGCANCELMSG Msg;
     173    VBOXDNDHGCANCELMSG Msg;
    175174    RT_ZERO(Msg);
     175    Msg.hdr.result      = VERR_WRONG_ORDER;
    176176    Msg.hdr.u32ClientID = pCtx->uClientID;
    177     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_CANCEL;
     177    Msg.hdr.u32Function = HOST_DND_HG_EVT_CANCEL;
    178178    Msg.hdr.cParms      = 0;
    179179
     
    185185}
    186186
    187 static int vbglR3DnDHGProcessSendDirMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
    188                                             char     *pszDirname,
    189                                             uint32_t  cbDirname,
    190                                             uint32_t *pcbDirnameRecv,
    191                                             uint32_t *pfMode)
     187static int vbglR3DnDHGRecvDir(PVBGLR3GUESTDNDCMDCTX pCtx,
     188                              char     *pszDirname,
     189                              uint32_t  cbDirname,
     190                              uint32_t *pcbDirnameRecv,
     191                              uint32_t *pfMode)
    192192{
    193193    AssertPtrReturn(pCtx,           VERR_INVALID_POINTER);
     
    197197    AssertPtrReturn(pfMode,         VERR_INVALID_POINTER);
    198198
    199     DragAndDropSvc::VBOXDNDHGSENDDIRMSG Msg;
     199    VBOXDNDHGSENDDIRMSG Msg;
    200200    RT_ZERO(Msg);
     201    Msg.hdr.result      = VERR_WRONG_ORDER;
    201202    Msg.hdr.u32ClientID = pCtx->uClientID;
    202     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_DIR;
     203    Msg.hdr.u32Function = HOST_DND_HG_SND_DIR;
    203204    Msg.hdr.cParms      = 3;
    204205
    205206    Msg.pvName.SetPtr(pszDirname, cbDirname);
    206     Msg.cbName.SetUInt32(0);
     207    Msg.cbName.SetUInt32(cbDirname);
    207208    Msg.fMode.SetUInt32(0);
    208209
     
    223224}
    224225
    225 static int vbglR3DnDHGProcessSendFileMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
    226                                              char                 *pszFilename,
    227                                              uint32_t              cbFilename,
    228                                              uint32_t             *pcbFilenameRecv,
    229                                              void                 *pvData,
    230                                              uint32_t              cbData,
    231                                              uint32_t             *pcbDataRecv,
    232                                              uint32_t             *pfMode)
     226static int vbglR3DnDHGRecvFileData(PVBGLR3GUESTDNDCMDCTX pCtx,
     227                                   char                 *pszFilename,
     228                                   uint32_t              cbFilename,
     229                                   uint32_t             *pcbFilenameRecv,
     230                                   void                 *pvData,
     231                                   uint32_t              cbData,
     232                                   uint32_t             *pcbDataRecv,
     233                                   uint32_t             *pfMode)
    233234{
    234235    AssertPtrReturn(pCtx,            VERR_INVALID_POINTER);
     
    241242    AssertPtrReturn(pfMode,          VERR_INVALID_POINTER);
    242243
    243     DragAndDropSvc::VBOXDNDHGSENDFILEDATAMSG Msg;
     244    VBOXDNDHGSENDFILEDATAMSG Msg;
    244245    RT_ZERO(Msg);
     246    Msg.hdr.result      = VERR_WRONG_ORDER;
    245247    Msg.hdr.u32ClientID = pCtx->uClientID;
    246     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA;
     248    Msg.hdr.u32Function = HOST_DND_HG_SND_FILE_DATA;
    247249
    248250    if (pCtx->uProtocol <= 1)
    249251    {
    250252        Msg.u.v1.pvName.SetPtr(pszFilename, cbFilename);
    251         Msg.u.v1.cbName.SetUInt32(cbFilename);
     253        Msg.u.v1.cbName.SetUInt32(0);
    252254        Msg.u.v1.pvData.SetPtr(pvData, cbData);
    253         Msg.u.v1.cbData.SetUInt32(cbData);
     255        Msg.u.v1.cbData.SetUInt32(0);
    254256        Msg.u.v1.fMode.SetUInt32(0);
    255257
    256258        Msg.hdr.cParms = 5;
    257259    }
    258     else
    259     {
    260         Msg.u.v2.uContext.SetUInt32(0); /** @todo Not used yet. */
     260    else if (pCtx->uProtocol == 2)
     261    {
     262        Msg.u.v2.uContext.SetUInt32(0);
    261263        Msg.u.v2.pvData.SetPtr(pvData, cbData);
    262264        Msg.u.v2.cbData.SetUInt32(cbData);
     
    264266        Msg.hdr.cParms = 3;
    265267    }
     268    else if (pCtx->uProtocol >= 3)
     269    {
     270        Msg.u.v3.uContext.SetUInt32(0);
     271        Msg.u.v3.pvData.SetPtr(pvData, cbData);
     272        Msg.u.v3.cbData.SetUInt32(0);
     273        Msg.u.v3.pvChecksum.SetPtr(NULL, 0);
     274        Msg.u.v3.cbChecksum.SetUInt32(0);
     275
     276        Msg.hdr.cParms = 5;
     277    }
     278    else
     279        AssertMsgFailed(("Protocol %RU32 not implemented\n", pCtx->uProtocol));
    266280
    267281    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    280294                AssertReturn(cbData     >= *pcbDataRecv,     VERR_TOO_MUCH_DATA);
    281295            }
    282             else
    283             {
     296            else if (pCtx->uProtocol == 2)
     297            {
     298                /** @todo Context ID not used yet. */
    284299                rc = Msg.u.v2.cbData.GetUInt32(pcbDataRecv);     AssertRC(rc);
    285300                AssertReturn(cbData     >= *pcbDataRecv,     VERR_TOO_MUCH_DATA);
    286301            }
    287         }
    288     }
    289 
    290     LogFlowFuncLeaveRC(rc);
    291     return rc;
    292 }
    293 
    294 static int vbglR3DnDHGProcessSendFileHdrMessage(PVBGLR3GUESTDNDCMDCTX  pCtx,
    295                                                 char                  *pszFilename,
    296                                                 uint32_t               cbFilename,
    297                                                 uint32_t              *puFlags,
    298                                                 uint32_t              *pfMode,
    299                                                 uint64_t              *pcbTotal)
     302            else if (pCtx->uProtocol >= 3)
     303            {
     304                /** @todo Context ID not used yet. */
     305                rc = Msg.u.v3.cbData.GetUInt32(pcbDataRecv);     AssertRC(rc);
     306                AssertReturn(cbData     >= *pcbDataRecv,     VERR_TOO_MUCH_DATA);
     307                /** @todo Add checksum support. */
     308            }
     309            else
     310                AssertMsgFailed(("Protocol %RU32 not implemented\n", pCtx->uProtocol));
     311        }
     312    }
     313
     314    return rc;
     315}
     316
     317static int vbglR3DnDHGRecvFileHdr(PVBGLR3GUESTDNDCMDCTX  pCtx,
     318                                  char                  *pszFilename,
     319                                  uint32_t               cbFilename,
     320                                  uint32_t              *puFlags,
     321                                  uint32_t              *pfMode,
     322                                  uint64_t              *pcbTotal)
    300323{
    301324    AssertPtrReturn(pCtx,        VERR_INVALID_POINTER);
     
    306329    AssertReturn(pcbTotal,       VERR_INVALID_POINTER);
    307330
    308     DragAndDropSvc::VBOXDNDHGSENDFILEHDRMSG Msg;
     331    VBOXDNDHGSENDFILEHDRMSG Msg;
    309332    RT_ZERO(Msg);
     333    Msg.hdr.result      = VERR_WRONG_ORDER;
    310334    Msg.hdr.u32ClientID = pCtx->uClientID;
    311     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR;
     335    Msg.hdr.u32Function = HOST_DND_HG_SND_FILE_HDR;
    312336
    313337    int rc;
     
    348372}
    349373
    350 static int vbglR3DnDHGProcessURIMessages(PVBGLR3GUESTDNDCMDCTX   pCtx,
    351                                          void                  **ppvData,
    352                                          uint32_t                cbData,
    353                                          size_t                 *pcbDataRecv)
    354 {
    355     AssertPtrReturn(pCtx,        VERR_INVALID_POINTER);
    356     AssertPtrReturn(ppvData,     VERR_INVALID_POINTER);
    357     AssertReturn(cbData,         VERR_INVALID_PARAMETER);
    358     AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
     374static int vbglR3DnDHGRecvURIData(PVBGLR3GUESTDNDCMDCTX pCtx, DnDDroppedFiles *pDroppedFiles)
     375{
     376    AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
     377    AssertPtrReturn(pDroppedFiles, VERR_INVALID_POINTER);
    359378
    360379    /*
    361      * Allocate chunk buffer.
     380     * Allocate temporary chunk buffer.
    362381     */
    363     uint32_t cbChunkMax = _64K; /** @todo Make this configurable? */
     382    uint32_t cbChunkMax = pCtx->cbMaxChunkSize;
    364383    void *pvChunk = RTMemAlloc(cbChunkMax);
    365384    if (!pvChunk)
    366385        return VERR_NO_MEMORY;
    367     uint32_t cbChunkRead = 0;
     386    uint32_t cbChunkRead   = 0;
    368387
    369388    uint64_t cbFileSize    = 0; /* Total file size (in bytes). */
     
    373392     * Create and query the (unique) drop target directory in the user's temporary directory.
    374393     */
    375     DnDDroppedFiles droppedFiles;
    376     int rc = droppedFiles.OpenTemp(0 /* fFlags */);
     394    int rc = pDroppedFiles->OpenTemp(0 /* fFlags */);
    377395    if (RT_FAILURE(rc))
    378396    {
     
    381399    }
    382400
    383     const char *pszDropDir = droppedFiles.GetDirAbs();
     401    const char *pszDropDir = pDroppedFiles->GetDirAbs();
    384402    AssertPtr(pszDropDir);
    385403
     
    387405     * Enter the main loop of retieving files + directories.
    388406     */
    389     DnDURIList lstURI;
    390407    DnDURIObject objFile(DnDURIObject::File);
    391408
     
    399416        uint32_t uNextMsg;
    400417        uint32_t cNextParms;
    401         rc = vbglR3DnDQueryNextHostMessageType(pCtx, &uNextMsg, &cNextParms, false /* fWait */);
     418        rc = vbglR3DnDGetNextMsgType(pCtx, &uNextMsg, &cNextParms, false /* fWait */);
    402419        if (RT_SUCCESS(rc))
    403420        {
     
    406423            switch (uNextMsg)
    407424            {
    408                 case DragAndDropSvc::HOST_DND_HG_SND_DIR:
     425                case HOST_DND_HG_SND_DIR:
    409426                {
    410                     rc = vbglR3DnDHGProcessSendDirMessage(pCtx,
    411                                                           szPathName,
    412                                                           sizeof(szPathName),
    413                                                           &cbPathName,
    414                                                           &fMode);
     427                    rc = vbglR3DnDHGRecvDir(pCtx,
     428                                            szPathName,
     429                                            sizeof(szPathName),
     430                                            &cbPathName,
     431                                            &fMode);
    415432                    LogFlowFunc(("HOST_DND_HG_SND_DIR pszPathName=%s, cbPathName=%RU32, fMode=0x%x, rc=%Rrc\n",
    416433                                 szPathName, cbPathName, fMode, rc));
     
    426443                        rc = RTDirCreate(pszPathAbs, fCreationMode, 0);
    427444                        if (RT_SUCCESS(rc))
    428                             rc = droppedFiles.AddDir(pszPathAbs);
     445                            rc = pDroppedFiles->AddDir(pszPathAbs);
    429446
    430447                        RTStrFree(pszPathAbs);
     
    434451                    break;
    435452                }
    436                 case DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR:
    437                 case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA:
     453                case HOST_DND_HG_SND_FILE_HDR:
     454                case HOST_DND_HG_SND_FILE_DATA:
    438455                {
    439                     if (uNextMsg == DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR)
     456                    if (uNextMsg == HOST_DND_HG_SND_FILE_HDR)
    440457                    {
    441                         rc = vbglR3DnDHGProcessSendFileHdrMessage(pCtx,
    442                                                                   szPathName,
    443                                                                   sizeof(szPathName),
    444                                                                   &fFlags,
    445                                                                   &fMode,
    446                                                                   &cbFileSize);
    447                         LogFlowFunc(("HOST_DND_HG_SND_FILE_HDR szPathName=%s, fFlags=0x%x, fMode=0x%x, cbFileSize=%RU64, rc=%Rrc\n",
     458                        rc = vbglR3DnDHGRecvFileHdr(pCtx,
     459                                                    szPathName,
     460                                                    sizeof(szPathName),
     461                                                    &fFlags,
     462                                                    &fMode,
     463                                                    &cbFileSize);
     464                        LogFlowFunc(("HOST_DND_HG_SND_FILE_HDR: "
     465                                     "szPathName=%s, fFlags=0x%x, fMode=0x%x, cbFileSize=%RU64, rc=%Rrc\n",
    448466                                     szPathName, fFlags, fMode, cbFileSize, rc));
    449467                    }
    450468                    else
    451469                    {
    452                         rc = vbglR3DnDHGProcessSendFileMessage(pCtx,
    453                                                                szPathName,
    454                                                                sizeof(szPathName),
    455                                                                &cbPathName,
    456                                                                pvChunk,
    457                                                                cbChunkMax,
    458                                                                &cbChunkRead,
    459                                                                &fMode);
    460                         LogFlowFunc(("HOST_DND_HG_SND_FILE_DATA "
     470                        rc = vbglR3DnDHGRecvFileData(pCtx,
     471                                                     szPathName,
     472                                                     sizeof(szPathName),
     473                                                     &cbPathName,
     474                                                     pvChunk,
     475                                                     cbChunkMax,
     476                                                     &cbChunkRead,
     477                                                     &fMode);
     478
     479                        LogFlowFunc(("HOST_DND_HG_SND_FILE_DATA: "
    461480                                     "szPathName=%s, cbPathName=%RU32, cbChunkRead=%RU32, fMode=0x%x, rc=%Rrc\n",
    462481                                     szPathName, cbPathName, cbChunkRead, fMode, rc));
     
    464483
    465484                    if (   RT_SUCCESS(rc)
    466                         && (   uNextMsg == DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR
    467                              /* Protocol v1 always sends the file name, so opening the file every time. */
     485                        && (   uNextMsg == HOST_DND_HG_SND_FILE_HDR
     486                            /* Protocol v1 always sends the file name, so opening the file every time. */
    468487                            || pCtx->uProtocol <= 1)
    469488                       )
     
    493512                                if (RT_SUCCESS(rc))
    494513                                {
    495                                     rc = droppedFiles.AddFile(strPathAbs.c_str());
     514                                    rc = pDroppedFiles->AddFile(strPathAbs.c_str());
    496515                                    if (RT_SUCCESS(rc))
    497516                                    {
     
    513532
    514533                    if (   RT_SUCCESS(rc)
    515                         && uNextMsg == DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA)
     534                        && uNextMsg == HOST_DND_HG_SND_FILE_DATA)
    516535                    {
    517536                        bool fClose = false;
     
    521540                        if (RT_SUCCESS(rc))
    522541                        {
     542                            LogFlowFunc(("HOST_DND_HG_SND_FILE_DATA "
     543                                         "cbChunkRead=%RU32, cbChunkWritten=%RU32, cbFileWritten=%RU64 cbFileSize=%RU64\n",
     544                                         cbChunkRead, cbChunkWritten, cbFileWritten + cbChunkWritten, cbFileSize));
     545
    523546                            if (pCtx->uProtocol >= 2)
    524547                            {
    525548                                /* Data transfer complete? Close the file. */
    526549                                fClose = objFile.IsComplete();
     550
     551                                /* Only since protocol v2 we know the file size upfront. */
     552                                Assert(cbFileWritten <= cbFileSize);
    527553                            }
    528554                            else
     
    530556
    531557                            cbFileWritten += cbChunkWritten;
    532                             Assert(cbFileWritten <= cbFileSize);
    533558                        }
    534559
     
    541566                    break;
    542567                }
    543                 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
     568                case HOST_DND_HG_EVT_CANCEL:
    544569                {
    545                     rc = vbglR3DnDHGProcessCancelMessage(pCtx);
     570                    rc = vbglR3DnDHGRecvCancel(pCtx);
    546571                    if (RT_SUCCESS(rc))
    547572                        rc = VERR_CANCELLED;
     
    568593        rc = VINF_SUCCESS;
    569594
    570     /* Delete chunk buffer again. */
     595    /* Delete temp buffer again. */
    571596    if (pvChunk)
    572597        RTMemFree(pvChunk);
     
    576601    if (RT_FAILURE(rc))
    577602    {
    578         int rc2 = droppedFiles.Rollback();
     603        objFile.Close();
     604
     605        int rc2 = pDroppedFiles->Rollback();
    579606        AssertRC(rc2); /* Not fatal, don't report back to host. */
    580607    }
    581608    else
    582609    {
    583         /*
    584          * Now we need to transform the URI list which came from the host into
    585          * an URI list which also has the final "Dropped Files" directory as a prefix
    586          * for each URI entry.
    587          *
    588          * So patch the old drop data with the new drop directory to let the drop
    589          * target on the guest can find the files later.
    590          */
    591         void  *pvURIData = *ppvData;
    592         size_t cbURIData = *pcbDataRecv;
    593 
    594         rc = lstURI.RootFromURIData(pvURIData, cbURIData, 0 /* fFlags */);
    595         if (RT_SUCCESS(rc))
    596         {
    597             /* Cleanup the old data and write the new data back to the event. */
    598             RTMemFree(pvURIData);
    599 
    600             RTCString strData = lstURI.RootToString(pszDropDir);
    601             Assert(!strData.isEmpty());
    602             LogFlowFunc(("New URI list now has %zu bytes (formerly %RU32 bytes)\n", strData.length() + 1, cbURIData));
    603 
    604             pvURIData = RTStrDupN(strData.c_str(), strData.length());
    605             if (pvURIData)
    606             {
    607                 cbURIData = strData.length() + 1;
    608             }
    609             else
    610                 rc = VERR_NO_MEMORY;
    611         }
    612 
    613         if (RT_SUCCESS(rc))
    614         {
    615             *ppvData     = pvURIData;
    616             *pcbDataRecv = cbURIData;
    617         }
    618 
    619610        /** @todo Compare the URI list with the dirs/files we really transferred. */
     611        /** @todo Implement checksum verification, if any. */
    620612    }
    621613
     
    625617     * by the client's drag'n drop operation lateron.
    626618     */
    627     int rc2 = droppedFiles.Reset(false /* fRemoveDropDir */);
     619    int rc2 = pDroppedFiles->Reset(false /* fRemoveDropDir */);
    628620    if (RT_FAILURE(rc2)) /* Not fatal, don't report back to host. */
    629621        LogFlowFunc(("Closing dropped files directory failed with %Rrc\n", rc2));
     
    633625}
    634626
    635 static int vbglR3DnDHGProcessDataMessageInternal(PVBGLR3GUESTDNDCMDCTX pCtx,
    636                                                  uint32_t *puScreenId,
    637                                                  char     *pszFormat,
    638                                                  uint32_t  cbFormat,
    639                                                  uint32_t *pcbFormatRecv,
    640                                                  void     *pvData,
    641                                                  uint32_t  cbData,
    642                                                  uint32_t *pcbDataTotal)
    643 {
    644     AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
    645     AssertPtrReturn(puScreenId,    VERR_INVALID_POINTER);
    646     AssertPtrReturn(pszFormat,     VERR_INVALID_POINTER);
    647     AssertReturn(cbFormat,         VERR_INVALID_PARAMETER);
    648     AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
    649     AssertPtrReturn(pvData,        VERR_INVALID_POINTER);
    650     AssertReturn(cbData,           VERR_INVALID_PARAMETER);
    651     AssertPtrReturn(pcbDataTotal,  VERR_INVALID_POINTER);
    652 
    653     DragAndDropSvc::VBOXDNDHGSENDDATAMSG Msg;
     627static int vbglR3DnDHGRecvDataRaw(PVBGLR3GUESTDNDCMDCTX pCtx, PVBOXDNDSNDDATAHDR pDataHdr,
     628                                  void *pvData, uint32_t cbData, uint32_t *pcbDataRecv)
     629{
     630    AssertPtrReturn(pCtx,     VERR_INVALID_POINTER);
     631    AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
     632    AssertPtrReturn(pvData,   VERR_INVALID_POINTER);
     633    AssertReturn(cbData,      VERR_INVALID_PARAMETER);
     634    /* pcbDataRecv is optional. */
     635
     636    int rc;
     637
     638    LogFlowFunc(("pvDate=%p, cbData=%RU32\n", pvData, cbData));
     639
     640    VBOXDNDHGSENDDATAMSG Msg;
    654641    RT_ZERO(Msg);
     642    Msg.hdr.result      = VERR_WRONG_ORDER;
    655643    Msg.hdr.u32ClientID = pCtx->uClientID;
    656     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_DATA;
    657     Msg.hdr.cParms      = 5;
    658 
     644    Msg.hdr.u32Function = HOST_DND_HG_SND_DATA;
     645
     646    do
     647    {
     648        uint32_t cbDataRecv;
     649
     650        if (pCtx->uProtocol < 3) /* For VBox < 5.0.8. */
     651        {
     652            Msg.hdr.cParms  = 5;
     653
     654            Msg.u.v1.uScreenId.SetUInt32(0);
     655            Msg.u.v1.pvFormat.SetPtr(pDataHdr->pvMetaFmt, pDataHdr->cbMetaFmt);
     656            Msg.u.v1.cbFormat.SetUInt32(0);
     657            Msg.u.v1.pvData.SetPtr(pvData, cbData);
     658            Msg.u.v1.cbData.SetUInt32(0);
     659
     660            rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     661            if (RT_SUCCESS(rc))
     662            {
     663                rc = Msg.hdr.result;
     664                if (   RT_SUCCESS(rc)
     665                    || rc == VERR_BUFFER_OVERFLOW)
     666                {
     667                    rc = Msg.u.v1.uScreenId.GetUInt32(&pDataHdr->uScreenId);
     668                    AssertRC(rc);
     669
     670                    /*
     671                     * In case of VERR_BUFFER_OVERFLOW get the data sizes required
     672                     * for the format + data blocks.
     673                     */
     674                    uint32_t cbFormatRecv;
     675                    rc = Msg.u.v1.cbFormat.GetUInt32(&cbFormatRecv);
     676                    AssertRC(rc);
     677                    if (cbFormatRecv >= pDataHdr->cbMetaFmt)
     678                    {
     679                        rc = VERR_TOO_MUCH_DATA;
     680                        break;
     681                    }
     682
     683                    rc = Msg.u.v1.cbData.GetUInt32(&cbDataRecv);
     684                    AssertRC(rc);
     685                    if (cbDataRecv >= pDataHdr->cbMeta)
     686                    {
     687                        rc = VERR_TOO_MUCH_DATA;
     688                        break;
     689                    }
     690
     691                    pDataHdr->cbMetaFmt = cbFormatRecv;
     692                }
     693            }
     694
     695            if (RT_FAILURE(rc))
     696                break;
     697        }
     698        else /* Protocol v3 and up. */
     699        {
     700            Msg.hdr.cParms = 5;
     701
     702            Msg.u.v3.uContext.SetUInt32(0);
     703            Msg.u.v3.pvData.SetPtr(pvData, cbData);
     704            Msg.u.v3.cbData.SetUInt32(0);
     705            Msg.u.v3.pvChecksum.SetPtr(NULL, 0);
     706            Msg.u.v3.cbChecksum.SetUInt32(0);
     707
     708            rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     709            if (RT_SUCCESS(rc))
     710            {
     711                rc = Msg.hdr.result;
     712                if (RT_SUCCESS(rc))
     713                {
     714                    rc = Msg.u.v3.cbData.GetUInt32(&cbDataRecv);
     715                    AssertRC(rc);
     716                }
     717
     718                /** @todo Use checksum for validating the received data. */
     719            }
     720
     721            if (RT_FAILURE(rc))
     722                break;
     723        }
     724
     725        if (pcbDataRecv)
     726            *pcbDataRecv = cbDataRecv;
     727
     728    } while (0);
     729
     730    LogFlowFuncLeaveRC(rc);
     731    return rc;
     732}
     733
     734static int vbglR3DnDHGRecvDataHdr(PVBGLR3GUESTDNDCMDCTX pCtx, PVBOXDNDSNDDATAHDR pDataHdr)
     735{
     736    AssertPtrReturn(pCtx,     VERR_INVALID_POINTER);
     737    AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
     738
     739    Assert(pCtx->uProtocol >= 3); /* Only for protocol v3 and up. */
     740
     741    VBOXDNDHGSENDDATAHDRMSG Msg;
     742    RT_ZERO(Msg);
     743    Msg.hdr.result      = VERR_WRONG_ORDER;
     744    Msg.hdr.u32ClientID = pCtx->uClientID;
     745    Msg.hdr.u32Function = HOST_DND_HG_SND_DATA_HDR;
     746    Msg.hdr.cParms      = 12;
     747
     748    Msg.uContext.SetUInt32(0);
     749    Msg.uFlags.SetUInt32(0);
    659750    Msg.uScreenId.SetUInt32(0);
    660     Msg.pvFormat.SetPtr(pszFormat, cbFormat);
    661     Msg.cFormat.SetUInt32(0);
     751    Msg.cbTotal.SetUInt64(0);
     752    Msg.cbMeta.SetUInt32(0);
     753    Msg.pvMetaFmt.SetPtr(pDataHdr->pvMetaFmt, pDataHdr->cbMetaFmt);
     754    Msg.cbMetaFmt.SetUInt32(0);
     755    Msg.cObjects.SetUInt64(0);
     756    Msg.enmCompression.SetUInt32(0);
     757    Msg.enmChecksumType.SetUInt32(0);
     758    Msg.pvChecksum.SetPtr(pDataHdr->pvChecksum, pDataHdr->cbChecksum);
     759    Msg.cbChecksum.SetUInt32(0);
     760
     761    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     762    if (RT_SUCCESS(rc))
     763    {
     764        rc = Msg.hdr.result;
     765        if (RT_SUCCESS(rc))
     766        {
     767            /* Msg.uContext not needed here. */
     768            Msg.uFlags.GetUInt32(&pDataHdr->uFlags);
     769            Msg.uScreenId.GetUInt32(&pDataHdr->uScreenId);
     770            Msg.cbTotal.GetUInt64(&pDataHdr->cbTotal);
     771            Msg.cbMeta.GetUInt32(&pDataHdr->cbMeta);
     772            Msg.cbMetaFmt.GetUInt32(&pDataHdr->cbMetaFmt);
     773            Msg.cObjects.GetUInt64(&pDataHdr->cObjects);
     774            Msg.enmCompression.GetUInt32(&pDataHdr->enmCompression);
     775            Msg.enmChecksumType.GetUInt32((uint32_t *)&pDataHdr->enmChecksumType);
     776            Msg.cbChecksum.GetUInt32(&pDataHdr->cbChecksum);
     777        }
     778    }
     779
     780    LogFlowFuncLeaveRC(rc);
     781    return rc;
     782}
     783
     784/** @todo Deprecated function; will be removed. */
     785static int vbglR3DnDHGRecvMoreData(PVBGLR3GUESTDNDCMDCTX pCtx,
     786                                   void *pvData, uint32_t cbData, uint32_t *pcbDataRecv)
     787{
     788    AssertPtrReturn(pCtx,        VERR_INVALID_POINTER);
     789    AssertPtrReturn(pvData,      VERR_INVALID_POINTER);
     790    AssertReturn(cbData,         VERR_INVALID_PARAMETER);
     791    AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
     792
     793    VBOXDNDHGSENDMOREDATAMSG Msg;
     794    RT_ZERO(Msg);
     795    Msg.hdr.result      = VERR_WRONG_ORDER;
     796    Msg.hdr.u32ClientID = pCtx->uClientID;
     797    Msg.hdr.u32Function = HOST_DND_HG_SND_MORE_DATA;
     798    Msg.hdr.cParms      = 2;
     799
    662800    Msg.pvData.SetPtr(pvData, cbData);
    663801    Msg.cbData.SetUInt32(0);
     
    670808            || rc == VERR_BUFFER_OVERFLOW)
    671809        {
    672             rc = Msg.uScreenId.GetUInt32(puScreenId);  AssertRC(rc);
    673 
    674             /*
    675              * In case of VERR_BUFFER_OVERFLOW get the data sizes required
    676              * for the format + data blocks.
    677              */
    678             rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
    679             rc = Msg.cbData.GetUInt32(pcbDataTotal); AssertRC(rc);
    680 
    681             AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
    682             AssertReturn(cbData   >= *pcbDataTotal, VERR_TOO_MUCH_DATA);
    683         }
    684     }
    685 
    686     return rc;
    687 }
    688 
    689 static int vbglR3DnDHGProcessMoreDataMessageInternal(PVBGLR3GUESTDNDCMDCTX pCtx,
    690                                                      void     *pvData,
    691                                                      uint32_t  cbData,
    692                                                      uint32_t *pcbDataTotal)
    693 {
    694     AssertPtrReturn(pCtx,         VERR_INVALID_POINTER);
    695     AssertPtrReturn(pvData,       VERR_INVALID_POINTER);
    696     AssertReturn(cbData,          VERR_INVALID_PARAMETER);
    697     AssertPtrReturn(pcbDataTotal, VERR_INVALID_POINTER);
    698 
    699     DragAndDropSvc::VBOXDNDHGSENDMOREDATAMSG Msg;
    700     RT_ZERO(Msg);
    701     Msg.hdr.u32ClientID = pCtx->uClientID;
    702     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA;
    703     Msg.hdr.cParms      = 2;
    704 
    705     Msg.pvData.SetPtr(pvData, cbData);
    706     Msg.cbData.SetUInt32(0);
    707 
    708     int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    709     if (RT_SUCCESS(rc))
    710     {
    711         rc = Msg.hdr.result;
    712         if (   RT_SUCCESS(rc)
    713             || rc == VERR_BUFFER_OVERFLOW)
    714         {
    715             rc = Msg.cbData.GetUInt32(pcbDataTotal); AssertRC(rc);
    716             AssertReturn(cbData >= *pcbDataTotal, VERR_TOO_MUCH_DATA);
    717         }
    718     }
    719     return rc;
    720 }
    721 
    722 static int vbglR3DnDHGProcessSendDataMessageLoop(PVBGLR3GUESTDNDCMDCTX pCtx,
    723                                                  uint32_t *puScreenId,
    724                                                  char     *pszFormat,
    725                                                  uint32_t  cbFormat,
    726                                                  uint32_t *pcbFormatRecv,
    727                                                  void    **ppvData,
    728                                                  uint32_t  cbData,
    729                                                  size_t   *pcbDataRecv)
    730 {
    731     AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
    732     AssertPtrReturn(puScreenId,    VERR_INVALID_POINTER);
    733     AssertPtrReturn(pszFormat,     VERR_INVALID_POINTER);
    734     AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
    735     AssertPtrReturn(ppvData,       VERR_INVALID_POINTER);
    736     /* pcbDataRecv is optional. */
    737 
    738     uint32_t cbDataReq = 0;
    739     int rc = vbglR3DnDHGProcessDataMessageInternal(pCtx,
    740                                                    puScreenId,
    741                                                    pszFormat,
    742                                                    cbFormat,
    743                                                    pcbFormatRecv,
    744                                                    *ppvData,
    745                                                    cbData,
    746                                                    &cbDataReq);
    747     uint32_t cbDataTotal = cbDataReq;
    748     void *pvData = *ppvData;
    749 
    750     LogFlowFunc(("HOST_DND_HG_SND_DATA cbDataReq=%RU32, rc=%Rrc\n", cbDataTotal, rc));
    751 
    752     while (rc == VERR_BUFFER_OVERFLOW)
    753     {
    754         uint32_t uNextMsg;
    755         uint32_t cNextParms;
    756         rc = vbglR3DnDQueryNextHostMessageType(pCtx, &uNextMsg, &cNextParms, false);
    757         if (RT_SUCCESS(rc))
    758         {
    759             switch(uNextMsg)
    760             {
    761                 case DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA:
     810            rc = Msg.cbData.GetUInt32(pcbDataRecv); AssertRC(rc);
     811            AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA);
     812        }
     813    }
     814    return rc;
     815}
     816
     817static int vbglR3DnDHGRecvDataLoop(PVBGLR3GUESTDNDCMDCTX pCtx, PVBOXDNDSNDDATAHDR pDataHdr,
     818                                   void **ppvData, uint64_t *pcbData)
     819{
     820    AssertPtrReturn(pCtx,     VERR_INVALID_POINTER);
     821    AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
     822    AssertPtrReturn(ppvData,  VERR_INVALID_POINTER);
     823    AssertPtrReturn(pcbData,  VERR_INVALID_POINTER);
     824
     825    int rc;
     826    uint32_t cbDataRecv;
     827
     828    if (pCtx->uProtocol < 3) /* For VBox < 5.0.8. */
     829    {
     830        uint64_t cbDataTmp = pCtx->cbMaxChunkSize;
     831        void    *pvDataTmp = RTMemAlloc(cbDataTmp);
     832
     833        if (!cbDataTmp)
     834            return VERR_NO_MEMORY;
     835
     836        /**
     837         * Protocols < v3 contain the header information in every HOST_DND_HG_SND_DATA
     838         * message, so do the actual retrieving immediately.
     839         *
     840         * Also, the initial implementation used VERR_BUFFER_OVERFLOW as a return code to
     841         * indicate that there will be more data coming in after the initial data chunk. There
     842         * was no way of telling the total data size upfront (in form of a header or some such),
     843         * so also handle this case to not break backwards compatibility.
     844         */
     845        rc = vbglR3DnDHGRecvDataRaw(pCtx, pDataHdr, pvDataTmp, pCtx->cbMaxChunkSize, &cbDataRecv);
     846
     847        /* See comment above. */
     848        while (rc == VERR_BUFFER_OVERFLOW)
     849        {
     850            uint32_t uNextMsg;
     851            uint32_t cNextParms;
     852            rc = vbglR3DnDGetNextMsgType(pCtx, &uNextMsg, &cNextParms, false /* fBlock */);
     853            if (RT_SUCCESS(rc))
     854            {
     855                switch(uNextMsg)
    762856                {
    763                     /** @todo r=andy Don't use reallocate here; can go wrong with *really* big URI lists.
    764                      *               Instead send as many URI entries as possible per chunk and add those entries
    765                      *               to our to-process list for immediata processing. Repeat the step after processing then. */
    766                     LogFlowFunc(("HOST_DND_HG_SND_MORE_DATA cbDataTotal: %RU32 -> %RU32\n", cbDataReq, cbDataReq + cbData));
    767                     pvData = RTMemRealloc(*ppvData, cbDataTotal + cbData);
    768                     if (!pvData)
     857                    case HOST_DND_HG_SND_MORE_DATA:
    769858                    {
    770                         rc = VERR_NO_MEMORY;
     859                        /** @todo r=andy Don't use reallocate here; can go wrong with *really* big URI lists.
     860                         *               Instead send as many URI entries as possible per chunk and add those entries
     861                         *               to our to-process list for immediata processing. Repeat the step after processing then. */
     862                        LogFlowFunc(("HOST_DND_HG_SND_MORE_DATA cbDataTotal: %RU64 -> %RU64\n",
     863                                     cbDataTmp, cbDataTmp + pCtx->cbMaxChunkSize));
     864                        void *pvDataNew = RTMemRealloc(pvDataTmp, cbDataTmp + pCtx->cbMaxChunkSize);
     865                        if (!pvDataNew)
     866                        {
     867                            rc = VERR_NO_MEMORY;
     868                            break;
     869                        }
     870
     871                        pvDataTmp = pvDataNew;
     872
     873                        uint8_t *pvDataOff = (uint8_t *)pvDataTmp + cbDataTmp;
     874                        rc = vbglR3DnDHGRecvMoreData(pCtx, pvDataOff, pCtx->cbMaxChunkSize, &cbDataRecv);
     875                        if (   RT_SUCCESS(rc)
     876                            || rc == VERR_BUFFER_OVERFLOW) /* Still can return VERR_BUFFER_OVERFLOW. */
     877                        {
     878                            cbDataTmp += cbDataRecv;
     879                        }
    771880                        break;
    772881                    }
    773                     rc = vbglR3DnDHGProcessMoreDataMessageInternal(pCtx,
    774                                                                    &((char *)pvData)[cbDataTotal],
    775                                                                    cbData,
    776                                                                    &cbDataReq);
    777                     cbDataTotal += cbDataReq;
    778                     break;
     882                    case HOST_DND_HG_EVT_CANCEL:
     883                    default:
     884                    {
     885                        rc = vbglR3DnDHGRecvCancel(pCtx);
     886                        if (RT_SUCCESS(rc))
     887                            rc = VERR_CANCELLED;
     888                        break;
     889                    }
    779890                }
    780                 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
    781                 default:
     891            }
     892        }
     893
     894        if (RT_SUCCESS(rc))
     895        {
     896            /* There was no way of telling the total data size upfront
     897             * (in form of a header or some such), so set the total data size here. */
     898            pDataHdr->cbTotal = cbDataTmp;
     899
     900            *ppvData = pvDataTmp;
     901            *pcbData = cbDataTmp;
     902        }
     903        else
     904            RTMemFree(pvDataTmp);
     905    }
     906    else /* Protocol v3 and up. Since VBox 5.0.8. */
     907    {
     908        rc = vbglR3DnDHGRecvDataHdr(pCtx, pDataHdr);
     909        if (RT_SUCCESS(rc))
     910        {
     911            LogFlowFunc(("cbMeta=%RU32\n", pDataHdr->cbMeta));
     912            if (pDataHdr->cbMeta)
     913            {
     914                uint64_t cbDataTmp = 0;
     915                void    *pvDataTmp = RTMemAlloc(pDataHdr->cbMeta);
     916                if (!pvDataTmp)
     917                    rc = VERR_NO_MEMORY;
     918
     919                if (RT_SUCCESS(rc))
    782920                {
    783                     rc = vbglR3DnDHGProcessCancelMessage(pCtx);
     921                    uint8_t *pvDataOff = (uint8_t *)pvDataTmp;
     922                    while (cbDataTmp < pDataHdr->cbMeta)
     923                    {
     924                        rc = vbglR3DnDHGRecvDataRaw(pCtx, pDataHdr,
     925                                                    pvDataOff, RT_MIN(pDataHdr->cbMeta - cbDataTmp, pCtx->cbMaxChunkSize),
     926                                                    &cbDataRecv);
     927                        if (RT_SUCCESS(rc))
     928                        {
     929                            LogFlowFunc(("cbDataRecv=%RU32, cbDataTmp=%RU64\n", cbDataRecv, cbDataTmp));
     930                            Assert(cbDataTmp + cbDataRecv <= pDataHdr->cbMeta);
     931                            cbDataTmp += cbDataRecv;
     932                            pvDataOff += cbDataRecv;
     933                        }
     934                        else
     935                            break;
     936                    }
     937
    784938                    if (RT_SUCCESS(rc))
    785                         rc = VERR_CANCELLED;
    786                     break;
     939                    {
     940                        Assert(cbDataTmp == pDataHdr->cbMeta);
     941
     942                        LogFlowFunc(("Received %RU64 bytes of data\n", cbDataTmp));
     943
     944                        *ppvData = pvDataTmp;
     945                        *pcbData = cbDataTmp;
     946                    }
     947                    else
     948                        RTMemFree(pvDataTmp);
    787949                }
    788950            }
    789         }
    790     }
    791 
    792     if (RT_SUCCESS(rc))
    793     {
    794         *ppvData         = pvData;
    795         if (pcbDataRecv)
    796             *pcbDataRecv = cbDataTotal;
     951            else
     952            {
     953                *ppvData = NULL;
     954                *pcbData = 0;
     955            }
     956        }
    797957    }
    798958
     
    801961}
    802962
    803 static int vbglR3DnDHGProcessSendDataMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
    804                                              uint32_t  *puScreenId,
    805                                              char      *pszFormat,
    806                                              uint32_t   cbFormat,
    807                                              uint32_t  *pcbFormatRecv,
    808                                              void     **ppvData,
    809                                              uint32_t   cbData,
    810                                              size_t    *pcbDataRecv)
    811 {
    812     AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
    813     AssertPtrReturn(puScreenId,    VERR_INVALID_POINTER);
    814     AssertPtrReturn(pszFormat,     VERR_INVALID_POINTER);
    815     AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
    816     AssertPtrReturn(ppvData,       VERR_INVALID_POINTER);
    817 
    818     int rc = vbglR3DnDHGProcessSendDataMessageLoop(pCtx,
    819                                                    puScreenId,
    820                                                    pszFormat,
    821                                                    cbFormat,
    822                                                    pcbFormatRecv,
    823                                                    ppvData,
    824                                                    cbData,
    825                                                    pcbDataRecv);
    826     if (RT_SUCCESS(rc))
    827     {
    828         /* Check if this is an URI event. If so, let VbglR3 do all the actual
     963/** @todo Replace the parameters (except pCtx) with PVBOXDNDSNDDATAHDR. Later. */
     964/** @todo Hand in the DnDURIList + DnDDroppedFiles objects so that this function
     965 *        can fill it directly instead of passing huge blobs of data around. */
     966static int vbglR3DnDHGRecvDataMain(PVBGLR3GUESTDNDCMDCTX  pCtx,
     967                                   uint32_t              *puScreenId,
     968                                   char                 **ppszFormat,
     969                                   uint32_t              *pcbFormat,
     970                                   void                 **ppvData,
     971                                   uint32_t              *pcbData)
     972{
     973    AssertPtrReturn(pCtx,       VERR_INVALID_POINTER);
     974    AssertPtrReturn(puScreenId, VERR_INVALID_POINTER);
     975    AssertPtrReturn(ppszFormat, VERR_INVALID_POINTER);
     976    AssertPtrReturn(pcbFormat,  VERR_INVALID_POINTER);
     977    AssertPtrReturn(ppvData,    VERR_INVALID_POINTER);
     978    AssertPtrReturn(pcbData,    VERR_INVALID_POINTER);
     979
     980    VBOXDNDDATAHDR dataHdr; /** @todo See todo above. */
     981    RT_ZERO(dataHdr);
     982
     983    dataHdr.cbMetaFmt = _64K;  /** @todo Make this configurable? */
     984    dataHdr.pvMetaFmt = RTMemAlloc(dataHdr.cbMetaFmt);
     985    if (!dataHdr.pvMetaFmt)
     986        return VERR_NO_MEMORY;
     987
     988    DnDURIList lstURI;
     989    DnDDroppedFiles droppedFiles;
     990
     991    void *pvData;    /** @todo See todo above. */
     992    uint64_t cbData; /** @todo See todo above. */
     993
     994    int rc = vbglR3DnDHGRecvDataLoop(pCtx, &dataHdr, &pvData, &cbData);
     995    if (RT_SUCCESS(rc))
     996    {
     997        /**
     998         * Check if this is an URI event. If so, let VbglR3 do all the actual
    829999         * data transfer + file/directory creation internally without letting
    8301000         * the caller know.
    8311001         *
    8321002         * This keeps the actual (guest OS-)dependent client (like VBoxClient /
    833          * VBoxTray) small by not having too much redundant code. */
    834         AssertPtr(pcbFormatRecv);
    835         if (DnDMIMEHasFileURLs(pszFormat, *pcbFormatRecv))
    836             rc = vbglR3DnDHGProcessURIMessages(pCtx,
    837                                                ppvData,
    838                                                cbData,
    839                                                pcbDataRecv);
    840         if (RT_FAILURE(rc))
    841         {
    842             int rc2 = VbglR3DnDHGSetProgress(pCtx, DragAndDropSvc::DND_PROGRESS_ERROR, 100 /* Percent */, rc);
    843             AssertRC(rc2);
    844         }
     1003         * VBoxTray) small by not having too much redundant code.
     1004         */
     1005        Assert(dataHdr.cbMetaFmt);
     1006        AssertPtr(dataHdr.pvMetaFmt);
     1007        if (DnDMIMEHasFileURLs((char *)dataHdr.pvMetaFmt, dataHdr.cbMetaFmt))
     1008        {
     1009            AssertPtr(pvData);
     1010            Assert(cbData);
     1011            rc = lstURI.RootFromURIData(pvData, cbData, 0 /* fFlags */);
     1012            if (RT_SUCCESS(rc))
     1013                rc = vbglR3DnDHGRecvURIData(pCtx, &droppedFiles);
     1014
     1015            if (RT_SUCCESS(rc)) /** @todo Remove this block as soon as we hand in DnDURIList. */
     1016            {
     1017                if (pvData)
     1018                {
     1019                    /* Reuse data buffer to fill in the transformed URI file list. */
     1020                    RTMemFree(pvData);
     1021                    pvData = NULL;
     1022                }
     1023
     1024                RTCString strData = lstURI.RootToString(droppedFiles.GetDirAbs());
     1025                Assert(!strData.isEmpty());
     1026
     1027                cbData = strData.length() + 1;
     1028                LogFlowFunc(("URI list has %zu bytes\n", cbData));
     1029
     1030                pvData = RTMemAlloc(cbData);
     1031                if (pvData)
     1032                {
     1033                    memcpy(pvData, strData.c_str(), cbData);
     1034                }
     1035                else
     1036                    rc =  VERR_NO_MEMORY;
     1037            }
     1038        }
     1039        else /* Raw data. */
     1040        {
     1041            const uint32_t cbDataRaw = dataHdr.cbMetaFmt;
     1042            if (cbData >= cbDataRaw)
     1043            {
     1044                if (cbDataRaw)
     1045                    memcpy(pvData, dataHdr.pvMetaFmt, cbDataRaw);
     1046                cbData = cbDataRaw;
     1047            }
     1048            else
     1049                rc = VERR_BUFFER_OVERFLOW;
     1050        }
     1051    }
     1052
     1053    if (   RT_FAILURE(rc)
     1054        && rc != VERR_CANCELLED)
     1055    {
     1056        if (dataHdr.pvMetaFmt)
     1057            RTMemFree(dataHdr.pvMetaFmt);
     1058        if (pvData)
     1059            RTMemFree(pvData);
     1060
     1061        int rc2 = VbglR3DnDHGSendProgress(pCtx, DND_PROGRESS_ERROR, 100 /* Percent */, rc);
     1062        AssertRC(rc2);
     1063    }
     1064    else if (RT_SUCCESS(rc))
     1065    {
     1066        *ppszFormat = (char *)dataHdr.pvMetaFmt;
     1067        *pcbFormat  =         dataHdr.cbMetaFmt;
     1068        *ppvData    = pvData;
     1069        *pcbData    = cbData;
    8451070    }
    8461071
     
    8491074}
    8501075
    851 static int vbglR3DnDGHProcessRequestPendingMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
    852                                                    uint32_t *puScreenId)
     1076static int vbglR3DnDGHRecvPending(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t *puScreenId)
    8531077{
    8541078    AssertPtrReturn(pCtx,       VERR_INVALID_POINTER);
    8551079    AssertPtrReturn(puScreenId, VERR_INVALID_POINTER);
    8561080
    857     DragAndDropSvc::VBOXDNDGHREQPENDINGMSG Msg;
     1081    VBOXDNDGHREQPENDINGMSG Msg;
    8581082    RT_ZERO(Msg);
     1083    Msg.hdr.result      = VERR_WRONG_ORDER;
    8591084    Msg.hdr.u32ClientID = pCtx->uClientID;
    860     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_REQ_PENDING;
     1085    Msg.hdr.u32Function = HOST_DND_GH_REQ_PENDING;
    8611086    Msg.hdr.cParms      = 1;
    8621087
     
    8761101}
    8771102
    878 static int vbglR3DnDGHProcessDroppedMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
    879                                             char     *pszFormat,
    880                                             uint32_t  cbFormat,
    881                                             uint32_t *pcbFormatRecv,
    882                                             uint32_t *puAction)
     1103static int vbglR3DnDGHRecvDropped(PVBGLR3GUESTDNDCMDCTX pCtx,
     1104                                  char     *pszFormat,
     1105                                  uint32_t  cbFormat,
     1106                                  uint32_t *pcbFormatRecv,
     1107                                  uint32_t *puAction)
    8831108{
    8841109    AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
     
    8881113    AssertPtrReturn(puAction,      VERR_INVALID_POINTER);
    8891114
    890     DragAndDropSvc::VBOXDNDGHDROPPEDMSG Msg;
     1115    VBOXDNDGHDROPPEDMSG Msg;
    8911116    RT_ZERO(Msg);
     1117    Msg.hdr.result      = VERR_WRONG_ORDER;
    8921118    Msg.hdr.u32ClientID = pCtx->uClientID;
    893     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_EVT_DROPPED;
     1119    Msg.hdr.u32Function = HOST_DND_GH_EVT_DROPPED;
    8941120    Msg.hdr.cParms      = 3;
    8951121
    8961122    Msg.pvFormat.SetPtr(pszFormat, cbFormat);
    897     Msg.cFormat.SetUInt32(0);
     1123    Msg.cbFormat.SetUInt32(0);
    8981124    Msg.uAction.SetUInt32(0);
    8991125
     
    9041130        if (RT_SUCCESS(rc))
    9051131        {
    906             rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
    907             rc = Msg.uAction.GetUInt32(puAction);      AssertRC(rc);
     1132            rc = Msg.cbFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
     1133            rc = Msg.uAction.GetUInt32(puAction);       AssertRC(rc);
    9081134
    9091135            AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
     
    9441170        {
    9451171            /* Set the default protocol version to use. */
    946             pCtx->uProtocol = 2;
     1172            pCtx->uProtocol = 3;
    9471173
    9481174            Assert(Info.u32ClientID);
     
    9671193            {
    9681194                fSupportsConnectReq = RTStrVersionCompare(pszHostVersion, "5.0") >= 0;
     1195                LogFlowFunc(("pszHostVersion=%s, fSupportsConnectReq=%RTbool\n", pszHostVersion, fSupportsConnectReq));
    9691196                VbglR3GuestPropReadValueFree(pszHostVersion);
    9701197            }
     
    9721199            VbglR3GuestPropDisconnect(uGuestPropSvcClientID);
    9731200        }
     1201
     1202        if (RT_FAILURE(rc2))
     1203            LogFlowFunc(("Retrieving host version failed with rc=%Rrc\n", rc2));
    9741204    }
    9751205
     
    9811211         *       does not implement this command.
    9821212         */
    983         DragAndDropSvc::VBOXDNDCONNECTMSG Msg;
     1213        VBOXDNDCONNECTMSG Msg;
    9841214        RT_ZERO(Msg);
    9851215        Msg.hdr.result      = VERR_WRONG_ORDER;
    9861216        Msg.hdr.u32ClientID = pCtx->uClientID;
    987         Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_CONNECT;
     1217        Msg.hdr.u32Function = GUEST_DND_CONNECT;
    9881218        Msg.hdr.cParms      = 2;
    9891219
     
    10051235        pCtx->uProtocol = 1; /* Fall back to protocol version 1 (< VBox 5.0). */
    10061236
     1237    pCtx->cbMaxChunkSize = _64K; /** @todo Use a scratch buffer on the heap? */
     1238
    10071239    LogFlowFunc(("uClient=%RU32, uProtocol=%RU32, rc=%Rrc\n", pCtx->uClientID, pCtx->uProtocol, rc));
    10081240    return rc;
     
    10241256}
    10251257
    1026 VBGLR3DECL(int) VbglR3DnDProcessNextMessage(PVBGLR3GUESTDNDCMDCTX pCtx, CPVBGLR3DNDHGCMEVENT pEvent)
     1258VBGLR3DECL(int) VbglR3DnDRecvNextMsg(PVBGLR3GUESTDNDCMDCTX pCtx, CPVBGLR3DNDHGCMEVENT pEvent)
    10271259{
    10281260    AssertPtrReturn(pCtx,   VERR_INVALID_POINTER);
    10291261    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
    10301262
    1031     uint32_t       uMsg       = 0;
    1032     uint32_t       uNumParms  = 0;
    1033     const uint32_t ccbFormats = _64K;
    1034     const uint32_t ccbData    = _64K;
    1035     int rc = vbglR3DnDQueryNextHostMessageType(pCtx, &uMsg, &uNumParms,
    1036                                                true /* fWait */);
     1263    uint32_t       uMsg      = 0;
     1264    uint32_t       uNumParms = 0;
     1265
     1266    const uint32_t cbDataMax   = pCtx->cbMaxChunkSize;
     1267    const uint32_t cbFormatMax = pCtx->cbMaxChunkSize;
     1268
     1269    int rc = vbglR3DnDGetNextMsgType(pCtx, &uMsg, &uNumParms, true /* fWait */);
    10371270    if (RT_SUCCESS(rc))
    10381271    {
     
    10411274        switch(uMsg)
    10421275        {
    1043             case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
    1044             case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
    1045             case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
    1046             {
    1047                 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
     1276            case HOST_DND_HG_EVT_ENTER:
     1277            case HOST_DND_HG_EVT_MOVE:
     1278            case HOST_DND_HG_EVT_DROPPED:
     1279            {
     1280                pEvent->pszFormats = static_cast<char*>(RTMemAlloc(cbFormatMax));
    10481281                if (!pEvent->pszFormats)
    10491282                    rc = VERR_NO_MEMORY;
    10501283
    10511284                if (RT_SUCCESS(rc))
    1052                     rc = vbglR3DnDHGProcessActionMessage(pCtx,
    1053                                                          uMsg,
    1054                                                          &pEvent->uScreenId,
    1055                                                          &pEvent->u.a.uXpos,
    1056                                                          &pEvent->u.a.uYpos,
    1057                                                          &pEvent->u.a.uDefAction,
    1058                                                          &pEvent->u.a.uAllActions,
    1059                                                          pEvent->pszFormats,
    1060                                                          ccbFormats,
    1061                                                          &pEvent->cbFormats);
     1285                    rc = vbglR3DnDHGRecvAction(pCtx,
     1286                                               uMsg,
     1287                                               &pEvent->uScreenId,
     1288                                               &pEvent->u.a.uXpos,
     1289                                               &pEvent->u.a.uYpos,
     1290                                               &pEvent->u.a.uDefAction,
     1291                                               &pEvent->u.a.uAllActions,
     1292                                               pEvent->pszFormats,
     1293                                               cbFormatMax,
     1294                                               &pEvent->cbFormats);
    10621295                break;
    10631296            }
    1064             case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE:
    1065             {
    1066                 rc = vbglR3DnDHGProcessLeaveMessage(pCtx);
     1297            case HOST_DND_HG_EVT_LEAVE:
     1298            {
     1299                rc = vbglR3DnDHGRecvLeave(pCtx);
    10671300                break;
    10681301            }
    1069             case DragAndDropSvc::HOST_DND_HG_SND_DATA:
    1070             {
    1071                 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
    1072                 if (!pEvent->pszFormats)
    1073                     rc = VERR_NO_MEMORY;
    1074 
    1075                 if (RT_SUCCESS(rc))
    1076                 {
    1077                     pEvent->u.b.pvData = RTMemAlloc(ccbData);
    1078                     if (!pEvent->u.b.pvData)
    1079                     {
    1080                         RTMemFree(pEvent->pszFormats);
    1081                         pEvent->pszFormats = NULL;
    1082 
    1083                         rc = VERR_NO_MEMORY;
    1084                     }
    1085                 }
    1086 
    1087                 if (RT_SUCCESS(rc))
    1088                     rc = vbglR3DnDHGProcessSendDataMessage(pCtx,
    1089                                                            &pEvent->uScreenId,
    1090                                                            pEvent->pszFormats,
    1091                                                            ccbFormats,
    1092                                                            &pEvent->cbFormats,
    1093                                                            &pEvent->u.b.pvData,
    1094                                                            ccbData,
    1095                                                            &pEvent->u.b.cbData);
     1302            case HOST_DND_HG_SND_DATA:
     1303                /* Protocol v1 + v2: Also contains the header data.
     1304                /* Note: Fall through is intentional. */
     1305            case HOST_DND_HG_SND_DATA_HDR:
     1306            {
     1307                rc = vbglR3DnDHGRecvDataMain(pCtx,
     1308                                             /* Screen ID */
     1309                                             &pEvent->uScreenId,
     1310                                             /* Format */
     1311                                             &pEvent->pszFormats,
     1312                                             &pEvent->cbFormats,
     1313                                             /* Data */
     1314                                             &pEvent->u.b.pvData,
     1315                                             &pEvent->u.b.cbData);
    10961316                break;
    10971317            }
    1098             case DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA:
    1099             case DragAndDropSvc::HOST_DND_HG_SND_DIR:
    1100             case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA:
     1318            case HOST_DND_HG_SND_MORE_DATA:
     1319            case HOST_DND_HG_SND_DIR:
     1320            case HOST_DND_HG_SND_FILE_DATA:
    11011321            {
    11021322                /*
    11031323                 * All messages in this case are handled internally
    1104                  * by vbglR3DnDHGProcessSendDataMessage() and must
    1105                  * be specified by a preceding HOST_DND_HG_SND_DATA call.
     1324                 * by vbglR3DnDHGRecvDataMain() and must be specified
     1325                 * by a preceding HOST_DND_HG_SND_DATA or HOST_DND_HG_SND_DATA_HDR
     1326                 * calls.
    11061327                 */
    11071328                rc = VERR_WRONG_ORDER;
    11081329                break;
    11091330            }
    1110             case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
    1111             {
    1112                 rc = vbglR3DnDHGProcessCancelMessage(pCtx);
     1331            case HOST_DND_HG_EVT_CANCEL:
     1332            {
     1333                rc = vbglR3DnDHGRecvCancel(pCtx);
    11131334                break;
    11141335            }
    11151336#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    1116             case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
    1117             {
    1118                 rc = vbglR3DnDGHProcessRequestPendingMessage(pCtx, &pEvent->uScreenId);
     1337            case HOST_DND_GH_REQ_PENDING:
     1338            {
     1339                rc = vbglR3DnDGHRecvPending(pCtx, &pEvent->uScreenId);
    11191340                break;
    11201341            }
    1121             case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
    1122             {
    1123                 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
     1342            case HOST_DND_GH_EVT_DROPPED:
     1343            {
     1344                pEvent->pszFormats = static_cast<char*>(RTMemAlloc(cbFormatMax));
    11241345                if (!pEvent->pszFormats)
    11251346                    rc = VERR_NO_MEMORY;
    11261347
    11271348                if (RT_SUCCESS(rc))
    1128                     rc = vbglR3DnDGHProcessDroppedMessage(pCtx,
    1129                                                           pEvent->pszFormats,
    1130                                                           ccbFormats,
    1131                                                           &pEvent->cbFormats,
    1132                                                           &pEvent->u.a.uDefAction);
     1349                    rc = vbglR3DnDGHRecvDropped(pCtx,
     1350                                                pEvent->pszFormats,
     1351                                                cbFormatMax,
     1352                                                &pEvent->cbFormats,
     1353                                                &pEvent->u.a.uDefAction);
    11331354                break;
    11341355            }
     
    11451366}
    11461367
    1147 VBGLR3DECL(int) VbglR3DnDHGAcknowledgeOperation(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uAction)
     1368VBGLR3DECL(int) VbglR3DnDHGSendAckOp(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uAction)
    11481369{
    11491370    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    11501371
    1151     DragAndDropSvc::VBOXDNDHGACKOPMSG Msg;
     1372    VBOXDNDHGACKOPMSG Msg;
    11521373    RT_ZERO(Msg);
    11531374    Msg.hdr.result      = VERR_WRONG_ORDER;
    11541375    Msg.hdr.u32ClientID = pCtx->uClientID;
    1155     Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_ACK_OP;
     1376    Msg.hdr.u32Function = GUEST_DND_HG_ACK_OP;
    11561377    Msg.hdr.cParms      = 1;
    11571378
     
    11651386}
    11661387
    1167 VBGLR3DECL(int) VbglR3DnDHGRequestData(PVBGLR3GUESTDNDCMDCTX pCtx, const char* pcszFormat)
     1388VBGLR3DECL(int) VbglR3DnDHGSendReqData(PVBGLR3GUESTDNDCMDCTX pCtx, const char* pcszFormat)
    11681389{
    11691390    AssertPtrReturn(pCtx,       VERR_INVALID_POINTER);
    11701391    AssertPtrReturn(pcszFormat, VERR_INVALID_POINTER);
    11711392
    1172     DragAndDropSvc::VBOXDNDHGREQDATAMSG Msg;
     1393    VBOXDNDHGREQDATAMSG Msg;
    11731394    RT_ZERO(Msg);
    11741395    Msg.hdr.result      = VERR_WRONG_ORDER;
    11751396    Msg.hdr.u32ClientID = pCtx->uClientID;
    1176     Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_REQ_DATA;
     1397    Msg.hdr.u32Function = GUEST_DND_HG_REQ_DATA;
    11771398    Msg.hdr.cParms      = 1;
    11781399
    1179     Msg.pFormat.SetPtr((void*)pcszFormat, (uint32_t)strlen(pcszFormat) + 1);
     1400    Msg.pFormat.SetPtr((void*)pcszFormat, strlen(pcszFormat) + 1 /* Include termination */);
    11801401
    11811402    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    11861407}
    11871408
    1188 VBGLR3DECL(int) VbglR3DnDHGSetProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr)
     1409VBGLR3DECL(int) VbglR3DnDHGSendProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr)
    11891410{
    11901411    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    1191     AssertReturn(uStatus > DragAndDropSvc::DND_PROGRESS_UNKNOWN, VERR_INVALID_PARAMETER);
    1192 
    1193     DragAndDropSvc::VBOXDNDHGEVTPROGRESSMSG Msg;
     1412    AssertReturn(uStatus > DND_PROGRESS_UNKNOWN, VERR_INVALID_PARAMETER);
     1413
     1414    VBOXDNDHGEVTPROGRESSMSG Msg;
    11941415    RT_ZERO(Msg);
    11951416    Msg.hdr.result      = VERR_WRONG_ORDER;
     
    12101431
    12111432#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    1212 VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending(PVBGLR3GUESTDNDCMDCTX pCtx,
    1213                                               uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats)
     1433VBGLR3DECL(int) VbglR3DnDGHSendAckPending(PVBGLR3GUESTDNDCMDCTX pCtx,
     1434                                          uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats, uint32_t cbFormats)
    12141435{
    12151436    AssertPtrReturn(pCtx,        VERR_INVALID_POINTER);
    12161437    AssertPtrReturn(pcszFormats, VERR_INVALID_POINTER);
    1217 
    1218     DragAndDropSvc::VBOXDNDGHACKPENDINGMSG Msg;
     1438    AssertReturn(cbFormats,      VERR_INVALID_PARAMETER);
     1439
     1440    VBOXDNDGHACKPENDINGMSG Msg;
    12191441    RT_ZERO(Msg);
    12201442    Msg.hdr.result      = VERR_WRONG_ORDER;
    12211443    Msg.hdr.u32ClientID = pCtx->uClientID;
    1222     Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_ACK_PENDING;
     1444    Msg.hdr.u32Function = GUEST_DND_GH_ACK_PENDING;
    12231445    Msg.hdr.cParms      = 3;
    12241446
    12251447    Msg.uDefAction.SetUInt32(uDefAction);
    12261448    Msg.uAllActions.SetUInt32(uAllActions);
    1227     Msg.pFormat.SetPtr((void*)pcszFormats, (uint32_t)strlen(pcszFormats) + 1);
     1449    Msg.pFormat.SetPtr((void*)pcszFormats, cbFormats);
    12281450
    12291451    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    12351457
    12361458static int vbglR3DnDGHSendDataInternal(PVBGLR3GUESTDNDCMDCTX pCtx,
    1237                                        void *pvData, uint32_t cbData, uint32_t cbAdditionalData)
     1459                                       void *pvData, uint64_t cbData, PVBOXDNDSNDDATAHDR pDataHdr)
    12381460{
    12391461    AssertPtrReturn(pCtx,   VERR_INVALID_POINTER);
     
    12411463    AssertReturn(cbData,    VERR_INVALID_PARAMETER);
    12421464    /* cbAdditionalData is optional. */
    1243 
    1244     DragAndDropSvc::VBOXDNDGHSENDDATAMSG Msg;
     1465    /* pDataHdr is optional in protocols < v3. */
     1466
     1467    int rc = VINF_SUCCESS;
     1468
     1469    /* For protocol v3 and up we need to send the data header first. */
     1470    if (pCtx->uProtocol > 2)
     1471    {
     1472        AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
     1473
     1474        VBOXDNDGHSENDDATAHDRMSG Msg;
     1475        RT_ZERO(Msg);
     1476        Msg.hdr.result      = VERR_WRONG_ORDER;
     1477        Msg.hdr.u32ClientID = pCtx->uClientID;
     1478        Msg.hdr.u32Function = GUEST_DND_GH_SND_DATA_HDR;
     1479        Msg.hdr.cParms      = 12;
     1480
     1481        Msg.uContext.SetUInt32(0);                           /** @todo Not used yet. */
     1482        Msg.uFlags.SetUInt32(0);                             /** @todo Not used yet. */
     1483        Msg.uScreenId.SetUInt32(0);                          /** @todo Not used for guest->host (yet). */
     1484        Msg.cbTotal.SetUInt64(pDataHdr->cbTotal);
     1485        Msg.cbMeta.SetUInt64(pDataHdr->cbMeta);
     1486        Msg.pvMetaFmt.SetPtr(pDataHdr->pvMetaFmt, pDataHdr->cbMetaFmt);
     1487        Msg.cbMetaFmt.SetUInt32(pDataHdr->cbMetaFmt);
     1488        Msg.cObjects.SetUInt64(pDataHdr->cObjects);
     1489        Msg.enmCompression.SetUInt32(0);                     /** @todo Not used yet. */
     1490        Msg.enmChecksumType.SetUInt32(RTDIGESTTYPE_INVALID); /** @todo Not used yet. */
     1491        Msg.pvChecksum.SetPtr(NULL, 0);                      /** @todo Not used yet. */
     1492        Msg.cbChecksum.SetUInt32(0);                         /** @todo Not used yet. */
     1493
     1494        rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     1495        if (RT_SUCCESS(rc))
     1496            rc = Msg.hdr.result;
     1497
     1498        LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU64, cObjects=%RU64, rc=%Rrc\n",
     1499                     pDataHdr->cbTotal, pDataHdr->cbMeta, pDataHdr->cObjects, rc));
     1500    }
     1501
     1502    if (RT_SUCCESS(rc))
     1503    {
     1504        VBOXDNDGHSENDDATAMSG Msg;
     1505        RT_ZERO(Msg);
     1506        Msg.hdr.result      = VERR_WRONG_ORDER;
     1507        Msg.hdr.u32ClientID = pCtx->uClientID;
     1508        Msg.hdr.u32Function = GUEST_DND_GH_SND_DATA;
     1509
     1510        if (pCtx->uProtocol > 2)
     1511        {
     1512            Msg.hdr.cParms = 5;
     1513
     1514            Msg.u.v3.uContext.SetUInt32(0);      /** @todo Not used yet. */
     1515            Msg.u.v3.pvChecksum.SetPtr(NULL, 0); /** @todo Not used yet. */
     1516            Msg.u.v3.cbChecksum.SetUInt32(0);    /** @todo Not used yet. */
     1517        }
     1518        else
     1519        {
     1520            Msg.hdr.cParms = 2;
     1521
     1522            /* Total amount of bytes to send (meta data + all directory/file objects). */
     1523            /* Note: Only supports uint32_t, so this is *not* a typo. */
     1524            Msg.u.v1.cbTotalBytes.SetUInt32((uint32_t)pDataHdr->cbTotal);
     1525        }
     1526
     1527        uint32_t       cbCurChunk;
     1528        const uint32_t cbMaxChunk = pCtx->cbMaxChunkSize;
     1529        uint32_t       cbSent     = 0;
     1530
     1531        HGCMFunctionParameter *pParm = (pCtx->uProtocol > 2)
     1532                                     ? &Msg.u.v3.pvData
     1533                                     : &Msg.u.v1.pvData;
     1534        while (cbSent < cbData)
     1535        {
     1536            cbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk);
     1537            pParm->SetPtr(static_cast<uint8_t *>(pvData) + cbSent, cbCurChunk);
     1538            if (pCtx->uProtocol > 2)
     1539                Msg.u.v3.cbData.SetUInt32(cbCurChunk);
     1540
     1541            rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     1542            if (RT_SUCCESS(rc))
     1543                rc = Msg.hdr.result;
     1544
     1545            if (RT_FAILURE(rc))
     1546                break;
     1547
     1548            cbSent += cbCurChunk;
     1549        }
     1550
     1551        if (RT_SUCCESS(rc))
     1552            Assert(cbSent == cbData);
     1553    }
     1554
     1555    LogFlowFunc(("Returning rc=%Rrc, cbData=%RU64\n", rc, cbData));
     1556    return rc;
     1557}
     1558
     1559static int vbglR3DnDGHSendDir(PVBGLR3GUESTDNDCMDCTX pCtx, DnDURIObject *pObj)
     1560{
     1561    AssertPtrReturn(pObj,                                    VERR_INVALID_POINTER);
     1562    AssertPtrReturn(pCtx,                                    VERR_INVALID_POINTER);
     1563    AssertReturn(pObj->GetType() == DnDURIObject::Directory, VERR_INVALID_PARAMETER);
     1564
     1565    VBOXDNDGHSENDDIRMSG Msg;
    12451566    RT_ZERO(Msg);
    12461567    Msg.hdr.result      = VERR_WRONG_ORDER;
    12471568    Msg.hdr.u32ClientID = pCtx->uClientID;
    1248     Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DATA;
    1249     Msg.hdr.cParms      = 2;
    1250 
    1251     /* Total amount of bytes to send (including this data block). */
    1252     Msg.cbTotalBytes.SetUInt32(cbData + cbAdditionalData);
    1253 
    1254     int rc = VINF_SUCCESS;
    1255 
    1256     uint32_t cbCurChunk;
    1257     uint32_t cbMaxChunk = _64K; /** @todo Transfer max. 64K chunks per message. Configurable? */
    1258     uint32_t cbSent     = 0;
    1259 
    1260     while (cbSent < cbData)
    1261     {
    1262         cbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk);
    1263         Msg.pvData.SetPtr(static_cast<uint8_t *>(pvData) + cbSent, cbCurChunk);
    1264 
    1265         rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    1266         if (RT_SUCCESS(rc))
    1267             rc = Msg.hdr.result;
    1268 
    1269         if (RT_FAILURE(rc))
    1270             break;
    1271 
    1272         cbSent += cbCurChunk;
    1273     }
    1274 
    1275     if (RT_SUCCESS(rc))
    1276         Assert(cbSent == cbData);
    1277 
    1278     LogFlowFunc(("Returning rc=%Rrc, cbData=%RU32, cbAddtionalData=%RU32, cbSent=%RU32\n",
    1279                  rc, cbData, cbAdditionalData, cbSent));
    1280     return rc;
    1281 }
    1282 
    1283 static int vbglR3DnDGHSendDir(PVBGLR3GUESTDNDCMDCTX pCtx, DnDURIObject *pObj)
    1284 {
    1285     AssertPtrReturn(pObj,                                    VERR_INVALID_POINTER);
    1286     AssertPtrReturn(pCtx,                                    VERR_INVALID_POINTER);
    1287     AssertReturn(pObj->GetType() == DnDURIObject::Directory, VERR_INVALID_PARAMETER);
    1288 
    1289     DragAndDropSvc::VBOXDNDGHSENDDIRMSG Msg;
    1290     RT_ZERO(Msg);
    1291     Msg.hdr.result      = VERR_WRONG_ORDER;
    1292     Msg.hdr.u32ClientID = pCtx->uClientID;
    1293     Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DIR;
     1569    Msg.hdr.u32Function = GUEST_DND_GH_SND_DIR;
    12941570    Msg.hdr.cParms      = 3;
    12951571
     
    13321608    if (pCtx->uProtocol >= 2) /* Protocol version 2 and up sends a file header first. */
    13331609    {
    1334         DragAndDropSvc::VBOXDNDGHSENDFILEHDRMSG MsgHdr;
     1610        VBOXDNDGHSENDFILEHDRMSG MsgHdr;
    13351611        RT_ZERO(MsgHdr);
    13361612        MsgHdr.hdr.result      = VERR_WRONG_ORDER;
    13371613        MsgHdr.hdr.u32ClientID = pCtx->uClientID;
    1338         MsgHdr.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR;
     1614        MsgHdr.hdr.u32Function = GUEST_DND_GH_SND_FILE_HDR;
    13391615        MsgHdr.hdr.cParms      = 6;
    13401616
     
    13601636         * Send the actual file data, chunk by chunk.
    13611637         */
    1362         DragAndDropSvc::VBOXDNDGHSENDFILEDATAMSG Msg;
     1638        VBOXDNDGHSENDFILEDATAMSG Msg;
    13631639        RT_ZERO(Msg);
    13641640        Msg.hdr.result      = VERR_WRONG_ORDER;
    13651641        Msg.hdr.u32ClientID = pCtx->uClientID;
    1366         Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA;
    1367 
    1368         if (pCtx->uProtocol <= 1)
    1369         {
    1370             Msg.hdr.cParms  = 5;
    1371 
    1372             Msg.u.v1.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
    1373             Msg.u.v1.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
    1374             Msg.u.v1.fMode.SetUInt32(pObj->GetMode());
    1375         }
    1376         else
    1377         {
    1378             /* Only send context ID, file chunk + chunk size. */
    1379             Msg.hdr.cParms  = 3;
    1380 
    1381             Msg.u.v2.uContext.SetUInt32(0); /** @todo Set context ID. */
     1642        Msg.hdr.u32Function = GUEST_DND_GH_SND_FILE_DATA;
     1643
     1644        switch (pCtx->uProtocol)
     1645        {
     1646            case 3:
     1647            {
     1648                Msg.hdr.cParms = 5;
     1649
     1650                Msg.u.v3.uContext.SetUInt32(0);
     1651                Msg.u.v3.pvChecksum.SetPtr(NULL, 0);
     1652                Msg.u.v3.cbChecksum.SetUInt32(0);
     1653                break;
     1654            }
     1655
     1656            case 2:
     1657            {
     1658                Msg.hdr.cParms  = 3;
     1659
     1660                Msg.u.v2.uContext.SetUInt32(0);
     1661                break;
     1662            }
     1663
     1664            default: /* Protocol v1 */
     1665            {
     1666                Msg.hdr.cParms  = 5;
     1667
     1668                Msg.u.v1.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
     1669                Msg.u.v1.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
     1670                Msg.u.v1.fMode.SetUInt32(pObj->GetMode());
     1671                break;
     1672            }
    13821673        }
    13831674
     
    13971688                && cbRead)
    13981689            {
    1399                 if (pCtx->uProtocol <= 1)
     1690                switch (pCtx->uProtocol)
    14001691                {
    1401                     Msg.u.v1.pvData.SetPtr(pvBuf, cbRead);
    1402                     Msg.u.v1.cbData.SetUInt32(cbRead);
    1403                 }
    1404                 else
    1405                 {
    1406                     Msg.u.v2.pvData.SetPtr(pvBuf, cbRead);
    1407                     Msg.u.v2.cbData.SetUInt32(cbRead);
     1692                    case 3:
     1693                    {
     1694                        Msg.u.v3.pvData.SetPtr(pvBuf, cbRead);
     1695                        Msg.u.v3.cbData.SetUInt32(cbRead);
     1696                        /** @todo Calculate + set checksums. */
     1697                        break;
     1698                    }
     1699
     1700                    case 2:
     1701                    {
     1702                        Msg.u.v2.pvData.SetPtr(pvBuf, cbRead);
     1703                        Msg.u.v2.cbData.SetUInt32(cbRead);
     1704                        break;
     1705                    }
     1706
     1707                    default:
     1708                    {
     1709                        Msg.u.v1.pvData.SetPtr(pvBuf, cbRead);
     1710                        Msg.u.v1.cbData.SetUInt32(cbRead);
     1711                        break;
     1712                    }
    14081713                }
    14091714
     
    14591764}
    14601765
    1461 static int vbglR3DnDGHProcessURIMessages(PVBGLR3GUESTDNDCMDCTX pCtx,
    1462                                          const void *pvData, uint32_t cbData)
     1766static int vbglR3DnDGHSendURIData(PVBGLR3GUESTDNDCMDCTX pCtx,
     1767                                  const void *pvData, uint32_t cbData)
    14631768{
    14641769    AssertPtrReturn(pCtx,   VERR_INVALID_POINTER);
     
    14771782    if (RT_SUCCESS(rc))
    14781783    {
    1479         /* Send metadata; in this case it's the (non-recursive) file/directory
    1480          * URI list the host needs to know to initialize the drag'n drop operation. */
     1784        /*
     1785         * Send the (meta) data; in case of URIs it's the (non-recursive) file/directory
     1786         * URI list the host needs to know upfront to set up the drag'n drop operation.
     1787         */
    14811788        RTCString strRootDest = lstURI.RootToString();
    1482         Assert(strRootDest.isNotEmpty());
    1483 
    1484         void *pvToSend = (void *)strRootDest.c_str();
    1485         uint32_t cbToSend = (uint32_t)strRootDest.length() + 1; /* Include string termination. */
    1486 
    1487         rc = vbglR3DnDGHSendDataInternal(pCtx, pvToSend, cbToSend,
    1488                                          /* Include total bytes of all file paths,
    1489                                           * file sizes etc. */
    1490                                          (uint32_t)lstURI.TotalBytes());
     1789        if (strRootDest.isNotEmpty())
     1790        {
     1791            void *pvURIList  = (void *)strRootDest.c_str(); /* URI root list. */
     1792            size_t cbURLIist = strRootDest.length() + 1;    /* Include string termination. */
     1793
     1794            /* The total size also contains the size of the meta data. */
     1795            uint64_t cbTotal  = cbURLIist;
     1796                     cbTotal += lstURI.TotalBytes();
     1797
     1798            /* We're going to send an URI list in text format. */
     1799            char szMetaFmt[] = "text/uri-list";
     1800
     1801            VBOXDNDDATAHDR dataHeader;
     1802            dataHeader.uFlags    = 0; /* Flags not used yet. */
     1803            dataHeader.cbTotal   = cbTotal;
     1804            dataHeader.cbMeta    = cbURLIist;
     1805            dataHeader.pvMetaFmt = (void *)szMetaFmt;
     1806            dataHeader.cbMetaFmt = strlen(szMetaFmt) + 1; /* Include termination. */
     1807            dataHeader.cObjects  = lstURI.TotalCount();
     1808
     1809            rc = vbglR3DnDGHSendDataInternal(pCtx,
     1810                                             pvURIList, cbURLIist, &dataHeader);
     1811        }
     1812        else
     1813            rc = VERR_INVALID_PARAMETER;
    14911814    }
    14921815
     
    15201843    if (DnDMIMEHasFileURLs(pszFormat, strlen(pszFormat)))
    15211844    {
    1522         rc = vbglR3DnDGHProcessURIMessages(pCtx, pvData, cbData);
    1523     }
    1524     else
    1525     {
    1526         rc = vbglR3DnDGHSendDataInternal(pCtx, pvData, cbData, 0 /* cbAdditionalData */);
     1845        rc = vbglR3DnDGHSendURIData(pCtx, pvData, cbData);
     1846    }
     1847    else /* Send raw data. */
     1848    {
     1849        rc = vbglR3DnDGHSendDataInternal(pCtx, pvData, cbData, NULL /* pDataHdr */);
    15271850    }
    15281851
     
    15411864    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    15421865
    1543     DragAndDropSvc::VBOXDNDGHEVTERRORMSG Msg;
     1866    VBOXDNDGHEVTERRORMSG Msg;
    15441867    RT_ZERO(Msg);
    15451868    Msg.hdr.result      = VERR_WRONG_ORDER;
    15461869    Msg.hdr.u32ClientID = pCtx->uClientID;
    1547     Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_EVT_ERROR;
     1870    Msg.hdr.u32Function = GUEST_DND_GH_EVT_ERROR;
    15481871    Msg.hdr.cParms      = 1;
    15491872
  • trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp

    r57416 r58212  
    939939                    uAction = toHGCMAction(static_cast<Atom>(e.xclient.data.l[XdndStatusAction]));
    940940
    941                 rc = VbglR3DnDHGAcknowledgeOperation(&m_dndCtx, uAction);
     941                rc = VbglR3DnDHGSendAckOp(&m_dndCtx, uAction);
    942942            }
    943943            else if (e.xclient.message_type == xAtom(XA_XdndFinished))
     
    18211821    {
    18221822        /* No window to process, so send a ignore ack event to the host. */
    1823         rc = VbglR3DnDHGAcknowledgeOperation(&m_dndCtx, DND_IGNORE_ACTION);
     1823        rc = VbglR3DnDHGSendAckOp(&m_dndCtx, DND_IGNORE_ACTION);
    18241824    }
    18251825    else
     
    18661866    char szFormat[] = { "text/uri-list" };
    18671867
    1868     int rc = VbglR3DnDHGRequestData(&m_dndCtx, szFormat);
     1868    int rc = VbglR3DnDHGSendReqData(&m_dndCtx, szFormat);
    18691869    logInfo("Drop event from host resuled in: %Rrc\n", rc);
    18701870
     
    20742074    }
    20752075
    2076     rc2 = VbglR3DnDGHAcknowledgePending(&m_dndCtx, uDefAction, uAllActions, strFormats.c_str());
     2076    rc2 = VbglR3DnDGHSendAckPending(&m_dndCtx, uDefAction, uAllActions,
     2077                                    strFormats.c_str(), strFormats.length() + 1 /* Include termination */);
    20772078    LogFlowThisFunc(("uClientID=%RU32, uDefAction=0x%x, allActions=0x%x, strFormats=%s, rc=%Rrc\n",
    20782079                     m_dndCtx.uClientID, uDefAction, uAllActions, strFormats.c_str(), rc2));
     
    31963197
    31973198        /* Wait for new events. */
    3198         rc = VbglR3DnDProcessNextMessage(&dndCtx, &e.hgcm);
     3199        rc = VbglR3DnDRecvNextMsg(&dndCtx, &e.hgcm);
    31993200        if (   RT_SUCCESS(rc)
    32003201            || rc == VERR_CANCELLED)
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageDebugVM.cpp

    r57993 r58212  
    250250    {
    251251        com::Utf8Str strTmp(strSettings);
    252         strSettings = "release: ";
     252        strSettings = "release:";
    253253        strSettings.append(strTmp);
    254254    }
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDDataObject_win.cpp

    r58069 r58212  
    4242UIDnDDataObject::UIDnDDataObject(UIDnDHandler *pDnDHandler, const QStringList &lstFormats)
    4343    : m_pDnDHandler(pDnDHandler)
    44     , mStatus(Uninitialized)
    45     , mRefCount(1)
    46     , mcFormats(0)
    47     , mpFormatEtc(NULL)
    48     , mpStgMedium(NULL)
    49     , mSemEvent(NIL_RTSEMEVENT)
    50     , mpvData(NULL)
    51     , mcbData(0)
     44    , m_enmStatus(DnDDataObjectStatus_Uninitialized)
     45    , m_cRefs(1)
     46    , m_cFormats(0)
     47    , m_pFormatEtc(NULL)
     48    , m_pStgMedium(NULL)
     49    , m_SemEvent(NIL_RTSEMEVENT)
     50    , m_fDataRetrieved(false)
     51    , m_pvData(NULL)
     52    , m_cbData(0)
    5253{
    5354    HRESULT hr;
     
    5859    try
    5960    {
    60         mpFormatEtc = new FORMATETC[cMaxFormats];
    61         RT_BZERO(mpFormatEtc, sizeof(FORMATETC) * cMaxFormats);
    62         mpStgMedium = new STGMEDIUM[cMaxFormats];
    63         RT_BZERO(mpStgMedium, sizeof(STGMEDIUM) * cMaxFormats);
     61        m_pFormatEtc = new FORMATETC[cMaxFormats];
     62        RT_BZERO(m_pFormatEtc, sizeof(FORMATETC) * cMaxFormats);
     63        m_pStgMedium = new STGMEDIUM[cMaxFormats];
     64        RT_BZERO(m_pStgMedium, sizeof(STGMEDIUM) * cMaxFormats);
    6465
    6566        for (int i = 0;
     
    6869        {
    6970            const QString &strFormat = lstFormats.at(i);
    70             if (mlstFormats.contains(strFormat))
     71            if (m_lstFormats.contains(strFormat))
    7172                continue;
    7273
     
    7475            if (strFormat.contains("text/uri-list", Qt::CaseInsensitive))
    7576            {
    76                 RegisterFormat(&mpFormatEtc[cRegisteredFormats], CF_TEXT);
    77                 mpStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
    78                 RegisterFormat(&mpFormatEtc[cRegisteredFormats], CF_UNICODETEXT);
    79                 mpStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
    80                 RegisterFormat(&mpFormatEtc[cRegisteredFormats], CF_HDROP);
    81                 mpStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
    82 
    83                 mlstFormats << strFormat;
     77                RegisterFormat(&m_pFormatEtc[cRegisteredFormats], CF_TEXT);
     78                m_pStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
     79                RegisterFormat(&m_pFormatEtc[cRegisteredFormats], CF_UNICODETEXT);
     80                m_pStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
     81                RegisterFormat(&m_pFormatEtc[cRegisteredFormats], CF_HDROP);
     82                m_pStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
     83
     84                m_lstFormats << strFormat;
    8485            }
    8586            /* Plain text ("text/plain"). */
    8687            if (strFormat.contains("text/plain", Qt::CaseInsensitive))
    8788            {
    88                 RegisterFormat(&mpFormatEtc[cRegisteredFormats], CF_TEXT);
    89                 mpStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
    90                 RegisterFormat(&mpFormatEtc[cRegisteredFormats], CF_UNICODETEXT);
    91                 mpStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
    92 
    93                 mlstFormats << strFormat;
     89                RegisterFormat(&m_pFormatEtc[cRegisteredFormats], CF_TEXT);
     90                m_pStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
     91                RegisterFormat(&m_pFormatEtc[cRegisteredFormats], CF_UNICODETEXT);
     92                m_pStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
     93
     94                m_lstFormats << strFormat;
    9495            }
    9596        }
     
    106107    if (SUCCEEDED(hr))
    107108    {
    108         int rc2 = RTSemEventCreate(&mSemEvent);
     109        int rc2 = RTSemEventCreate(&m_SemEvent);
    109110        AssertRC(rc2);
    110111
     
    130131                       RegisterClipboardFormat(CFSTR_SHELLIDLISTOFFSET));
    131132#endif
    132         mcFormats = cRegisteredFormats;
    133         mStatus   = Dropped;
     133        m_cFormats = cRegisteredFormats;
     134        m_enmStatus = DnDDataObjectStatus_Dropping;
    134135    }
    135136
     
    139140UIDnDDataObject::~UIDnDDataObject(void)
    140141{
    141     if (mpFormatEtc)
    142         delete[] mpFormatEtc;
    143 
    144     if (mpStgMedium)
    145         delete[] mpStgMedium;
    146 
    147     if (mpvData)
    148         RTMemFree(mpvData);
    149 
    150     if (mSemEvent != NIL_RTSEMEVENT)
    151         RTSemEventDestroy(mSemEvent);
    152 
    153     LogFlowFunc(("mRefCount=%RI32\n", mRefCount));
     142    if (m_pFormatEtc)
     143        delete[] m_pFormatEtc;
     144
     145    if (m_pStgMedium)
     146        delete[] m_pStgMedium;
     147
     148    if (m_pvData)
     149        RTMemFree(m_pvData);
     150
     151    if (m_SemEvent != NIL_RTSEMEVENT)
     152        RTSemEventDestroy(m_SemEvent);
     153
     154    LogFlowFunc(("mRefCount=%RI32\n", m_cRefs));
    154155}
    155156
     
    160161STDMETHODIMP_(ULONG) UIDnDDataObject::AddRef(void)
    161162{
    162     return InterlockedIncrement(&mRefCount);
     163    return InterlockedIncrement(&m_cRefs);
    163164}
    164165
    165166STDMETHODIMP_(ULONG) UIDnDDataObject::Release(void)
    166167{
    167     LONG lCount = InterlockedDecrement(&mRefCount);
     168    LONG lCount = InterlockedDecrement(&m_cRefs);
    168169    if (lCount == 0)
    169170    {
     
    210211    LPSTGMEDIUM pThisMedium = NULL;
    211212
     213    LogFlowThisFunc(("\n"));
     214
    212215    /* Format supported? */
    213216    ULONG lIndex;
    214217    if (   LookupFormatEtc(pFormatEtc, &lIndex)
    215         && lIndex < mcFormats) /* Paranoia. */
    216     {
    217         pThisMedium = &mpStgMedium[lIndex];
     218        && lIndex < m_cFormats) /* Paranoia. */
     219    {
     220        pThisMedium = &m_pStgMedium[lIndex];
    218221        AssertPtr(pThisMedium);
    219         pThisFormat = &mpFormatEtc[lIndex];
     222        pThisFormat = &m_pFormatEtc[lIndex];
    220223        AssertPtr(pThisFormat);
    221224
    222         LogFlowFunc(("pThisMedium=%p, pThisFormat=%p\n", pThisMedium, pThisFormat));
    223         LogFlowFunc(("mStatus=%ld\n", mStatus));
    224         switch (mStatus)
     225        LogFlowThisFunc(("pThisMedium=%p, pThisFormat=%p\n", pThisMedium, pThisFormat));
     226        LogFlowThisFunc(("mStatus=%RU32\n", m_enmStatus));
     227        switch (m_enmStatus)
    225228        {
    226             case Dropping:
     229            case DnDDataObjectStatus_Dropping:
    227230            {
    228                     LogRel3(("DnD: Dropping\n"));
    229                     LogFlowFunc(("Waiting for event ...\n"));
    230                     int rc2 = RTSemEventWait(mSemEvent, RT_INDEFINITE_WAIT);
    231                     LogFlowFunc(("rc=%Rrc, mStatus=%ld\n", rc2, mStatus));
     231#if 0
     232                LogRel3(("DnD: Dropping\n"));
     233                LogFlowFunc(("Waiting for event ...\n"));
     234                int rc2 = RTSemEventWait(m_SemEvent, RT_INDEFINITE_WAIT);
     235                LogFlowFunc(("rc=%Rrc, mStatus=%RU32\n", rc2, m_enmStatus));
     236#endif
     237                break;
    232238            }
    233239
    234             case Dropped:
     240            case DnDDataObjectStatus_Dropped:
    235241            {
    236242                LogRel3(("DnD: Dropped\n"));
     
    239245                         pThisFormat->tymed, pThisFormat->dwAspect));
    240246                LogRel3(("DnD: Got strFormat=%s, pvData=%p, cbData=%RU32\n",
    241                          mstrFormat.toAscii().constData(), mpvData, mcbData));
     247                         m_strFormat.toAscii().constData(), m_pvData, m_cbData));
    242248
    243249                QVariant::Type vaType;
     
    288294
    289295                int rc;
    290                 if (!mVaData.isValid())
     296
     297                if (!m_fDataRetrieved)
    291298                {
    292                     /* Note:  We're usig Qt::MoveAction because this speeds up the whole operation
    293                      *        significantly: Instead of copying the data from the temporary location to
    294                      *        the final destination we just move it.
    295                      *
    296                      * Note2: The Qt::MoveAction *only* affects the behavior on the host! The desired
    297                      *        action for the guest (e.g. moving a file from guest to host) is not affected
    298                      *        by this setting. */
    299                     rc = m_pDnDHandler->retrieveData(Qt::MoveAction,
    300                                                      strMIMEType, vaType, mVaData);
     299                    if (m_pDnDHandler)
     300                    {
     301                        rc = m_pDnDHandler->retrieveData(Qt::CopyAction,
     302                                                         strMIMEType, vaType, m_vaData);
     303                    }
     304                    else
     305                        rc = VERR_NOT_FOUND;
     306
     307                    m_fDataRetrieved = true;
     308                    LogFlowFunc(("Retrieving data ended with %Rrc\n", rc));
    301309                }
    302                 else
    303                     rc = VINF_SUCCESS; /* Data already retrieved. */
    304 
    305                 if (RT_SUCCESS(rc))
     310                else /* Data already been retrieved. */
     311                    rc = VINF_SUCCESS;
     312
     313                if (   RT_SUCCESS(rc)
     314                    && m_vaData.isValid())
    306315                {
    307316                    if (   strMIMEType.startsWith("text/uri-list")
    308317                               /* One item. */
    309                         && (   mVaData.canConvert(QVariant::String)
     318                        && (   m_vaData.canConvert(QVariant::String)
    310319                               /* Multiple items. */
    311                             || mVaData.canConvert(QVariant::StringList))
     320                            || m_vaData.canConvert(QVariant::StringList))
    312321                       )
    313322                    {
    314                         QStringList lstFilesURI = mVaData.toStringList();
     323                        QStringList lstFilesURI = m_vaData.toStringList();
    315324                        QStringList lstFiles;
    316325                        for (size_t i = 0; i < lstFilesURI.size(); i++)
     
    331340
    332341                        size_t cFiles = lstFiles.size();
     342                        LogFlowThisFunc(("Files (%zu)\n", cFiles));
    333343                        if (   RT_SUCCESS(rc)
    334344                            && cFiles)
    335345                        {
    336 #ifdef DEBUG
    337                             LogFlowFunc(("Files (%zu)\n", cFiles));
    338                             for (size_t i = 0; i < cFiles; i++)
    339                                 LogFlowFunc(("\tFile: %s\n", lstFiles.at(i).toAscii().constData()));
    340 #endif
    341                             size_t cchFiles = 0; /* Number of ASCII characters. */
     346                            size_t cchFiles = 0; /* Number of characters. */
    342347                            for (size_t i = 0; i < cFiles; i++)
    343348                            {
    344                                 cchFiles += strlen(lstFiles.at(i).toAscii().constData());
     349                                const char *pszFile = lstFiles.at(i).toAscii().constData();
     350                                cchFiles += strlen(pszFile);
    345351                                cchFiles += 1; /* Terminating '\0'. */
     352                                LogFlowThisFunc(("\tFile: %s (cchFiles=%zu)\n", pszFile, cchFiles));
    346353                            }
    347354
    348                             size_t cbBuf = sizeof(DROPFILES) + ((cchFiles + 1) * sizeof(RTUTF16));
     355                            /* List termination with '\0'. */
     356                            cchFiles++;
     357
     358                            size_t cbBuf = sizeof(DROPFILES) + (cchFiles * sizeof(RTUTF16));
    349359                            DROPFILES *pDropFiles = (DROPFILES *)RTMemAllocZ(cbBuf);
    350360                            if (pDropFiles)
    351361                            {
    352                                 pDropFiles->pFiles = sizeof(DROPFILES);
    353                                 pDropFiles->fWide = 1; /* We use unicode. Always. */
     362                                /* Put the files list right after our DROPFILES structure. */
     363                                pDropFiles->pFiles = sizeof(DROPFILES); /* Offset to file list. */
     364                                pDropFiles->fWide  = 1;                 /* We use Unicode. Always. */
    354365
    355366                                uint8_t *pCurFile = (uint8_t *)pDropFiles + pDropFiles->pFiles;
    356367                                AssertPtr(pCurFile);
    357368
     369                                LogFlowThisFunc(("Encoded:\n"));
    358370                                for (size_t i = 0; i < cFiles; i++)
    359371                                {
     372                                    const char *pszFile = lstFiles.at(i).toUtf8().constData();
     373                                    Assert(strlen(pszFile));
     374
    360375                                    size_t cchCurFile;
    361376                                    PRTUTF16 pwszFile;
    362                                     rc = RTStrToUtf16(lstFiles.at(i).toAscii().constData(), &pwszFile);
     377                                    rc = RTStrToUtf16(pszFile, &pwszFile);
    363378                                    if (RT_SUCCESS(rc))
    364379                                    {
     
    376391                                    *pCurFile = L'\0';
    377392                                    pCurFile += sizeof(RTUTF16);
     393
     394                                    LogFlowThisFunc(("\t#%zu: cchCurFile=%zu\n", i, cchCurFile));
    378395                                }
    379396
     
    382399                                    *pCurFile = L'\0'; /* Final list terminator. */
    383400
    384                                     pMedium->tymed = TYMED_HGLOBAL;
     401                                    /*
     402                                     * Fill out the medium structure we're going to report back.
     403                                     */
     404                                    pMedium->tymed          = TYMED_HGLOBAL;
    385405                                    pMedium->pUnkForRelease = NULL;
    386                                     pMedium->hGlobal = GlobalAlloc(  GMEM_ZEROINIT
    387                                                                    | GMEM_MOVEABLE
    388                                                                    | GMEM_DDESHARE, cbBuf);
     406                                    pMedium->hGlobal        = GlobalAlloc(  GMEM_ZEROINIT
     407                                                                          | GMEM_MOVEABLE
     408                                                                          | GMEM_DDESHARE, cbBuf);
    389409                                    if (pMedium->hGlobal)
    390410                                    {
     
    402422                                    else
    403423                                        rc = VERR_NO_MEMORY;
     424
     425                                    LogFlowThisFunc(("Copying to TYMED_HGLOBAL (%zu bytes): %Rrc\n", cbBuf, rc));
    404426                                }
    405427
    406428                                RTMemFree(pDropFiles);
    407429                            }
     430                            else
     431                                rc = VERR_NO_MEMORY;
     432
     433                            if (RT_FAILURE(rc))
     434                                LogFlowThisFunc(("Failed with %Rrc\n", rc));
    408435                        }
    409436                    }
    410437                    else if (   strMIMEType.startsWith("text/plain")
    411                              && mVaData.canConvert(QVariant::String))
     438                             && m_vaData.canConvert(QVariant::String))
    412439                    {
    413                         bool fUnicode = pFormatEtc->cfFormat == CF_UNICODETEXT;
    414                         int cbCh = fUnicode
    415                                  ? sizeof(WCHAR) : sizeof(char);
    416 
    417                         QString strText = mVaData.toString();
     440                        const bool fUnicode = pFormatEtc->cfFormat == CF_UNICODETEXT;
     441                        const size_t cbCh  = fUnicode
     442                                            ? sizeof(WCHAR) : sizeof(char);
     443
     444                        QString strText = m_vaData.toString();
    418445                        size_t cbSrc = strText.length() * cbCh;
    419446                        Assert(cbSrc);
     
    423450                        AssertPtr(pvSrc);
    424451
    425                         LogFlowFunc(("pvSrc=0x%p, cbSrc=%zu, cbch=%d, fUnicode=%RTbool\n",
     452                        LogFlowFunc(("pvSrc=0x%p, cbSrc=%zu, cbCh=%zu, fUnicode=%RTbool\n",
    426453                                     pvSrc, cbSrc, cbCh, fUnicode));
    427454
    428                         pMedium->tymed = TYMED_HGLOBAL;
     455                        pMedium->tymed          = TYMED_HGLOBAL;
    429456                        pMedium->pUnkForRelease = NULL;
    430                         pMedium->hGlobal = GlobalAlloc(  GMEM_ZEROINIT
    431                                                        | GMEM_MOVEABLE
    432                                                        | GMEM_DDESHARE,
    433                                                        cbSrc);
     457                        pMedium->hGlobal        = GlobalAlloc(GHND | GMEM_SHARE, cbSrc);
    434458                        if (pMedium->hGlobal)
    435459                        {
     
    449473                    }
    450474                    else
    451                         LogFlowFunc(("MIME type=%s not supported\n",
    452                                      strMIMEType.toAscii().constData()));
    453 
    454                     LogFlowFunc(("Handling formats ended with rc=%Rrc\n", rc));
     475                        LogRel2(("DnD: MIME type '%s' not supported\n", strMIMEType.toAscii().constData()));
     476
     477                    LogFlowThisFunc(("Handling formats ended with rc=%Rrc\n", rc));
    455478                }
     479
     480                break;
    456481            }
    457482
     
    488513    }
    489514
    490     LogFlowFunc(("Returning hr=%Rhrc\n", hr));
     515    LogFlowThisFunc(("Returning hr=%Rhrc\n", hr));
    491516    return hr;
    492517}
     
    535560{
    536561    LogFlowFunc(("dwDirection=%RI32, mcFormats=%RI32, mpFormatEtc=%p\n",
    537                  dwDirection, mcFormats, mpFormatEtc));
     562                 dwDirection, m_cFormats, m_pFormatEtc));
    538563
    539564    HRESULT hr;
    540565    if (dwDirection == DATADIR_GET)
    541566    {
    542         hr = UIDnDEnumFormatEtc::CreateEnumFormatEtc(mcFormats, mpFormatEtc, ppEnumFormatEtc);
     567        hr = UIDnDEnumFormatEtc::CreateEnumFormatEtc(m_cFormats, m_pFormatEtc, ppEnumFormatEtc);
    543568    }
    544569    else
     
    571596{
    572597    LogFlowFunc(("Aborting ...\n"));
    573     mStatus = Aborted;
    574     return RTSemEventSignal(mSemEvent);
     598    m_enmStatus = DnDDataObjectStatus_Aborted;
     599    return RTSemEventSignal(m_SemEvent);
    575600}
    576601
     
    661686    /* puIndex is optional. */
    662687
    663     for (ULONG i = 0; i < mcFormats; i++)
    664     {
    665         if(    (pFormatEtc->tymed & mpFormatEtc[i].tymed)
    666             && pFormatEtc->cfFormat == mpFormatEtc[i].cfFormat
    667             && pFormatEtc->dwAspect == mpFormatEtc[i].dwAspect)
     688    for (ULONG i = 0; i < m_cFormats; i++)
     689    {
     690        if(    (pFormatEtc->tymed & m_pFormatEtc[i].tymed)
     691            && pFormatEtc->cfFormat == m_pFormatEtc[i].cfFormat
     692            && pFormatEtc->dwAspect == m_pFormatEtc[i].dwAspect)
    668693        {
    669694            LogRel3(("DnD: Format found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32, ulIndex=%RU32\n",
    670                      pFormatEtc->tymed, pFormatEtc->cfFormat, UIDnDDataObject::ClipboardFormatToString(mpFormatEtc[i].cfFormat),
     695                     pFormatEtc->tymed, pFormatEtc->cfFormat, UIDnDDataObject::ClipboardFormatToString(m_pFormatEtc[i].cfFormat),
    671696                     pFormatEtc->dwAspect, i));
    672697
     
    677702    }
    678703
     704#if 0
    679705    LogRel3(("DnD: Format NOT found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32\n",
    680706             pFormatEtc->tymed, pFormatEtc->cfFormat, UIDnDDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
    681707             pFormatEtc->dwAspect));
     708#endif
    682709
    683710    return false;
    684 }
    685 
    686 /* static */
    687 HGLOBAL UIDnDDataObject::MemDup(HGLOBAL hMemSource)
    688 {
    689     DWORD dwLen    = GlobalSize(hMemSource);
    690     AssertReturn(dwLen, NULL);
    691     PVOID pvSource = GlobalLock(hMemSource);
    692     if (pvSource)
    693     {
    694         PVOID pvDest = GlobalAlloc(GMEM_FIXED, dwLen);
    695         if (pvDest)
    696             memcpy(pvDest, pvSource, dwLen);
    697 
    698         GlobalUnlock(hMemSource);
    699         return pvDest;
    700     }
    701 
    702     return NULL;
    703711}
    704712
     
    719727}
    720728
    721 void UIDnDDataObject::SetStatus(Status status)
    722 {
    723     LogFlowFunc(("Setting status to %ld\n", status));
    724     mStatus = status;
     729void UIDnDDataObject::SetStatus(DnDDataObjectStatus enmStatus)
     730{
     731    LogFlowFunc(("Setting status to %RU32\n", enmStatus));
     732    m_enmStatus = enmStatus;
     733}
     734
     735void UIDnDDataObject::Signal(void)
     736{
     737    SetStatus(DnDDataObjectStatus_Dropped);
    725738}
    726739
     
    732745    int rc;
    733746
    734     SetStatus(Dropped);
    735 
    736     mstrFormat = strFormat;
    737747    if (cbData)
    738748    {
    739         mpvData = RTMemAlloc(cbData);
    740         if (mpvData)
     749        m_pvData = RTMemAlloc(cbData);
     750        if (m_pvData)
    741751        {
    742             memcpy(mpvData, pvData, cbData);
    743             mcbData = cbData;
     752            memcpy(m_pvData, pvData, cbData);
     753            m_cbData = cbData;
    744754            rc = VINF_SUCCESS;
    745755        }
     
    750760        rc = VINF_SUCCESS;
    751761
    752     if (RT_FAILURE(rc))
    753         mStatus = Aborted;
     762    if (RT_SUCCESS(rc))
     763    {
     764        m_strFormat = strFormat;
     765        SetStatus(DnDDataObjectStatus_Dropped);
     766    }
     767    else
     768        SetStatus(DnDDataObjectStatus_Aborted);
    754769
    755770    /* Signal in any case. */
    756     int rc2 = RTSemEventSignal(mSemEvent);
     771    int rc2 = RTSemEventSignal(m_SemEvent);
    757772    if (RT_SUCCESS(rc))
    758773        rc = rc2;
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDDataObject_win.h

    r56780 r58212  
    3737public:
    3838
    39     enum Status
     39    enum DnDDataObjectStatus
    4040    {
    41         Uninitialized = 0,
    42         Initialized,
    43         Dropping,
    44         Dropped,
    45         Aborted
     41        DnDDataObjectStatus_Uninitialized = 0,
     42        DnDDataObjectStatus_Initialized,
     43        DnDDataObjectStatus_Dropping,
     44        DnDDataObjectStatus_Dropped,
     45        DnDDataObjectStatus_Aborted,
     46        DnDDataObjectStatus_32Bit_Hack = 0x7fffffff
    4647    };
    4748
     
    7172public:
    7273
    73     static const char* ClipboardFormatToString(CLIPFORMAT fmt);
     74    static const char *ClipboardFormatToString(CLIPFORMAT fmt);
    7475
    7576    int Abort(void);
    76     void SetStatus(Status status);
     77    void Signal(void);
    7778    int Signal(const QString &strFormat, const void *pvData, uint32_t cbData);
    7879
    7980protected:
    8081
     82    void SetStatus(DnDDataObjectStatus enmStatus);
     83
    8184    bool LookupFormatEtc(LPFORMATETC pFormatEtc, ULONG *puIndex);
    82     static HGLOBAL MemDup(HGLOBAL hMemSource);
    8385    void RegisterFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat, TYMED tyMed = TYMED_HGLOBAL,
    8486                        LONG lindex = -1, DWORD dwAspect = DVASPECT_CONTENT, DVTARGETDEVICE *pTargetDevice = NULL);
    8587
    86     UIDnDHandler   *m_pDnDHandler;
    87 
    88     Status          mStatus;
    89     LONG            mRefCount;
     88    /** Pointe rto drag and drop handler. */
     89    UIDnDHandler           *m_pDnDHandler;
     90    /** Current drag and drop status. */
     91    DnDDataObjectStatus     m_enmStatus;
     92    /** Internal reference count of this object. */
     93    LONG                    m_cRefs;
    9094    /** Number of native formats registered. This can be a different number than supplied with mlstFormats. */
    91     ULONG           mcFormats;
    92     FORMATETC      *mpFormatEtc;
    93     STGMEDIUM      *mpStgMedium;
    94     RTSEMEVENT      mSemEvent;
    95     QStringList     mlstFormats;
    96     QString         mstrFormat;
     95    ULONG                   m_cFormats;
     96    FORMATETC              *m_pFormatEtc;
     97    STGMEDIUM              *m_pStgMedium;
     98    RTSEMEVENT              m_SemEvent;
     99    QStringList             m_lstFormats;
     100    QString                 m_strFormat;
    97101    /** The retrieved data as a QVariant. Needed for buffering in case a second format needs the same data,
    98102     *  e.g. CF_TEXT and CF_UNICODETEXT. */
    99     QVariant        mVaData;
     103    QVariant                m_vaData;
     104    /** Whether the data already was retrieved or not. */
     105    bool                    m_fDataRetrieved;
    100106    /** The retrieved data as a raw buffer. */
    101     void           *mpvData;
     107    void                   *m_pvData;
    102108    /** Raw buffer size (in bytes). */
    103     uint32_t        mcbData;
     109    uint32_t                m_cbData;
    104110};
    105111
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDDropSource_win.cpp

    r56780 r58212  
    2424#include <iprt/thread.h>
    2525
     26/* Qt includes: */
     27#include <QApplication>
     28
     29/* Windows includes: */
     30#include <QApplication>
    2631#include <windows.h>
    2732#include <new> /* For bad_alloc. */
    2833
    2934#include "UIDnDDropSource_win.h"
     35#include "UIDnDDataObject_win.h"
    3036
    31 
    32 
    33 UIDnDDropSource::UIDnDDropSource(QWidget *pParent)
    34     : mRefCount(1),
    35       mpParent(pParent),
    36       mdwCurEffect(0),
    37       muCurAction(Qt::IgnoreAction)
     37UIDnDDropSource::UIDnDDropSource(QWidget *pParent, UIDnDDataObject *pDataObject)
     38    : m_cRefCount(1)
     39    , m_pParent(pParent)
     40    , m_pDataObject(pDataObject)
     41    , m_dwCurEffect(DROPEFFECT_NONE)
     42    , m_uCurAction(Qt::IgnoreAction)
    3843{
    39     LogFlowFunc(("pParent=0x%p\n", mpParent));
     44    LogFlowFunc(("pParent=0x%p\n", m_pParent));
    4045}
    4146
    4247UIDnDDropSource::~UIDnDDropSource(void)
    4348{
    44     LogFlowFunc(("mRefCount=%RI32\n", mRefCount));
     49    LogFlowFunc(("mRefCount=%RU32\n", m_cRefCount));
    4550}
    4651
     
    5156STDMETHODIMP_(ULONG) UIDnDDropSource::AddRef(void)
    5257{
    53     return InterlockedIncrement(&mRefCount);
     58    LogFlowFunc(("mRefCount=%RU32\n", m_cRefCount + 1));
     59    return (ULONG)InterlockedIncrement(&m_cRefCount);
    5460}
    5561
    5662STDMETHODIMP_(ULONG) UIDnDDropSource::Release(void)
    5763{
    58     LONG lCount = InterlockedDecrement(&mRefCount);
    59     if (lCount == 0)
     64    Assert(m_cRefCount > 0);
     65    LogFlowFunc(("mRefCount=%RU32\n", m_cRefCount - 1));
     66    LONG lCount = InterlockedDecrement(&m_cRefCount);
     67    if (lCount <= 0)
    6068    {
    6169        delete this;
     
    6371    }
    6472
    65     return lCount;
     73    return (ULONG)lCount;
    6674}
    6775
     
    94102STDMETHODIMP UIDnDDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD dwKeyState)
    95103{
    96 #ifndef DEBUG_andy
    97     LogFlowFunc(("fEscapePressed=%RTbool, dwKeyState=0x%x, mdwCurEffect=%RI32, muCurAction=%RU32\n",
    98                  fEscapePressed, dwKeyState, mdwCurEffect, muCurAction));
    99 #endif
     104    LogFlowFunc(("fEscapePressed=%RTbool, dwKeyState=0x%x, m_dwCurEffect=%RI32, m_uCurAction=%RU32\n",
     105                 RT_BOOL(fEscapePressed), dwKeyState, m_dwCurEffect, m_uCurAction));
    100106
    101107    /* ESC pressed? Bail out. */
    102108    if (fEscapePressed)
    103109    {
    104         mdwCurEffect = 0;
    105         muCurAction = Qt::IgnoreAction;
     110        m_dwCurEffect = DROPEFFECT_NONE;
     111        m_uCurAction = Qt::IgnoreAction;
    106112
    107113        LogRel2(("DnD: User cancelled dropping data to the host\n"));
     
    118124    if (fDropContent)
    119125    {
     126        if (m_pDataObject)
     127            m_pDataObject->Signal();
     128
    120129        LogRel2(("DnD: User dropped data to the host\n"));
    121130        return DRAGDROP_S_DROP;
    122131    }
     132
     133    QApplication::processEvents();
    123134
    124135    /* No change, just continue. */
     
    134145STDMETHODIMP UIDnDDropSource::GiveFeedback(DWORD dwEffect)
    135146{
    136      Qt::DropActions dropActions = Qt::IgnoreAction;
     147    Qt::DropActions dropActions = Qt::IgnoreAction;
    137148
    138 #ifndef DEBUG_andy
    139149    LogFlowFunc(("dwEffect=0x%x\n", dwEffect));
    140 #endif
    141150    if (dwEffect)
    142151    {
     
    147156        if (dwEffect & DROPEFFECT_LINK)
    148157            dropActions |= Qt::LinkAction;
     158
     159        m_dwCurEffect = dwEffect;
    149160    }
    150161
    151     mdwCurEffect = dwEffect;
    152     muCurAction = dropActions;
     162    m_uCurAction  = dropActions;
    153163
    154164    return DRAGDROP_S_USEDEFAULTCURSORS;
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDDropSource_win.h

    r55821 r58212  
    2222#include "COMEnums.h"
    2323
     24class UIDnDDataObject;
     25
     26/**
     27 * Implementation of IDropSource for drag and drop on the host.
     28 */
    2429class UIDnDDropSource : public IDropSource
    2530{
    2631public:
    2732
    28     UIDnDDropSource(QWidget *pParent);
     33    UIDnDDropSource(QWidget *pParent, UIDnDDataObject *pDataObject);
    2934    virtual ~UIDnDDropSource(void);
    3035
    3136public:
    3237
    33     uint32_t GetCurrentAction(void) { return muCurAction; }
     38    uint32_t GetCurrentAction(void) const { return m_uCurAction; }
    3439
    3540public: /* IUnknown methods. */
     
    4651protected:
    4752
    48     LONG             mRefCount;
    49     QWidget         *mpParent;
    50     DWORD            mdwCurEffect;
    51     Qt::DropActions  muCurAction;
     53    /** Pointer to parent widget. */
     54    QWidget         *m_pParent;
     55    UIDnDDataObject *m_pDataObject;
     56    /** The current reference count. */
     57    LONG             m_cRefCount;
     58    /** Current (last) drop effect issued. */
     59    DWORD            m_dwCurEffect;
     60    /** Current drop action to perform in case of a successful drop. */
     61    Qt::DropActions  m_uCurAction;
    5262};
    5363
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.cpp

    r57292 r58212  
    335335
    336336# ifdef RT_OS_WINDOWS
    337 
    338     UIDnDDropSource *pDropSource = new UIDnDDropSource(m_pParent);
    339     if (!pDropSource)
    340         return VERR_NO_MEMORY;
    341337    UIDnDDataObject *pDataObject = new UIDnDDataObject(this, lstFormats);
    342338    if (!pDataObject)
     339        return VERR_NO_MEMORY;
     340    UIDnDDropSource *pDropSource = new UIDnDDropSource(m_pParent, pDataObject);
     341    if (!pDropSource)
    343342        return VERR_NO_MEMORY;
    344343
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDMIMEData.cpp

    r57288 r58212  
    109109
    110110    /* Let the user know. */
    111     LogRel(("Drag and drop support for OS X is disabled in this version."));
     111    LogRel(("DnD: Drag and drop support for OS X is not available in this version\n"));
    112112# endif /* VBOX_WITH_DRAG_AND_DROP_PROMISES */
    113113#else /* !RT_OS_DARWIN */
     
    120120    {
    121121        LogFlowFunc(("Current drop action is 0x%x, so can't drop yet\n", m_curAction));
    122         rc = VERR_WRONG_ORDER;
     122        rc = VERR_NOT_FOUND;
    123123    }
    124124#endif
     
    172172
    173173    if (RT_FAILURE(rc))
    174         LogRel(("DnD: Retrieving data failed with %Rrc\n", rc));
     174        LogRel2(("DnD: Retrieving data failed with %Rrc\n", rc));
    175175
    176176    return QVariant(QVariant::Invalid);
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.cpp

    r58011 r58212  
    101101
    102102
    103 #ifdef DEBUG_andy
     103#ifdef DEBUG
     104# ifdef DEBUG_andy
    104105/* Macro for debugging drag and drop actions which usually would
    105106 * go to Main's logging group. */
    106 # define DNDDEBUG(x) LogRel(x)
    107 #else
    108 # define DNDDEBUG(x)
     107#  define DNDDEBUG(x) LogFlowFunc(x)
     108# else
     109#  define DNDDEBUG(x)
     110# endif
    109111#endif
    110112
  • trunk/src/VBox/GuestHost/DragAndDrop/DnDDroppedFiles.cpp

    r57776 r58212  
    2828#include <VBox/GuestHost/DragAndDrop.h>
    2929
     30#ifdef LOG_GROUP
     31 #undef LOG_GROUP
     32#endif
     33#define LOG_GROUP LOG_GROUP_GUEST_DND
     34#include <VBox/log.h>
     35
    3036DnDDroppedFiles::DnDDroppedFiles(void)
    3137    : hDir(NULL)
    32     , fOpen(false) { }
    33 
    34 DnDDroppedFiles::DnDDroppedFiles(const char *pszPath, uint32_t fFlags)
     38    , fOpen(0) { }
     39
     40DnDDroppedFiles::DnDDroppedFiles(const char *pszPath, uint32_t fOpen)
    3541    : hDir(NULL)
    36     , fOpen(false)
    37 {
    38     OpenEx(pszPath, fFlags);
     42    , fOpen(0)
     43{
     44    OpenEx(pszPath, fOpen);
    3945}
    4046
    4147DnDDroppedFiles::~DnDDroppedFiles(void)
    4248{
    43     Reset(true /* fRemoveDropDir */);
     49    /* Only make sure to not leak any handles and stuff, don't delete any
     50     * directories / files here. */
     51    closeInternal();
    4452}
    4553
     
    6270}
    6371
     72int DnDDroppedFiles::closeInternal(void)
     73{
     74    int rc;
     75    if (this->hDir != NULL)
     76    {
     77        rc = RTDirClose(this->hDir);
     78        if (RT_SUCCESS(rc))
     79            this->hDir = NULL;
     80    }
     81    else
     82        rc = VINF_SUCCESS;
     83
     84    LogFlowFuncLeaveRC(rc);
     85    return rc;
     86}
     87
     88int DnDDroppedFiles::Close(void)
     89{
     90    return closeInternal();
     91}
     92
    6493const char *DnDDroppedFiles::GetDirAbs(void) const
    6594{
     
    6998bool DnDDroppedFiles::IsOpen(void) const
    7099{
    71     return this->fOpen;
     100    return (this->hDir != NULL);
    72101}
    73102
     
    129158                this->hDir       = phDir;
    130159                this->strPathAbs = pszDropDir;
    131                 this->fOpen      = true;
     160                this->fOpen      = fFlags;
    132161            }
    133162        }
     
    135164    } while (0);
    136165
     166    LogFlowFuncLeaveRC(rc);
    137167    return rc;
    138168}
     
    157187int DnDDroppedFiles::Reset(bool fRemoveDropDir)
    158188{
    159     int rc = VINF_SUCCESS;
    160     if (this->fOpen)
    161     {
    162         rc = RTDirClose(this->hDir);
    163         if (RT_SUCCESS(rc))
    164         {
    165             this->fOpen = false;
    166             this->hDir  = NULL;
    167         }
    168     }
    169     if (RT_SUCCESS(rc))
    170     {
    171         this->lstDirs.clear();
    172         this->lstFiles.clear();
    173 
    174         if (   fRemoveDropDir
    175             && this->strPathAbs.isNotEmpty())
    176         {
    177             /* Try removing the (empty) drop directory in any case. */
    178             rc = RTDirRemove(this->strPathAbs.c_str());
    179             if (RT_SUCCESS(rc)) /* Only clear if successfully removed. */
    180                 this->strPathAbs = "";
    181         }
    182     }
    183 
    184     return rc;
     189    int rc = closeInternal();
     190    if (RT_SUCCESS(rc))
     191    {
     192        if (fRemoveDropDir)
     193        {
     194            rc = Rollback();
     195        }
     196        else
     197        {
     198            this->lstDirs.clear();
     199            this->lstFiles.clear();
     200        }
     201    }
     202
     203    LogFlowFuncLeaveRC(rc);
     204    return rc;
     205}
     206
     207int DnDDroppedFiles::Reopen(void)
     208{
     209    if (this->strPathAbs.isEmpty())
     210        return VERR_NOT_FOUND;
     211
     212    return OpenEx(this->strPathAbs.c_str(), this->fOpen);
    185213}
    186214
     
    190218        return VINF_SUCCESS;
    191219
    192     Assert(this->fOpen);
    193     Assert(this->hDir != NULL);
    194 
    195220    int rc = VINF_SUCCESS;
    196     int rc2;
    197221
    198222    /* Rollback by removing any stuff created.
    199223     * Note: Only remove empty directories, never ever delete
    200224     *       anything recursive here! Steam (tm) knows best ... :-) */
     225    int rc2;
    201226    for (size_t i = 0; i < this->lstFiles.size(); i++)
    202227    {
    203228        rc2 = RTFileDelete(this->lstFiles.at(i).c_str());
     229        if (RT_SUCCESS(rc2))
     230            this->lstFiles.removeAt(i);
     231
     232        if (RT_SUCCESS(rc))
     233           rc = rc2;
     234        /* Keep going. */
     235    }
     236
     237    for (size_t i = 0; i < this->lstDirs.size(); i++)
     238    {
     239        rc2 = RTDirRemove(this->lstDirs.at(i).c_str());
     240        if (RT_SUCCESS(rc2))
     241            this->lstDirs.removeAt(i);
     242
    204243        if (RT_SUCCESS(rc))
    205244            rc = rc2;
    206     }
    207 
    208     for (size_t i = 0; i < this->lstDirs.size(); i++)
    209     {
    210         rc2 = RTDirRemove(this->lstDirs.at(i).c_str());
    211         if (RT_SUCCESS(rc))
    212             rc = rc2;
    213     }
    214 
    215     /* Try to remove the empty root dropped files directory as well. */
    216     rc2 = RTDirRemove(this->strPathAbs.c_str());
     245        /* Keep going. */
     246    }
     247
     248    if (RT_SUCCESS(rc))
     249    {
     250        Assert(this->lstFiles.isEmpty());
     251        Assert(this->lstDirs.isEmpty());
     252
     253        rc2 = closeInternal();
     254        if (RT_SUCCESS(rc2))
     255        {
     256            /* Try to remove the empty root dropped files directory as well.
     257             * Might return VERR_DIR_NOT_EMPTY or similar. */
     258            rc2 = RTDirRemove(this->strPathAbs.c_str());
     259        }
     260    }
     261
    217262    if (RT_SUCCESS(rc))
    218263        rc = rc2;
    219264
    220     return rc;
    221 }
    222 
     265    LogFlowFuncLeaveRC(rc);
     266    return rc;
     267}
     268
  • trunk/src/VBox/GuestHost/DragAndDrop/DnDURIList.cpp

    r58069 r58212  
    284284        RTPathChangeToUnixSlashes(pszPathNative, true /* fForce */);
    285285
    286         char *pszPathURI = RTUriCreate("file" /* pszScheme */, "/" /* pszAuthority */,
     286        char *pszPathURI = RTUriCreate("file" /* pszScheme */, NULL /* pszAuthority */,
    287287                                       pszPathNative, NULL /* pszQuery */, NULL /* pszFragment */);
    288288        if (pszPathURI)
     
    486486
    487487RTCString DnDURIList::RootToString(const RTCString &strPathBase /* = "" */,
    488                                    const RTCString &strSeparator /* = "\r\n" */)
     488                                   const RTCString &strSeparator /* = "\r\n" */) const
    489489{
    490490    RTCString strRet;
     
    504504                {
    505505                    strRet += RTCString(pszPathURI) + strSeparator;
    506                     LogFlowFunc(("URI: %s\n", strRet.c_str()));
     506                    LogFlowFunc(("URI (Base): %s\n", strRet.c_str()));
    507507                    RTStrFree(pszPathURI);
    508508                }
  • trunk/src/VBox/HostServices/DragAndDrop/dndmanager.cpp

    r57372 r58212  
    8484            }
    8585
     86            case DragAndDropSvc::HOST_DND_HG_SND_DATA_HDR:
     87            {
     88                LogFlowFunc(("HOST_DND_HG_SND_DATA_HDR\n"));
     89                break;
     90            }
     91
    8692            case DragAndDropSvc::HOST_DND_HG_SND_DATA:
    8793            {
     
    116122            {
    117123                LogFlowFunc(("HOST_DND_GH_REQ_PENDING\n"));
    118 
    119                 /* Verify parameter count and types. */
    120                 if (   cParms != 1
    121                     || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */)
    122                 {
    123                     rc = VERR_INVALID_PARAMETER;
    124                 }
    125124                break;
    126125            }
     
    129128            {
    130129                LogFlowFunc(("HOST_DND_GH_EVT_DROPPED\n"));
    131 
    132                 /* Verify parameter count and types. */
    133                 if (   cParms != 3
    134                     || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR   /* format */
    135                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* format size */
    136                     || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* action */)
    137                 {
    138                     rc = VERR_INVALID_PARAMETER;
    139                 }
    140130                break;
    141131            }
     
    147137        }
    148138
    149         if (!pMessage) /* Generic message needed? */
    150             pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
    151 
    152         if (fAppend)
    153             m_dndMessageQueue.append(pMessage);
    154         else
    155             m_dndMessageQueue.prepend(pMessage);
     139        if (RT_SUCCESS(rc))
     140        {
     141            if (!pMessage) /* Generic message needed? */
     142                pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
     143
     144            if (fAppend)
     145                m_dndMessageQueue.append(pMessage);
     146            else
     147                m_dndMessageQueue.prepend(pMessage);
     148        }
    156149    }
    157150    catch(std::bad_alloc &)
  • trunk/src/VBox/HostServices/DragAndDrop/service.cpp

    r57760 r58212  
    1616 */
    1717
    18 /** @page pg_svc_guest_control   Guest Control HGCM Service
     18/** @page pg_svc_guest_control   Drag and drop HGCM Service
    1919 *
    20  * This service acts as a proxy for handling and buffering host command requests
    21  * and clients on the guest. It tries to be as transparent as possible to let
    22  * the guest (client) and host side do their protocol handling as desired.
    23  *
    24  * The following terms are used:
    25  * - Host:   A host process (e.g. VBoxManage or another tool utilizing the Main API)
    26  *           which wants to control something on the guest.
    27  * - Client: A client (e.g. VBoxService) running inside the guest OS waiting for
    28  *           new host commands to perform. There can be multiple clients connected
    29  *           to a service. A client is represented by its HGCM client ID.
    30  * - Context ID: An (almost) unique ID automatically generated on the host (Main API)
    31  *               to not only distinguish clients but individual requests. Because
    32  *               the host does not know anything about connected clients it needs
    33  *               an indicator which it can refer to later. This context ID gets
    34  *               internally bound by the service to a client which actually processes
    35  *               the command in order to have a relationship between client<->context ID(s).
    36  *
    37  * The host can trigger commands which get buffered by the service (with full HGCM
    38  * parameter info). As soon as a client connects (or is ready to do some new work)
    39  * it gets a buffered host command to process it. This command then will be immediately
    40  * removed from the command list. If there are ready clients but no new commands to be
    41  * processed, these clients will be set into a deferred state (that is being blocked
    42  * to return until a new command is available).
    43  *
    44  * If a client needs to inform the host that something happened, it can send a
    45  * message to a low level HGCM callback registered in Main. This callback contains
    46  * the actual data as well as the context ID to let the host do the next necessary
    47  * steps for this context. This context ID makes it possible to wait for an event
    48  * inside the host's Main API function (like starting a process on the guest and
    49  * wait for getting its PID returned by the client) as well as cancelling blocking
    50  * host calls in order the client terminated/crashed (HGCM detects disconnected
    51  * clients and reports it to this service's callback).
     20 * TODO
    5221 */
    5322
     
    6332#include <map>
    6433
     34#include <VBox/GuestHost/DragAndDrop.h>
     35#include <VBox/HostServices/Service.h>
     36#include <VBox/HostServices/DragAndDropSvc.h>
     37
    6538#include "dndmanager.h"
    6639
     40using namespace DragAndDropSvc;
    6741
    6842/*********************************************************************************************************************************
     
    158132    {
    159133        AssertMsgFailed(("Maximum number of clients reached\n"));
    160         return VERR_BUFFER_OVERFLOW;
     134        return VERR_MAX_PROCS_REACHED;
    161135    }
    162136
     
    263237    switch (u32Function)
    264238    {
    265         case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
     239        case GUEST_DND_GET_NEXT_HOST_MSG:
    266240        {
    267241            if (modeGet() != VBOX_DRAG_AND_DROP_MODE_OFF)
     
    277251        }
    278252
    279         /* Note: New since protocol version 2. */
    280         case DragAndDropSvc::GUEST_DND_CONNECT:
     253        /* New since protocol v2. */
     254        case GUEST_DND_CONNECT:
    281255        {
    282256            /*
     
    288262            break;
    289263        }
    290         case DragAndDropSvc::GUEST_DND_HG_ACK_OP:
     264        case GUEST_DND_HG_ACK_OP:
    291265            /* Fall through is intentional. */
    292         case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
     266        case GUEST_DND_HG_REQ_DATA:
    293267            /* Fall through is intentional. */
    294         case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS:
     268        case GUEST_DND_HG_EVT_PROGRESS:
    295269        {
    296270            if (   modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
     
    304278        }
    305279
    306         case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
    307         case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
    308         case DragAndDropSvc::GUEST_DND_GH_SND_DIR:
    309         case DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR:
    310         case DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA:
    311         case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
     280        case GUEST_DND_GH_ACK_PENDING:
     281        case GUEST_DND_GH_SND_DATA_HDR:
     282        case GUEST_DND_GH_SND_DATA:
     283        case GUEST_DND_GH_SND_DIR:
     284        case GUEST_DND_GH_SND_FILE_HDR:
     285        case GUEST_DND_GH_SND_FILE_DATA:
     286        case GUEST_DND_GH_EVT_ERROR:
    312287        {
    313288#ifdef VBOX_WITH_DRAG_AND_DROP_GH
     
    347322        HGCM::Client *pClient = itClient->second;
    348323        AssertPtr(pClient);
     324
     325        LogFlowFunc(("Client %RU32: Protocol v%RU32\n", pClient->clientId(), pClient->protocol()));
     326
     327        rc = VERR_INVALID_PARAMETER; /* Play safe. */
    349328
    350329        switch (u32Function)
     
    357336             *       handle HOST_DND_GH_REQ_PENDING.
    358337             */
    359             case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
     338            case GUEST_DND_GET_NEXT_HOST_MSG:
    360339            {
    361340                LogFlowFunc(("GUEST_DND_GET_NEXT_HOST_MSG\n"));
    362                 if (   cParms != 3
    363                     || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* message */
    364                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* parameter count */
    365                     || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* blocking */)
    366                 {
    367                     rc = VERR_INVALID_PARAMETER;
    368                 }
    369                 else
     341                if (cParms == 3)
    370342                {
    371343                    rc = m_pManager->nextMessageInfo(&paParms[0].u.uint32 /* uMsg */, &paParms[1].u.uint32 /* cParms */);
     
    374346                        if (m_pfnHostCallback) /* Try asking the host. */
    375347                        {
    376                             DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSG data;
    377                             data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG;
     348                            VBOXDNDCBHGGETNEXTHOSTMSG data;
     349                            data.hdr.u32Magic = CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG;
    378350                            rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
    379351                            if (RT_SUCCESS(rc))
     
    405377                break;
    406378            }
    407             case DragAndDropSvc::GUEST_DND_CONNECT:
     379            case GUEST_DND_CONNECT:
    408380            {
    409381                LogFlowFunc(("GUEST_DND_CONNECT\n"));
    410                 if (   cParms != 2
    411                     || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* protocol version */
    412                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* additional connection flags */)
    413                     rc = VERR_INVALID_PARAMETER;
    414                 else
     382                if (cParms == 2)
    415383                {
    416384                    uint32_t uProtocol;
     
    420388                    if (RT_SUCCESS(rc))
    421389                    {
     390                        LogFlowFunc(("Client %RU32 is now using protocol v%RU32\n", pClient->clientId(), pClient->protocol()));
    422391                        /** @todo Handle connection flags (paParms[1]). */
    423392                    }
     
    428397                break;
    429398            }
    430             case DragAndDropSvc::GUEST_DND_HG_ACK_OP:
     399            case GUEST_DND_HG_ACK_OP:
    431400            {
    432401                LogFlowFunc(("GUEST_DND_HG_ACK_OP\n"));
    433                 if (   cParms != 1
    434                     || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* action */)
    435                     rc = VERR_INVALID_PARAMETER;
    436                 else
    437                 {
    438                     DragAndDropSvc::VBOXDNDCBHGACKOPDATA data;
    439                     data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_ACK_OP;
     402                if (cParms == 1)
     403                {
     404                    VBOXDNDCBHGACKOPDATA data;
     405                    data.hdr.u32Magic = CB_MAGIC_DND_HG_ACK_OP;
    440406                    rc = paParms[0].getUInt32(&data.uAction); /* Get drop action. */
    441407                    DO_HOST_CALLBACK();
     
    443409                break;
    444410            }
    445             case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
     411            case GUEST_DND_HG_REQ_DATA:
    446412            {
    447413                LogFlowFunc(("GUEST_DND_HG_REQ_DATA\n"));
    448                 if (   cParms != 1
    449                     || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* format */)
    450                     rc = VERR_INVALID_PARAMETER;
    451                 else
    452                 {
    453                     DragAndDropSvc::VBOXDNDCBHGREQDATADATA data;
    454                     data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_REQ_DATA;
     414                if (cParms == 1)
     415                {
     416                    VBOXDNDCBHGREQDATADATA data;
     417                    data.hdr.u32Magic = CB_MAGIC_DND_HG_REQ_DATA;
    455418                    rc = paParms[0].getPointer((void**)&data.pszFormat, &data.cbFormat);
    456419                    DO_HOST_CALLBACK();
     
    458421                break;
    459422            }
    460             case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS:
     423            case GUEST_DND_HG_EVT_PROGRESS:
    461424            {
    462425                LogFlowFunc(("GUEST_DND_HG_EVT_PROGRESS\n"));
    463                 if (   cParms != 3
    464                     || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* status */
    465                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* percent */
    466                     || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* rc */)
    467                     rc = VERR_INVALID_PARAMETER;
    468                 else
    469                 {
    470                     DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA data;
    471                     data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS;
     426                if (cParms == 3)
     427                {
     428                    VBOXDNDCBHGEVTPROGRESSDATA data;
     429                    data.hdr.u32Magic = CB_MAGIC_DND_HG_EVT_PROGRESS;
    472430                    rc = paParms[0].getUInt32(&data.uStatus);
    473431                    if (RT_SUCCESS(rc))
     
    480438            }
    481439#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    482             case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
     440            case GUEST_DND_GH_ACK_PENDING:
    483441            {
    484442                LogFlowFunc(("GUEST_DND_GH_ACK_PENDING\n"));
    485                 if (   cParms != 3
    486                     || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* defaction */
    487                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* alloctions */
    488                     || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR   /* format */)
    489                     rc = VERR_INVALID_PARAMETER;
    490                 else
    491                 {
    492                     DragAndDropSvc::VBOXDNDCBGHACKPENDINGDATA data;
    493                     data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_ACK_PENDING;
     443                if (cParms == 3)
     444                {
     445                    VBOXDNDCBGHACKPENDINGDATA data;
     446                    data.hdr.u32Magic = CB_MAGIC_DND_GH_ACK_PENDING;
    494447                    rc = paParms[0].getUInt32(&data.uDefAction);
    495448                    if (RT_SUCCESS(rc))
     
    501454                break;
    502455            }
    503             case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
     456            /* New since protocol v3. */
     457            case GUEST_DND_GH_SND_DATA_HDR:
     458            {
     459                LogFlowFunc(("GUEST_DND_GH_SND_DATA_HDR\n"));
     460                if (cParms == 12)
     461                {
     462                    VBOXDNDCBSNDDATAHDRDATA data;
     463                    data.hdr.u32Magic = CB_MAGIC_DND_GH_SND_DATA_HDR;
     464                    rc = paParms[0].getUInt32(&data.hdr.u32ContextID);
     465                    if (RT_SUCCESS(rc))
     466                        rc = paParms[1].getUInt32(&data.data.uFlags);
     467                    if (RT_SUCCESS(rc))
     468                        rc = paParms[2].getUInt32(&data.data.uScreenId);
     469                    if (RT_SUCCESS(rc))
     470                        rc = paParms[3].getUInt64(&data.data.cbTotal);
     471                    if (RT_SUCCESS(rc))
     472                        rc = paParms[4].getUInt32(&data.data.cbMeta);
     473                    if (RT_SUCCESS(rc))
     474                        rc = paParms[5].getPointer(&data.data.pvMetaFmt, &data.data.cbMetaFmt);
     475                    if (RT_SUCCESS(rc))
     476                        rc = paParms[6].getUInt32(&data.data.cbMetaFmt);
     477                    if (RT_SUCCESS(rc))
     478                        rc = paParms[7].getUInt64(&data.data.cObjects);
     479                    if (RT_SUCCESS(rc))
     480                        rc = paParms[8].getUInt32(&data.data.enmCompression);
     481                    if (RT_SUCCESS(rc))
     482                        rc = paParms[9].getUInt32((uint32_t *)&data.data.enmChecksumType);
     483                    if (RT_SUCCESS(rc))
     484                        rc = paParms[10].getPointer(&data.data.pvChecksum, &data.data.cbChecksum);
     485                    if (RT_SUCCESS(rc))
     486                        rc = paParms[11].getUInt32(&data.data.cbChecksum);
     487
     488                    LogFlowFunc(("fFlags=0x%x, cbTotalSize=%RU64, cObj=%RU64\n",
     489                                 data.data.uFlags, data.data.cbTotal, data.data.cObjects));
     490                    DO_HOST_CALLBACK();
     491                }
     492                break;
     493            }
     494            case GUEST_DND_GH_SND_DATA:
    504495            {
    505496                LogFlowFunc(("GUEST_DND_GH_SND_DATA\n"));
    506                 if (   cParms != 2
    507                     || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR   /* data */
    508                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
    509                     rc = VERR_INVALID_PARAMETER;
    510                 else
    511                 {
    512                     DragAndDropSvc::VBOXDNDCBSNDDATADATA data;
    513                     data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA;
    514                     rc = paParms[0].getPointer((void**)&data.pvData, &data.cbData);
    515                     if (RT_SUCCESS(rc))
    516                         rc = paParms[1].getUInt32(&data.cbTotalSize);
    517                     DO_HOST_CALLBACK();
    518                 }
    519                 break;
    520             }
    521             case DragAndDropSvc::GUEST_DND_GH_SND_DIR:
     497                switch (pClient->protocol())
     498                {
     499                    case 3:
     500                    {
     501                        if (cParms == 5)
     502                        {
     503                            VBOXDNDCBSNDDATADATA data;
     504                            data.hdr.u32Magic = CB_MAGIC_DND_GH_SND_DATA;
     505                            rc = paParms[0].getUInt32(&data.hdr.u32ContextID);
     506                            if (RT_SUCCESS(rc))
     507                                rc = paParms[1].getPointer((void**)&data.data.u.v3.pvData, &data.data.u.v3.cbData);
     508                            if (RT_SUCCESS(rc))
     509                                rc = paParms[2].getUInt32(&data.data.u.v3.cbData);
     510                            if (RT_SUCCESS(rc))
     511                                rc = paParms[3].getPointer((void**)&data.data.u.v3.pvChecksum, &data.data.u.v3.cbChecksum);
     512                            if (RT_SUCCESS(rc))
     513                                rc = paParms[4].getUInt32(&data.data.u.v3.cbChecksum);
     514                            DO_HOST_CALLBACK();
     515                        }
     516                        break;
     517                    }
     518
     519                    case 2:
     520                    default:
     521                    {
     522                        if (cParms == 2)
     523                        {
     524                            VBOXDNDCBSNDDATADATA data;
     525                            data.hdr.u32Magic = CB_MAGIC_DND_GH_SND_DATA;
     526                            rc = paParms[0].getPointer((void**)&data.data.u.v1.pvData, &data.data.u.v1.cbData);
     527                            if (RT_SUCCESS(rc))
     528                                rc = paParms[1].getUInt32(&data.data.u.v1.cbTotalSize);
     529                            DO_HOST_CALLBACK();
     530                        }
     531                        break;
     532                    }
     533                }
     534                break;
     535            }
     536            case GUEST_DND_GH_SND_DIR:
    522537            {
    523538                LogFlowFunc(("GUEST_DND_GH_SND_DIR\n"));
    524                 if (   cParms != 3
    525                     || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR   /* path */
    526                     || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* path length */
    527                     || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* creation mode */)
    528                     rc = VERR_INVALID_PARAMETER;
    529                 else
    530                 {
    531                     DragAndDropSvc::VBOXDNDCBSNDDIRDATA data;
    532                     data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_DIR;
     539                if (cParms == 3)
     540                {
     541                    VBOXDNDCBSNDDIRDATA data;
     542                    data.hdr.u32Magic = CB_MAGIC_DND_GH_SND_DIR;
    533543                    uint32_t cTmp;
    534544                    rc = paParms[0].getPointer((void**)&data.pszPath, &cTmp);
     
    543553                break;
    544554            }
    545             /* Note: Since protocol v2 (>= VBox 5.0). */
    546             case DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR:
     555            /* New since protocol v2 (>= VBox 5.0). */
     556            case GUEST_DND_GH_SND_FILE_HDR:
    547557            {
    548558                LogFlowFunc(("GUEST_DND_GH_SND_FILE_HDR\n"));
    549                 if (   cParms != 6
    550                     || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* context ID */
    551                     || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR   /* file path */
    552                     || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* file path length  */
    553                     || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* flags */
    554                     || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* file mode */
    555                     || paParms[5].type != VBOX_HGCM_SVC_PARM_64BIT /* file size */)
    556                     rc = VERR_INVALID_PARAMETER;
    557                 else
    558                 {
    559                     DragAndDropSvc::VBOXDNDCBSNDFILEHDRDATA data;
    560                     data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_HDR;
     559                if (cParms == 6)
     560                {
     561                    VBOXDNDCBSNDFILEHDRDATA data;
     562                    data.hdr.u32Magic = CB_MAGIC_DND_GH_SND_FILE_HDR;
    561563                    uint32_t cTmp;
    562564                    /* paParms[0] is context ID; unused yet. */
     
    577579                break;
    578580            }
    579             case DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA:
     581            case GUEST_DND_GH_SND_FILE_DATA:
    580582            {
    581583                LogFlowFunc(("GUEST_DND_GH_SND_FILE_DATA\n"));
     
    583585                switch (pClient->protocol())
    584586                {
    585                     case 2: /* Protocol version 2 only sends the next data chunks to reduce traffic. */
     587                    /* Protocol v3 adds (optional) checksums. */
     588                    case 3:
    586589                    {
    587                         if (   cParms != 3
    588                             /* paParms[0] is context ID; unused yet. */
    589                             || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR   /* file data */
    590                             || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* file data length */)
     590                        if (cParms == 5)
    591591                        {
    592                             rc = VERR_INVALID_PARAMETER;
     592                            VBOXDNDCBSNDFILEDATADATA data;
     593                            data.hdr.u32Magic = CB_MAGIC_DND_GH_SND_FILE_DATA;
     594                            rc = paParms[0].getUInt32(&data.hdr.u32ContextID);
     595                            if (RT_SUCCESS(rc))
     596                                rc = paParms[1].getPointer((void**)&data.pvData, &data.cbData);
     597                            if (RT_SUCCESS(rc))
     598                                rc = paParms[2].getUInt32(&data.cbData);
     599                            if (RT_SUCCESS(rc))
     600                                rc = paParms[3].getPointer((void**)&data.u.v3.pvChecksum, &data.u.v3.cbChecksum);
     601                            if (RT_SUCCESS(rc))
     602                                rc = paParms[4].getUInt32(&data.u.v3.cbChecksum);
     603
     604                            LogFlowFunc(("pvData=0x%p, cbData=%RU32\n", data.pvData, data.cbData));
     605                            DO_HOST_CALLBACK();
    593606                        }
    594                         else
     607                        break;
     608                    }
     609                    /* Protocol v2 only sends the next data chunks to reduce traffic. */
     610                    case 2:
     611                    {
     612                        if (cParms == 3)
    595613                        {
    596                             DragAndDropSvc::VBOXDNDCBSNDFILEDATADATA data;
    597                             data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_DATA;
    598                             /* paParms[0] is context ID; unused yet. */
    599                             rc = paParms[1].getPointer((void**)&data.pvData, &data.cbData);
     614                            VBOXDNDCBSNDFILEDATADATA data;
     615                            data.hdr.u32Magic = CB_MAGIC_DND_GH_SND_FILE_DATA;
     616                            rc = paParms[0].getUInt32(&data.hdr.u32ContextID);
     617                            if (RT_SUCCESS(rc))
     618                                rc = paParms[1].getPointer((void**)&data.pvData, &data.cbData);
    600619                            if (RT_SUCCESS(rc))
    601620                                rc = paParms[2].getUInt32(&data.cbData);
     
    606625                        break;
    607626                    }
     627                    /* Protocol v1 sends the file path and attributes for every file chunk (!). */
    608628                    default:
    609629                    {
    610                         if (   cParms != 5
    611                             || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR   /* file path */
    612                             || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* file path length */
    613                             || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR   /* file data */
    614                             || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* file data length */
    615                             || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* creation mode */)
     630                        if (cParms == 5)
    616631                        {
    617                             rc = VERR_INVALID_PARAMETER;
    618                         }
    619                         else
    620                         {
    621                             DragAndDropSvc::VBOXDNDCBSNDFILEDATADATA data;
    622                             data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_DATA;
     632                            VBOXDNDCBSNDFILEDATADATA data;
     633                            data.hdr.u32Magic = CB_MAGIC_DND_GH_SND_FILE_DATA;
    623634                            uint32_t cTmp;
    624635                            rc = paParms[0].getPointer((void**)&data.u.v1.pszFilePath, &cTmp);
     
    641652                break;
    642653            }
    643             case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
     654            case GUEST_DND_GH_EVT_ERROR:
    644655            {
    645656                LogFlowFunc(("GUEST_DND_GH_EVT_ERROR\n"));
    646                 if (   cParms != 1
    647                     || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* rc */)
    648                     rc = VERR_INVALID_PARAMETER;
    649                 else
    650                 {
    651                     DragAndDropSvc::VBOXDNDCBEVTERRORDATA data;
    652                     data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR;
     657                if (cParms == 1)
     658                {
     659                    VBOXDNDCBEVTERRORDATA data;
     660                    data.hdr.u32Magic = CB_MAGIC_DND_GH_EVT_ERROR;
    653661
    654662                    uint32_t rcOp;
     
    670678                    if (m_pfnHostCallback)
    671679                    {
    672                         DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSGDATA data;
    673                         data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG_DATA;
     680                        VBOXDNDCBHGGETNEXTHOSTMSGDATA data;
     681                        data.hdr.u32Magic = CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG_DATA;
    674682                        data.uMsg    = u32Function;
    675683                        data.cParms  = cParms;
     
    728736
    729737    int rc;
    730     if (u32Function == DragAndDropSvc::HOST_DND_SET_MODE)
     738    if (u32Function == HOST_DND_SET_MODE)
    731739    {
    732740        if (cParms != 1)
     
    755763                     */
    756764                    uint32_t uMsg = pClient->message();
    757                     if (uMsg == DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG)
     765                    if (uMsg == GUEST_DND_GET_NEXT_HOST_MSG)
    758766                    {
    759767                        LogFlowFunc(("Client %RU32 is waiting for next host msg\n", pClient->clientId()));
     
    822830                     uStatus, uPercentage, rc));
    823831
    824         DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA data;
    825         data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS;
     832        VBOXDNDCBHGEVTPROGRESSDATA data;
     833        data.hdr.u32Magic = CB_MAGIC_DND_HG_EVT_PROGRESS;
    826834        data.uPercentage  = RT_MIN(uPercentage, 100);
    827835        data.uStatus      = uStatus;
     
    829837
    830838        return pSelf->m_pfnHostCallback(pSelf->m_pvHostData,
    831                                         DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS,
     839                                        GUEST_DND_HG_EVT_PROGRESS,
    832840                                        &data, sizeof(data));
    833841    }
  • trunk/src/VBox/Main/include/GuestDnDPrivate.h

    r57776 r58212  
    2222#include <iprt/dir.h>
    2323#include <iprt/file.h>
    24 
    25 #include "VBox/hgcmsvc.h" /* For PVBOXHGCMSVCPARM. */
    26 #include "VBox/GuestHost/DragAndDrop.h"
     24#include <iprt/path.h>
     25
     26#include <VBox/hgcmsvc.h> /* For PVBOXHGCMSVCPARM. */
     27#include <VBox/GuestHost/DragAndDrop.h>
     28#include <VBox/HostServices/DragAndDropSvc.h>
     29
     30#ifdef LOG_GROUP
     31 #undef LOG_GROUP
     32#endif
     33#define LOG_GROUP LOG_GROUP_GUEST_DND
     34#include <VBox/log.h>
    2735
    2836/**
     
    3644class Progress;
    3745
     46/**
     47 * Type definitions.
     48 */
     49
     50/** List (vector) of MIME types. */
     51typedef std::vector<com::Utf8Str> GuestDnDMIMEList;
     52
    3853class GuestDnDCallbackEvent
    3954{
     
    6580
    6681/**
    67  * Structure for keeping the (URI) data to be sent/received.
    68  */
    69 typedef struct GuestDnDData
     82 * Class for handling the (raw) meta data.
     83 */
     84class GuestDnDMetaData
    7085{
     86public:
     87
     88    GuestDnDMetaData(void)
     89        : pvData(NULL)
     90        , cbData(0)
     91        , cbDataUsed(0) { }
     92
     93    virtual ~GuestDnDMetaData(void)
     94    {
     95        reset();
     96    }
     97
     98public:
     99
     100    size_t add(const void *pvDataAdd, size_t cbDataAdd)
     101    {
     102        if (!cbDataAdd)
     103            return 0;
     104        AssertPtrReturn(pvDataAdd, 0);
     105
     106        int rc = resize(cbData + cbDataAdd);
     107        if (RT_FAILURE(rc))
     108            return 0;
     109
     110        Assert(cbData >= cbDataUsed + cbDataAdd);
     111        memcpy((uint8_t *)pvData + cbDataUsed, pvDataAdd, cbDataAdd);
     112
     113        cbDataUsed += cbDataAdd;
     114
     115        return cbDataAdd;
     116    }
     117
     118    size_t add(const std::vector<BYTE> &vecAdd)
     119    {
     120        if (!vecAdd.size())
     121            return 0;
     122
     123        return add(&vecAdd.front(), vecAdd.size());
     124    }
     125
     126    void reset(void)
     127    {
     128        if (pvData)
     129        {
     130            Assert(cbData);
     131            RTMemFree(pvData);
     132            pvData = NULL;
     133        }
     134
     135        cbData     = 0;
     136        cbDataUsed = 0;
     137    }
     138
     139    const void *getData(void) const { return pvData; }
     140
     141    void *getDataMutable(void) { return pvData; }
     142
     143    size_t getSize(void) const { return cbDataUsed; }
     144
     145public:
     146
     147    int fromString(const RTCString &strData)
     148    {
     149        int rc = VINF_SUCCESS;
     150
     151        if (strData.isNotEmpty())
     152        {
     153            const size_t cbData = strData.length() + 1; /* Include terminating zero. */
     154            rc = resize(cbData);
     155            if (RT_SUCCESS(rc))
     156                memcpy(pvData, strData.c_str(), cbData);
     157        }
     158
     159        return rc;
     160    }
     161
     162    int fromURIList(const DnDURIList &lstURI)
     163    {
     164        return fromString(lstURI.RootToString());
     165    }
     166
     167protected:
     168
     169    int resize(size_t cbSize)
     170    {
     171        if (!cbSize)
     172        {
     173            reset();
     174            return VINF_SUCCESS;
     175        }
     176
     177        if (cbSize == cbData)
     178            return VINF_SUCCESS;
     179
     180        void *pvTmp = NULL;
     181        if (!cbData)
     182        {
     183            Assert(cbDataUsed == 0);
     184            pvTmp = RTMemAllocZ(cbSize);
     185        }
     186        else
     187        {
     188            AssertPtr(pvData);
     189            pvTmp = RTMemRealloc(pvData, cbSize);
     190            RT_BZERO(pvTmp, cbSize);
     191        }
     192
     193        if (pvTmp)
     194        {
     195            pvData = pvTmp;
     196            cbData = cbSize;
     197            return VINF_SUCCESS;
     198        }
     199
     200        return VERR_NO_MEMORY;
     201    }
     202
     203protected:
     204
     205    void   *pvData;
     206    size_t  cbData;
     207    size_t  cbDataUsed;
     208};
     209
     210/**
     211 * Class for keeping drag and drop (meta) data
     212 * to be sent/received.
     213 */
     214class GuestDnDData
     215{
     216public:
     217
    71218    GuestDnDData(void)
    72         : cbToProcess(0)
    73         , cbProcessed(0) { }
    74 
    75     void Reset(void)
    76     {
    77         vecData.clear();
    78         cbToProcess = 0;
     219        : cbProcessed(0)
     220        , cbAddData(0) { }
     221
     222    virtual ~GuestDnDData(void)
     223    {
     224        reset();
     225    }
     226
     227public:
     228
     229    uint64_t addProcessed(uint32_t cbDataAdd)
     230    {
     231        const uint64_t cbTotal = getTotal();
     232        Assert(cbProcessed + cbDataAdd <= cbTotal);
     233        cbProcessed += cbDataAdd;
     234        return cbProcessed;
     235    }
     236
     237    bool isComplete(void) const
     238    {
     239        const uint64_t cbTotal = getTotal();
     240        Assert(cbProcessed <= cbTotal);
     241        return (cbProcessed == cbTotal);
     242    }
     243
     244    void *getChkSumMutable(void) { return dataHdr.pvChecksum; }
     245
     246    uint32_t getChkSumSize(void) const { return dataHdr.cbChecksum; }
     247
     248    void *getFmtMutable(void) { return dataHdr.pvMetaFmt; }
     249
     250    uint32_t getFmtSize(void) const { return dataHdr.cbMetaFmt; }
     251
     252    GuestDnDMetaData &getMeta(void) { return dataMeta; }
     253
     254    uint8_t getPercentComplete(void) const
     255    {
     256        int64_t cbTotal  = RT_MAX(getTotal(), 1);
     257        return (uint8_t)(cbProcessed * 100 / cbTotal);
     258    }
     259
     260    uint64_t getProcessed(void) const { return cbProcessed; }
     261
     262    uint64_t getRemaining(void) const
     263    {
     264        const uint64_t cbTotal = getTotal();
     265        Assert(cbProcessed <= cbTotal);
     266        return cbTotal - cbProcessed;
     267    }
     268
     269    uint64_t getTotal(void) const { return dataMeta.getSize() + cbAddData; }
     270
     271    void reset(void)
     272    {
     273        clearFmt();
     274        clearChkSum();
     275
     276        RT_ZERO(dataHdr);
     277
     278        dataMeta.reset();
    79279        cbProcessed = 0;
    80     }
    81 
    82     /** Array (vector) of guest DnD data. This might be an URI list, according
    83      *  to the format being set. */
    84     std::vector<BYTE>         vecData;
    85     /** Overall size (in bytes) of data to send. */
    86     uint64_t                  cbToProcess;
    87     /** Overall size (in bytes) of processed file data. */
    88     uint64_t                  cbProcessed;
    89 
    90 } GuestDnDData;
     280        cbAddData   = 0;
     281    }
     282
     283    int setFmt(const void *pvFmt, uint32_t cbFmt)
     284    {
     285        if (cbFmt)
     286        {
     287            AssertPtrReturn(pvFmt, VERR_INVALID_POINTER);
     288            void *pvFmtTmp = RTMemAlloc(cbFmt);
     289            if (!pvFmtTmp)
     290                return VERR_NO_MEMORY;
     291
     292            clearFmt();
     293
     294            memcpy(pvFmtTmp, pvFmt, cbFmt);
     295
     296            dataHdr.pvMetaFmt = pvFmtTmp;
     297            dataHdr.cbMetaFmt = cbFmt;
     298        }
     299        else
     300            clearFmt();
     301
     302        return VINF_SUCCESS;
     303    }
     304
     305    void setAdditionalSize(uint64_t cbAdd)
     306    {
     307        LogFlowFunc(("cbAdd=%RU64\n", cbAdd));
     308
     309        cbAddData = cbAdd;
     310
     311        invalidate();
     312    }
     313
     314    void setEstimatedSize(uint64_t cbTotal, uint32_t cbMeta)
     315    {
     316        Assert(cbMeta <= cbTotal);
     317
     318        LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU64\n", cbTotal, cbMeta));
     319
     320        dataMeta.reset();
     321
     322        dataHdr.cbMeta = cbMeta;
     323        setAdditionalSize(cbTotal - cbMeta);
     324    }
     325
     326protected:
     327
     328    void clearChkSum(void)
     329    {
     330        if (dataHdr.pvChecksum)
     331        {
     332            Assert(dataHdr.cbChecksum);
     333            RTMemFree(dataHdr.pvChecksum);
     334            dataHdr.pvChecksum = NULL;
     335        }
     336
     337        dataHdr.cbChecksum = 0;
     338    }
     339
     340    void clearFmt(void)
     341    {
     342        if (dataHdr.pvMetaFmt)
     343        {
     344            Assert(dataHdr.cbMetaFmt);
     345            RTMemFree(dataHdr.pvMetaFmt);
     346            dataHdr.pvMetaFmt = NULL;
     347        }
     348
     349        dataHdr.cbMetaFmt = 0;
     350    }
     351
     352    void invalidate(void)
     353    {
     354        /* Update data header. */
     355        dataHdr.cbMeta  = dataMeta.getSize();
     356        dataHdr.cbTotal = dataHdr.cbMeta + cbAddData;
     357
     358        LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU32\n", dataHdr.cbTotal, dataHdr.cbMeta));
     359    }
     360
     361protected:
     362
     363    /** The data header. */
     364    VBOXDNDDATAHDR    dataHdr;
     365    /** For storing the actual meta data.
     366     *  This might be an URI list or just plain raw data,
     367     *  according to the format being sent. */
     368    GuestDnDMetaData  dataMeta;
     369    /** Overall size (in bytes) of processed data. */
     370    uint64_t          cbProcessed;
     371    /** Additional data to process which does not count
     372     *  as meta data. Just in here for accounting reasons. */
     373    uint64_t          cbAddData;
     374};
    91375
    92376/**
    93  * Structure for keeping an URI object's context around.
    94  */
    95 typedef struct GuestDnDURIObjCtx
     377 * Structure for keeping a DnDURIObject context around.
     378 */
     379class GuestDnDURIObjCtx
    96380{
     381public:
     382
    97383    GuestDnDURIObjCtx(void)
    98384        : pObjURI(NULL)
    99         , fAllocated(false)
     385        , fIntermediate(false)
    100386        , fHeaderSent(false) { }
    101387
    102388    virtual ~GuestDnDURIObjCtx(void)
    103389    {
    104         Reset();
    105     }
    106 
    107 public:
    108 
    109     void Reset(void)
     390        destroy();
     391    }
     392
     393public:
     394
     395    DnDURIObject *createIntermediate(void)
     396    {
     397        reset();
     398
     399        try
     400        {
     401            pObjURI       = new DnDURIObject();
     402            fIntermediate = true;
     403        }
     404        catch (std::bad_alloc &)
     405        {
     406        }
     407
     408        return pObjURI;
     409    }
     410
     411    void destroy(void)
    110412    {
    111413        if (   pObjURI
    112             && fAllocated)
     414            && fIntermediate)
    113415        {
    114416            delete pObjURI;
    115         }
    116 
    117         pObjURI     = NULL;
    118 
    119         fAllocated  = false;
    120         fHeaderSent = false;
    121     }
    122 
     417            fIntermediate = false;
     418        }
     419
     420        pObjURI = NULL;
     421    }
     422
     423    bool isIntermediate(void) { return fIntermediate; }
     424
     425    bool isValid(void) const { return (pObjURI != NULL); }
     426
     427    void reset(void)
     428    {
     429        destroy();
     430
     431        fIntermediate = false;
     432        fHeaderSent   = false;
     433    }
    123434
    124435    /** Pointer to current object being handled. */
    125436    DnDURIObject             *pObjURI;
    126437    /** Flag whether pObjURI needs deletion after use. */
    127     bool                      fAllocated;
     438    bool                      fIntermediate;
    128439    /** Flag whether the object's file header has been sent already. */
    129440    bool                      fHeaderSent;
    130441    /** @todo Add more statistics / information here. */
    131 
    132 } GuestDnDURIObjCtx;
     442};
    133443
    134444/**
    135  * Structure for keeping around URI (list) data.
    136  */
    137 typedef struct GuestDnDURIData
     445 * Structure for keeping around an URI (data) transfer.
     446 */
     447class GuestDnDURIData
    138448{
     449
     450public:
     451
    139452    GuestDnDURIData(void)
    140         : pvScratchBuf(NULL)
     453        : cObjToProcess(0)
     454        , cObjProcessed(0)
     455        , pvScratchBuf(NULL)
    141456        , cbScratchBuf(0) { }
    142457
    143458    virtual ~GuestDnDURIData(void)
    144459    {
    145         Reset();
    146     }
    147 
    148     int Init(size_t cbBuf = _64K)
    149     {
    150         Reset();
     460        reset();
     461
     462        if (pvScratchBuf)
     463        {
     464            Assert(cbScratchBuf);
     465            RTMemFree(pvScratchBuf);
     466            pvScratchBuf = NULL;
     467        }
     468        cbScratchBuf = 0;
     469    }
     470
     471    DnDDroppedFiles &getDroppedFiles(void) { return droppedFiles; }
     472
     473    DnDURIList &getURIList(void) { return lstURI; }
     474
     475    int init(size_t cbBuf = _64K)
     476    {
     477        reset();
    151478
    152479        pvScratchBuf = RTMemAlloc(cbBuf);
     
    158485    }
    159486
    160     const void *GetBuffer(void) const { return pvScratchBuf; }
    161 
    162     void *GetBufferMutable(void) { return pvScratchBuf; }
    163 
    164     size_t GetBufferSize(void) const { return cbScratchBuf; }
    165 
    166     void Reset(void)
    167     {
     487    bool isComplete(void) const
     488    {
     489        LogFlowFunc(("cObjToProcess=%RU64, cObjProcessed=%RU64\n", cObjToProcess, cObjProcessed));
     490        Assert(cObjProcessed <= cObjToProcess);
     491        return (cObjProcessed == cObjToProcess);
     492    }
     493
     494    const void *getBuffer(void) const { return pvScratchBuf; }
     495
     496    void *getBufferMutable(void) { return pvScratchBuf; }
     497
     498    size_t getBufferSize(void) const { return cbScratchBuf; }
     499
     500    GuestDnDURIObjCtx &getObj(uint64_t uID = 0)
     501    {
     502        AssertMsg(uID == 0, ("Other objects than object 0 is not supported yet\n"));
     503        return objCtx;
     504    }
     505
     506    GuestDnDURIObjCtx &getObjCurrent(void)
     507    {
     508        DnDURIObject *pCurObj = lstURI.First();
     509        if (   !lstURI.IsEmpty()
     510            && pCurObj)
     511        {
     512            /* Point the context object to the current DnDURIObject to process. */
     513            objCtx.pObjURI = pCurObj;
     514        }
     515        else
     516            objCtx.reset();
     517
     518        return objCtx;
     519    }
     520
     521    uint64_t getObjToProcess(void) const { return cObjToProcess; }
     522
     523    uint64_t getObjProcessed(void) const { return cObjProcessed; }
     524
     525    int processObject(const DnDURIObject &Obj)
     526    {
     527        int rc;
     528
     529        /** @todo Find objct in lstURI first! */
     530        switch (Obj.GetType())
     531        {
     532            case DnDURIObject::Directory:
     533                rc = processDirectory(Obj.GetDestPath().c_str(), Obj.GetMode());
     534                break;
     535
     536            case DnDURIObject::File:
     537                rc = VINF_SUCCESS;
     538                break;
     539
     540            default:
     541                rc = VERR_NOT_IMPLEMENTED;
     542                break;
     543        }
     544
     545        if (RT_SUCCESS(rc))
     546        {
     547            if (cObjToProcess)
     548            {
     549                cObjProcessed++;
     550                Assert(cObjProcessed <= cObjToProcess);
     551            }
     552        }
     553
     554        return rc;
     555    }
     556
     557    void removeObjCurrent(void)
     558    {
     559        if (cObjToProcess)
     560        {
     561            cObjProcessed++;
     562            Assert(cObjProcessed <= cObjToProcess);
     563        }
     564
     565        lstURI.RemoveFirst();
     566        objCtx.reset();
     567    }
     568
     569    void reset(uint64_t cObjs = 0)
     570    {
     571        cObjToProcess = cObjs;
     572        cObjProcessed = 0;
     573
     574        LogFlowFunc(("cObjToProcess=%RU64\n", cObjToProcess));
     575
     576        droppedFiles.Close();
     577
    168578        lstURI.Clear();
    169         objCtx.Reset();
    170 
    171         int rc2 = droppedFiles.Rollback();
    172         AssertRC(rc2);
    173         rc2 = droppedFiles.Reset(true /* fRemoveDropDir */);
    174         AssertRC(rc2);
    175 
    176         if (pvScratchBuf)
    177         {
    178             Assert(cbScratchBuf);
    179             RTMemFree(pvScratchBuf);
    180             pvScratchBuf = NULL;
    181         }
    182         cbScratchBuf = 0;
    183     }
    184 
     579        objCtx.reset();
     580    }
     581
     582public:
     583
     584    int fromMetaData(const GuestDnDMetaData &Data)
     585    {
     586        reset();
     587
     588        size_t      cbList  = Data.getSize();
     589        const char *pszList = (const char *)Data.getData();
     590        if (   !pszList
     591            || !cbList)
     592        {
     593            return VINF_SUCCESS;
     594        }
     595
     596        RTCList<RTCString> lstURIOrg = RTCString(pszList, cbList).split("\r\n");
     597        if (lstURIOrg.isEmpty())
     598            return VINF_SUCCESS;
     599
     600        /* Note: All files to be transferred will be kept open during the entire DnD
     601         *       operation, also to keep the accounting right. */
     602        return lstURI.AppendURIPathsFromList(lstURIOrg, DNDURILIST_FLAGS_KEEP_OPEN);
     603    }
     604
     605    int toMetaData(std::vector<BYTE> &vecData)
     606    {
     607        const char *pszDroppedFilesDir = droppedFiles.GetDirAbs();
     608
     609        Utf8Str strURIs = lstURI.RootToString(RTCString(pszDroppedFilesDir));
     610        size_t cbData = strURIs.length();
     611
     612        LogFlowFunc(("%zu root URIs (%zu bytes)\n", lstURI.RootCount(), cbData));
     613
     614        int rc;
     615
     616        try
     617        {
     618            vecData.resize(cbData + 1 /* Include termination */);
     619            memcpy(&vecData.front(), strURIs.c_str(), cbData);
     620
     621            rc = VINF_SUCCESS;
     622        }
     623        catch (std::bad_alloc &)
     624        {
     625            rc = VERR_NO_MEMORY;
     626        }
     627
     628        return rc;
     629    }
     630
     631protected:
     632
     633    int processDirectory(const char *pszPath, uint32_t fMode)
     634    {
     635        /** @todo Find directory in lstURI first! */
     636        int rc;
     637
     638        const char *pszDroppedFilesDir = droppedFiles.GetDirAbs();
     639        char *pszDir = RTPathJoinA(pszDroppedFilesDir, pszPath);
     640        if (pszDir)
     641        {
     642            rc = RTDirCreateFullPath(pszDir, fMode);
     643            if (cObjToProcess)
     644            {
     645                cObjProcessed++;
     646                Assert(cObjProcessed <= cObjToProcess);
     647            }
     648
     649            RTStrFree(pszDir);
     650        }
     651        else
     652             rc = VERR_NO_MEMORY;
     653
     654        return rc;
     655    }
     656
     657protected:
     658
     659    /** Number of objects to process. */
     660    uint64_t                        cObjToProcess;
     661    /** Number of objects already processed. */
     662    uint64_t                        cObjProcessed;
    185663    /** Handles all drop files for this operation. */
    186664    DnDDroppedFiles                 droppedFiles;
     
    191669     *  only have one context at a time. */
    192670    GuestDnDURIObjCtx               objCtx;
    193 
    194 protected:
    195 
    196671    /** Pointer to an optional scratch buffer to use for
    197672     *  doing the actual chunk transfers. */
     
    199674    /** Size (in bytes) of scratch buffer. */
    200675    size_t                          cbScratchBuf;
    201 
    202 } GuestDnDURIData;
    203 
    204 /** List (vector) of MIME types. */
    205 typedef std::vector<com::Utf8Str> GuestDnDMIMEList;
     676};
    206677
    207678/**
     
    227698    GuestDnDURIData                     mURI;
    228699    /** Callback event to use. */
    229     GuestDnDCallbackEvent               mCallback;
     700    GuestDnDCallbackEvent               mCBEvent;
    230701
    231702} SENDDATACTX, *PSENDDATACTX;
     
    247718    /** Original drop format requested to receive from the guest. */
    248719    com::Utf8Str                        mFmtReq;
    249     /** Intermediate drop format to be received from the host.
     720    /** Intermediate drop format to be received from the guest.
    250721     *  Some original drop formats require a different intermediate
    251722     *  drop format:
     
    253724     *  Receiving a file link as "text/plain"  requires still to
    254725     *  receive the file from the guest as "text/uri-list" first,
    255      *  then pointing to the file path on the host in the "text/plain"
    256      *  data returned. */
     726     *  then pointing to the file path on the host with the data
     727     *  in "text/plain" format returned. */
    257728    com::Utf8Str                        mFmtRecv;
    258729    /** Desired drop action to perform on the host.
     
    266737    GuestDnDURIData                     mURI;
    267738    /** Callback event to use. */
    268     GuestDnDCallbackEvent               mCallback;
     739    GuestDnDCallbackEvent               mCBEvent;
    269740
    270741} RECVDATACTX, *PRECVDATACTX;
     
    284755
    285756    virtual ~GuestDnDMsg(void)
     757    {
     758        reset();
     759    }
     760
     761public:
     762
     763    PVBOXHGCMSVCPARM getNextParam(void)
     764    {
     765        if (cParms >= cParmsAlloc)
     766        {
     767            if (!paParms)
     768                paParms = (PVBOXHGCMSVCPARM)RTMemAlloc(4 * sizeof(VBOXHGCMSVCPARM));
     769            else
     770                paParms = (PVBOXHGCMSVCPARM)RTMemRealloc(paParms, (cParmsAlloc + 4) * sizeof(VBOXHGCMSVCPARM));
     771            if (!paParms)
     772                throw VERR_NO_MEMORY;
     773            RT_BZERO(&paParms[cParmsAlloc], 4 * sizeof(VBOXHGCMSVCPARM));
     774            cParmsAlloc += 4;
     775        }
     776
     777        return &paParms[cParms++];
     778    }
     779
     780    uint32_t getCount(void) const { return cParms; }
     781    PVBOXHGCMSVCPARM getParms(void) const { return paParms; }
     782    uint32_t getType(void) const { return uMsg; }
     783
     784    void reset(void)
    286785    {
    287786        if (paParms)
     
    299798
    300799            RTMemFree(paParms);
    301         }
    302     }
    303 
    304 public:
    305 
    306     PVBOXHGCMSVCPARM getNextParam(void)
    307     {
    308         if (cParms >= cParmsAlloc)
    309         {
    310             paParms = (PVBOXHGCMSVCPARM)RTMemRealloc(paParms, (cParmsAlloc + 4) * sizeof(VBOXHGCMSVCPARM));
    311             if (!paParms)
    312                 throw VERR_NO_MEMORY;
    313             RT_BZERO(&paParms[cParmsAlloc], 4 * sizeof(VBOXHGCMSVCPARM));
    314             cParmsAlloc += 4;
    315         }
    316 
    317         return &paParms[cParms++];
    318     }
    319 
    320     uint32_t getCount(void) const { return cParms; }
    321     PVBOXHGCMSVCPARM getParms(void) const { return paParms; }
    322     uint32_t getType(void) const { return uMsg; }
     800            paParms = NULL;
     801        }
     802
     803        uMsg = cParms = cParmsAlloc = 0;
     804    }
    323805
    324806    int setNextPointer(void *pvBuf, uint32_t cbBuf)
    325807    {
    326         AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
    327         AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
    328 
    329808        PVBOXHGCMSVCPARM pParm = getNextParam();
    330809        if (!pParm)
    331810            return VERR_NO_MEMORY;
    332811
    333         void *pvTmp = RTMemDup(pvBuf, cbBuf);
    334         if (!pvTmp)
    335         {
    336             RTMemFree(pParm);
    337             return VERR_NO_MEMORY;
     812        void *pvTmp = NULL;
     813        if (pvBuf)
     814        {
     815            Assert(cbBuf);
     816            pvTmp = RTMemDup(pvBuf, cbBuf);
     817            if (!pvTmp)
     818                return VERR_NO_MEMORY;
    338819        }
    339820
     
    350831        char *pszTemp = RTStrDup(pszString);
    351832        if (!pszTemp)
    352         {
    353             RTMemFree(pParm);
    354833            return VERR_NO_MEMORY;
    355         }
    356834
    357835        pParm->setString(pszTemp);
     
    477955    GuestDnDMIMEList      m_lstFormats;
    478956    /** Pointer to IGuest parent object. */
    479     ComObjPtr<Guest>      m_parent;
     957    ComObjPtr<Guest>      m_pParent;
    480958    /** Pointer to associated progress object. Optional. */
    481     ComObjPtr<Progress>   m_progress;
     959    ComObjPtr<Progress>   m_pProgress;
    482960    /** Callback map. */
    483961    GuestDnDCallbackMap   m_mapCallbacks;
     
    488966 * implementation. Can't be instanciated directly, only via
    489967 * the factory pattern.
     968 *
     969 ** @todo Move this into GuestDnDBase.
    490970 */
    491971class GuestDnD
     
    5241004    /** @name Public helper functions.
    5251005     * @{ */
    526     HRESULT                    adjustScreenCoordinates(ULONG uScreenId, ULONG *puX, ULONG *puY) const;
    527     int                        hostCall(uint32_t u32Function, uint32_t cParms, PVBOXHGCMSVCPARM paParms) const;
    528     GuestDnDResponse          *response(void) { return m_pResponse; }
    529     std::vector<com::Utf8Str>  defaultFormats(void) const { return m_strDefaultFormats; }
     1006    HRESULT           adjustScreenCoordinates(ULONG uScreenId, ULONG *puX, ULONG *puY) const;
     1007    int               hostCall(uint32_t u32Function, uint32_t cParms, PVBOXHGCMSVCPARM paParms) const;
     1008    GuestDnDResponse *response(void) { return m_pResponse; }
     1009    GuestDnDMIMEList  defaultFormats(void) const { return m_strDefaultFormats; }
    5301010    /** @}  */
    5311011
     
    5551035     * @{ */
    5561036    /** List of supported default MIME/Content-type formats. */
    557     std::vector<com::Utf8Str>  m_strDefaultFormats;
     1037    GuestDnDMIMEList           m_strDefaultFormats;
    5581038    /** Pointer to guest implementation. */
    5591039    const ComObjPtr<Guest>     m_pGuest;
     
    6101090
    6111091    int sendCancel(void);
    612     int waitForEvent(RTMSINTERVAL msTimeout, GuestDnDCallbackEvent &Event, GuestDnDResponse *pResp);
     1092    int updateProgress(GuestDnDData *pData, GuestDnDResponse *pResp, uint32_t cbDataAdd = 0);
     1093    int waitForEvent(GuestDnDCallbackEvent *pEvent, GuestDnDResponse *pResp, RTMSINTERVAL msTimeout);
    6131094
    6141095protected:
     
    6241105    /** @}  */
    6251106
     1107    /**
     1108     * Internal stuff.
     1109     */
    6261110    struct
    6271111    {
    628         /** Flag indicating whether a drop operation currently
    629          *  is in progress or not. */
    630         bool                        mfTransferIsPending;
     1112        /** Number of active transfers (guest->host or host->guest). */
     1113        uint32_t                    m_cTransfersPending;
    6311114        /** The DnD protocol version to use, depending on the
    632          *  installed Guest Additions. */
    633         uint32_t                    mProtocolVersion;
    634         /** Outgoing message queue. */
    635         GuestDnDMsgList             mListOutgoing;
     1115         *  installed Guest Additions. See DragAndDropSvc.h for
     1116         *  a protocol changelog. */
     1117        uint32_t                    m_uProtocolVersion;
     1118        /** Outgoing message queue (FIFO). */
     1119        GuestDnDMsgList             m_lstMsgOut;
    6361120    } mDataBase;
    6371121};
  • trunk/src/VBox/Main/include/GuestDnDSourceImpl.h

    r57500 r58212  
    1818#ifndef ____H_GUESTDNDSOURCEIMPL
    1919#define ____H_GUESTDNDSOURCEIMPL
     20
     21#include <VBox/GuestHost/DragAndDrop.h>
     22#include <VBox/HostServices/DragAndDropSvc.h>
     23
     24using namespace DragAndDropSvc;
    2025
    2126#include "GuestDnDSourceWrap.h"
     
    6570    /** @name Dispatch handlers for the HGCM callbacks.
    6671     * @{ */
    67     int i_onReceiveData(PRECVDATACTX pCtx, const void *pvData, uint32_t cbData, uint64_t cbTotalSize);
     72    int i_onReceiveDataHdr(PRECVDATACTX pCtx, PVBOXDNDSNDDATAHDR pDataHdr);
     73    int i_onReceiveData(PRECVDATACTX pCtx, PVBOXDNDSNDDATA pSndData);
    6874    int i_onReceiveDir(PRECVDATACTX pCtx, const char *pszPath, uint32_t cbPath, uint32_t fMode);
    69     int i_onReceiveFileHdr(PRECVDATACTX pCtx, GuestDnDURIObjCtx *pObjCtx, const char *pszPath, uint32_t cbPath, uint64_t cbSize, uint32_t fMode, uint32_t fFlags);
    70     int i_onReceiveFileData(PRECVDATACTX pCtx, GuestDnDURIObjCtx *pObjCtx, const void *pvData, uint32_t cbData);
     75    int i_onReceiveFileHdr(PRECVDATACTX pCtx, const char *pszPath, uint32_t cbPath, uint64_t cbSize, uint32_t fMode, uint32_t fFlags);
     76    int i_onReceiveFileData(PRECVDATACTX pCtx,const void *pvData, uint32_t cbData);
    7177    /** @}  */
    7278#endif
     
    9399    int i_receiveRawData(PRECVDATACTX pCtx, RTMSINTERVAL msTimeout);
    94100    int i_receiveURIData(PRECVDATACTX pCtx, RTMSINTERVAL msTimeout);
    95     int i_updateProcess(PRECVDATACTX pCtx, uint64_t cbDataAdd);
    96101
    97102protected:
     
    101106        /** Maximum data block size (in bytes) the source can handle. */
    102107        uint32_t    mcbBlockSize;
    103         /** The context for receiving data from the guest. */
     108        /** The context for receiving data from the guest.
     109         *  At the moment only one transfer at a time is supported. */
    104110        RECVDATACTX mRecvCtx;
    105111    } mData;
  • trunk/src/VBox/Main/include/GuestDnDTargetImpl.h

    r57500 r58212  
    8585    int i_cancelOperation(void);
    8686    int i_sendData(PSENDDATACTX pCtx, RTMSINTERVAL msTimeout);
     87    int i_sendDataBody(PSENDDATACTX pCtx, GuestDnDData *pData);
     88    int i_sendDataHeader(PSENDDATACTX pCtx, GuestDnDData *pData, GuestDnDURIData *pURIData /* = NULL */);
    8789    int i_sendDirectory(PSENDDATACTX pCtx, GuestDnDURIObjCtx *pObjCtx, GuestDnDMsg *pMsg);
    8890    int i_sendFile(PSENDDATACTX pCtx, GuestDnDURIObjCtx *pObjCtx, GuestDnDMsg *pMsg);
    8991    int i_sendFileData(PSENDDATACTX pCtx, GuestDnDURIObjCtx *pObjCtx, GuestDnDMsg *pMsg);
     92    int i_sendRawData(PSENDDATACTX pCtx, RTMSINTERVAL msTimeout);
    9093    int i_sendURIData(PSENDDATACTX pCtx, RTMSINTERVAL msTimeout);
    91     int i_sendRawData(PSENDDATACTX pCtx, RTMSINTERVAL msTimeout);
    9294    int i_sendURIDataLoop(PSENDDATACTX pCtx, GuestDnDMsg *pMsg);
    9395
  • trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp

    r57500 r58212  
    194194    , m_defAction(0)
    195195    , m_allActions(0)
    196     , m_parent(pGuest)
     196    , m_pParent(pGuest)
    197197{
    198198    int rc = RTSemEventCreate(&m_EventSem);
     
    226226HRESULT GuestDnDResponse::resetProgress(const ComObjPtr<Guest>& pParent)
    227227{
    228     m_progress.setNull();
    229 
    230     HRESULT hr = m_progress.createObject();
     228    m_pProgress.setNull();
     229
     230    HRESULT hr = m_pProgress.createObject();
    231231    if (SUCCEEDED(hr))
    232232    {
    233         hr = m_progress->init(static_cast<IGuest *>(pParent),
    234                               Bstr(pParent->tr("Dropping data")).raw(),
    235                               TRUE /* aCancelable */);
     233        hr = m_pProgress->init(static_cast<IGuest *>(pParent),
     234                               Bstr(pParent->tr("Dropping data")).raw(),
     235                               TRUE /* aCancelable */);
    236236    }
    237237
     
    242242{
    243243    BOOL fCanceled;
    244     if (!m_progress.isNull())
    245     {
    246         HRESULT hr = m_progress->COMGETTER(Canceled)(&fCanceled);
     244    if (!m_pProgress.isNull())
     245    {
     246        HRESULT hr = m_pProgress->COMGETTER(Canceled)(&fCanceled);
    247247        AssertComRC(hr);
    248248    }
     
    285285
    286286    int rc = VINF_SUCCESS;
    287     if (!m_progress.isNull())
     287    if (!m_pProgress.isNull())
    288288    {
    289289        BOOL fCompleted;
    290         HRESULT hr = m_progress->COMGETTER(Completed)(&fCompleted);
     290        HRESULT hr = m_pProgress->COMGETTER(Completed)(&fCompleted);
    291291        AssertComRC(hr);
    292292
    293293        BOOL fCanceled;
    294         hr = m_progress->COMGETTER(Canceled)(&fCanceled);
     294        hr = m_pProgress->COMGETTER(Canceled)(&fCanceled);
    295295        AssertComRC(hr);
    296296
     
    303303                case DragAndDropSvc::DND_PROGRESS_ERROR:
    304304                {
    305                     hr = m_progress->i_notifyComplete(VBOX_E_IPRT_ERROR,
    306                                                       COM_IIDOF(IGuest),
    307                                                       m_parent->getComponentName(), strMsg.c_str());
     305                    hr = m_pProgress->i_notifyComplete(VBOX_E_IPRT_ERROR,
     306                                                       COM_IIDOF(IGuest),
     307                                                       m_pParent->getComponentName(), strMsg.c_str());
    308308                    reset();
    309309                    break;
     
    312312                case DragAndDropSvc::DND_PROGRESS_CANCELLED:
    313313                {
    314                     hr = m_progress->i_notifyComplete(S_OK);
     314                    hr = m_pProgress->i_notifyComplete(S_OK);
    315315                    AssertComRC(hr);
    316316
     
    324324                    if (!fCanceled)
    325325                    {
    326                         hr = m_progress->SetCurrentOperationProgress(uPercentage);
     326                        hr = m_pProgress->SetCurrentOperationProgress(uPercentage);
    327327                        AssertComRC(hr);
    328328                        if (   uStatus     == DragAndDropSvc::DND_PROGRESS_COMPLETE
    329329                            || uPercentage >= 100)
    330330                        {
    331                             hr = m_progress->i_notifyComplete(S_OK);
     331                            hr = m_pProgress->i_notifyComplete(S_OK);
    332332                            AssertComRC(hr);
    333333                        }
     
    341341        }
    342342
    343         hr = m_progress->COMGETTER(Completed)(&fCompleted);
     343        hr = m_pProgress->COMGETTER(Completed)(&fCompleted);
    344344        AssertComRC(hr);
    345         hr = m_progress->COMGETTER(Canceled)(&fCanceled);
     345        hr = m_pProgress->COMGETTER(Canceled)(&fCanceled);
    346346        AssertComRC(hr);
    347347
     
    382382
    383383            if (   pCBData->cbFormat == 0
    384                 || pCBData->cbFormat > _64K)
     384                || pCBData->cbFormat > _64K) /** @todo Make this configurable? */
    385385            {
    386386                rc = VERR_INVALID_PARAMETER;
     
    470470HRESULT GuestDnDResponse::queryProgressTo(IProgress **ppProgress)
    471471{
    472     return m_progress.queryInterfaceTo(ppProgress);
     472    return m_pProgress.queryInterfaceTo(ppProgress);
    473473}
    474474
     
    738738GuestDnDBase::GuestDnDBase(void)
    739739{
    740     mDataBase.mfTransferIsPending = false;
    741 
    742     /*
    743      * Initialize public attributes.
    744      */
     740    /* Initialize public attributes. */
    745741    m_lstFmtSupported = GuestDnDInst()->defaultFormats();
     742
     743    /* Initialzie private stuff. */
     744    mDataBase.m_cTransfersPending = 0;
    746745}
    747746
     
    796795}
    797796
    798 int GuestDnDBase::getProtocolVersion(uint32_t *puVersion)
    799 {
    800     AssertPtrReturn(puVersion, VERR_INVALID_POINTER);
     797int GuestDnDBase::getProtocolVersion(uint32_t *puProto)
     798{
     799    AssertPtrReturn(puProto, VERR_INVALID_POINTER);
    801800
    802801    int rc;
    803802
    804     uint32_t uVer, uVerAdditions = 0;
     803    uint32_t uProto        = 1; /* Use protocol v1 as a fallback. */
     804    uint32_t uVerAdditions = 0;
    805805    if (   m_pGuest
    806806        && (uVerAdditions = m_pGuest->i_getAdditionsVersion()) > 0)
    807807    {
    808         uint32_t uVBoxMajor = VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions);
    809         uint32_t uVBoxMinor = VBOX_FULL_VERSION_GET_MINOR(uVerAdditions);
    810 
    811 #if 0 /*def DEBUG_andy*/
     808#if 1
    812809        /* Hardcode the to-used protocol version; nice for testing side effects. */
    813         uVer = 2;
     810        uProto = 3;
    814811#else
    815         uVer = (  uVBoxMajor  >= 5)
    816              ? 2  /* VBox 5.0 and up: Protocol version 2. */
    817              : 1; /* VBox <= 4.3:     Protocol version 1. */
    818         /* Build revision is ignored. */
     812        if (uVerAdditions >= VBOX_FULL_VERSION_MAKE(5, 0, 0))
     813        {
     814            if (uVerAdditions >= VBOX_FULL_VERSION_MAKE(5, 0, 8))
     815            {
     816                uProto = 3; /* Since VBox 5.0.8: Protocol v3. */
     817            }
     818            else
     819                uProto = 2; /* VBox 5.0.0 - 5.0.6: Protocol v2. */
     820        }
    819821#endif
    820 
    821         LogFlowThisFunc(("uVerAdditions=%RU32 (%RU32.%RU32)\n", uVerAdditions, uVBoxMajor, uVBoxMinor));
     822        LogRel3(("DnD: uVerAdditions=%RU32 (%RU32.%RU32.%RU32)\n",
     823                 uVerAdditions, VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions), VBOX_FULL_VERSION_GET_MINOR(uVerAdditions),
     824                                VBOX_FULL_VERSION_GET_BUILD(uVerAdditions)));
    822825        rc = VINF_SUCCESS;
    823826    }
    824827    else
    825828    {
    826         uVer = 1; /* Fallback. */
     829        uProto = 1; /* Fallback. */
    827830        rc = VERR_NOT_FOUND;
    828831    }
    829832
    830     LogFlowThisFunc(("uVer=%RU32, uVerAdditions=%RU32, rc=%Rrc\n", uVer, uVerAdditions, rc));
    831 
    832     *puVersion = uVer;
     833    LogRel3(("DnD: uProto=%RU32, rc=%Rrc\n", uProto, rc));
     834
     835    *puProto = uProto;
    833836    return rc;
    834837}
     
    836839int GuestDnDBase::msgQueueAdd(GuestDnDMsg *pMsg)
    837840{
    838     mDataBase.mListOutgoing.push_back(pMsg);
     841    mDataBase.m_lstMsgOut.push_back(pMsg);
    839842    return VINF_SUCCESS;
    840843}
     
    842845GuestDnDMsg *GuestDnDBase::msgQueueGetNext(void)
    843846{
    844     if (mDataBase.mListOutgoing.empty())
     847    if (mDataBase.m_lstMsgOut.empty())
    845848        return NULL;
    846     return mDataBase.mListOutgoing.front();
     849    return mDataBase.m_lstMsgOut.front();
    847850}
    848851
    849852void GuestDnDBase::msgQueueRemoveNext(void)
    850853{
    851     if (!mDataBase.mListOutgoing.empty())
    852     {
    853         GuestDnDMsg *pMsg = mDataBase.mListOutgoing.front();
     854    if (!mDataBase.m_lstMsgOut.empty())
     855    {
     856        GuestDnDMsg *pMsg = mDataBase.m_lstMsgOut.front();
    854857        if (pMsg)
    855858            delete pMsg;
    856         mDataBase.mListOutgoing.pop_front();
     859        mDataBase.m_lstMsgOut.pop_front();
    857860    }
    858861}
     
    860863void GuestDnDBase::msgQueueClear(void)
    861864{
    862     GuestDnDMsgList::iterator itMsg = mDataBase.mListOutgoing.begin();
    863     while (itMsg != mDataBase.mListOutgoing.end())
    864     {
    865         delete *itMsg;
    866     }
    867 
    868     mDataBase.mListOutgoing.clear();
     865    LogFlowFunc(("cMsg=%zu\n", mDataBase.m_lstMsgOut.size()));
     866
     867    GuestDnDMsgList::iterator itMsg = mDataBase.m_lstMsgOut.begin();
     868    while (itMsg != mDataBase.m_lstMsgOut.end())
     869    {
     870        GuestDnDMsg *pMsg = *itMsg;
     871        if (pMsg)
     872            delete pMsg;
     873
     874        itMsg++;
     875    }
     876
     877    mDataBase.m_lstMsgOut.clear();
    869878}
    870879
     
    888897}
    889898
     899int GuestDnDBase::updateProgress(GuestDnDData *pData, GuestDnDResponse *pResp,
     900                                 uint32_t cbDataAdd /* = 0 */)
     901{
     902    AssertPtrReturn(pData, VERR_INVALID_POINTER);
     903    AssertPtrReturn(pResp, VERR_INVALID_POINTER);
     904    /* cbDataAdd is optional. */
     905
     906    LogFlowFunc(("cbTotal=%RU64, cbProcessed=%RU64, cbRemaining=%RU64, cbDataAdd=%RU32\n",
     907                 pData->getProcessed(), pData->getProcessed(), pData->getRemaining(), cbDataAdd));
     908
     909    if (!pResp)
     910        return VINF_SUCCESS;
     911
     912    if (cbDataAdd)
     913        pData->addProcessed(cbDataAdd);
     914
     915    int rc = pResp->setProgress(pData->getPercentComplete(),
     916                                  pData->isComplete()
     917                                ? DND_PROGRESS_COMPLETE
     918                                : DND_PROGRESS_RUNNING);
     919    LogFlowFuncLeaveRC(rc);
     920    return rc;
     921}
     922
    890923/** @todo GuestDnDResponse *pResp needs to go. */
    891 int GuestDnDBase::waitForEvent(RTMSINTERVAL msTimeout, GuestDnDCallbackEvent &Event, GuestDnDResponse *pResp)
    892 {
     924int GuestDnDBase::waitForEvent(GuestDnDCallbackEvent *pEvent, GuestDnDResponse *pResp, RTMSINTERVAL msTimeout)
     925{
     926    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
     927    AssertPtrReturn(pResp, VERR_INVALID_POINTER);
     928
    893929    int rc;
    894930
     
    901937         * respond, do busy waiting here.
    902938         */
    903         rc = Event.Wait(500 /* ms */);
     939        rc = pEvent->Wait(500 /* ms */);
    904940        if (RT_SUCCESS(rc))
    905941        {
    906             rc = Event.Result();
     942            rc = pEvent->Result();
    907943            LogFlowFunc(("Callback done, result is %Rrc\n", rc));
    908944            break;
  • trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp

    r57776 r58212  
    3737
    3838#include <VBox/com/array.h>
    39 #include <VBox/GuestHost/DragAndDrop.h>
    40 #include <VBox/HostServices/DragAndDropSvc.h>
    4139
    4240#ifdef LOG_GROUP
     
    246244
    247245    /* Determine guest DnD protocol to use. */
    248     GuestDnDBase::getProtocolVersion(&mDataBase.mProtocolVersion);
     246    GuestDnDBase::getProtocolVersion(&mDataBase.m_uProtocolVersion);
    249247
    250248    /* Default is ignoring the action. */
     
    254252
    255253    GuestDnDMsg Msg;
    256     Msg.setType(DragAndDropSvc::HOST_DND_GH_REQ_PENDING);
     254    Msg.setType(HOST_DND_GH_REQ_PENDING);
    257255    Msg.setNextUInt32(uScreenId);
    258256
     
    333331        return S_OK;
    334332
    335     /* Note: At the moment we only support one transfer at a time. */
    336     if (ASMAtomicReadBool(&mDataBase.mfTransferIsPending))
     333    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     334
     335    /* At the moment we only support one transfer at a time. */
     336    if (mDataBase.m_cTransfersPending)
    337337        return setError(E_INVALIDARG, tr("Another drop operation already is in progress"));
    338 
    339     /* Gets reset when the thread is finished. */
    340     ASMAtomicWriteBool(&mDataBase.mfTransferIsPending, true);
    341338
    342339    /* Dito. */
     
    363360        LogFlowFunc(("Starting thread ...\n"));
    364361
    365         int rc = RTThreadCreate(NULL, GuestDnDSource::i_receiveDataThread,
     362        RTTHREAD threadRcv;
     363        int rc = RTThreadCreate(&threadRcv, GuestDnDSource::i_receiveDataThread,
    366364                                (void *)pTask, 0, RTTHREADTYPE_MAIN_WORKER, 0, "dndSrcRcvData");
    367365        if (RT_SUCCESS(rc))
    368366        {
    369             hr = pResp->queryProgressTo(aProgress.asOutParam());
    370             ComAssertComRC(hr);
    371 
    372             /* Note: pTask is now owned by the worker thread. */
     367            rc = RTThreadUserWait(threadRcv, 30 * 1000 /* 30s timeout */);
     368            if (RT_SUCCESS(rc))
     369            {
     370                mDataBase.m_cTransfersPending++;
     371
     372                hr = pResp->queryProgressTo(aProgress.asOutParam());
     373                ComAssertComRC(hr);
     374
     375                /* Note: pTask is now owned by the worker thread. */
     376            }
     377            else
     378                hr = setError(VBOX_E_IPRT_ERROR, tr("Waiting for receiving thread failed (%Rrc)"), rc);
    373379        }
    374380        else
    375381            hr = setError(VBOX_E_IPRT_ERROR, tr("Starting thread failed (%Rrc)"), rc);
     382
     383        if (FAILED(hr))
     384            delete pTask;
    376385    }
    377386    catch(std::bad_alloc &)
     
    379388        hr = setError(E_OUTOFMEMORY);
    380389    }
    381 
    382     /* Note: mDataBase.mfTransferIsPending will be set to false again by i_receiveDataThread. */
    383390
    384391    LogFlowFunc(("Returning hr=%Rhrc\n", hr));
     
    393400#else /* VBOX_WITH_DRAG_AND_DROP */
    394401
    395     /* Input validation. */
    396 
    397402    AutoCaller autoCaller(this);
    398403    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    399404
    400     /* Don't allow receiving the actual data until our transfer
    401      * actually is complete. */
    402     if (ASMAtomicReadBool(&mDataBase.mfTransferIsPending))
    403         return setError(E_INVALIDARG, tr("Current drop operation still in progress"));
     405    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     406
     407    /* Don't allow receiving the actual data until our transfer actually is complete. */
     408    if (mDataBase.m_cTransfersPending)
     409        return setError(E_FAIL, tr("Current drop operation still in progress"));
    404410
    405411    PRECVDATACTX pCtx = &mData.mRecvCtx;
    406412
    407     if (pCtx->mData.vecData.empty())
    408     {
     413    if (pCtx->mData.getMeta().getSize() == 0)
     414    {
     415        LogFlowFunc(("No data available, returning 0\n"));
    409416        aData.resize(0);
    410417        return S_OK;
     
    419426        if (fHasURIList)
    420427        {
    421             const char *pszDroppedFilesDir = pCtx->mURI.droppedFiles.GetDirAbs();
    422             Utf8Str strURIs = pCtx->mURI.lstURI.RootToString(RTCString(pszDroppedFilesDir));
    423             cbData = strURIs.length();
    424 
    425             LogFlowFunc(("Found %zu root URIs (%zu bytes)\n", pCtx->mURI.lstURI.RootCount(), cbData));
    426 
    427             aData.resize(cbData + 1 /* Include termination */);
    428             memcpy(&aData.front(), strURIs.c_str(), cbData);
     428            LogRel2(("DnD: Drop directory is: %s\n", pCtx->mURI.getDroppedFiles().GetDirAbs()));
     429            int rc2 = pCtx->mURI.toMetaData(aData);
     430            if (RT_FAILURE(rc2))
     431                hr = E_OUTOFMEMORY;
    429432        }
    430433        else
    431434        {
    432             cbData = pCtx->mData.vecData.size();
     435            cbData = pCtx->mData.getMeta().getSize();
    433436
    434437            /* Copy the data into a safe array of bytes. */
    435438            aData.resize(cbData);
    436             memcpy(&aData.front(), &pCtx->mData.vecData[0], cbData);
     439            memcpy(&aData.front(), pCtx->mData.getMeta().getData(), cbData);
    437440        }
    438441    }
     
    523526
    524527#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    525 int GuestDnDSource::i_onReceiveData(PRECVDATACTX pCtx, const void *pvData, uint32_t cbData, uint64_t cbTotalSize)
     528int GuestDnDSource::i_onReceiveDataHdr(PRECVDATACTX pCtx, PVBOXDNDSNDDATAHDR pDataHdr)
     529{
     530    AssertPtrReturn(pCtx,  VERR_INVALID_POINTER);
     531    AssertReturn(pDataHdr, VERR_INVALID_POINTER);
     532
     533    pCtx->mData.setEstimatedSize(pDataHdr->cbTotal, pDataHdr->cbMeta);
     534
     535    Assert(pCtx->mURI.getObjToProcess() == 0);
     536    pCtx->mURI.reset(pDataHdr->cObjects);
     537
     538    /** @todo Handle compression type. */
     539    /** @todo Handle checksum type. */
     540
     541    LogFlowFuncLeave();
     542    return VINF_SUCCESS;
     543}
     544
     545int GuestDnDSource::i_onReceiveData(PRECVDATACTX pCtx, PVBOXDNDSNDDATA pSndData)
    526546{
    527547    AssertPtrReturn(pCtx,     VERR_INVALID_POINTER);
    528     AssertPtrReturn(pvData,   VERR_INVALID_POINTER);
    529     AssertReturn(cbData,      VERR_INVALID_PARAMETER);
    530     AssertReturn(cbTotalSize, VERR_INVALID_PARAMETER);
    531 
    532     LogFlowFunc(("cbData=%RU32, cbTotalSize=%RU64\n", cbData, cbTotalSize));
     548    AssertPtrReturn(pSndData, VERR_INVALID_POINTER);
    533549
    534550    int rc = VINF_SUCCESS;
     
    536552    try
    537553    {
    538         if (   cbData > cbTotalSize
    539             || cbData > mData.mcbBlockSize)
    540         {
    541             LogFlowFunc(("Data sizes invalid: cbData=%RU32, cbTotalSize=%RU64\n", cbData, cbTotalSize));
     554        GuestDnDData     *pData = &pCtx->mData;
     555        GuestDnDURIData  *pURI  = &pCtx->mURI;
     556
     557        uint32_t cbData;
     558        void    *pvData;
     559        uint64_t cbToProcess;
     560        uint32_t cbMeta;
     561
     562        if (mDataBase.m_uProtocolVersion < 3)
     563        {
     564            cbData = pSndData->u.v1.cbData;
     565            pvData = pSndData->u.v1.pvData;
     566
     567            /* Sends the total data size to receive for every data chunk. */
     568            cbToProcess = pSndData->u.v1.cbTotalSize;
     569
     570            /* Meta data size always is cbData, meaning there cannot be an
     571             * extended data chunk transfer by sending further data. */
     572            cbMeta      = cbData;
     573        }
     574        else
     575        {
     576            cbData = pSndData->u.v3.cbData;
     577            pvData = pSndData->u.v3.pvData;
     578
     579            /* Note: Data sizes get updated in i_onReceiveDataHdr(). */
     580            cbToProcess = pData->getTotal();
     581            cbMeta      = pData->getMeta().getSize();
     582        }
     583        Assert(cbToProcess);
     584
     585        if (   cbData == 0
     586            || cbData >  cbToProcess /* Paranoia */)
     587        {
     588            LogFlowFunc(("Incoming data size invalid: cbData=%RU32, cbToProcess=%RU64\n", cbData, pData->getTotal()));
    542589            rc = VERR_INVALID_PARAMETER;
    543590        }
    544         else if (cbData < pCtx->mData.vecData.size())
    545         {
    546             AssertMsgFailed(("New size (%RU64) is smaller than current size (%zu)\n", cbTotalSize, pCtx->mData.vecData.size()));
     591        else if (cbToProcess < cbMeta)
     592        {
     593            AssertMsgFailed(("cbToProcess (%RU64) is smaller than meta size (%zu)\n", cbToProcess, cbMeta));
    547594            rc = VERR_INVALID_PARAMETER;
    548595        }
     
    550597        if (RT_SUCCESS(rc))
    551598        {
    552             pCtx->mData.vecData.insert(pCtx->mData.vecData.begin(), (BYTE *)pvData, (BYTE *)pvData + cbData);
    553 
    554             LogFlowFunc(("vecDataSize=%zu, cbData=%RU32, cbTotalSize=%RU64\n", pCtx->mData.vecData.size(), cbData, cbTotalSize));
    555 
    556             /* Data transfer complete? */
    557             Assert(cbData <= pCtx->mData.vecData.size());
    558             if (cbData == pCtx->mData.vecData.size())
     599            pData->getMeta().add(pvData, cbData);
     600            LogFlowThisFunc(("cbMetaSize=%zu, cbData=%RU32, cbMeta=%RU32, cbToProcess=%RU64\n",
     601                             pData->getMeta().getSize(), cbData, cbMeta, cbToProcess));
     602        }
     603
     604        if (RT_SUCCESS(rc))
     605        {
     606            /* (Meta) Data transfer complete? */
     607            Assert(cbMeta <= pData->getMeta().getSize());
     608            if (cbMeta == pData->getMeta().getSize())
    559609            {
    560610                bool fHasURIList = DnDMIMENeedsDropDir(pCtx->mFmtRecv.c_str(), pCtx->mFmtRecv.length());
    561                 LogFlowFunc(("fHasURIList=%RTbool, cbTotalSize=%RU32\n", fHasURIList, cbTotalSize));
     611                LogFlowThisFunc(("fHasURIList=%RTbool\n", fHasURIList));
    562612                if (fHasURIList)
    563613                {
    564614                    /* Try parsing the data as URI list. */
    565                     rc = pCtx->mURI.lstURI.RootFromURIData(&pCtx->mData.vecData[0], pCtx->mData.vecData.size(), 0 /* uFlags */);
     615                    rc = pURI->fromMetaData(pData->getMeta());
    566616                    if (RT_SUCCESS(rc))
    567617                    {
    568                         /* Reset processed bytes. */
    569                         pCtx->mData.cbProcessed = 0;
     618                        if (mDataBase.m_uProtocolVersion < 3)
     619                            pData->setEstimatedSize(cbToProcess, cbMeta);
    570620
    571621                        /*
    572                          * Assign new total size which also includes all file data to receive
    573                          * from the guest.
     622                         * Update our process with the data we already received.
     623                         * Note: The total size will consist of the meta data (in pVecData) and
     624                         *       the actual accumulated file/directory data from the guest.
    574625                         */
    575                         pCtx->mData.cbToProcess = cbTotalSize;
    576 
    577                         /* Update our process with the data we already received.
    578                          * Note: The total size will consist of the meta data (in vecData) and
    579                          *       the actual accumulated file/directory data from the guest. */
    580                         rc = i_updateProcess(pCtx, (uint64_t)pCtx->mData.vecData.size());
    581 
    582                         LogFlowFunc(("URI data => cbProcessed=%RU64, cbToProcess=%RU64, rc=%Rrc\n",
    583                                      pCtx->mData.cbProcessed, pCtx->mData.cbToProcess, rc));
     626                        rc = updateProgress(pData, pCtx->mpResp, (uint32_t)pData->getMeta().getSize());
    584627                    }
    585628                }
     
    604647    LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x\n", pszPath, cbPath, fMode));
    605648
     649    /*
     650     * Sanity checking.
     651     */
     652    if (   !cbPath
     653        || cbPath > RTPATH_MAX)
     654    {
     655        return VERR_INVALID_PARAMETER;
     656    }
     657
     658    if (!RTStrIsValidEncoding(pszPath))
     659        return VERR_INVALID_PARAMETER;
     660
     661    if (pCtx->mURI.isComplete())
     662        return VERR_INVALID_PARAMETER;
     663
     664    GuestDnDURIObjCtx objCtx = pCtx->mURI.getObj(0); /** @todo Fill in context ID. */
     665    DnDURIObject *pObj       = objCtx.createIntermediate();
     666    if (!pObj)
     667        return VERR_NO_MEMORY;
     668
    606669    int rc;
    607670
    608     const char *pszDroppedFilesDir = pCtx->mURI.droppedFiles.GetDirAbs();
     671    const char *pszDroppedFilesDir = pCtx->mURI.getDroppedFiles().GetDirAbs();
    609672    char *pszDir = RTPathJoinA(pszDroppedFilesDir, pszPath);
    610673    if (pszDir)
    611674    {
     675#ifdef RT_OS_WINDOWS
     676        RTPathChangeToDosSlashes(pszDir, true /* fForce */);
     677#else
     678        RTPathChangeToDosSlashes(pszDir, true /* fForce */);
     679#endif
    612680        rc = RTDirCreateFullPath(pszDir, fMode);
    613         if (RT_FAILURE(rc))
    614             LogRel2(("DnD: Error creating guest directory '%s' on the host, rc=%Rrc\n", pszDir, rc));
     681        if (RT_SUCCESS(rc))
     682            LogRel2(("DnD: Created guest directory on host: %s\n", pszDir));
     683        else
     684            LogRel(("DnD: Error creating guest directory '%s' on host, rc=%Rrc\n", pszDir, rc));
     685
     686        pCtx->mURI.removeObjCurrent();
    615687
    616688        RTStrFree(pszDir);
     
    623695}
    624696
    625 int GuestDnDSource::i_onReceiveFileHdr(PRECVDATACTX pCtx, GuestDnDURIObjCtx *pObjCtx, const char *pszPath, uint32_t cbPath,
     697int GuestDnDSource::i_onReceiveFileHdr(PRECVDATACTX pCtx, const char *pszPath, uint32_t cbPath,
    626698                                       uint64_t cbSize, uint32_t fMode, uint32_t fFlags)
    627699{
    628700    AssertPtrReturn(pCtx,    VERR_INVALID_POINTER);
    629     AssertPtrReturn(pObjCtx, VERR_INVALID_POINTER);
    630701    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
    631702    AssertReturn(cbPath,     VERR_INVALID_PARAMETER);
     
    635706    LogFlowFunc(("pszPath=%s, cbPath=%RU32, cbSize=%RU64, fMode=0x%x, fFlags=0x%x\n", pszPath, cbPath, cbSize, fMode, fFlags));
    636707
     708    /*
     709     * Sanity checking.
     710     */
     711    if (   !cbPath
     712        || cbPath > RTPATH_MAX)
     713    {
     714        return VERR_INVALID_PARAMETER;
     715    }
     716
     717    if (!RTStrIsValidEncoding(pszPath))
     718        return VERR_INVALID_PARAMETER;
     719
     720    if (cbSize > pCtx->mData.getTotal())
     721    {
     722        AssertMsgFailed(("File size (%RU64) exceeds total size to transfer (%RU64)\n", cbSize, pCtx->mData.getTotal()));
     723        return VERR_INVALID_PARAMETER;
     724    }
     725
     726    if (pCtx->mURI.isComplete())
     727        return VERR_INVALID_PARAMETER;
     728
    637729    int rc = VINF_SUCCESS;
    638730
    639731    do
    640732    {
    641         DnDURIObject *pObj = pObjCtx->pObjURI;
    642 
    643         if (    pObj
    644             &&  pObj->IsOpen()
    645             && !pObj->IsComplete())
    646         {
    647             AssertMsgFailed(("Object '%s' not complete yet\n", pObj->GetDestPath().c_str()));
    648             rc = VERR_WRONG_ORDER;
    649             break;
    650         }
    651 
    652         if (   pObj
    653             && pObj->IsOpen()) /* File already opened? */
    654         {
    655             AssertMsgFailed(("Current opened object is '%s', close this first\n", pObj->GetDestPath().c_str()));
    656             rc = VERR_WRONG_ORDER;
    657             break;
    658         }
    659 
    660         if (cbSize > pCtx->mData.cbToProcess)
    661         {
    662             AssertMsgFailed(("File size (%RU64) exceeds total size to transfer (%RU64)\n", cbSize, pCtx->mData.cbToProcess));
    663             rc = VERR_INVALID_PARAMETER;
    664             break;
    665         }
    666 
    667         const char *pszDroppedFilesDir = pCtx->mURI.droppedFiles.GetDirAbs();
    668 
    669         char pszPathAbs[RTPATH_MAX];
    670         rc = RTPathJoin(pszPathAbs, sizeof(pszPathAbs), pszDroppedFilesDir, pszPath);
    671         if (RT_FAILURE(rc))
    672         {
    673             LogFlowFunc(("Warning: Rebasing current file failed with rc=%Rrc\n", rc));
    674             break;
    675         }
    676 
    677         rc = DnDPathSanitize(pszPathAbs, sizeof(pszPathAbs));
    678         if (RT_FAILURE(rc))
    679         {
    680             LogFlowFunc(("Warning: Rebasing current file failed with rc=%Rrc\n", rc));
    681             break;
    682         }
    683 
    684         LogFunc(("Rebased to: %s\n", pszPathAbs));
    685 
    686         if (   pObj
    687             && pObjCtx->fAllocated)
    688         {
    689             delete pObj;
    690             pObj = NULL;
    691         }
    692 
    693         try
    694         {
    695             pObj = new DnDURIObject();
    696 
    697             pObjCtx->pObjURI    = pObj;
    698             pObjCtx->fAllocated = true;
    699         }
    700         catch (std::bad_alloc &)
    701         {
     733        GuestDnDURIObjCtx objCtx = pCtx->mURI.getObj(0); /** @todo Fill in context ID. */
     734        DnDURIObject *pObj       = objCtx.pObjURI;
     735
     736        /*
     737         * Sanity checking.
     738         */
     739        if (pObj)
     740        {
     741            if (    pObj->IsOpen()
     742                && !pObj->IsComplete())
     743            {
     744                AssertMsgFailed(("Object '%s' not complete yet\n", pObj->GetDestPath().c_str()));
     745                rc = VERR_WRONG_ORDER;
     746                break;
     747            }
     748
     749            if (pObj->IsOpen()) /* File already opened? */
     750            {
     751                AssertMsgFailed(("Current opened object is '%s', close this first\n", pObj->GetDestPath().c_str()));
     752                rc = VERR_WRONG_ORDER;
     753                break;
     754            }
     755        }
     756
     757        /*
     758         * Create new intermediate object to work with.
     759         */
     760        pObj = objCtx.createIntermediate();
     761        if (!pObj)
    702762            rc = VERR_NO_MEMORY;
    703         }
    704763
    705764        if (RT_SUCCESS(rc))
    706765        {
     766            const char *pszDroppedFilesDir = pCtx->mURI.getDroppedFiles().GetDirAbs();
     767
     768            char pszPathAbs[RTPATH_MAX];
     769            rc = RTPathJoin(pszPathAbs, sizeof(pszPathAbs), pszDroppedFilesDir, pszPath);
     770            if (RT_FAILURE(rc))
     771            {
     772                LogFlowFunc(("Warning: Rebasing current file failed with rc=%Rrc\n", rc));
     773                break;
     774            }
     775
     776            rc = DnDPathSanitize(pszPathAbs, sizeof(pszPathAbs));
     777            if (RT_FAILURE(rc))
     778            {
     779                LogFlowFunc(("Warning: Rebasing current file failed with rc=%Rrc\n", rc));
     780                break;
     781            }
     782
     783            LogFunc(("Rebased to: %s\n", pszPathAbs));
     784
    707785            /** @todo Add sparse file support based on fFlags? (Use Open(..., fFlags | SPARSE). */
    708786            rc = pObj->OpenEx(pszPathAbs, DnDURIObject::File, DnDURIObject::Target,
     
    714792        {
    715793            /* Note: Protocol v1 does not send any file sizes, so always 0. */
    716             if (mDataBase.mProtocolVersion >= 2)
     794            if (mDataBase.m_uProtocolVersion >= 2)
    717795                rc = pObj->SetSize(cbSize);
    718796
     
    740818}
    741819
    742 int GuestDnDSource::i_onReceiveFileData(PRECVDATACTX pCtx, GuestDnDURIObjCtx *pObjCtx, const void *pvData, uint32_t cbData)
     820int GuestDnDSource::i_onReceiveFileData(PRECVDATACTX pCtx, const void *pvData, uint32_t cbData)
    743821{
    744822    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    745     AssertPtrReturn(pObjCtx, VERR_INVALID_POINTER);
    746823    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
    747824    AssertReturn(cbData, VERR_INVALID_PARAMETER);
     
    749826    int rc = VINF_SUCCESS;
    750827
     828    /*
     829     * Sanity checking.
     830     */
     831    if (cbData > mData.mcbBlockSize)
     832        return VERR_INVALID_PARAMETER;
     833
    751834    do
    752835    {
    753         DnDURIObject *pObj = pObjCtx->pObjURI;
     836        GuestDnDURIObjCtx objCtx = pCtx->mURI.getObj(0); /** @todo Fill in context ID. */
     837        DnDURIObject *pObj       = objCtx.pObjURI;
     838
    754839        if (!pObj)
    755840        {
     
    784869
    785870            if (RT_SUCCESS(rc))
    786                 rc = i_updateProcess(pCtx, cbWritten);
     871                rc = updateProgress(&pCtx->mData, pCtx->mpResp, cbWritten);
    787872        }
    788873
     
    793878                /** @todo Sanitize path. */
    794879                LogRel2(("DnD: File transfer to host complete: %s\n", pObj->GetDestPath().c_str()));
     880                objCtx.reset();
     881
    795882                rc = VINF_EOF;
    796 
    797                 /* Deletion needed? */
    798                 if (pObjCtx->fAllocated)
    799                 {
    800                     delete pObj;
    801                     pObj = NULL;
    802 
    803                     pObjCtx->fAllocated = false;
    804                 }
    805883            }
    806884        }
     
    821899{
    822900    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     901
     902    /* Is this context already in receiving state? */
     903    if (ASMAtomicReadBool(&pCtx->mIsActive))
     904        return VERR_WRONG_ORDER;
     905    ASMAtomicWriteBool(&pCtx->mIsActive, true);
    823906
    824907    GuestDnD *pInst = GuestDnDInst();
     
    829912    AssertPtr(pCtx->mpResp);
    830913
    831     /* Is this context already in receiving state? */
    832     if (ASMAtomicReadBool(&pCtx->mIsActive))
    833         return VERR_WRONG_ORDER;
    834 
    835     ASMAtomicWriteBool(&pCtx->mIsActive, true);
    836 
    837     int rc = pCtx->mCallback.Reset();
     914    int rc = pCtx->mCBEvent.Reset();
    838915    if (RT_FAILURE(rc))
    839916        return rc;
     
    842919     * Reset any old data.
    843920     */
    844     pCtx->mData.Reset();
    845     pCtx->mURI.Reset();
     921    pCtx->mData.reset();
     922    pCtx->mURI.reset();
    846923    pResp->reset();
    847924
     
    901978    AssertPtrReturn(pTask, VERR_INVALID_POINTER);
    902979
    903     const ComObjPtr<GuestDnDSource> pSource(pTask->getSource());
    904     Assert(!pSource.isNull());
    905 
    906     int rc;
    907 
    908     AutoCaller autoCaller(pSource);
    909     if (SUCCEEDED(autoCaller.rc()))
    910     {
    911         rc = pSource->i_receiveData(pTask->getCtx(), RT_INDEFINITE_WAIT /* msTimeout */);
    912     }
    913     else
    914         rc = VERR_COM_INVALID_OBJECT_STATE;
    915 
    916     ASMAtomicWriteBool(&pSource->mDataBase.mfTransferIsPending, false);
     980    const ComObjPtr<GuestDnDSource> pThis(pTask->getSource());
     981    Assert(!pThis.isNull());
     982
     983    AutoCaller autoCaller(pThis);
     984    if (FAILED(autoCaller.rc())) return VERR_COM_INVALID_OBJECT_STATE;
     985
     986    int rc = RTThreadUserSignal(Thread);
     987    AssertRC(rc);
     988
     989    rc = pThis->i_receiveData(pTask->getCtx(), RT_INDEFINITE_WAIT /* msTimeout */);
    917990
    918991    if (pTask)
    919992        delete pTask;
    920993
    921     LogFlowFunc(("pSource=%p returning rc=%Rrc\n", (GuestDnDSource *)pSource, rc));
     994    AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
     995
     996    Assert(pThis->mDataBase.m_cTransfersPending);
     997    pThis->mDataBase.m_cTransfersPending--;
     998
     999    LogFlowFunc(("pSource=%p returning rc=%Rrc\n", (GuestDnDSource *)pThis, rc));
    9221000    return rc;
    9231001}
     
    9481026     * Register callbacks.
    9491027     */
    950     REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_EVT_ERROR);
    951     REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DATA);
     1028    REGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
     1029    REGISTER_CALLBACK(GUEST_DND_GH_SND_DATA);
    9521030
    9531031    do
     
    9571035         */
    9581036        GuestDnDMsg Msg;
    959         Msg.setType(DragAndDropSvc::HOST_DND_GH_EVT_DROPPED);
     1037        Msg.setType(HOST_DND_GH_EVT_DROPPED);
    9601038        Msg.setNextPointer((void*)pCtx->mFmtRecv.c_str(), (uint32_t)pCtx->mFmtRecv.length() + 1);
    9611039        Msg.setNextUInt32((uint32_t)pCtx->mFmtRecv.length() + 1);
     
    9671045        if (RT_SUCCESS(rc))
    9681046        {
    969             rc = waitForEvent(msTimeout, pCtx->mCallback, pCtx->mpResp);
     1047            rc = waitForEvent(&pCtx->mCBEvent, pCtx->mpResp, msTimeout);
    9701048            if (RT_SUCCESS(rc))
    971                 rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_COMPLETE, VINF_SUCCESS);
     1049                rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_COMPLETE, VINF_SUCCESS);
    9721050        }
    9731051
     
    9771055     * Unregister callbacks.
    9781056     */
    979     UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_EVT_ERROR);
    980     UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DATA);
     1057    UNREGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
     1058    UNREGISTER_CALLBACK(GUEST_DND_GH_SND_DATA);
    9811059
    9821060#undef REGISTER_CALLBACK
     
    9871065        if (rc == VERR_CANCELLED)
    9881066        {
    989             int rc2 = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_CANCELLED, VINF_SUCCESS);
     1067            int rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_CANCELLED, VINF_SUCCESS);
    9901068            AssertRC(rc2);
    9911069
     
    9951073        else if (rc != VERR_GSTDND_GUEST_ERROR) /* Guest-side error are already handled in the callback. */
    9961074        {
    997             rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR,
     1075            rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR,
    9981076                                           rc, GuestDnDSource::i_hostErrorToString(rc));
    9991077        }
     
    10321110     */
    10331111    /* Guest callbacks. */
    1034     REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_EVT_ERROR);
    1035     REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DATA);
    1036     REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DIR);
    1037     if (mDataBase.mProtocolVersion >= 2)
    1038         REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR);
    1039     REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA);
    1040 
    1041     DnDDroppedFiles &droppedFiles = pCtx->mURI.droppedFiles;
     1112    REGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
     1113    if (mDataBase.m_uProtocolVersion >= 3)
     1114        REGISTER_CALLBACK(GUEST_DND_GH_SND_DATA_HDR);
     1115    REGISTER_CALLBACK(GUEST_DND_GH_SND_DATA);
     1116    REGISTER_CALLBACK(GUEST_DND_GH_SND_DIR);
     1117    if (mDataBase.m_uProtocolVersion >= 2)
     1118        REGISTER_CALLBACK(GUEST_DND_GH_SND_FILE_HDR);
     1119    REGISTER_CALLBACK(GUEST_DND_GH_SND_FILE_DATA);
     1120
     1121    DnDDroppedFiles &droppedFiles = pCtx->mURI.getDroppedFiles();
    10421122
    10431123    do
     
    10541134         */
    10551135        GuestDnDMsg Msg;
    1056         Msg.setType(DragAndDropSvc::HOST_DND_GH_EVT_DROPPED);
     1136        Msg.setType(HOST_DND_GH_EVT_DROPPED);
    10571137        Msg.setNextPointer((void*)pCtx->mFmtRecv.c_str(), (uint32_t)pCtx->mFmtRecv.length() + 1);
    10581138        Msg.setNextUInt32((uint32_t)pCtx->mFmtRecv.length() + 1);
     
    10661146            LogFlowFunc(("Waiting ...\n"));
    10671147
    1068             rc = waitForEvent(msTimeout, pCtx->mCallback, pCtx->mpResp);
     1148            rc = waitForEvent(&pCtx->mCBEvent, pCtx->mpResp, msTimeout);
    10691149            if (RT_SUCCESS(rc))
    1070                 rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_COMPLETE, VINF_SUCCESS);
     1150                rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_COMPLETE, VINF_SUCCESS);
    10711151
    10721152            LogFlowFunc(("Waiting ended with rc=%Rrc\n", rc));
     
    10781158     * Unregister callbacks.
    10791159     */
    1080     UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_EVT_ERROR);
    1081     UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DATA);
    1082     UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DIR);
    1083     if (mDataBase.mProtocolVersion >= 2)
    1084         UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR);
    1085     UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA);
     1160    UNREGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
     1161    UNREGISTER_CALLBACK(GUEST_DND_GH_SND_DATA_HDR);
     1162    UNREGISTER_CALLBACK(GUEST_DND_GH_SND_DATA);
     1163    UNREGISTER_CALLBACK(GUEST_DND_GH_SND_DIR);
     1164    UNREGISTER_CALLBACK(GUEST_DND_GH_SND_FILE_HDR);
     1165    UNREGISTER_CALLBACK(GUEST_DND_GH_SND_FILE_DATA);
    10861166
    10871167#undef REGISTER_CALLBACK
     
    10941174        if (rc == VERR_CANCELLED)
    10951175        {
    1096             rc2 = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_CANCELLED, VINF_SUCCESS);
     1176            rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_CANCELLED, VINF_SUCCESS);
    10971177            AssertRC(rc2);
    10981178
     
    11021182        else if (rc != VERR_GSTDND_GUEST_ERROR) /* Guest-side error are already handled in the callback. */
    11031183        {
    1104             rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR,
     1184            rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR,
    11051185                                           rc, GuestDnDSource::i_hostErrorToString(rc));
    11061186        }
     
    11091189    if (RT_FAILURE(rc))
    11101190    {
    1111         rc2 = droppedFiles.Rollback(); /** @todo Inform user on rollback failure? */
    1112         LogFlowFunc(("Rolling back ended with rc=%Rrc\n", rc2));
    1113     }
    1114 
    1115     rc2 = droppedFiles.Reset(RT_FAILURE(rc) ? true : false /* fRemoveDropDir */);
    1116     if (RT_SUCCESS(rc))
    1117         rc = rc2;
     1191        rc2 = droppedFiles.Rollback();
     1192        if (RT_FAILURE(rc2))
     1193            LogRel2(("DnD: Rollback failed with %Rrc\n", rc2));
     1194    }
     1195
     1196    droppedFiles.Close();
    11181197
    11191198    LogFlowFuncLeaveRC(rc);
     
    11401219    {
    11411220#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    1142         case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
    1143         {
    1144             DragAndDropSvc::PVBOXDNDCBSNDDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDDATADATA>(pvParms);
     1221        case GUEST_DND_GH_SND_DATA_HDR:
     1222        {
     1223            PVBOXDNDCBSNDDATAHDRDATA pCBData = reinterpret_cast<PVBOXDNDCBSNDDATAHDRDATA>(pvParms);
    11451224            AssertPtr(pCBData);
    1146             AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDDATADATA) == cbParms, VERR_INVALID_PARAMETER);
    1147             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    1148 
    1149             rc = pThis->i_onReceiveData(pCtx, pCBData->pvData, pCBData->cbData, pCBData->cbTotalSize);
    1150             break;
    1151         }
    1152         case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
    1153         {
    1154             DragAndDropSvc::PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBEVTERRORDATA>(pvParms);
     1225            AssertReturn(sizeof(VBOXDNDCBSNDDATAHDRDATA) == cbParms, VERR_INVALID_PARAMETER);
     1226            AssertReturn(CB_MAGIC_DND_GH_SND_DATA_HDR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1227
     1228            rc = pThis->i_onReceiveDataHdr(pCtx, &pCBData->data);
     1229            break;
     1230        }
     1231        case GUEST_DND_GH_SND_DATA:
     1232        {
     1233            PVBOXDNDCBSNDDATADATA pCBData = reinterpret_cast<PVBOXDNDCBSNDDATADATA>(pvParms);
    11551234            AssertPtr(pCBData);
    1156             AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER);
    1157             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1235            AssertReturn(sizeof(VBOXDNDCBSNDDATADATA) == cbParms, VERR_INVALID_PARAMETER);
     1236            AssertReturn(CB_MAGIC_DND_GH_SND_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1237
     1238            rc = pThis->i_onReceiveData(pCtx, &pCBData->data);
     1239            break;
     1240        }
     1241        case GUEST_DND_GH_EVT_ERROR:
     1242        {
     1243            PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<PVBOXDNDCBEVTERRORDATA>(pvParms);
     1244            AssertPtr(pCBData);
     1245            AssertReturn(sizeof(VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER);
     1246            AssertReturn(CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    11581247
    11591248            pCtx->mpResp->reset();
     
    11621251                pCBData->rc = VERR_GENERAL_FAILURE; /* Make sure some error is set. */
    11631252
    1164             rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, pCBData->rc,
     1253            rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, pCBData->rc,
    11651254                                           GuestDnDSource::i_guestErrorToString(pCBData->rc));
    11661255            if (RT_SUCCESS(rc))
     
    11761265    if (RT_FAILURE(rc))
    11771266    {
    1178         int rc2 = pCtx->mCallback.Notify(rc);
     1267        int rc2 = pCtx->mCBEvent.Notify(rc);
    11791268        AssertRC(rc2);
    11801269    }
     
    12031292    {
    12041293#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    1205         case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
    1206         {
    1207             DragAndDropSvc::PVBOXDNDCBSNDDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDDATADATA>(pvParms);
     1294        case GUEST_DND_GH_SND_DATA_HDR:
     1295        {
     1296            PVBOXDNDCBSNDDATAHDRDATA pCBData = reinterpret_cast<PVBOXDNDCBSNDDATAHDRDATA>(pvParms);
    12081297            AssertPtr(pCBData);
    1209             AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDDATADATA) == cbParms, VERR_INVALID_PARAMETER);
    1210             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    1211 
    1212             rc = pThis->i_onReceiveData(pCtx, pCBData->pvData, pCBData->cbData, pCBData->cbTotalSize);
    1213             break;
    1214         }
    1215         case DragAndDropSvc::GUEST_DND_GH_SND_DIR:
    1216         {
    1217             DragAndDropSvc::PVBOXDNDCBSNDDIRDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDDIRDATA>(pvParms);
     1298            AssertReturn(sizeof(VBOXDNDCBSNDDATAHDRDATA) == cbParms, VERR_INVALID_PARAMETER);
     1299            AssertReturn(CB_MAGIC_DND_GH_SND_DATA_HDR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1300
     1301            rc = pThis->i_onReceiveDataHdr(pCtx, &pCBData->data);
     1302            break;
     1303        }
     1304        case GUEST_DND_GH_SND_DATA:
     1305        {
     1306            PVBOXDNDCBSNDDATADATA pCBData = reinterpret_cast<PVBOXDNDCBSNDDATADATA>(pvParms);
    12181307            AssertPtr(pCBData);
    1219             AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDDIRDATA) == cbParms, VERR_INVALID_PARAMETER);
    1220             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DIR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1308            AssertReturn(sizeof(VBOXDNDCBSNDDATADATA) == cbParms, VERR_INVALID_PARAMETER);
     1309            AssertReturn(CB_MAGIC_DND_GH_SND_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1310
     1311            rc = pThis->i_onReceiveData(pCtx, &pCBData->data);
     1312            break;
     1313        }
     1314        case GUEST_DND_GH_SND_DIR:
     1315        {
     1316            PVBOXDNDCBSNDDIRDATA pCBData = reinterpret_cast<PVBOXDNDCBSNDDIRDATA>(pvParms);
     1317            AssertPtr(pCBData);
     1318            AssertReturn(sizeof(VBOXDNDCBSNDDIRDATA) == cbParms, VERR_INVALID_PARAMETER);
     1319            AssertReturn(CB_MAGIC_DND_GH_SND_DIR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    12211320
    12221321            rc = pThis->i_onReceiveDir(pCtx, pCBData->pszPath, pCBData->cbPath, pCBData->fMode);
    12231322            break;
    12241323        }
    1225         case DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR:
    1226         {
    1227             DragAndDropSvc::PVBOXDNDCBSNDFILEHDRDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDFILEHDRDATA>(pvParms);
     1324        case GUEST_DND_GH_SND_FILE_HDR:
     1325        {
     1326            PVBOXDNDCBSNDFILEHDRDATA pCBData = reinterpret_cast<PVBOXDNDCBSNDFILEHDRDATA>(pvParms);
    12281327            AssertPtr(pCBData);
    1229             AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDFILEHDRDATA) == cbParms, VERR_INVALID_PARAMETER);
    1230             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_HDR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    1231 
    1232             rc = pThis->i_onReceiveFileHdr(pCtx, &pCtx->mURI.objCtx, pCBData->pszFilePath, pCBData->cbFilePath,
     1328            AssertReturn(sizeof(VBOXDNDCBSNDFILEHDRDATA) == cbParms, VERR_INVALID_PARAMETER);
     1329            AssertReturn(CB_MAGIC_DND_GH_SND_FILE_HDR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1330
     1331            rc = pThis->i_onReceiveFileHdr(pCtx, pCBData->pszFilePath, pCBData->cbFilePath,
    12331332                                           pCBData->cbSize, pCBData->fMode, pCBData->fFlags);
    12341333            break;
    12351334        }
    1236         case DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA:
    1237         {
    1238             DragAndDropSvc::PVBOXDNDCBSNDFILEDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDFILEDATADATA>(pvParms);
     1335        case GUEST_DND_GH_SND_FILE_DATA:
     1336        {
     1337            PVBOXDNDCBSNDFILEDATADATA pCBData = reinterpret_cast<PVBOXDNDCBSNDFILEDATADATA>(pvParms);
    12391338            AssertPtr(pCBData);
    1240             AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDFILEDATADATA) == cbParms, VERR_INVALID_PARAMETER);
    1241             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    1242 
    1243             if (pThis->mDataBase.mProtocolVersion <= 1)
     1339            AssertReturn(sizeof(VBOXDNDCBSNDFILEDATADATA) == cbParms, VERR_INVALID_PARAMETER);
     1340            AssertReturn(CB_MAGIC_DND_GH_SND_FILE_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1341
     1342            if (pThis->mDataBase.m_uProtocolVersion <= 1)
    12441343            {
    12451344                /**
     
    12501349                 *   appended data to the desired file. So just pass 0 as cbSize.
    12511350                 */
    1252                 rc = pThis->i_onReceiveFileHdr(pCtx, &pCtx->mURI.objCtx,
    1253                                                pCBData->u.v1.pszFilePath, pCBData->u.v1.cbFilePath,
     1351                rc = pThis->i_onReceiveFileHdr(pCtx, pCBData->u.v1.pszFilePath, pCBData->u.v1.cbFilePath,
    12541352                                               0 /* cbSize */, pCBData->u.v1.fMode, 0 /* fFlags */);
    12551353                if (RT_SUCCESS(rc))
    1256                     rc = pThis->i_onReceiveFileData(pCtx, &pCtx->mURI.objCtx, pCBData->pvData, pCBData->cbData);
     1354                    rc = pThis->i_onReceiveFileData(pCtx, pCBData->pvData, pCBData->cbData);
    12571355            }
    12581356            else /* Protocol v2 and up. */
    1259                 rc = pThis->i_onReceiveFileData(pCtx, &pCtx->mURI.objCtx, pCBData->pvData, pCBData->cbData);
    1260             break;
    1261         }
    1262         case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
    1263         {
    1264             DragAndDropSvc::PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBEVTERRORDATA>(pvParms);
     1357                rc = pThis->i_onReceiveFileData(pCtx, pCBData->pvData, pCBData->cbData);
     1358            break;
     1359        }
     1360        case GUEST_DND_GH_EVT_ERROR:
     1361        {
     1362            PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<PVBOXDNDCBEVTERRORDATA>(pvParms);
    12651363            AssertPtr(pCBData);
    1266             AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER);
    1267             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1364            AssertReturn(sizeof(VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER);
     1365            AssertReturn(CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    12681366
    12691367            pCtx->mpResp->reset();
     
    12721370                pCBData->rc = VERR_GENERAL_FAILURE; /* Make sure some error is set. */
    12731371
    1274             rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, pCBData->rc,
     1372            rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, pCBData->rc,
    12751373                                           GuestDnDSource::i_guestErrorToString(pCBData->rc));
    12761374            if (RT_SUCCESS(rc))
     
    13151413    }
    13161414
    1317     /* All URI data processed? */
    1318     if (pCtx->mData.cbProcessed >= pCtx->mData.cbToProcess)
    1319     {
    1320         Assert(pCtx->mData.cbProcessed == pCtx->mData.cbToProcess);
     1415    /* All data processed? */
     1416    if (   pCtx->mURI.isComplete()
     1417        && pCtx->mData.isComplete())
     1418    {
    13211419        fNotify = true;
    13221420    }
    13231421
    13241422    LogFlowFunc(("cbProcessed=%RU64, cbToProcess=%RU64, fNotify=%RTbool, rcCallback=%Rrc, rc=%Rrc\n",
    1325                  pCtx->mData.cbProcessed, pCtx->mData.cbToProcess, fNotify, rcCallback, rc));
     1423                 pCtx->mData.getProcessed(), pCtx->mData.getTotal(), fNotify, rcCallback, rc));
    13261424
    13271425    if (fNotify)
    13281426    {
    1329         int rc2 = pCtx->mCallback.Notify(rcCallback);
     1427        int rc2 = pCtx->mCBEvent.Notify(rcCallback);
    13301428        AssertRC(rc2);
    13311429    }
     
    13351433}
    13361434
    1337 int GuestDnDSource::i_updateProcess(PRECVDATACTX pCtx, uint64_t cbDataAdd)
    1338 {
    1339     AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    1340 
    1341     LogFlowFunc(("cbProcessed=%RU64 (+ %RU64 = %RU64), cbToProcess=%RU64\n",
    1342                  pCtx->mData.cbProcessed, cbDataAdd, pCtx->mData.cbProcessed + cbDataAdd, pCtx->mData.cbToProcess));
    1343 
    1344     pCtx->mData.cbProcessed += cbDataAdd;
    1345     Assert(pCtx->mData.cbProcessed <= pCtx->mData.cbToProcess);
    1346 
    1347     int64_t cbTotal  = pCtx->mData.cbToProcess;
    1348     uint8_t uPercent = pCtx->mData.cbProcessed * 100 / (cbTotal ? cbTotal : 1);
    1349 
    1350     int rc = pCtx->mpResp->setProgress(uPercent,
    1351                                          uPercent >= 100
    1352                                        ? DragAndDropSvc::DND_PROGRESS_COMPLETE
    1353                                        : DragAndDropSvc::DND_PROGRESS_RUNNING);
    1354     return rc;
    1355 }
  • trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp

    r57505 r58212  
    262262
    263263    /* Determine guest DnD protocol to use. */
    264     GuestDnDBase::getProtocolVersion(&mDataBase.mProtocolVersion);
     264    GuestDnDBase::getProtocolVersion(&mDataBase.m_uProtocolVersion);
    265265
    266266    /* Default action is ignoring. */
     
    302302    {
    303303        GuestDnDMsg Msg;
    304         Msg.setType(DragAndDropSvc::HOST_DND_HG_EVT_ENTER);
     304        Msg.setType(HOST_DND_HG_EVT_ENTER);
    305305        Msg.setNextUInt32(aScreenId);
    306306        Msg.setNextUInt32(aX);
     
    376376    {
    377377        GuestDnDMsg Msg;
    378         Msg.setType(DragAndDropSvc::HOST_DND_HG_EVT_MOVE);
     378        Msg.setType(HOST_DND_HG_EVT_MOVE);
    379379        Msg.setNextUInt32(aScreenId);
    380380        Msg.setNextUInt32(aX);
     
    418418
    419419    HRESULT hr = S_OK;
    420     int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_HG_EVT_LEAVE,
     420    int rc = GuestDnDInst()->hostCall(HOST_DND_HG_EVT_LEAVE,
    421421                                      0 /* cParms */, NULL /* paParms */);
    422422    if (RT_SUCCESS(rc))
     
    488488    {
    489489        GuestDnDMsg Msg;
    490         Msg.setType(DragAndDropSvc::HOST_DND_HG_EVT_DROPPED);
     490        Msg.setType(HOST_DND_HG_EVT_DROPPED);
    491491        Msg.setNextUInt32(aScreenId);
    492492        Msg.setNextUInt32(aX);
     
    545545    AssertPtrReturn(pTask, VERR_INVALID_POINTER);
    546546
    547     const ComObjPtr<GuestDnDTarget> pTarget(pTask->getTarget());
    548     Assert(!pTarget.isNull());
    549 
    550     int rc;
    551 
    552     AutoCaller autoCaller(pTarget);
    553     if (SUCCEEDED(autoCaller.rc()))
    554     {
    555         rc = pTarget->i_sendData(pTask->getCtx(), RT_INDEFINITE_WAIT /* msTimeout */);
    556         /* Nothing to do here anymore. */
    557     }
    558     else
    559         rc = VERR_COM_INVALID_OBJECT_STATE;
    560 
    561     ASMAtomicWriteBool(&pTarget->mDataBase.mfTransferIsPending, false);
     547    const ComObjPtr<GuestDnDTarget> pThis(pTask->getTarget());
     548    Assert(!pThis.isNull());
     549
     550    AutoCaller autoCaller(pThis);
     551    if (FAILED(autoCaller.rc())) return VERR_COM_INVALID_OBJECT_STATE;
     552
     553    int rc = RTThreadUserSignal(Thread);
     554    AssertRC(rc);
     555
     556    rc = pThis->i_sendData(pTask->getCtx(), RT_INDEFINITE_WAIT /* msTimeout */);
    562557
    563558    if (pTask)
    564559        delete pTask;
    565560
    566     LogFlowFunc(("pTarget=%p returning rc=%Rrc\n", (GuestDnDTarget *)pTarget, rc));
     561    AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
     562
     563    Assert(pThis->mDataBase.m_cTransfersPending);
     564    pThis->mDataBase.m_cTransfersPending--;
     565
     566    LogFlowFunc(("pTarget=%p returning rc=%Rrc\n", (GuestDnDTarget *)pThis, rc));
    567567    return rc;
    568568}
     
    594594        return setError(E_INVALIDARG, tr("No data to send specified"));
    595595
    596     /* Note: At the moment we only support one transfer at a time. */
    597     if (ASMAtomicReadBool(&mDataBase.mfTransferIsPending))
    598         return setError(E_INVALIDARG, tr("Another send operation already is in progress"));
    599 
    600     ASMAtomicWriteBool(&mDataBase.mfTransferIsPending, true);
     596    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     597
     598    /* At the moment we only support one transfer at a time. */
     599    if (mDataBase.m_cTransfersPending)
     600        return setError(E_INVALIDARG, tr("Another drop operation already is in progress"));
    601601
    602602    /* Dito. */
     
    617617        pSendCtx->mScreenID     = aScreenId;
    618618        pSendCtx->mFmtReq       = aFormat;
    619         pSendCtx->mData.vecData = aData;
     619
     620        pSendCtx->mData.getMeta().add(aData);
    620621
    621622        SendDataTask *pTask = new SendDataTask(this, pSendCtx);
     
    624625        LogFlowFunc(("Starting thread ...\n"));
    625626
    626         int rc = RTThreadCreate(NULL, GuestDnDTarget::i_sendDataThread,
     627        RTTHREAD threadSnd;
     628        int rc = RTThreadCreate(&threadSnd, GuestDnDTarget::i_sendDataThread,
    627629                                (void *)pTask, 0, RTTHREADTYPE_MAIN_WORKER, 0, "dndTgtSndData");
    628630        if (RT_SUCCESS(rc))
    629631        {
    630             hr = pResp->queryProgressTo(aProgress.asOutParam());
    631             ComAssertComRC(hr);
    632 
    633             /* Note: pTask is now owned by the worker thread. */
     632            rc = RTThreadUserWait(threadSnd, 30 * 1000 /* 30s timeout */);
     633            if (RT_SUCCESS(rc))
     634            {
     635                mDataBase.m_cTransfersPending++;
     636
     637                hr = pResp->queryProgressTo(aProgress.asOutParam());
     638                ComAssertComRC(hr);
     639
     640                /* Note: pTask is now owned by the worker thread. */
     641            }
     642            else
     643                hr = setError(VBOX_E_IPRT_ERROR, tr("Waiting for sending thread failed (%Rrc)"), rc);
    634644        }
    635645        else
    636646            hr = setError(VBOX_E_IPRT_ERROR, tr("Starting thread failed (%Rrc)"), rc);
    637647
    638         if (RT_FAILURE(rc))
     648        if (FAILED(hr))
    639649            delete pSendCtx;
    640650    }
     
    643653        hr = setError(E_OUTOFMEMORY);
    644654    }
    645 
    646     /* Note: mDataBase.mfTransferIsPending will be set to false again by i_sendDataThread. */
    647655
    648656    LogFlowFunc(("Returning hr=%Rhrc\n", hr));
     
    662670
    663671    LogFlowFunc(("Cancelling operation, telling guest ...\n"));
    664     return GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_HG_EVT_CANCEL, 0 /* cParms */, NULL /*paParms*/);
     672    return GuestDnDInst()->hostCall(HOST_DND_HG_EVT_CANCEL, 0 /* cParms */, NULL /*paParms*/);
    665673}
    666674
     
    746754
    747755    /* Clear all remaining outgoing messages. */
    748     mDataBase.mListOutgoing.clear();
     756    mDataBase.m_lstMsgOut.clear();
    749757
    750758    /**
     
    775783}
    776784
     785int GuestDnDTarget::i_sendDataBody(PSENDDATACTX pCtx, GuestDnDData *pData)
     786{
     787    AssertPtrReturn(pCtx,  VERR_INVALID_POINTER);
     788    AssertPtrReturn(pData, VERR_INVALID_POINTER);
     789
     790    /** @todo Add support for multiple HOST_DND_HG_SND_DATA messages in case of more than 64K data! */
     791    if (pData->getMeta().getSize() > _64K)
     792        return VERR_NOT_IMPLEMENTED;
     793
     794    GuestDnDMsg Msg;
     795
     796    LogFlowFunc(("cbFmt=%RU32, cbMeta=%RU32, cbChksum=%RU32\n",
     797                 pData->getFmtSize(), pData->getMeta().getSize(), pData->getChkSumSize()));
     798
     799    Msg.setType(HOST_DND_HG_SND_DATA);
     800    if (mDataBase.m_uProtocolVersion < 3)
     801    {
     802        Msg.setNextUInt32(pCtx->mScreenID);                                                /* uScreenId */
     803        Msg.setNextPointer(pData->getFmtMutable(), pData->getFmtSize());                   /* pvFormat */
     804        Msg.setNextUInt32(pData->getFmtSize());                                            /* cbFormat */
     805        Msg.setNextPointer(pData->getMeta().getDataMutable(), pData->getMeta().getSize()); /* pvData */
     806        /* Note1: Fill in the total data to send.
     807         * Note2: Only supports uint32_t. */
     808        Msg.setNextUInt32((uint32_t)pData->getTotal());                                    /* cbData */
     809    }
     810    else
     811    {
     812        Msg.setNextUInt32(0);                                                              /** @todo uContext; not used yet. */
     813        Msg.setNextPointer(pData->getMeta().getDataMutable(), pData->getMeta().getSize()); /* pvData */
     814        Msg.setNextUInt32(pData->getMeta().getSize());                                     /* cbData */
     815        Msg.setNextPointer(pData->getChkSumMutable(), pData->getChkSumSize());             /** @todo pvChecksum; not used yet. */
     816        Msg.setNextUInt32(pData->getChkSumSize());                                         /** @todo cbChecksum; not used yet. */
     817    }
     818
     819    int rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
     820    if (RT_SUCCESS(rc))
     821        rc = updateProgress(pData, pCtx->mpResp, pData->getMeta().getSize());
     822
     823    LogFlowFuncLeaveRC(rc);
     824    return rc;
     825}
     826
     827int GuestDnDTarget::i_sendDataHeader(PSENDDATACTX pCtx, GuestDnDData *pData, GuestDnDURIData *pURIData /* = NULL */)
     828{
     829    AssertPtrReturn(pCtx,  VERR_INVALID_POINTER);
     830    AssertPtrReturn(pData, VERR_INVALID_POINTER);
     831    /* pURIData is optional. */
     832
     833    GuestDnDMsg Msg;
     834
     835    Msg.setType(HOST_DND_HG_SND_DATA_HDR);
     836
     837    Msg.setNextUInt32(0);                                                /** @todo uContext; not used yet. */
     838    Msg.setNextUInt32(0);                                                /** @todo uFlags; not used yet. */
     839    Msg.setNextUInt32(pCtx->mScreenID);                                  /* uScreen */
     840    Msg.setNextUInt64(pData->getTotal());                                /* cbTotal */
     841    Msg.setNextUInt32(pData->getMeta().getSize());                       /* cbMeta*/
     842    Msg.setNextPointer(pData->getFmtMutable(), pData->getFmtSize());     /* pvMetaFmt */
     843    Msg.setNextUInt32(pData->getFmtSize());                              /* cbMetaFmt */
     844    Msg.setNextUInt64(pURIData ? pURIData->getObjToProcess() : 0);       /* cObjects */
     845    Msg.setNextUInt32(0);                                                /** @todo enmCompression; not used yet. */
     846    Msg.setNextUInt32(0);                                                /** @todo enmChecksumType; not used yet. */
     847    Msg.setNextPointer(NULL, 0);                                         /** @todo pvChecksum; not used yet. */
     848    Msg.setNextUInt32(0);                                                /** @todo cbChecksum; not used yet. */
     849
     850    int rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
     851
     852    LogFlowFuncLeaveRC(rc);
     853    return rc;
     854}
     855
    777856int GuestDnDTarget::i_sendDirectory(PSENDDATACTX pCtx, GuestDnDURIObjCtx *pObjCtx, GuestDnDMsg *pMsg)
    778857{
     
    790869        return VERR_BUFFER_OVERFLOW;
    791870
    792     LogFlowFunc(("Sending directory \"%s\" using protocol v%RU32 ...\n", strPath.c_str(), mDataBase.mProtocolVersion));
    793 
    794     pMsg->setType(DragAndDropSvc::HOST_DND_HG_SND_DIR);
     871    LogRel2(("DnD: Transferring host directory to guest: %s\n", strPath.c_str()));
     872
     873    pMsg->setType(HOST_DND_HG_SND_DIR);
    795874    pMsg->setNextString(strPath.c_str());                  /* path */
    796     pMsg->setNextUInt32((uint32_t)(strPath.length() + 1)); /* path length - note: Maximum is RTPATH_MAX on guest side. */
     875    pMsg->setNextUInt32((uint32_t)(strPath.length() + 1)); /* path length (maximum is RTPATH_MAX on guest side). */
    797876    pMsg->setNextUInt32(pObj->GetMode());                  /* mode */
    798877
     
    816895
    817896    LogFlowFunc(("Sending file with %RU32 bytes buffer, using protocol v%RU32 ...\n",
    818                   mData.mcbBlockSize, mDataBase.mProtocolVersion));
     897                  mData.mcbBlockSize, mDataBase.m_uProtocolVersion));
    819898    LogFlowFunc(("strPathSrc=%s, fIsOpen=%RTbool, cbSize=%RU64\n", strPathSrc.c_str(), pObj->IsOpen(), pObj->GetSize()));
    820899
     
    831910    if (RT_SUCCESS(rc))
    832911    {
    833         if (mDataBase.mProtocolVersion >= 2)
     912        if (mDataBase.m_uProtocolVersion >= 2)
    834913        {
    835914            if (!pObjCtx->fHeaderSent)
     
    840919                 * The just registered callback will be called by the guest afterwards.
    841920                 */
    842                 pMsg->setType(DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR);
     921                pMsg->setType(HOST_DND_HG_SND_FILE_HDR);
    843922                pMsg->setNextUInt32(0);                                            /* uContextID */
    844923                rc = pMsg->setNextString(pObj->GetDestPath().c_str());             /* pvName */
     
    899978
    900979    /* Set the message type. */
    901     pMsg->setType(DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA);
     980    pMsg->setType(HOST_DND_HG_SND_FILE_DATA);
    902981
    903982    /* Protocol version 1 sends the file path *every* time with a new file chunk.
    904983     * In protocol version 2 we only do this once with HOST_DND_HG_SND_FILE_HDR. */
    905     if (mDataBase.mProtocolVersion <= 1)
     984    if (mDataBase.m_uProtocolVersion <= 1)
    906985    {
    907986        pMsg->setNextString(pObj->GetDestPath().c_str());                  /* pvName */
    908987        pMsg->setNextUInt32((uint32_t)(pObj->GetDestPath().length() + 1)); /* cbName */
    909988    }
    910     else
    911     {
    912         /* Protocol version 2 also sends the context ID. Currently unused. */
    913         pMsg->setNextUInt32(0);                                            /* context ID */
     989    else if (mDataBase.m_uProtocolVersion >= 2)
     990    {
     991        /* Since protocol v2 we also send the context ID. Currently unused. */
     992        pMsg->setNextUInt32(0);                                            /* uContext */
    914993    }
    915994
    916995    uint32_t cbRead = 0;
    917996
    918     int rc = pObj->Read(pCtx->mURI.GetBufferMutable(), pCtx->mURI.GetBufferSize(), &cbRead);
     997    int rc = pObj->Read(pCtx->mURI.getBufferMutable(), pCtx->mURI.getBufferSize(), &cbRead);
    919998    if (RT_SUCCESS(rc))
    920999    {
    921         pCtx->mData.cbProcessed += cbRead;
    922         LogFlowFunc(("cbBufSize=%zu, cbRead=%RU32, cbProcessed=%RU64, rc=%Rrc\n",
    923                      pCtx->mURI.GetBufferSize(), cbRead, pCtx->mData.cbProcessed, rc));
    924 
    925         if (mDataBase.mProtocolVersion <= 1)
    926         {
    927             pMsg->setNextPointer(pCtx->mURI.GetBufferMutable(), cbRead);   /* pvData */
    928             pMsg->setNextUInt32(cbRead);                                   /* cbData */
    929             pMsg->setNextUInt32(pObj->GetMode());                          /* fMode */
    930         }
    931         else
    932         {
    933             pMsg->setNextPointer(pCtx->mURI.GetBufferMutable(), cbRead);   /* pvData */
    934             pMsg->setNextUInt32(cbRead);                                   /* cbData */
     1000        pCtx->mData.addProcessed(cbRead);
     1001        LogFlowFunc(("cbBufSize=%zu, cbRead=%RU32\n", pCtx->mURI.getBufferSize(), cbRead));
     1002
     1003        if (mDataBase.m_uProtocolVersion <= 1)
     1004        {
     1005            pMsg->setNextPointer(pCtx->mURI.getBufferMutable(), cbRead);    /* pvData */
     1006            pMsg->setNextUInt32(cbRead);                                    /* cbData */
     1007            pMsg->setNextUInt32(pObj->GetMode());                           /* fMode */
     1008        }
     1009        else /* Protocol v2 and up. */
     1010        {
     1011            pMsg->setNextPointer(pCtx->mURI.getBufferMutable(), cbRead);    /* pvData */
     1012            pMsg->setNextUInt32(cbRead);                                    /* cbData */
     1013
     1014            if (mDataBase.m_uProtocolVersion >= 3)
     1015            {
     1016                /** @todo Calculate checksum. */
     1017                pMsg->setNextPointer(NULL, 0);                              /* pvChecksum */
     1018                pMsg->setNextUInt32(0);                                     /* cbChecksum */
     1019            }
    9351020        }
    9361021
     
    9611046    LogFlowFunc(("pThis=%p, uMsg=%RU32\n", pThis, uMsg));
    9621047
    963     int rc      = VINF_SUCCESS; /* Will be reported back to guest. */
    964     int rcGuest = VINF_SUCCESS; /* Contains error code from guest in case of VERR_GSTDND_GUEST_ERROR. */
     1048    int  rc      = VINF_SUCCESS;
     1049    int  rcGuest = VINF_SUCCESS; /* Contains error code from guest in case of VERR_GSTDND_GUEST_ERROR. */
    9651050    bool fNotify = false;
    9661051
    9671052    switch (uMsg)
    9681053    {
    969         case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
    970         {
    971             DragAndDropSvc::PVBOXDNDCBHGGETNEXTHOSTMSG pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGGETNEXTHOSTMSG>(pvParms);
     1054        case GUEST_DND_GET_NEXT_HOST_MSG:
     1055        {
     1056            PVBOXDNDCBHGGETNEXTHOSTMSG pCBData = reinterpret_cast<PVBOXDNDCBHGGETNEXTHOSTMSG>(pvParms);
    9721057            AssertPtr(pCBData);
    973             AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSG) == cbParms, VERR_INVALID_PARAMETER);
    974             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1058            AssertReturn(sizeof(VBOXDNDCBHGGETNEXTHOSTMSG) == cbParms, VERR_INVALID_PARAMETER);
     1059            AssertReturn(CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    9751060
    9761061            try
     
    10071092            break;
    10081093        }
    1009         case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
    1010         {
    1011             DragAndDropSvc::PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBEVTERRORDATA>(pvParms);
     1094        case GUEST_DND_GH_EVT_ERROR:
     1095        {
     1096            PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<PVBOXDNDCBEVTERRORDATA>(pvParms);
    10121097            AssertPtr(pCBData);
    1013             AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER);
    1014             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1098            AssertReturn(sizeof(VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER);
     1099            AssertReturn(CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    10151100
    10161101            pCtx->mpResp->reset();
     
    10221107            }
    10231108
    1024             rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, pCBData->rc,
     1109            rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, pCBData->rc,
    10251110                                           GuestDnDTarget::i_guestErrorToString(pCBData->rc));
    10261111            if (RT_SUCCESS(rc))
     
    10311116            break;
    10321117        }
    1033         case DragAndDropSvc::HOST_DND_HG_SND_DIR:
    1034         case DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR:
    1035         case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA:
    1036         {
    1037             DragAndDropSvc::PVBOXDNDCBHGGETNEXTHOSTMSGDATA pCBData
    1038                 = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGGETNEXTHOSTMSGDATA>(pvParms);
     1118        case HOST_DND_HG_SND_DIR:
     1119        case HOST_DND_HG_SND_FILE_HDR:
     1120        case HOST_DND_HG_SND_FILE_DATA:
     1121        {
     1122            PVBOXDNDCBHGGETNEXTHOSTMSGDATA pCBData
     1123                = reinterpret_cast<PVBOXDNDCBHGGETNEXTHOSTMSGDATA>(pvParms);
    10391124            AssertPtr(pCBData);
    1040             AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSGDATA) == cbParms, VERR_INVALID_PARAMETER);
    1041             AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
     1125            AssertReturn(sizeof(VBOXDNDCBHGGETNEXTHOSTMSGDATA) == cbParms, VERR_INVALID_PARAMETER);
     1126            AssertReturn(CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    10421127
    10431128            LogFlowFunc(("pCBData->uMsg=%RU32, paParms=%p, cParms=%RU32\n", pCBData->uMsg, pCBData->paParms, pCBData->cParms));
     
    10531138                    || pCBData->cParms  != pMsg->getCount())
    10541139                {
     1140                    LogFlowFunc(("Current message does not match:\n"));
     1141                    LogFlowFunc(("\tCallback: uMsg=%RU32, cParms=%RU32, paParms=%p\n",
     1142                                 pCBData->uMsg, pCBData->cParms, pCBData->paParms));
     1143                    LogFlowFunc(("\t    Next: uMsg=%RU32, cParms=%RU32\n", pMsg->getType(), pMsg->getCount()));
     1144
    10551145                    /* Start over. */
    10561146                    pThis->msgQueueClear();
     
    11411231    if (fNotify)
    11421232    {
    1143         int rc2 = pCtx->mCallback.Notify(rc); /** @todo Also pass guest error back? */
     1233        int rc2 = pCtx->mCBEvent.Notify(rc); /** @todo Also pass guest error back? */
    11441234        AssertRC(rc2);
    11451235    }
     
    11731263    }
    11741264
    1175     int rc = pCtx->mURI.Init(mData.mcbBlockSize);
     1265    int rc = pCtx->mURI.init(mData.mcbBlockSize);
    11761266    if (RT_FAILURE(rc))
    11771267        return rc;
    11781268
    1179     rc = pCtx->mCallback.Reset();
     1269    rc = pCtx->mCBEvent.Reset();
    11801270    if (RT_FAILURE(rc))
    11811271        return rc;
     
    11851275     */
    11861276    /* Guest callbacks. */
    1187     REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG);
    1188     REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_EVT_ERROR);
     1277    REGISTER_CALLBACK(GUEST_DND_GET_NEXT_HOST_MSG);
     1278    REGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
    11891279    /* Host callbacks. */
    1190     REGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_DIR);
    1191     if (mDataBase.mProtocolVersion >= 2)
    1192         REGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR);
    1193     REGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA);
     1280    REGISTER_CALLBACK(HOST_DND_HG_SND_DIR);
     1281    if (mDataBase.m_uProtocolVersion >= 2)
     1282        REGISTER_CALLBACK(HOST_DND_HG_SND_FILE_HDR);
     1283    REGISTER_CALLBACK(HOST_DND_HG_SND_FILE_DATA);
    11941284
    11951285    do
    11961286    {
    11971287        /*
    1198          * Extract URI list from byte data.
     1288         * Extract URI list from current meta data.
    11991289         */
    1200         DnDURIList &lstURI = pCtx->mURI.lstURI; /* Use the URI list from the context. */
    1201 
    1202         const char *pszList = (const char *)&pCtx->mData.vecData.front();
    1203         URI_DATA_IS_VALID_BREAK(pszList);
    1204 
    1205         uint32_t cbList = pCtx->mData.vecData.size();
    1206         URI_DATA_IS_VALID_BREAK(cbList);
    1207 
    1208         RTCList<RTCString> lstURIOrg = RTCString(pszList, cbList).split("\r\n");
    1209         URI_DATA_IS_VALID_BREAK(!lstURIOrg.isEmpty());
    1210 
    1211         /* Note: All files to be transferred will be kept open during the entire DnD
    1212          *       operation, also to keep the accounting right. */
    1213         rc = lstURI.AppendURIPathsFromList(lstURIOrg, DNDURILIST_FLAGS_KEEP_OPEN);
     1290        GuestDnDData    *pData = &pCtx->mData;
     1291        GuestDnDURIData *pURI  = &pCtx->mURI;
     1292
     1293        rc = pURI->fromMetaData(pData->getMeta());
     1294        if (RT_FAILURE(rc))
     1295            break;
     1296
     1297        LogFlowFunc(("URI root objects: %zu, total bytes (raw data to transfer): %zu\n",
     1298                     pURI->getURIList().RootCount(), pURI->getURIList().TotalBytes()));
     1299
     1300        /*
     1301         * Set the new meta data with the URI list in it.
     1302         */
     1303        rc = pData->getMeta().fromURIList(pURI->getURIList());
     1304        if (RT_FAILURE(rc))
     1305            break;
     1306
     1307        /*
     1308         * Set the additional size we are going to send after the meta data header + meta data.
     1309         * This additional data will contain the actual file data we want to transfer.
     1310         */
     1311        pData->setAdditionalSize(pURI->getURIList().TotalBytes());
     1312
     1313        void    *pvFmt = (void *)pCtx->mFmtReq.c_str();
     1314        uint32_t cbFmt = pCtx->mFmtReq.length() + 1;        /* Include terminating zero. */
     1315
     1316        pData->setFmt(pvFmt, cbFmt);
     1317
     1318        /*
     1319         * The first message always is the data header. The meta data itself then follows
     1320         * and *only* contains the root elements of an URI list.
     1321         *
     1322         * After the meta data we generate the messages required to send the
     1323         * file/directory data itself.
     1324         *
     1325         * Note: Protocol < v3 use the first data message to tell what's being sent.
     1326         */
     1327        GuestDnDMsg Msg;
     1328
     1329        /*
     1330         * Send the data header first.
     1331         */
     1332        if (mDataBase.m_uProtocolVersion >= 3)
     1333            rc = i_sendDataHeader(pCtx, pData, &pCtx->mURI);
     1334
     1335        /*
     1336         * Send the (meta) data body.
     1337         */
    12141338        if (RT_SUCCESS(rc))
    1215             LogFlowFunc(("URI root objects: %zu, total bytes (raw data to transfer): %zu\n",
    1216                          lstURI.RootCount(), lstURI.TotalBytes()));
    1217         else
    1218             break;
    1219 
    1220         pCtx->mData.cbProcessed = 0;
    1221         pCtx->mData.cbToProcess = lstURI.TotalBytes();
    1222 
    1223         /*
    1224          * The first message always is the meta info for the data. The meta
    1225          * info *only* contains the root elements of an URI list.
    1226          *
    1227          * After the meta data we generate the messages required to send the data itself.
    1228          */
    1229         Assert(!lstURI.IsEmpty());
    1230         RTCString strData = lstURI.RootToString().c_str();
    1231         size_t    cbData  = strData.length() + 1; /* Include terminating zero. */
    1232 
    1233         GuestDnDMsg MsgSndData;
    1234         MsgSndData.setType(DragAndDropSvc::HOST_DND_HG_SND_DATA);
    1235         MsgSndData.setNextUInt32(pCtx->mScreenID);
    1236         MsgSndData.setNextPointer((void *)pCtx->mFmtReq.c_str(), (uint32_t)pCtx->mFmtReq.length() + 1);
    1237         MsgSndData.setNextUInt32((uint32_t)pCtx->mFmtReq.length() + 1);
    1238         MsgSndData.setNextPointer((void*)strData.c_str(), (uint32_t)cbData);
    1239         MsgSndData.setNextUInt32((uint32_t)cbData);
    1240 
    1241         rc = GuestDnDInst()->hostCall(MsgSndData.getType(), MsgSndData.getCount(), MsgSndData.getParms());
     1339            rc = i_sendDataBody(pCtx, pData);
     1340
    12421341        if (RT_SUCCESS(rc))
    12431342        {
    1244             rc = waitForEvent(msTimeout, pCtx->mCallback, pCtx->mpResp);
     1343            rc = waitForEvent(&pCtx->mCBEvent, pCtx->mpResp, msTimeout);
    12451344            if (RT_FAILURE(rc))
    12461345            {
    12471346                if (rc == VERR_CANCELLED)
    1248                     rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_CANCELLED, VINF_SUCCESS);
     1347                    rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_CANCELLED, VINF_SUCCESS);
    12491348                else if (rc != VERR_GSTDND_GUEST_ERROR) /* Guest-side error are already handled in the callback. */
    1250                     rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, rc,
     1349                    rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, rc,
    12511350                                                   GuestDnDTarget::i_hostErrorToString(rc));
    12521351            }
    12531352            else
    1254                 rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_COMPLETE, VINF_SUCCESS);
     1353                rc = pCtx->mpResp->setProgress(100, DND_PROGRESS_COMPLETE, VINF_SUCCESS);
    12551354        }
    12561355
     
    12611360     */
    12621361    /* Guest callbacks. */
    1263     UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG);
    1264     UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_EVT_ERROR);
     1362    UNREGISTER_CALLBACK(GUEST_DND_GET_NEXT_HOST_MSG);
     1363    UNREGISTER_CALLBACK(GUEST_DND_GH_EVT_ERROR);
    12651364    /* Host callbacks. */
    1266     UNREGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_DIR);
    1267     if (mDataBase.mProtocolVersion >= 2)
    1268         UNREGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR);
    1269     UNREGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA);
     1365    UNREGISTER_CALLBACK(HOST_DND_HG_SND_DIR);
     1366    if (mDataBase.m_uProtocolVersion >= 2)
     1367        UNREGISTER_CALLBACK(HOST_DND_HG_SND_FILE_HDR);
     1368    UNREGISTER_CALLBACK(HOST_DND_HG_SND_FILE_DATA);
    12701369
    12711370#undef REGISTER_CALLBACK
     
    12921391{
    12931392    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    1294 
    1295     DnDURIList &lstURI = pCtx->mURI.lstURI;
    1296 
    1297     uint64_t cbTotal = pCtx->mData.cbToProcess;
    1298     uint8_t uPercent = pCtx->mData.cbProcessed * 100 / (cbTotal ? cbTotal : 1);
    1299 
    1300     LogFlowFunc(("%RU64 / %RU64 -- %RU8%%\n", pCtx->mData.cbProcessed, cbTotal, uPercent));
    1301 
    1302     bool fComplete = (uPercent >= 100) || lstURI.IsEmpty();
    1303 
    1304     if (pCtx->mpResp)
    1305     {
    1306         int rc2 = pCtx->mpResp->setProgress(uPercent,
    1307                                               fComplete
    1308                                             ? DragAndDropSvc::DND_PROGRESS_COMPLETE
    1309                                             : DragAndDropSvc::DND_PROGRESS_RUNNING);
    1310         AssertRC(rc2);
    1311     }
    1312 
    1313     if (fComplete)
     1393    AssertPtrReturn(pMsg, VERR_INVALID_POINTER);
     1394
     1395    int rc = updateProgress(&pCtx->mData, pCtx->mpResp);
     1396    AssertRC(rc);
     1397
     1398    if (   pCtx->mData.isComplete()
     1399        && pCtx->mURI.isComplete())
     1400    {
    13141401        return VINF_EOF;
    1315 
    1316     Assert(!lstURI.IsEmpty());
    1317     DnDURIObject *pCurObj = lstURI.First();
    1318 
    1319     /* As we transfer all objects one after another at a time at the moment,
    1320      * we only need one object context at the moment. */
    1321     GuestDnDURIObjCtx *pObjCtx = &pCtx->mURI.objCtx;
    1322 
    1323     /* Assign the pointer of the current object to our context. */
    1324     pObjCtx->pObjURI = pCurObj;
     1402    }
     1403
     1404    GuestDnDURIObjCtx &objCtx = pCtx->mURI.getObjCurrent();
     1405    if (!objCtx.isValid())
     1406        return VERR_WRONG_ORDER;
     1407
     1408    DnDURIObject *pCurObj = objCtx.pObjURI;
     1409    AssertPtr(pCurObj);
    13251410
    13261411    uint32_t fMode = pCurObj->GetMode();
    1327     LogFlowFunc(("Processing srcPath=%s, dstPath=%s, fMode=0x%x, cbSize=%RU32, fIsDir=%RTbool, fIsFile=%RTbool\n",
    1328                  pCurObj->GetSourcePath().c_str(), pCurObj->GetDestPath().c_str(),
    1329                  fMode, pCurObj->GetSize(),
    1330                  RTFS_IS_DIRECTORY(fMode), RTFS_IS_FILE(fMode)));
    1331     int rc;
     1412    LogRel3(("DnD: Processing: srcPath=%s, dstPath=%s, fMode=0x%x, cbSize=%RU32, fIsDir=%RTbool, fIsFile=%RTbool\n",
     1413             pCurObj->GetSourcePath().c_str(), pCurObj->GetDestPath().c_str(),
     1414             fMode, pCurObj->GetSize(),
     1415             RTFS_IS_DIRECTORY(fMode), RTFS_IS_FILE(fMode)));
     1416
    13321417    if (RTFS_IS_DIRECTORY(fMode))
    13331418    {
    1334         rc = i_sendDirectory(pCtx, pObjCtx, pMsg);
     1419        rc = i_sendDirectory(pCtx, &objCtx, pMsg);
    13351420    }
    13361421    else if (RTFS_IS_FILE(fMode))
    13371422    {
    1338         rc = i_sendFile(pCtx, pObjCtx, pMsg);
     1423        rc = i_sendFile(pCtx, &objCtx, pMsg);
    13391424    }
    13401425    else
     
    13551440    {
    13561441        LogFlowFunc(("Removing \"%s\" from list, rc=%Rrc\n", pCurObj->GetSourcePath().c_str(), rc));
    1357         lstURI.RemoveFirst();
     1442        pCtx->mURI.removeObjCurrent();
    13581443    }
    13591444
     
    13701455    AssertPtr(pInst);
    13711456
    1372     /** @todo At the moment we only allow sending up to 64K raw data. Fix this by
    1373      *        using HOST_DND_HG_SND_MORE_DATA. */
    1374     size_t cbDataTotal = pCtx->mData.vecData.size();
    1375     if (   !cbDataTotal
    1376         || cbDataTotal > _64K)
    1377     {
    1378         return VERR_INVALID_PARAMETER;
    1379     }
    1380 
    1381     /* Just copy over the raw data. */
    1382     GuestDnDMsg Msg;
    1383     Msg.setType(DragAndDropSvc::HOST_DND_HG_SND_DATA);
    1384     Msg.setNextUInt32(pCtx->mScreenID);
    1385     Msg.setNextPointer((void *)pCtx->mFmtReq.c_str(), (uint32_t)pCtx->mFmtReq.length() + 1);
    1386     Msg.setNextUInt32((uint32_t)pCtx->mFmtReq.length() + 1);
    1387     Msg.setNextPointer((void*)&pCtx->mData.vecData.front(), (uint32_t)cbDataTotal);
    1388     Msg.setNextUInt32(cbDataTotal);
    1389 
    1390     LogFlowFunc(("Transferring %zu total bytes of raw data ('%s')\n", cbDataTotal, pCtx->mFmtReq.c_str()));
     1457    GuestDnDData *pData = &pCtx->mData;
     1458
     1459    /** @todo At the moment we only allow sending up to 64K raw data.
     1460     *        For protocol v1+v2: Fix this by using HOST_DND_HG_SND_MORE_DATA.
     1461     *        For protocol v3   : Send another HOST_DND_HG_SND_DATA message. */
     1462    if (!pData->getMeta().getSize())
     1463        return VINF_SUCCESS;
     1464
     1465    int rc = VINF_SUCCESS;
     1466
     1467    /*
     1468     * Send the data header first.
     1469     */
     1470    if (mDataBase.m_uProtocolVersion >= 3)
     1471        rc = i_sendDataHeader(pCtx, pData, NULL /* URI list */);
     1472
     1473    /*
     1474     * Send the (meta) data body.
     1475     */
     1476    if (RT_SUCCESS(rc))
     1477        rc = i_sendDataBody(pCtx, pData);
    13911478
    13921479    int rc2;
    1393 
    1394     int rc = pInst->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
    13951480    if (RT_FAILURE(rc))
    1396         rc2 = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, rc,
     1481        rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, rc,
    13971482                                        GuestDnDTarget::i_hostErrorToString(rc));
    13981483    else
    1399         rc2 = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_COMPLETE, rc);
     1484        rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_COMPLETE, rc);
    14001485    AssertRC(rc2);
    14011486
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