Changeset 55422 in vbox
- Timestamp:
- Apr 24, 2015 1:52:33 PM (10 years ago)
- svn:sync-xref-src-repo-rev:
- 99765
- Location:
- trunk
- Files:
-
- 1 added
- 26 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/GuestHost/DragAndDrop.h
r51211 r55422 60 60 }; 61 61 62 enum Dest 63 { 64 Source = 0, 65 Target 66 }; 67 68 DnDURIObject(void); 62 69 DnDURIObject(Type type, 63 const RTCString &strSrcPath ,64 const RTCString &strDstPath ,65 uint32_t fMode , uint64_t cbSize);70 const RTCString &strSrcPath = "", 71 const RTCString &strDstPath = "", 72 uint32_t fMode = 0, uint64_t cbSize = 0); 66 73 virtual ~DnDURIObject(void); 67 74 … … 69 76 70 77 const RTCString &GetSourcePath(void) const { return m_strSrcPath; } 71 const RTCString &GetDestPath(void) const { return m_strDstPath; } 72 uint32_t GetMode(void) const { return m_fMode; } 78 const RTCString &GetDestPath(void) const { return m_strTgtPath; } 79 uint64_t GetMode(void) const { return m_fMode; } 80 uint64_t GetProcessed(void) const { return m_cbProcessed; } 73 81 uint64_t GetSize(void) const { return m_cbSize; } 74 82 Type GetType(void) const { return m_Type; } … … 76 84 public: 77 85 86 int SetSize(uint64_t uSize) { m_cbSize = uSize; return VINF_SUCCESS; } 87 88 public: 89 90 void Close(void); 78 91 bool IsComplete(void) const; 79 static int RebaseURIPath(RTCString &strPath, const RTCString &strBaseOld, const RTCString &strBaseNew); 80 int Read(void *pvBuf, uint32_t cbToRead, uint32_t *pcbRead); 92 bool IsOpen(void) const; 93 int Open(Dest enmDest, uint64_t fOpen); 94 int OpenEx(const RTCString &strPath, Type enmType, Dest enmDest, uint64_t fMode = 0, uint32_t fFlags = 0); 95 int Read(void *pvBuf, size_t cbBuf, uint32_t *pcbRead); 96 int Write(const void *pvBuf, size_t cbBuf, uint32_t *pcbWritten); 97 98 public: 99 100 static int RebaseURIPath(RTCString &strPath, const RTCString &strBaseOld = "", const RTCString &strBaseNew = ""); 81 101 82 102 protected: … … 88 108 Type m_Type; 89 109 RTCString m_strSrcPath; 90 RTCString m_strDstPath; 91 uint32_t m_fMode; 110 RTCString m_strTgtPath; 111 /** File mode. */ 112 uint64_t m_fMode; 92 113 /** Size (in bytes) to read/write. */ 93 114 uint64_t m_cbSize; -
trunk/include/VBox/HostServices/DragAndDropSvc.h
r55091 r55422 4 4 5 5 /* 6 * Copyright (C) 2011-201 4Oracle Corporation6 * Copyright (C) 2011-2015 Oracle Corporation 7 7 * 8 8 * This file is part of VirtualBox Open Source Edition (OSE), as … … 27 27 #define ___VBox_HostService_DragAndDropSvc_h 28 28 29 #include <VBox/hgcmsvc.h> 29 30 #include <VBox/VMMDev.h> 30 31 #include <VBox/VBoxGuest2.h> … … 86 87 enum eHostFn 87 88 { 89 /** The host just has set a new DnD mode. */ 88 90 HOST_DND_SET_MODE = 100, 89 91 … … 92 94 */ 93 95 96 /** The host entered the VM window for starting an actual 97 * DnD operation. */ 94 98 HOST_DND_HG_EVT_ENTER = 200, 99 /** The host's DnD cursor moved within the VM window. */ 95 100 HOST_DND_HG_EVT_MOVE = 201, 101 /** The host left the guest VM window. */ 96 102 HOST_DND_HG_EVT_LEAVE = 202, 103 /** The host issued a "drop" event, meaning that the host is 104 * ready to transfer data over to the guest. */ 97 105 HOST_DND_HG_EVT_DROPPED = 203, 106 /** The host requested to cancel the current DnD operation. */ 98 107 HOST_DND_HG_EVT_CANCEL = 204, 99 108 /** Gets the actual MIME data, based on 100 * the format(s) specified by HOST_DND_HG_EVT_ENTER. */ 109 * the format(s) specified by HOST_DND_HG_EVT_ENTER. If the guest 110 * supplied buffer too small to send the actual data, the host 111 * will send a HOST_DND_HG_SND_MORE_DATA message as follow-up. */ 101 112 HOST_DND_HG_SND_DATA = 205, 102 113 /** Sent when the actual buffer for HOST_DND_HG_SND_DATA 103 114 * was too small, issued by the DnD host service. */ 104 115 HOST_DND_HG_SND_MORE_DATA = 206, 105 /** Directory entry to be handled onthe guest. */116 /** Directory entry to be sent to the guest. */ 106 117 HOST_DND_HG_SND_DIR = 207, 107 /** File entry to be handled on the guest. */ 108 HOST_DND_HG_SND_FILE = 208, 118 /** File data chunk to send to the guest. */ 119 HOST_DND_HG_SND_FILE_DATA = 208, 120 /** File header to send to the guest. 121 * Note: Only for protocol version 2 and up (>= VBox 5.0). */ 122 HOST_DND_HG_SND_FILE_HDR = 209, 109 123 110 124 /* … … 118 132 * has been started and that the host wants the data in 119 133 * a specific MIME type. */ 120 HOST_DND_GH_EVT_DROPPED ,121 134 HOST_DND_GH_EVT_DROPPED = 601, 135 /** Creates a directory on the guest. */ 122 136 HOST_DND_GH_RECV_DIR = 650, 123 HOST_DND_GH_RECV_FILE = 670 137 /** Retrieves file data from the guest. */ 138 HOST_DND_GH_RECV_FILE_DATA = 670, 139 /** Retrieves a file header from the guest. 140 * Note: Only for protocol version 2 and up (>= VBox 5.0). */ 141 HOST_DND_GH_RECV_FILE_HDR = 671, 142 /** Blow the type up to 32-bit. */ 143 HOST_DND_32BIT_HACK = 0x7fffffff 124 144 }; 125 145 … … 127 147 * The service functions which are called by guest. 128 148 * Note: When adding new functions to this table, make sure that the actual ID 129 * does *not* overlap with the e GuestFn enumeration above!149 * does *not* overlap with the eHostFn enumeration above! 130 150 */ 131 151 enum eGuestFn 132 152 { 153 /* Guest sends a connection request to the HGCM service. 154 * Note: New since protocol version 2. */ 155 GUEST_DND_CONNECT = 10, 156 133 157 /** 134 158 * Guest waits for a new message the host wants to process … … 137 161 GUEST_DND_GET_NEXT_HOST_MSG = 300, 138 162 139 /* H->G */ 163 /* 164 * Host -> Guest operation messages. 165 */ 166 140 167 /** The guest acknowledges that the pending DnD data from 141 168 * the host can be dropped on the currently selected source … … 145 172 * from the host. */ 146 173 GUEST_DND_HG_REQ_DATA = 401, 174 /** Reports back the guest's progress on a host -> guest operation. */ 147 175 GUEST_DND_HG_EVT_PROGRESS = 402, 148 176 149 /* G->H */ 177 /* 178 * Guest -> Host operation messages. 179 */ 180 150 181 /** 151 182 * The guests acknowledges that it currently has a drag'n drop … … 160 191 */ 161 192 GUEST_DND_GH_SND_DATA = 501, 193 /** Reports an error back to the host. */ 162 194 GUEST_DND_GH_EVT_ERROR = 502, 163 195 /** Guest sends a directory entry to the host. */ 164 196 GUEST_DND_GH_SND_DIR = 700, 165 GUEST_DND_GH_SND_FILE = 701 197 /** Guest sends file data to the host. */ 198 /* Note: On protocol version 1 this also contains the file name 199 * and other attributes. */ 200 GUEST_DND_GH_SND_FILE_DATA = 701, 201 /** Guest sends a file header to the host, marking the 202 * beginning of a (new) file transfer. 203 * Note: Available since protocol version 2 (VBox 5.0). */ 204 GUEST_DND_GH_SND_FILE_HDR = 702, 205 /** Blow the type up to 32-bit. */ 206 GUEST_DND_32BIT_HACK = 0x7fffffff 166 207 }; 167 208 168 209 /** 169 * The possible states for the progress operations. 170 */ 171 enum 172 { 173 DND_PROGRESS_RUNNING = 1, 210 * DnD operation progress states. 211 */ 212 typedef enum DNDPROGRESS 213 { 214 DND_PROGRESS_UNKNOWN = 0, 215 DND_PROGRESS_RUNNING = 1, 174 216 DND_PROGRESS_COMPLETE, 175 217 DND_PROGRESS_CANCELLED, 176 DND_PROGRESS_ERROR 177 }; 218 DND_PROGRESS_ERROR, 219 /** Blow the type up to 32-bit. */ 220 DND_PROGRESS_32BIT_HACK = 0x7fffffff 221 } DNDPROGRESS, *PDNDPROGRESS; 178 222 179 223 #pragma pack (1) … … 273 317 } VBOXDNDHGSENDDIRMSG; 274 318 275 typedef struct VBOXDNDHGSENDFILEMSG 276 { 277 VBoxGuestHGCMCallInfo hdr; 278 279 /** 280 * HG File event. 281 * 282 * Used by: 283 * HOST_DND_HG_SND_FILE 284 */ 319 /** 320 * File header event. 321 * Note: Only for protocol version 2 and up. 322 * 323 * Used by: 324 * HOST_DND_HG_SND_FILE_HDR 325 * HOST_DND_GH_SND_FILE_HDR 326 */ 327 typedef struct VBOXDNDHGSENDFILEHDRMSG 328 { 329 VBoxGuestHGCMCallInfo hdr; 330 331 /** Context ID. Unused at the moment. */ 332 HGCMFunctionParameter uContext; /* OUT uint32_t */ 333 /** File path. */ 285 334 HGCMFunctionParameter pvName; /* OUT ptr */ 335 /** Size (in bytes) of file path. */ 286 336 HGCMFunctionParameter cbName; /* OUT uint32_t */ 287 HGCMFunctionParameter pvData; /* OUT ptr */ 288 HGCMFunctionParameter cbData; /* OUT uint32_t */ 337 /** Optional flags; unused at the moment. */ 338 HGCMFunctionParameter uFlags; /* OUT uint32_t */ 339 /** File creation mode. */ 289 340 HGCMFunctionParameter fMode; /* OUT uint32_t */ 290 } VBOXDNDHGSENDFILEMSG; 341 /** Total size (in bytes). */ 342 HGCMFunctionParameter cbTotal; /* OUT uint64_t */ 343 344 } VBOXDNDHGSENDFILEHDRMSG; 345 346 /** 347 * HG: File data (chunk) event. 348 * 349 * Used by: 350 * HOST_DND_HG_SND_FILE 351 */ 352 typedef struct VBOXDNDHGSENDFILEDATAMSG 353 { 354 VBoxGuestHGCMCallInfo hdr; 355 356 union 357 { 358 struct 359 { 360 HGCMFunctionParameter pvName; /* OUT ptr */ 361 HGCMFunctionParameter cbName; /* OUT uint32_t */ 362 HGCMFunctionParameter pvData; /* OUT ptr */ 363 HGCMFunctionParameter cbData; /* OUT uint32_t */ 364 HGCMFunctionParameter fMode; /* OUT uint32_t */ 365 } v1; 366 struct 367 { 368 /** Note: pvName is now part of the VBOXDNDHGSENDFILEHDRMSG message. */ 369 /** Note: cbName is now part of the VBOXDNDHGSENDFILEHDRMSG message. */ 370 HGCMFunctionParameter uContext; /* OUT uint32_t */ 371 HGCMFunctionParameter pvData; /* OUT ptr */ 372 HGCMFunctionParameter cbData; /* OUT uint32_t */ 373 /** Note: fMode is now part of the VBOXDNDHGSENDFILEHDRMSG message. */ 374 } v2; 375 } u; 376 377 } VBOXDNDHGSENDFILEDATAMSG; 291 378 292 379 typedef struct VBOXDNDGHREQPENDINGMSG … … 322 409 */ 323 410 411 /** 412 * The returned command the host wants to 413 * run on the guest. 414 * 415 * Used by: 416 * GUEST_DND_GET_NEXT_HOST_MSG 417 */ 324 418 typedef struct VBOXDNDNEXTMSGMSG 325 419 { 326 420 VBoxGuestHGCMCallInfo hdr; 327 421 328 /**329 * The returned command the host wants to330 * run on the guest.331 *332 * Used by:333 * GUEST_DND_GET_NEXT_HOST_MSG334 */335 422 HGCMFunctionParameter msg; /* OUT uint32_t */ 336 423 /** Number of parameters the message needs. */ … … 342 429 } VBOXDNDNEXTMSGMSG; 343 430 431 /** 432 * Connection request. Used to tell the DnD protocol 433 * version to the (host) service. 434 * 435 * Used by: 436 * GUEST_DND_CONNECT 437 */ 438 typedef struct VBOXDNDCONNECTPMSG 439 { 440 VBoxGuestHGCMCallInfo hdr; 441 442 /** Protocol version to use. */ 443 HGCMFunctionParameter uProtocol; /* OUT uint32_t */ 444 /** Connection flags. Optional. */ 445 HGCMFunctionParameter uFlags; /* OUT uint32_t */ 446 447 } VBOXDNDCONNECTPMSG; 448 449 /** 450 * HG Acknowledge Operation event. 451 * 452 * Used by: 453 * GUEST_DND_HG_ACK_OP 454 */ 344 455 typedef struct VBOXDNDHGACKOPMSG 345 456 { 346 457 VBoxGuestHGCMCallInfo hdr; 347 458 348 /**349 * HG Acknowledge Operation event.350 *351 * Used by:352 * GUEST_DND_HG_ACK_OP353 */354 459 HGCMFunctionParameter uAction; /* OUT uint32_t */ 355 460 } VBOXDNDHGACKOPMSG; 356 461 462 /** 463 * HG request for data event. 464 * 465 * Used by: 466 * GUEST_DND_HG_REQ_DATA 467 */ 357 468 typedef struct VBOXDNDHGREQDATAMSG 358 469 { 359 470 VBoxGuestHGCMCallInfo hdr; 360 471 361 /**362 * HG request for data event.363 *364 * Used by:365 * GUEST_DND_HG_REQ_DATA366 */367 472 HGCMFunctionParameter pFormat; /* OUT ptr */ 368 473 } VBOXDNDHGREQDATAMSG; 369 474 475 typedef struct VBOXDNDHGEVTPROGRESSMSG 476 { 477 VBoxGuestHGCMCallInfo hdr; 478 479 HGCMFunctionParameter uStatus; 480 HGCMFunctionParameter uPercent; 481 HGCMFunctionParameter rc; 482 } VBOXDNDHGEVTPROGRESSMSG; 483 484 /** 485 * GH Acknowledge Pending event. 486 * 487 * Used by: 488 * GUEST_DND_GH_ACK_PENDING 489 */ 370 490 typedef struct VBOXDNDGHACKPENDINGMSG 371 491 { 372 492 VBoxGuestHGCMCallInfo hdr; 373 493 374 /**375 * GH Acknowledge Pending event.376 *377 * Used by:378 * GUEST_DND_GH_ACK_PENDING379 */380 494 HGCMFunctionParameter uDefAction; /* OUT uint32_t */ 381 495 HGCMFunctionParameter uAllActions; /* OUT uint32_t */ … … 383 497 } VBOXDNDGHACKPENDINGMSG; 384 498 499 /** 500 * GH Send Data event. 501 * 502 * Used by: 503 * GUEST_DND_GH_SND_DATA 504 */ 385 505 typedef struct VBOXDNDGHSENDDATAMSG 386 506 { 387 507 VBoxGuestHGCMCallInfo hdr; 388 508 389 /**390 * GH Send Data event.391 *392 * Used by:393 * GUEST_DND_GH_SND_DATA394 */395 509 HGCMFunctionParameter pvData; /* OUT ptr */ 396 510 /** Total bytes to send. This can be more than … … 400 514 } VBOXDNDGHSENDDATAMSG; 401 515 516 /** 517 * GH Directory event. 518 * 519 * Used by: 520 * GUEST_DND_GH_SND_DIR 521 */ 402 522 typedef struct VBOXDNDGHSENDDIRMSG 403 523 { 404 524 VBoxGuestHGCMCallInfo hdr; 405 525 406 /**407 * GH Directory event.408 *409 * Used by:410 * GUEST_DND_HG_SND_DIR411 */412 526 HGCMFunctionParameter pvName; /* OUT ptr */ 413 527 HGCMFunctionParameter cbName; /* OUT uint32_t */ … … 415 529 } VBOXDNDGHSENDDIRMSG; 416 530 417 typedef struct VBOXDNDGHSENDFILEMSG 418 { 419 VBoxGuestHGCMCallInfo hdr; 420 421 /** 422 * GH File event. 423 * 424 * Used by: 425 * GUEST_DND_HG_SND_FILE 426 */ 427 HGCMFunctionParameter pvName; /* OUT ptr */ 428 HGCMFunctionParameter cbName; /* OUT uint32_t */ 429 HGCMFunctionParameter pvData; /* OUT ptr */ 430 HGCMFunctionParameter cbData; /* OUT uint32_t */ 431 HGCMFunctionParameter fMode; /* OUT uint32_t */ 432 } VBOXDNDGHSENDFILEMSG; 433 531 /** 532 * GH File header event. 533 * Note: Only for protocol version 2 and up. 534 * 535 * Used by: 536 * HOST_DND_GH_SND_FILE_HDR 537 */ 538 typedef struct VBOXDNDHGSENDFILEHDRMSG VBOXDNDGHSENDFILEHDRMSG; 539 540 /** 541 * GH File data event. 542 * 543 * Used by: 544 * GUEST_DND_HG_SND_FILE_DATA 545 */ 546 typedef struct VBOXDNDGHSENDFILEDATAMSG 547 { 548 VBoxGuestHGCMCallInfo hdr; 549 550 union 551 { 552 /* Note: Protocol v1 sends the file name + file mode 553 * every time a file data chunk is being sent. */ 554 struct 555 { 556 HGCMFunctionParameter pvName; /* OUT ptr */ 557 HGCMFunctionParameter cbName; /* OUT uint32_t */ 558 HGCMFunctionParameter fMode; /* OUT uint32_t */ 559 HGCMFunctionParameter pvData; /* OUT ptr */ 560 HGCMFunctionParameter cbData; /* OUT uint32_t */ 561 } v1; 562 struct 563 { 564 /** Context ID. Unused at the moment. */ 565 HGCMFunctionParameter uContext; /* OUT uint32_t */ 566 HGCMFunctionParameter pvData; /* OUT ptr */ 567 HGCMFunctionParameter cbData; /* OUT uint32_t */ 568 } v2; 569 } u; 570 571 } VBOXDNDGHSENDFILEDATAMSG; 572 573 /** 574 * GH Error event. 575 * 576 * Used by: 577 * GUEST_DND_GH_EVT_ERROR 578 */ 434 579 typedef struct VBOXDNDGHEVTERRORMSG 435 580 { 436 581 VBoxGuestHGCMCallInfo hdr; 437 582 438 /** 439 * GH Error event. 440 * 441 * Used by: 442 * GUEST_DND_GH_EVT_ERROR 443 */ 444 HGCMFunctionParameter uRC; /* OUT uint32_t */ 583 HGCMFunctionParameter rc; /* OUT uint32_t */ 445 584 } VBOXDNDGHEVTERRORMSG; 446 585 … … 452 591 enum 453 592 { 454 CB_MAGIC_DND_HG_ACK_OP = 0xe2100b93, 455 CB_MAGIC_DND_HG_REQ_DATA = 0x5cb3faf9, 456 CB_MAGIC_DND_HG_EVT_PROGRESS = 0x8c8a6956, 457 CB_MAGIC_DND_GH_ACK_PENDING = 0xbe975a14, 458 CB_MAGIC_DND_GH_SND_DATA = 0x4eb61bff, 459 CB_MAGIC_DND_GH_SND_DIR = 0x411ca754, 460 CB_MAGIC_DND_GH_SND_FILE = 0x65e35eaf, 461 CB_MAGIC_DND_GH_EVT_ERROR = 0x117a87c4 593 CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG = 0x19820126, 594 CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG_DATA = 0x19850630, 595 CB_MAGIC_DND_HG_ACK_OP = 0xe2100b93, 596 CB_MAGIC_DND_HG_REQ_DATA = 0x5cb3faf9, 597 CB_MAGIC_DND_HG_EVT_PROGRESS = 0x8c8a6956, 598 CB_MAGIC_DND_GH_ACK_PENDING = 0xbe975a14, 599 CB_MAGIC_DND_GH_SND_DATA = 0x4eb61bff, 600 CB_MAGIC_DND_GH_SND_DIR = 0x411ca754, 601 CB_MAGIC_DND_GH_SND_FILE_HDR = 0x65e35eaf, 602 CB_MAGIC_DND_GH_SND_FILE_DATA = 0x19840804, 603 CB_MAGIC_DND_GH_EVT_ERROR = 0x117a87c4 462 604 }; 463 605 … … 468 610 /** Context ID to identify callback data. */ 469 611 uint32_t u32ContextID; 470 } VBOXDNDCBHEADERDATA; 471 typedef VBOXDNDCBHEADERDATA *PVBOXDNDCBHEADERDATA; 612 } VBOXDNDCBHEADERDATA, *PVBOXDNDCBHEADERDATA; 613 614 typedef struct VBOXDNDCBHGGETNEXTHOSTMSG 615 { 616 /** Callback data header. */ 617 VBOXDNDCBHEADERDATA hdr; 618 uint32_t uMsg; 619 uint32_t cParms; 620 } VBOXDNDCBHGGETNEXTHOSTMSG, *PVBOXDNDCBHGGETNEXTHOSTMSG; 621 622 typedef struct VBOXDNDCBHGGETNEXTHOSTMSGDATA 623 { 624 /** Callback data header. */ 625 VBOXDNDCBHEADERDATA hdr; 626 uint32_t uMsg; 627 uint32_t cParms; 628 PVBOXHGCMSVCPARM paParms; 629 } VBOXDNDCBHGGETNEXTHOSTMSGDATA, *PVBOXDNDCBHGGETNEXTHOSTMSGDATA; 472 630 473 631 typedef struct VBOXDNDCBHGACKOPDATA … … 476 634 VBOXDNDCBHEADERDATA hdr; 477 635 uint32_t uAction; 478 } VBOXDNDCBHGACKOPDATA; 479 typedef VBOXDNDCBHGACKOPDATA *PVBOXDNDCBHGACKOPDATA; 636 } VBOXDNDCBHGACKOPDATA, *PVBOXDNDCBHGACKOPDATA; 480 637 481 638 typedef struct VBOXDNDCBHGREQDATADATA … … 484 641 VBOXDNDCBHEADERDATA hdr; 485 642 char *pszFormat; 486 } VBOXDNDCBHGREQDATADATA; 487 typedef VBOXDNDCBHGREQDATADATA *PVBOXDNDCBHGREQDATADATA; 643 } VBOXDNDCBHGREQDATADATA, *PVBOXDNDCBHGREQDATADATA; 488 644 489 645 typedef struct VBOXDNDCBHGEVTPROGRESSDATA … … 492 648 VBOXDNDCBHEADERDATA hdr; 493 649 uint32_t uPercentage; 494 uint32_t uState; 495 int rc; 496 } VBOXDNDCBHGEVTPROGRESSDATA; 497 typedef VBOXDNDCBHGEVTPROGRESSDATA *PVBOXDNDCBHGEVTPROGRESSDATA; 650 uint32_t uStatus; 651 uint32_t rc; 652 } VBOXDNDCBHGEVTPROGRESSDATA, *PVBOXDNDCBHGEVTPROGRESSDATA; 498 653 499 654 typedef struct VBOXDNDCBGHACKPENDINGDATA … … 504 659 uint32_t uAllActions; 505 660 char *pszFormat; 506 } VBOXDNDCBGHACKPENDINGDATA; 507 typedef VBOXDNDCBGHACKPENDINGDATA *PVBOXDNDCBGHACKPENDINGDATA; 661 } VBOXDNDCBGHACKPENDINGDATA, *PVBOXDNDCBGHACKPENDINGDATA; 508 662 509 663 typedef struct VBOXDNDCBSNDDATADATA … … 516 670 * with every message because the size can change. */ 517 671 uint32_t cbTotalSize; 518 } VBOXDNDCBSNDDATADATA; 519 typedef VBOXDNDCBSNDDATADATA *PVBOXDNDCBSNDDATADATA; 672 } VBOXDNDCBSNDDATADATA, *PVBOXDNDCBSNDDATADATA; 520 673 521 674 typedef struct VBOXDNDCBSNDDIRDATA … … 526 679 uint32_t cbPath; 527 680 uint32_t fMode; 528 } VBOXDNDCBSNDDIRDATA; 529 typedef VBOXDNDCBSNDDIRDATA *PVBOXDNDCBSNDDIRDATA; 530 531 typedef struct VBOXDNDCBSNDFILEDATA 532 { 533 /** Callback data header. */ 534 VBOXDNDCBHEADERDATA hdr; 681 } VBOXDNDCBSNDDIRDATA, *PVBOXDNDCBSNDDIRDATA; 682 683 /* Note: Only for protocol version 2 and up (>= VBox 5.0). */ 684 typedef struct VBOXDNDCBSNDFILEHDRDATA 685 { 686 /** Callback data header. */ 687 VBOXDNDCBHEADERDATA hdr; 688 /** File path (name). */ 535 689 char *pszFilePath; 690 /** Size (in bytes) of file path. */ 536 691 uint32_t cbFilePath; 692 /** Total size (in bytes) of this file. */ 693 uint64_t cbSize; 694 /** File (creation) mode. */ 537 695 uint32_t fMode; 538 void *pvData; 539 uint32_t cbData; 540 } VBOXDNDCBSNDFILEDATA; 541 typedef VBOXDNDCBSNDFILEDATA *PVBOXDNDCBSNDFILEDATA; 696 /** Additional flags. Not used at the moment. */ 697 uint32_t fFlags; 698 } VBOXDNDCBSNDFILEHDRDATA, *PVBOXDNDCBSNDFILEHDRDATA; 699 700 typedef struct VBOXDNDCBSNDFILEDATADATA 701 { 702 /** Callback data header. */ 703 VBOXDNDCBHEADERDATA hdr; 704 /** Current file data chunk. */ 705 void *pvData; 706 /** Size (in bytes) of current data chunk. */ 707 uint32_t cbData; 708 union 709 { 710 struct 711 { 712 /** File path (name). */ 713 char *pszFilePath; 714 /** Size (in bytes) of file path. */ 715 uint32_t cbFilePath; 716 /** File (creation) mode. */ 717 uint32_t fMode; 718 } v1; 719 /* Note: Protocol version 2 has the file attributes (name, size, 720 mode, ...) in the VBOXDNDCBSNDFILEHDRDATA structure. */ 721 } u; 722 } VBOXDNDCBSNDFILEDATADATA, *PVBOXDNDCBSNDFILEDATADATA; 542 723 543 724 typedef struct VBOXDNDCBEVTERRORDATA … … 546 727 VBOXDNDCBHEADERDATA hdr; 547 728 int32_t rc; 548 } VBOXDNDCBEVTERRORDATA; 549 typedef VBOXDNDCBEVTERRORDATA *PVBOXDNDCBEVTERRORDATA; 729 } VBOXDNDCBEVTERRORDATA, *PVBOXDNDCBEVTERRORDATA; 550 730 551 731 } /* namespace DragAndDropSvc */ -
trunk/include/VBox/HostServices/Service.h
r55353 r55422 4 4 5 5 /* 6 * Copyright (C) 2011-201 2Oracle Corporation6 * Copyright (C) 2011-2015 Oracle Corporation 7 7 * 8 8 * This file is part of VirtualBox Open Source Edition (OSE), as … … 50 50 initData(uMsg, cParms, aParms); 51 51 } 52 ~Message() 52 53 virtual ~Message(void) 53 54 { 54 55 cleanup(); … … 90 91 return VINF_SUCCESS; 91 92 } 93 92 94 int getParmU64Info(uint32_t iParm, uint64_t *pu64Info) const 93 95 { … … 100 102 return VINF_SUCCESS; 101 103 } 104 102 105 int getParmPtrInfo(uint32_t iParm, void **ppvAddr, uint32_t *pcSize) const 103 106 { … … 113 116 } 114 117 115 int copyParms(uint32_t cParms, PVBOXHGCMSVCPARM paParmsSrc, PVBOXHGCMSVCPARM paParmsDst) const118 static int copyParms(uint32_t cParms, PVBOXHGCMSVCPARM paParmsSrc, PVBOXHGCMSVCPARM paParmsDst) 116 119 { 117 120 return copyParmsInternal(cParms, paParmsSrc, paParmsDst, false /* fCreatePtrs */); … … 119 122 120 123 private: 124 121 125 uint32_t m_uMsg; 122 126 uint32_t m_cParms; … … 149 153 } 150 154 151 int copyParmsInternal(uint32_t cParms, PVBOXHGCMSVCPARM paParmsSrc, PVBOXHGCMSVCPARM paParmsDst, bool fCreatePtrs) const155 static int copyParmsInternal(uint32_t cParms, PVBOXHGCMSVCPARM paParmsSrc, PVBOXHGCMSVCPARM paParmsDst, bool fCreatePtrs) 152 156 { 153 157 int rc = VINF_SUCCESS; … … 188 192 /* No, but we have to check if there is enough room. */ 189 193 if (paParmsDst[i].u.pointer.size < paParmsSrc[i].u.pointer.size) 194 { 190 195 rc = VERR_BUFFER_OVERFLOW; 196 break; 197 } 191 198 } 199 192 200 if ( paParmsDst[i].u.pointer.addr 193 201 && paParmsSrc[i].u.pointer.size > 0 194 202 && paParmsDst[i].u.pointer.size > 0) 203 { 195 204 memcpy(paParmsDst[i].u.pointer.addr, 196 205 paParmsSrc[i].u.pointer.addr, 197 206 RT_MIN(paParmsDst[i].u.pointer.size, paParmsSrc[i].u.pointer.size)); 207 } 198 208 break; 199 209 } … … 236 246 { 237 247 public: 238 Client(uint32_t uClientId, VBOXHGCMCALLHANDLE hHandle, uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[]) 248 Client(uint32_t uClientId, VBOXHGCMCALLHANDLE hHandle = NULL, 249 uint32_t uMsg = 0, uint32_t cParms = 0, VBOXHGCMSVCPARM aParms[] = NULL) 239 250 : m_uClientId(uClientId) 251 , m_uProtocol(0) 240 252 , m_hHandle(hHandle) 241 253 , m_uMsg(uMsg) … … 243 255 , m_paParms(aParms) {} 244 256 245 VBOXHGCMCALLHANDLE handle() const { return m_hHandle; } 246 uint32_t message() const { return m_uMsg; } 247 uint32_t clientId() const { return m_uClientId; } 257 public: 258 259 VBOXHGCMCALLHANDLE handle(void) const { return m_hHandle; } 260 uint32_t message(void) const { return m_uMsg; } 261 uint32_t clientId(void) const { return m_uClientId; } 262 uint32_t protocol(void) const { return m_uProtocol; } 263 264 public: 265 266 int setProtocol(uint32_t uProtocol) { m_uProtocol = uProtocol; return VINF_SUCCESS; } 267 268 public: 248 269 249 270 int addMessageInfo(uint32_t uMsg, uint32_t cParms) … … 259 280 int addMessageInfo(const Message *pMessage) 260 281 { 282 AssertPtrReturn(pMessage, VERR_INVALID_POINTER); 261 283 if (m_cParms != 3) 262 284 return VERR_INVALID_PARAMETER; … … 269 291 int addMessage(const Message *pMessage) 270 292 { 293 AssertPtrReturn(pMessage, VERR_INVALID_POINTER); 271 294 return pMessage->getData(m_uMsg, m_cParms, m_paParms); 272 295 } 296 273 297 private: 298 274 299 uint32_t m_uClientId; 300 /** Optional protocol version the client uses. */ 301 uint32_t m_uProtocol; 275 302 VBOXHGCMCALLHANDLE m_hHandle; 276 303 uint32_t m_uMsg; -
trunk/include/VBox/VBoxGuestLib.h
r54010 r55422 4 4 5 5 /* 6 * Copyright (C) 2006-201 4Oracle Corporation6 * Copyright (C) 2006-2015 Oracle Corporation 7 7 * 8 8 * This file is part of VirtualBox Open Source Edition (OSE), as … … 606 606 * Structure containing the context required for 607 607 * either retrieving or sending a HGCM guest control 608 * command from or to the host.608 * commands from or to the host. 609 609 * 610 610 * Note: Do not change parameter order without also … … 713 713 /** @name Drag and Drop 714 714 * @{ */ 715 /** 716 * Structure containing the context required for 717 * either retrieving or sending a HGCM guest drag'n drop 718 * commands from or to the host. 719 * 720 * Note: Do not change parameter order without also 721 * adapting all structure initializers. 722 */ 723 typedef struct VBGLR3GUESTDNDCMDCTX 724 { 725 /** @todo This struct could be handy if we want to implement 726 * a second communication channel, e.g. via TCP/IP. 727 * Use a union for the HGCM stuff then. */ 728 729 /** IN: HGCM client ID to use for communication. */ 730 uint32_t uClientID; 731 /** IN: Protocol version to use. */ 732 uint32_t uProtocol; 733 /** OUT: Number of parameters retrieved. */ 734 uint32_t uNumParms; 735 } VBGLR3GUESTDNDCMDCTX, *PVBGLR3GUESTDNDCMDCTX; 736 715 737 typedef struct VBGLR3DNDHGCMEVENT 716 738 { 717 uint32_t uType; /** The event type this struct contains */718 uint32_t uScreenId; /** Screen ID this request belongs to */719 char *pszFormats; /** Format list (\r\n separated) */720 uint32_t cbFormats; /** Size of pszFormats (\0 included) */739 uint32_t uType; /** The event type this struct contains. */ 740 uint32_t uScreenId; /** Screen ID this request belongs to. */ 741 char *pszFormats; /** Format list (\r\n separated). */ 742 uint32_t cbFormats; /** Size of pszFormats (\0 included). */ 721 743 union 722 744 { 723 745 struct 724 746 { 725 uint32_t uXpos; /** X position of guest screen */726 uint32_t uYpos; /** Y position of guest screen */727 uint32_t uDefAction; /** Proposed DnD action */728 uint32_t uAllActions; /** Allowed DnD actions */729 } a; /** Values used in init, move and drop event type*/747 uint32_t uXpos; /** X position of guest screen. */ 748 uint32_t uYpos; /** Y position of guest screen. */ 749 uint32_t uDefAction; /** Proposed DnD action. */ 750 uint32_t uAllActions; /** Allowed DnD actions. */ 751 } a; /** Values used in init, move and drop event type. */ 730 752 struct 731 753 { 732 void *pvData; /** Data request */733 size_t cbData; /** Size of pvData */734 } b; /** Values used in drop data event type*/735 } u;754 void *pvData; /** Data request. */ 755 size_t cbData; /** Size of pvData. */ 756 } b; /** Values used in drop data event type. */ 757 } u; 736 758 } VBGLR3DNDHGCMEVENT; 737 759 typedef VBGLR3DNDHGCMEVENT *PVBGLR3DNDHGCMEVENT; 738 760 typedef const PVBGLR3DNDHGCMEVENT CPVBGLR3DNDHGCMEVENT; 739 VBGLR3DECL(int) VbglR3DnDConnect(uint32_t *pu32ClientId); 740 VBGLR3DECL(int) VbglR3DnDDisconnect(uint32_t u32ClientId); 741 742 VBGLR3DECL(int) VbglR3DnDProcessNextMessage(uint32_t u32ClientId, CPVBGLR3DNDHGCMEVENT pEvent); 743 744 VBGLR3DECL(int) VbglR3DnDHGAcknowledgeOperation(uint32_t u32ClientId, uint32_t uAction); 745 VBGLR3DECL(int) VbglR3DnDHGRequestData(uint32_t u32ClientId, const char* pcszFormat); 761 VBGLR3DECL(int) VbglR3DnDConnect(PVBGLR3GUESTDNDCMDCTX pCtx); 762 VBGLR3DECL(int) VbglR3DnDDisconnect(PVBGLR3GUESTDNDCMDCTX pCtx); 763 764 VBGLR3DECL(int) VbglR3DnDProcessNextMessage(PVBGLR3GUESTDNDCMDCTX pCtx, CPVBGLR3DNDHGCMEVENT pEvent); 765 766 VBGLR3DECL(int) VbglR3DnDHGAcknowledgeOperation(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uAction); 767 VBGLR3DECL(int) VbglR3DnDHGRequestData(PVBGLR3GUESTDNDCMDCTX pCtx, const char* pcszFormat); 768 VBGLR3DECL(int) VbglR3DnDHGSetProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr); 746 769 # ifdef VBOX_WITH_DRAG_AND_DROP_GH 747 VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending( uint32_t u32ClientId, uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats);748 VBGLR3DECL(int) VbglR3DnDGHSendData( uint32_t u32ClientId, const char *pszFormat, void *pvData, uint32_t cbData);749 VBGLR3DECL(int) VbglR3DnDGHSendError( uint32_t u32ClientId, int rcOp);770 VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats); 771 VBGLR3DECL(int) VbglR3DnDGHSendData(PVBGLR3GUESTDNDCMDCTX pCtx, const char *pszFormat, void *pvData, uint32_t cbData); 772 VBGLR3DECL(int) VbglR3DnDGHSendError(PVBGLR3GUESTDNDCMDCTX pCtx, int rcOp); 750 773 # endif /* VBOX_WITH_DRAG_AND_DROP_GH */ 751 774 /** @} */ -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.cpp
r55180 r55422 5 5 6 6 /* 7 * Copyright (C) 2013-201 4Oracle Corporation7 * Copyright (C) 2013-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 72 72 pDropTarget(NULL), 73 73 #endif 74 mClientID(UINT32_MAX),75 74 mMode(Unknown), 76 75 mState(Uninitialized) … … 707 706 int VBoxDnDWnd::OnCreate(void) 708 707 { 709 int rc = VbglR3DnDConnect(&m ClientID);708 int rc = VbglR3DnDConnect(&mDnDCtx); 710 709 if (RT_FAILURE(rc)) 711 710 { … … 714 713 } 715 714 716 LogFlowThisFunc(("Client ID=%RU32, rc=%Rrc\n", m ClientID, rc));715 LogFlowThisFunc(("Client ID=%RU32, rc=%Rrc\n", mDnDCtx.uClientID, rc)); 717 716 return rc; 718 717 } … … 723 722 void VBoxDnDWnd::OnDestroy(void) 724 723 { 725 VbglR3DnDDisconnect( mClientID);724 VbglR3DnDDisconnect(&mDnDCtx); 726 725 LogFlowThisFuncLeave(); 727 726 } … … 853 852 if (RT_SUCCESS(rc)) 854 853 { 855 rc = VbglR3DnDHGAcknowledgeOperation( mClientID, uActionNotify);854 rc = VbglR3DnDHGAcknowledgeOperation(&mDnDCtx, uActionNotify); 856 855 if (RT_FAILURE(rc)) 857 856 LogFlowThisFunc(("Acknowledging operation failed with rc=%Rrc\n", rc)); … … 923 922 { 924 923 LogRel(("DnD: Requesting data as '%s' ...\n", mFormatRequested.c_str())); 925 rc = VbglR3DnDHGRequestData( mClientID, mFormatRequested.c_str());924 rc = VbglR3DnDHGRequestData(&mDnDCtx, mFormatRequested.c_str()); 926 925 if (RT_FAILURE(rc)) 927 926 LogFlowThisFunc(("Requesting data failed with rc=%Rrc\n", rc)); 928 927 } 928 929 929 } 930 930 else /* Should never happen. */ … … 976 976 977 977 /** 978 * Handles actions required when the host wants to cancel an action978 * Handles actions required when the host wants to cancel the current 979 979 * host -> guest operation. 980 980 * … … 1122 1122 uAllActions = uDefAction; 1123 1123 1124 rc = VbglR3DnDGHAcknowledgePending( mClientID,1124 rc = VbglR3DnDGHAcknowledgePending(&mDnDCtx, 1125 1125 uDefAction, uAllActions, strFormats.c_str()); 1126 1126 if (RT_FAILURE(rc)) … … 1199 1199 Assert(cbData); 1200 1200 1201 rc = VbglR3DnDGHSendData(mClientID, pszFormat, pvData, cbData); 1202 LogFlowFunc(("Sent pvData=0x%p, cbData=%RU32, rc=%Rrc\n", 1203 pvData, cbData, rc)); 1204 1205 1201 rc = VbglR3DnDGHSendData(&mDnDCtx, pszFormat, pvData, cbData); 1202 LogFlowFunc(("Sent pvData=0x%p, cbData=%RU32, rc=%Rrc\n", pvData, cbData, rc)); 1206 1203 } 1207 1204 } … … 1231 1228 { 1232 1229 static int s_iBitchedAboutFailedDnDMessages = 0; 1233 if (s_iBitchedAboutFailedDnDMessages++ < 10)1230 if (s_iBitchedAboutFailedDnDMessages++ < 32) 1234 1231 { 1235 1232 DWORD dwErr = GetLastError(); … … 1619 1616 AssertPtr(pCtx); 1620 1617 1621 uint32_t uClientID; 1622 int rc = VbglR3DnDConnect(&uClientID); 1618 VBGLR3GUESTDNDCMDCTX ctxDnD; /* The thread's own DnD context. */ 1619 1620 int rc = VbglR3DnDConnect(&ctxDnD); 1623 1621 if (RT_FAILURE(rc)) 1624 1622 return rc; … … 1642 1640 /* Note: pEvent will be free'd by the consumer later. */ 1643 1641 1644 rc = VbglR3DnDProcessNextMessage( uClientID, &pEvent->Event);1642 rc = VbglR3DnDProcessNextMessage(&ctxDnD, &pEvent->Event); 1645 1643 LogFlowFunc(("VbglR3DnDProcessNextMessage returned uType=%RU32, rc=%Rrc\n", 1646 1644 pEvent->Event.uType, rc)); … … 1649 1647 break; 1650 1648 1651 if (RT_SUCCESS(rc)) 1649 if ( RT_SUCCESS(rc) 1650 || rc == VERR_CANCELLED) 1652 1651 { 1653 1652 cMsgSkippedInvalid = 0; /* Reset skipped messages count. */ … … 1658 1657 if (RT_FAILURE(rc2)) 1659 1658 LogFlowFunc(("Processing event failed with rc=%Rrc\n", rc2)); 1660 }1661 else if (rc == VERR_CANCELLED)1662 {1663 int rc2 = pWnd->OnHgCancel();1664 if (RT_FAILURE(rc2))1665 LogFlowFunc(("Cancelling failed with rc=%Rrc\n", rc2));1666 break;1667 1659 } 1668 1660 else … … 1679 1671 } 1680 1672 1681 int rc2 = VbglR3DnDGHSendError( uClientID, rc);1673 int rc2 = VbglR3DnDGHSendError(&ctxDnD, rc); 1682 1674 AssertRC(rc2); 1683 1675 } … … 1693 1685 LogFlowFunc(("Shutting down ...\n")); 1694 1686 1695 VbglR3DnDDisconnect( uClientID);1687 VbglR3DnDDisconnect(&ctxDnD); 1696 1688 1697 1689 LogFlowFuncLeaveRC(rc); -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnD.h
r51675 r55422 5 5 6 6 /* 7 * Copyright (C) 2013-201 4Oracle Corporation7 * Copyright (C) 2013-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 121 121 protected: 122 122 123 LONG mRefCount;124 VBoxDnDWnd *mpWndParent;125 uint32_t mClientID;126 DWORD mdwCurEffect;127 uint32_t muCurAction;123 LONG mRefCount; 124 VBoxDnDWnd *mpWndParent; 125 VBGLR3GUESTDNDCMDCTX mDnDCtx; 126 DWORD mdwCurEffect; 127 uint32_t muCurAction; 128 128 }; 129 129 … … 162 162 protected: 163 163 164 LONG mRefCount;165 VBoxDnDWnd *mpWndParent;166 uint32_t mClientID;167 DWORD mdwCurEffect;164 LONG mRefCount; 165 VBoxDnDWnd *mpWndParent; 166 VBGLR3GUESTDNDCMDCTX mDnDCtx; 167 DWORD mdwCurEffect; 168 168 /** Copy of the data object's FORMATETC struct. 169 * Note: We don't keep the pointer of the 170 * DVTARGETDEVICE here! */ 171 FORMATETC mFormatEtc; 172 RTCString mFormats; 173 void *mpvData; 174 uint32_t mcbData; 175 RTSEMEVENT hEventDrop; 176 int mDroppedRc; 169 * Note: We don't keep the pointer of the DVTARGETDEVICE here! */ 170 FORMATETC mFormatEtc; 171 RTCString mFormats; 172 void *mpvData; 173 uint32_t mcbData; 174 RTSEMEVENT hEventDrop; 175 int mDroppedRc; 177 176 }; 178 177 … … 392 391 #endif /* RT_OS_WINDOWS */ 393 392 394 /** The window's own HGCM client ID. */395 uint32_t mClientID;393 /** The window's own DnD context. */ 394 VBGLR3GUESTDNDCMDCTX mDnDCtx; 396 395 /** The current operation mode. */ 397 396 Mode mMode; -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnDDropSource.cpp
r51476 r55422 5 5 6 6 /* 7 * Copyright (C) 2013-201 4Oracle Corporation7 * Copyright (C) 2013-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 35 35 : mRefCount(1), 36 36 mpWndParent(pParent), 37 mClientID(UINT32_MAX),38 37 mdwCurEffect(0), 39 38 muCurAction(DND_IGNORE_ACTION) 40 39 { 41 int rc = VbglR3DnDConnect(&m ClientID);40 int rc = VbglR3DnDConnect(&mDnDCtx); 42 41 43 42 LogFlowFunc(("rc=%Rrc\n", rc)); … … 46 45 VBoxDnDDropSource::~VBoxDnDDropSource(void) 47 46 { 48 int rc = VbglR3DnDDisconnect( mClientID);47 int rc = VbglR3DnDDisconnect(&mDnDCtx); 49 48 50 49 LogFlowFunc(("rc=%Rrc, mRefCount=%RI32\n", rc, mRefCount)); -
trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnDDropTarget.cpp
r55180 r55422 5 5 6 6 /* 7 * Copyright (C) 2014 Oracle Corporation7 * Copyright (C) 2014-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 37 37 : mRefCount(1), 38 38 mpWndParent(pParent), 39 mClientID(UINT32_MAX),40 39 mdwCurEffect(0), 41 40 mpvData(NULL), … … 43 42 hEventDrop(NIL_RTSEMEVENT) 44 43 { 45 int rc = VbglR3DnDConnect(&m ClientID);44 int rc = VbglR3DnDConnect(&mDnDCtx); 46 45 if (RT_SUCCESS(rc)) 47 46 rc = RTSemEventCreate(&hEventDrop); 48 47 49 LogFlowFunc(("clientID=%RU32, rc=%Rrc\n", 50 mClientID, rc)); 48 LogFlowFunc(("clientID=%RU32, rc=%Rrc\n", mDnDCtx.uClientID, rc)); 51 49 } 52 50 … … 55 53 reset(); 56 54 57 int rc2 = VbglR3DnDDisconnect( mClientID);55 int rc2 = VbglR3DnDDisconnect(&mDnDCtx); 58 56 AssertRC(rc2); 59 57 rc2 = RTSemEventDestroy(hEventDrop); -
trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp
r54858 r55422 5 5 6 6 /* 7 * Copyright (C) 2011-201 3Oracle Corporation7 * Copyright (C) 2011-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 44 44 #include <VBox/log.h> 45 45 46 #include <VBox/VBoxGuestLib.h> 46 47 #include <VBox/GuestHost/DragAndDrop.h> 47 48 #include <VBox/HostServices/DragAndDropSvc.h> … … 63 64 ******************************************************************************/ 64 65 65 static int vbglR3DnDQueryNextHostMessageType(uint32_t uClientId, uint32_t *puMsg, uint32_t *pcParms, bool fWait) 66 { 66 static int vbglR3DnDQueryNextHostMessageType(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t *puMsg, uint32_t *pcParms, bool fWait) 67 { 68 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 67 69 AssertPtrReturn(puMsg, VERR_INVALID_POINTER); 68 70 AssertPtrReturn(pcParms, VERR_INVALID_POINTER); … … 71 73 RT_ZERO(Msg); 72 74 Msg.hdr.result = VERR_WRONG_ORDER; 73 Msg.hdr.u32ClientID = uClientId;75 Msg.hdr.u32ClientID = pCtx->uClientID; 74 76 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG; 75 77 Msg.hdr.cParms = 3; … … 77 79 Msg.msg.SetUInt32(0); 78 80 Msg.num_parms.SetUInt32(0); 79 Msg.block.SetUInt32(fWait );81 Msg.block.SetUInt32(fWait ? 1 : 0); 80 82 81 83 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg)); … … 93 95 } 94 96 95 static int vbglR3DnDHGProcessActionMessage( uint32_t uClientId,97 static int vbglR3DnDHGProcessActionMessage(PVBGLR3GUESTDNDCMDCTX pCtx, 96 98 uint32_t uMsg, 97 99 uint32_t *puScreenId, … … 104 106 uint32_t *pcbFormatsRecv) 105 107 { 108 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 106 109 AssertPtrReturn(puScreenId, VERR_INVALID_POINTER); 107 110 AssertPtrReturn(puX, VERR_INVALID_POINTER); … … 115 118 DragAndDropSvc::VBOXDNDHGACTIONMSG Msg; 116 119 RT_ZERO(Msg); 117 Msg.hdr.u32ClientID = uClientId;120 Msg.hdr.u32ClientID = pCtx->uClientID; 118 121 Msg.hdr.u32Function = uMsg; 119 122 Msg.hdr.cParms = 7; … … 147 150 } 148 151 149 static int vbglR3DnDHGProcessLeaveMessage(uint32_t uClientId) 150 { 152 static int vbglR3DnDHGProcessLeaveMessage(PVBGLR3GUESTDNDCMDCTX pCtx) 153 { 154 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 155 151 156 DragAndDropSvc::VBOXDNDHGLEAVEMSG Msg; 152 157 RT_ZERO(Msg); 153 Msg.hdr.u32ClientID = uClientId;158 Msg.hdr.u32ClientID = pCtx->uClientID; 154 159 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_LEAVE; 155 160 Msg.hdr.cParms = 0; … … 162 167 } 163 168 164 static int vbglR3DnDHGProcessCancelMessage(uint32_t uClientId) 165 { 169 static int vbglR3DnDHGProcessCancelMessage(PVBGLR3GUESTDNDCMDCTX pCtx) 170 { 171 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 172 166 173 DragAndDropSvc::VBOXDNDHGCANCELMSG Msg; 167 174 RT_ZERO(Msg); 168 Msg.hdr.u32ClientID = uClientId;175 Msg.hdr.u32ClientID = pCtx->uClientID; 169 176 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_CANCEL; 170 177 Msg.hdr.cParms = 0; … … 177 184 } 178 185 179 static int vbglR3DnDHGProcessSendDirMessage( uint32_t uClientId,186 static int vbglR3DnDHGProcessSendDirMessage(PVBGLR3GUESTDNDCMDCTX pCtx, 180 187 char *pszDirname, 181 188 uint32_t cbDirname, … … 183 190 uint32_t *pfMode) 184 191 { 192 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 185 193 AssertPtrReturn(pszDirname, VERR_INVALID_POINTER); 186 194 AssertReturn(cbDirname, VERR_INVALID_PARAMETER); … … 190 198 DragAndDropSvc::VBOXDNDHGSENDDIRMSG Msg; 191 199 RT_ZERO(Msg); 192 Msg.hdr.u32ClientID = uClientId;200 Msg.hdr.u32ClientID = pCtx->uClientID; 193 201 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_DIR; 194 202 Msg.hdr.cParms = 3; … … 214 222 } 215 223 216 static int vbglR3DnDHGProcessSendFileMessage( uint32_t uClientId,224 static int vbglR3DnDHGProcessSendFileMessage(PVBGLR3GUESTDNDCMDCTX pCtx, 217 225 char *pszFilename, 218 226 uint32_t cbFilename, … … 223 231 uint32_t *pfMode) 224 232 { 233 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 225 234 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER); 226 235 AssertReturn(cbFilename, VERR_INVALID_PARAMETER); … … 231 240 AssertPtrReturn(pfMode, VERR_INVALID_POINTER); 232 241 233 DragAndDropSvc::VBOXDNDHGSENDFILEMSG Msg; 234 RT_ZERO(Msg); 235 Msg.hdr.u32ClientID = uClientId; 236 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_FILE; 237 Msg.hdr.cParms = 5; 238 239 Msg.pvName.SetPtr(pszFilename, cbFilename); 240 Msg.cbName.SetUInt32(0); 241 Msg.pvData.SetPtr(pvData, cbData); 242 Msg.cbData.SetUInt32(0); 243 Msg.fMode.SetUInt32(0); 242 DragAndDropSvc::VBOXDNDHGSENDFILEDATAMSG Msg; 243 RT_ZERO(Msg); 244 Msg.hdr.u32ClientID = pCtx->uClientID; 245 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA; 246 247 if (pCtx->uProtocol <= 1) 248 { 249 Msg.u.v1.pvName.SetPtr(pszFilename, cbFilename); 250 Msg.u.v1.cbName.SetUInt32(0); 251 Msg.u.v1.pvData.SetPtr(pvData, cbData); 252 Msg.u.v1.cbData.SetUInt32(0); 253 Msg.u.v1.fMode.SetUInt32(0); 254 255 Msg.hdr.cParms = 5; 256 } 257 else 258 { 259 Msg.u.v2.pvData.SetPtr(pvData, cbData); 260 Msg.u.v2.cbData.SetUInt32(0); 261 262 Msg.hdr.cParms = 2; 263 } 244 264 245 265 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg)); … … 249 269 if (RT_SUCCESS(rc)) 250 270 { 251 rc = Msg.cbName.GetUInt32(pcbFilenameRecv); AssertRC(rc); 252 rc = Msg.cbData.GetUInt32(pcbDataRecv); AssertRC(rc); 253 rc = Msg.fMode.GetUInt32(pfMode); AssertRC(rc); 254 255 AssertReturn(cbFilename >= *pcbFilenameRecv, VERR_TOO_MUCH_DATA); 256 AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA); 257 } 258 } 259 260 return rc; 261 } 262 263 static int vbglR3DnDHGProcessURIMessages(uint32_t uClientId, 271 if (pCtx->uProtocol <= 1) 272 { 273 rc = Msg.u.v1.cbName.GetUInt32(pcbFilenameRecv); AssertRC(rc); 274 rc = Msg.u.v1.cbData.GetUInt32(pcbDataRecv); AssertRC(rc); 275 rc = Msg.u.v1.fMode.GetUInt32(pfMode); AssertRC(rc); 276 277 AssertReturn(cbFilename >= *pcbFilenameRecv, VERR_TOO_MUCH_DATA); 278 AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA); 279 } 280 else 281 { 282 rc = Msg.u.v2.cbData.GetUInt32(pcbDataRecv); AssertRC(rc); 283 AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA); 284 } 285 } 286 } 287 288 return rc; 289 } 290 291 static int vbglR3DnDHGProcessSendFileHdrMessage(PVBGLR3GUESTDNDCMDCTX pCtx, 292 char *pszFilename, 293 uint32_t cbFilename, 294 uint32_t *puFlags, 295 uint32_t *pfMode, 296 uint64_t *pcbTotal) 297 { 298 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 299 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER); 300 AssertReturn(cbFilename, VERR_INVALID_PARAMETER); 301 AssertPtrReturn(puFlags, VERR_INVALID_POINTER); 302 AssertPtrReturn(pfMode, VERR_INVALID_POINTER); 303 AssertReturn(pcbTotal, VERR_INVALID_POINTER); 304 305 DragAndDropSvc::VBOXDNDHGSENDFILEHDRMSG Msg; 306 RT_ZERO(Msg); 307 Msg.hdr.u32ClientID = pCtx->uClientID; 308 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR; 309 310 int rc; 311 312 if (pCtx->uProtocol <= 1) 313 { 314 rc = VERR_NOT_SUPPORTED; 315 } 316 else 317 { 318 Msg.pvName.SetPtr(pszFilename, cbFilename); 319 Msg.cbName.SetUInt32(0); 320 Msg.uContext.SetUInt32(0); /** @todo Not used yet. */ 321 Msg.uFlags.SetUInt32(0); 322 Msg.fMode.SetUInt32(0); 323 Msg.cbTotal.SetUInt64(0); 324 325 Msg.hdr.cParms = 6; 326 327 rc = VINF_SUCCESS; 328 } 329 330 if (RT_SUCCESS(rc)) 331 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg)); 332 if (RT_SUCCESS(rc)) 333 { 334 rc = Msg.hdr.result; 335 if (RT_SUCCESS(rc)) 336 { 337 /** @todo Get context ID. */ 338 rc = Msg.uFlags.GetUInt32(puFlags); AssertRC(rc); 339 rc = Msg.fMode.GetUInt32(pfMode); AssertRC(rc); 340 rc = Msg.cbTotal.GetUInt64(pcbTotal); AssertRC(rc); 341 } 342 } 343 344 return rc; 345 } 346 347 static int vbglR3DnDHGProcessURIMessages(PVBGLR3GUESTDNDCMDCTX pCtx, 264 348 uint32_t *puScreenId, 265 349 char *pszFormat, … … 270 354 size_t *pcbDataRecv) 271 355 { 272 AssertPtrReturn(ppvData, VERR_INVALID_POINTER); 273 AssertPtrReturn(cbData, VERR_INVALID_PARAMETER); 356 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 357 AssertPtrReturn(ppvData, VERR_INVALID_POINTER); 358 AssertPtrReturn(cbData, VERR_INVALID_PARAMETER); 274 359 AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER); 275 360 276 if (!*pcbDataRecv) 277 return VERR_INVALID_PARAMETER; 361 void *pvData = *ppvData; 362 uint32_t cbDataRecv = 0; 363 uint64_t cbDataToRead = *pcbDataRecv; 364 uint64_t cbDataWritten = 0; 365 366 int rc = VINF_SUCCESS; 278 367 279 368 /* Allocate temp buffer. */ … … 281 370 void *pvTmpData = RTMemAlloc(cbTmpData); 282 371 if (!pvTmpData) 283 r eturnVERR_NO_MEMORY;372 rc = VERR_NO_MEMORY; 284 373 285 374 /* Create and query the (unique) drop target directory. */ 286 char pszDropDir[RTPATH_MAX]; 287 int rc = DnDDirCreateDroppedFiles(pszDropDir, sizeof(pszDropDir)); 375 DnDURIList lstURI; 376 char szDropDir[RTPATH_MAX]; 377 if (RT_SUCCESS(rc)) 378 rc = DnDDirCreateDroppedFiles(szDropDir, sizeof(szDropDir)); 379 288 380 if (RT_FAILURE(rc)) 289 381 { 290 RTMemFree(pvTmpData); 382 int rc2 = VbglR3DnDHGSetProgress(pCtx, DragAndDropSvc::DND_PROGRESS_ERROR, 100 /* Percent */, rc); 383 AssertRC(rc2); 384 385 if (pvTmpData) 386 RTMemFree(pvTmpData); 291 387 return rc; 292 388 } 293 389 294 /* Patch the old drop data with the new drop directory, so the drop target 295 * can find the files. */ 296 DnDURIList lstURI; 297 rc = lstURI.RootFromURIData(*ppvData, *pcbDataRecv, 298 0 /* fFlags */); 299 if (RT_SUCCESS(rc)) 300 { 301 /* Cleanup the old data and write the new data back to the event. */ 302 RTMemFree(*ppvData); 303 304 RTCString strData = lstURI.RootToString(pszDropDir); 305 *ppvData = RTStrDupN(strData.c_str(), strData.length()); 306 *pcbDataRecv = strData.length() + 1; 307 } 308 309 /* Lists for holding created files & directories 310 * in the case of a rollback. */ 390 /* Lists for holding created files & directories in the case of a rollback. */ 311 391 RTCList<RTCString> guestDirList; 312 392 RTCList<RTCString> guestFileList; 313 393 314 char szPathName[RTPATH_MAX]; 394 DnDURIObject objFile(DnDURIObject::File); 395 396 char szPathName[RTPATH_MAX] = { 0 }; 315 397 uint32_t cbPathName = 0; 316 317 bool fLoop = RT_SUCCESS(rc); /* No error occurred yet? */ 318 while (fLoop) 398 uint32_t fFlags = 0; 399 uint32_t fMode = 0; 400 401 while (RT_SUCCESS(rc)) 319 402 { 320 403 uint32_t uNextMsg; 321 404 uint32_t cNextParms; 322 rc = vbglR3DnDQueryNextHostMessageType(uClientId, &uNextMsg, &cNextParms, false /* fWait */); 405 LogFlowFunc(("Waiting for new message ...\n")); 406 rc = vbglR3DnDQueryNextHostMessageType(pCtx, &uNextMsg, &cNextParms, false /* fWait */); 323 407 if (RT_SUCCESS(rc)) 324 408 { 409 LogFlowFunc(("uNextMsg=%RU32, cNextParms=%RU32\n", uNextMsg, cNextParms)); 410 325 411 switch (uNextMsg) 326 412 { 327 413 case DragAndDropSvc::HOST_DND_HG_SND_DIR: 328 414 { 329 uint32_t fMode = 0; 330 rc = vbglR3DnDHGProcessSendDirMessage(uClientId, 415 rc = vbglR3DnDHGProcessSendDirMessage(pCtx, 331 416 szPathName, 332 417 sizeof(szPathName), 333 418 &cbPathName, 334 419 &fMode); 335 #ifdef DEBUG_andy336 420 LogFlowFunc(("HOST_DND_HG_SND_DIR pszPathName=%s, cbPathName=%RU32, fMode=0x%x, rc=%Rrc\n", 337 421 szPathName, cbPathName, fMode, rc)); 338 #endif 422 423 /* 424 * Important: HOST_DND_HG_SND_DIR sends the path (directory) name without URI specifications, that is, 425 * only the pure name! To match the accounting though we have to translate the pure name into 426 * a valid URI again. 427 * 428 ** @todo Fix this URI translation! 429 */ 430 RTCString strPath(szPathName); 339 431 if (RT_SUCCESS(rc)) 340 rc = DnDPathSanitize(szPathName, sizeof(szPathName));432 rc = objFile.RebaseURIPath(strPath); 341 433 if (RT_SUCCESS(rc)) 342 434 { 343 char *pszNewDir = RTPathJoinA(pszDropDir, szPathName); 435 rc = DnDPathSanitize(szPathName, sizeof(szPathName)); 436 char *pszNewDir = RTPathJoinA(szDropDir, szPathName); 344 437 if (pszNewDir) 345 438 { 346 439 rc = RTDirCreate(pszNewDir, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRWXU, 0); 347 if (!guestDirList.contains(pszNewDir))348 guestDirList.append(pszNewDir);349 350 440 RTStrFree(pszNewDir); 351 441 } 352 442 else 353 443 rc = VERR_NO_MEMORY; 444 445 if (RT_SUCCESS(rc)) 446 { 447 if (!guestDirList.contains(strPath)) 448 guestDirList.append(strPath); 449 } 354 450 } 355 451 break; 356 452 } 357 case DragAndDropSvc::HOST_DND_HG_SND_FILE :453 case DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR: 358 454 { 359 uint32_t cbDataRecv; 360 uint32_t fMode = 0; 361 rc = vbglR3DnDHGProcessSendFileMessage(uClientId, 455 rc = vbglR3DnDHGProcessSendFileHdrMessage(pCtx, 456 szPathName, 457 sizeof(szPathName), 458 &fFlags, 459 &fMode, 460 &cbDataToRead); 461 LogFlowFunc(("HOST_DND_HG_SND_FILE_HDR pszPathName=%s, fFlags=0x%x, fMode=0x%x, cbDataToRead=%RU64, rc=%Rrc\n", 462 szPathName, fFlags, fMode, cbDataToRead, rc)); 463 464 cbDataWritten = 0; 465 break; 466 } 467 case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA: 468 { 469 rc = vbglR3DnDHGProcessSendFileMessage(pCtx, 362 470 szPathName, 363 471 sizeof(szPathName), … … 367 475 &cbDataRecv, 368 476 &fMode); 369 #ifdef DEBUG_andy370 477 LogFlowFunc(("HOST_DND_HG_SND_FILE pszPathName=%s, cbPathName=%RU32, pvData=0x%p, cbDataRecv=%RU32, fMode=0x%x, rc=%Rrc\n", 371 478 szPathName, cbPathName, pvTmpData, cbDataRecv, fMode, rc)); 372 #endif 479 480 /* 481 * Important: HOST_DND_HG_SND_FILE sends the path (directory) name without URI specifications, that is, 482 * only the pure name! To match the accounting though we have to translate the pure name into 483 * a valid URI again. 484 * 485 ** @todo Fix this URI translation! 486 */ 487 RTCString strPath(szPathName); 373 488 if (RT_SUCCESS(rc)) 374 rc = DnDPathSanitize(szPathName, sizeof(szPathName));489 rc = objFile.RebaseURIPath(strPath); 375 490 if (RT_SUCCESS(rc)) 376 491 { 377 char *pszPathAbs = RTPathJoinA(pszDropDir, szPathName);378 if ( pszPathAbs)492 rc = DnDPathSanitize(szPathName, sizeof(szPathName)); 493 if (RT_SUCCESS(rc)) 379 494 { 380 RTFILE hFile; 381 /** @todo r=andy Keep the file open and locked during the actual file transfer. Otherwise this will 382 * create all sorts of funny races because we don't know if the guest has 383 * modified the file in between the file data send calls. */ 384 rc = RTFileOpen(&hFile, pszPathAbs, 385 RTFILE_O_WRITE | RTFILE_O_APPEND | RTFILE_O_DENY_ALL | RTFILE_O_OPEN_CREATE); 386 if (RT_SUCCESS(rc)) 495 char *pszPathAbs = RTPathJoinA(szDropDir, szPathName); 496 if (pszPathAbs) 387 497 { 388 /** @todo r=andy Not very safe to assume that we were last appending to the current file. */ 389 rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, NULL); 498 RTFILE hFile; 499 /** @todo r=andy Keep the file open and locked during the actual file transfer. Otherwise this will 500 * create all sorts of funny races because we don't know if the guest has 501 * modified the file in between the file data send calls. 502 * 503 * See HOST_DND_HG_SND_FILE_HDR for a good place to do this. */ 504 rc = RTFileOpen(&hFile, pszPathAbs, 505 RTFILE_O_WRITE | RTFILE_O_APPEND | RTFILE_O_DENY_ALL | RTFILE_O_OPEN_CREATE); 390 506 if (RT_SUCCESS(rc)) 391 507 { 392 rc = RTFileWrite(hFile, pvTmpData, cbDataRecv, 0); 393 /* Valid UNIX mode? */ 394 if ( RT_SUCCESS(rc) 395 && (fMode & RTFS_UNIX_MASK)) 396 rc = RTFileSetMode(hFile, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR); 508 /** @todo r=andy Not very safe to assume that we were last appending to the current file. */ 509 rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, NULL); 510 if (RT_SUCCESS(rc)) 511 { 512 rc = RTFileWrite(hFile, pvTmpData, cbDataRecv, 0); 513 if (RT_SUCCESS(rc)) 514 { 515 if (fMode & RTFS_UNIX_MASK) /* Valid UNIX mode? */ 516 rc = RTFileSetMode(hFile, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR); 517 518 cbDataWritten += cbDataRecv; 519 Assert(cbDataWritten <= cbDataToRead); 520 } 521 } 522 523 RTFileClose(hFile); 524 525 if (!guestFileList.contains(pszPathAbs)) /* Add the file to (rollback) list. */ 526 guestFileList.append(pszPathAbs); 397 527 } 398 399 RTFileClose(hFile); 400 401 if (!guestFileList.contains(pszPathAbs)) 402 guestFileList.append(pszPathAbs); 528 else 529 LogFlowFunc(("Opening file failed with rc=%Rrc\n", rc)); 530 531 RTStrFree(pszPathAbs); 403 532 } 404 #ifdef DEBUG405 533 else 406 LogFlowFunc(("Opening file failed with rc=%Rrc\n", rc)); 407 #endif 408 RTStrFree(pszPathAbs); 534 rc = VERR_NO_MEMORY; 409 535 } 410 else411 rc = VERR_NO_MEMORY;412 536 } 413 537 break; … … 415 539 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL: 416 540 { 417 rc = vbglR3DnDHGProcessCancelMessage( uClientId);541 rc = vbglR3DnDHGProcessCancelMessage(pCtx); 418 542 if (RT_SUCCESS(rc)) 419 543 rc = VERR_CANCELLED; 420 /* Break out of the loop. */544 break; 421 545 } 422 546 default: 423 fLoop = false; 547 LogFlowFunc(("Message %RU32 not supported\n", uNextMsg)); 548 rc = VERR_NOT_SUPPORTED; 424 549 break; 425 550 } 551 552 #if 0 553 if (pCtx->uProtocol >= XXX) 554 { 555 /* 556 * Send the progress back to the host. 557 */ 558 uint32_t uStatus; 559 int guestRc; 560 uint8_t uPercent; 561 switch (rc) 562 { 563 case VINF_SUCCESS: 564 { 565 if (!cbData) 566 cbData = 1; 567 uPercent = cbDataWritten * 100 / (cbDataToRead ? cbDataToRead : 1); 568 uStatus = uPercent >= 100 ? 569 DragAndDropSvc::DND_PROGRESS_COMPLETE : DragAndDropSvc::DND_PROGRESS_RUNNING; 570 guestRc = VINF_SUCCESS; 571 break; 572 } 573 574 case VERR_CANCELLED: 575 { 576 uStatus = DragAndDropSvc::DND_PROGRESS_CANCELLED; 577 uPercent = 100; 578 guestRc = VINF_SUCCESS; 579 break; 580 } 581 582 default: 583 { 584 uStatus = DragAndDropSvc::DND_PROGRESS_ERROR; 585 uPercent = 100; 586 guestRc = rc; 587 break; 588 } 589 } 590 591 int rc2 = VbglR3DnDHGSetProgress(pCtx, uStatus, uPercent, guestRc); 592 LogFlowFunc(("cbDataWritten=%RU64 / cbDataToRead=%RU64 => %RU8%% (uStatus=%ld, %Rrc), rc=%Rrc\n", cbDataWritten, cbDataToRead, 593 uPercent, uStatus, guestRc, rc2)); 594 if (RT_SUCCESS(rc)) 595 rc = rc2; 596 597 /* All data transferred? */ 598 if ( RT_SUCCESS(rc) 599 && uPercent == 100) 600 { 601 rc = VINF_EOF; 602 break; 603 } 604 } 605 #endif 426 606 } 427 607 else 428 608 { 609 /* All URI data processed? */ 429 610 if (rc == VERR_NO_DATA) 430 611 rc = VINF_SUCCESS; … … 437 618 } /* while */ 438 619 620 LogFlowFunc(("Loop ended with %Rrc\n", rc)); 621 439 622 if (pvTmpData) 440 623 RTMemFree(pvTmpData); 441 624 442 /* Cleanup on failure or if the user has canceled . */625 /* Cleanup on failure or if the user has canceled the operation. */ 443 626 if (RT_FAILURE(rc)) 444 627 { 445 /* Remove any stuff created. */ 628 LogFlowFunc(("Rolling back ...\n")); 629 630 /* Rollback by removing any stuff created. */ 446 631 for (size_t i = 0; i < guestFileList.size(); ++i) 447 632 RTFileDelete(guestFileList.at(i).c_str()); 448 633 for (size_t i = 0; i < guestDirList.size(); ++i) 449 634 RTDirRemove(guestDirList.at(i).c_str()); 450 RTDirRemove(pszDropDir); 451 452 LogFlowFunc(("Failed with rc=%Rrc\n", rc)); 453 } 454 455 return rc; 456 } 457 458 static int vbglR3DnDHGProcessDataMessageInternal(uint32_t uClientId, 635 } 636 else 637 { 638 /* 639 * Patch the old drop data with the new drop directory, so the drop target can find the files. 640 */ 641 rc = lstURI.RootFromURIData(pvData, cbDataToRead, 0 /* fFlags */); 642 if (RT_SUCCESS(rc)) 643 { 644 /* Cleanup the old data and write the new data back to the event. */ 645 RTMemFree(pvData); 646 647 RTCString strData = lstURI.RootToString(szDropDir); 648 LogFlowFunc(("cbDataToRead: %zu -> %zu\n", cbDataToRead, strData.length() + 1)); 649 650 pvData = RTStrDupN(strData.c_str(), strData.length()); 651 cbDataToRead = strData.length() + 1; 652 } 653 654 if (RT_SUCCESS(rc)) 655 { 656 *ppvData = pvData; 657 *pcbDataRecv = cbDataToRead; 658 } 659 660 /** @todo Compare the URI list with the dirs/files we really transferred. */ 661 } 662 663 /* Try removing the (empty) drop directory in any case. */ 664 int rc2 = RTDirRemove(szDropDir); 665 if (RT_FAILURE(rc2)) 666 LogFunc(("Warning: Unable to remove drop directory \"%s\": %Rrc\n", szDropDir, rc2)); 667 668 LogFlowFuncLeaveRC(rc); 669 return rc; 670 } 671 672 static int vbglR3DnDHGProcessDataMessageInternal(PVBGLR3GUESTDNDCMDCTX pCtx, 459 673 uint32_t *puScreenId, 460 674 char *pszFormat, … … 465 679 uint32_t *pcbDataTotal) 466 680 { 681 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 467 682 AssertPtrReturn(puScreenId, VERR_INVALID_POINTER); 468 683 AssertPtrReturn(pszFormat, VERR_INVALID_POINTER); … … 475 690 DragAndDropSvc::VBOXDNDHGSENDDATAMSG Msg; 476 691 RT_ZERO(Msg); 477 Msg.hdr.u32ClientID = uClientId;692 Msg.hdr.u32ClientID = pCtx->uClientID; 478 693 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_DATA; 479 694 Msg.hdr.cParms = 5; … … 493 708 { 494 709 rc = Msg.uScreenId.GetUInt32(puScreenId); AssertRC(rc); 710 711 /* 712 * In case of VERR_BUFFER_OVERFLOW get the data sizes required 713 * for the format + data blocks. 714 */ 495 715 rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc); 496 rc = Msg.cbData.GetUInt32(pcbDataTotal); 716 rc = Msg.cbData.GetUInt32(pcbDataTotal); AssertRC(rc); 497 717 498 718 AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA); 499 AssertReturn(cbData >= *pcbDataTotal, 500 } 501 } 502 503 return rc; 504 } 505 506 static int vbglR3DnDHGProcessMoreDataMessageInternal( uint32_t uClientId,719 AssertReturn(cbData >= *pcbDataTotal, VERR_TOO_MUCH_DATA); 720 } 721 } 722 723 return rc; 724 } 725 726 static int vbglR3DnDHGProcessMoreDataMessageInternal(PVBGLR3GUESTDNDCMDCTX pCtx, 507 727 void *pvData, 508 728 uint32_t cbData, 509 uint32_t *pcbDataRecv) 510 { 511 AssertPtrReturn(pvData, VERR_INVALID_POINTER); 512 AssertReturn(cbData, VERR_INVALID_PARAMETER); 513 AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER); 729 uint32_t *pcbDataTotal) 730 { 731 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 732 AssertPtrReturn(pvData, VERR_INVALID_POINTER); 733 AssertReturn(cbData, VERR_INVALID_PARAMETER); 734 AssertPtrReturn(pcbDataTotal, VERR_INVALID_POINTER); 514 735 515 736 DragAndDropSvc::VBOXDNDHGSENDMOREDATAMSG Msg; 516 737 RT_ZERO(Msg); 517 Msg.hdr.u32ClientID = uClientId;738 Msg.hdr.u32ClientID = pCtx->uClientID; 518 739 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA; 519 740 Msg.hdr.cParms = 2; … … 529 750 || rc == VERR_BUFFER_OVERFLOW) 530 751 { 531 rc = Msg.cbData.GetUInt32(pcbData Recv); AssertRC(rc);532 AssertReturn(cbData >= *pcbData Recv, VERR_TOO_MUCH_DATA);533 } 534 } 535 return rc; 536 } 537 538 static int vbglR3DnDHGProcessSendDataMessageLoop( uint32_t uClientId,752 rc = Msg.cbData.GetUInt32(pcbDataTotal); AssertRC(rc); 753 AssertReturn(cbData >= *pcbDataTotal, VERR_TOO_MUCH_DATA); 754 } 755 } 756 return rc; 757 } 758 759 static int vbglR3DnDHGProcessSendDataMessageLoop(PVBGLR3GUESTDNDCMDCTX pCtx, 539 760 uint32_t *puScreenId, 540 761 char *pszFormat, … … 545 766 size_t *pcbDataRecv) 546 767 { 547 uint32_t cbDataRecv = 0; 548 int rc = vbglR3DnDHGProcessDataMessageInternal(uClientId, 768 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 769 AssertPtrReturn(puScreenId, VERR_INVALID_POINTER); 770 AssertPtrReturn(pszFormat, VERR_INVALID_POINTER); 771 AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER); 772 AssertPtrReturn(ppvData, VERR_INVALID_POINTER); 773 /* pcbDataRecv is optional. */ 774 775 uint32_t cbDataReq = 0; 776 int rc = vbglR3DnDHGProcessDataMessageInternal(pCtx, 549 777 puScreenId, 550 778 pszFormat, … … 553 781 *ppvData, 554 782 cbData, 555 &cbDataRecv); 556 uint32_t cbAllDataRecv = cbDataRecv; 783 &cbDataReq); 784 uint32_t cbDataTotal = cbDataReq; 785 void *pvData = *ppvData; 786 787 LogFlowFunc(("HOST_DND_HG_SND_DATA cbDataReq=%RU32, rc=%Rrc\n", cbDataTotal, rc)); 788 557 789 while (rc == VERR_BUFFER_OVERFLOW) 558 790 { 559 791 uint32_t uNextMsg; 560 792 uint32_t cNextParms; 561 rc = vbglR3DnDQueryNextHostMessageType( uClientId, &uNextMsg, &cNextParms, false);793 rc = vbglR3DnDQueryNextHostMessageType(pCtx, &uNextMsg, &cNextParms, false); 562 794 if (RT_SUCCESS(rc)) 563 795 { … … 566 798 case DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA: 567 799 { 568 *ppvData = RTMemRealloc(*ppvData, cbAllDataRecv + cbData); 569 if (!*ppvData) 800 /** @todo r=andy Don't use reallocate here; can go wrong with *really* big URI lists. 801 * Instead send as many URI entries as possible per chunk and add those entries 802 * to our to-process list for immediata processing. Repeat the step after processing then. */ 803 LogFlowFunc(("HOST_DND_HG_SND_MORE_DATA cbDataTotal: %RU32 -> %RU32\n", cbDataReq, cbDataReq + cbData)); 804 pvData = RTMemRealloc(*ppvData, cbDataTotal + cbData); 805 if (!pvData) 570 806 { 571 807 rc = VERR_NO_MEMORY; 572 808 break; 573 809 } 574 rc = vbglR3DnDHGProcessMoreDataMessageInternal( uClientId,575 &((char *)*ppvData)[cbAllDataRecv],810 rc = vbglR3DnDHGProcessMoreDataMessageInternal(pCtx, 811 &((char *)pvData)[cbDataTotal], 576 812 cbData, 577 &cbDataRe cv);578 cb AllDataRecv += cbDataRecv;813 &cbDataReq); 814 cbDataTotal += cbDataReq; 579 815 break; 580 816 } … … 582 818 default: 583 819 { 584 rc = vbglR3DnDHGProcessCancelMessage( uClientId);820 rc = vbglR3DnDHGProcessCancelMessage(pCtx); 585 821 if (RT_SUCCESS(rc)) 586 822 rc = VERR_CANCELLED; … … 590 826 } 591 827 } 592 if (RT_SUCCESS(rc)) 593 *pcbDataRecv = cbAllDataRecv; 594 595 return rc; 596 } 597 598 static int vbglR3DnDHGProcessSendDataMessage(uint32_t uClientId, 828 829 if (RT_SUCCESS(rc)) 830 { 831 *ppvData = pvData; 832 if (pcbDataRecv) 833 *pcbDataRecv = cbDataTotal; 834 } 835 836 return rc; 837 } 838 839 static int vbglR3DnDHGProcessSendDataMessage(PVBGLR3GUESTDNDCMDCTX pCtx, 599 840 uint32_t *puScreenId, 600 841 char *pszFormat, … … 605 846 size_t *pcbDataRecv) 606 847 { 607 int rc = vbglR3DnDHGProcessSendDataMessageLoop(uClientId, 848 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 849 AssertPtrReturn(puScreenId, VERR_INVALID_POINTER); 850 AssertPtrReturn(pszFormat, VERR_INVALID_POINTER); 851 AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER); 852 AssertPtrReturn(ppvData, VERR_INVALID_POINTER); 853 854 int rc = vbglR3DnDHGProcessSendDataMessageLoop(pCtx, 608 855 puScreenId, 609 856 pszFormat, … … 623 870 AssertPtr(pcbFormatRecv); 624 871 if (DnDMIMEHasFileURLs(pszFormat, *pcbFormatRecv)) 625 rc = vbglR3DnDHGProcessURIMessages( uClientId,872 rc = vbglR3DnDHGProcessURIMessages(pCtx, 626 873 puScreenId, 627 874 pszFormat, … … 631 878 cbData, 632 879 pcbDataRecv); 633 } 634 635 return rc; 636 } 637 638 static int vbglR3DnDGHProcessRequestPendingMessage(uint32_t uClientId, 880 else 881 rc = VERR_NOT_SUPPORTED; 882 } 883 884 return rc; 885 } 886 887 static int vbglR3DnDGHProcessRequestPendingMessage(PVBGLR3GUESTDNDCMDCTX pCtx, 639 888 uint32_t *puScreenId) 640 889 { 890 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 641 891 AssertPtrReturn(puScreenId, VERR_INVALID_POINTER); 642 892 643 893 DragAndDropSvc::VBOXDNDGHREQPENDINGMSG Msg; 644 894 RT_ZERO(Msg); 645 Msg.hdr.u32ClientID = uClientId;895 Msg.hdr.u32ClientID = pCtx->uClientID; 646 896 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_REQ_PENDING; 647 897 Msg.hdr.cParms = 1; … … 662 912 } 663 913 664 static int vbglR3DnDGHProcessDroppedMessage( uint32_t uClientId,914 static int vbglR3DnDGHProcessDroppedMessage(PVBGLR3GUESTDNDCMDCTX pCtx, 665 915 char *pszFormat, 666 916 uint32_t cbFormat, … … 668 918 uint32_t *puAction) 669 919 { 920 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 670 921 AssertPtrReturn(pszFormat, VERR_INVALID_POINTER); 671 922 AssertReturn(cbFormat, VERR_INVALID_PARAMETER); … … 675 926 DragAndDropSvc::VBOXDNDGHDROPPEDMSG Msg; 676 927 RT_ZERO(Msg); 677 Msg.hdr.u32ClientID = uClientId;928 Msg.hdr.u32ClientID = pCtx->uClientID; 678 929 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_EVT_DROPPED; 679 930 Msg.hdr.cParms = 3; … … 703 954 ******************************************************************************/ 704 955 705 VBGLR3DECL(int) VbglR3DnDConnect( uint32_t *pu32ClientId)706 { 707 AssertPtrReturn(p u32ClientId, VERR_INVALID_POINTER);956 VBGLR3DECL(int) VbglR3DnDConnect(PVBGLR3GUESTDNDCMDCTX pCtx) 957 { 958 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 708 959 709 960 /* Initialize header */ … … 712 963 Info.result = VERR_WRONG_ORDER; 713 964 Info.u32ClientID = UINT32_MAX; /* try make valgrind shut up. */ 714 /* Initialize parameter */715 965 Info.Loc.type = VMMDevHGCMLoc_LocalHost_Existing; 966 716 967 int rc = RTStrCopy(Info.Loc.u.host.achName, sizeof(Info.Loc.u.host.achName), "VBoxDragAndDropSvc"); 717 if (RT_FAILURE(rc)) return rc; 718 /* Do request */ 968 if (RT_FAILURE(rc)) 969 return rc; 970 719 971 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CONNECT, &Info, sizeof(Info)); 720 972 if (RT_SUCCESS(rc)) 721 973 { 722 974 rc = Info.result; 723 if (RT_SUCCESS(rc)) 724 *pu32ClientId = Info.u32ClientID; 725 } 726 if (rc == VERR_HGCM_SERVICE_NOT_FOUND) 727 rc = VINF_PERMISSION_DENIED; 728 return rc; 729 } 730 731 VBGLR3DECL(int) VbglR3DnDDisconnect(uint32_t u32ClientId) 732 { 975 if (rc == VERR_HGCM_SERVICE_NOT_FOUND) 976 rc = VINF_PERMISSION_DENIED; 977 978 /* Set the protocol version to use. */ 979 pCtx->uProtocol = 2; 980 981 Assert(Info.u32ClientID); 982 pCtx->uClientID = Info.u32ClientID; 983 } 984 985 if (RT_SUCCESS(rc)) 986 { 987 /* 988 * Try sending the connect message to tell the protocol version to use. 989 * Note: This might fail when the Guest Additions run on an older VBox host (< VBox 5.0) which 990 * does not implement this command. 991 */ 992 DragAndDropSvc::VBOXDNDCONNECTPMSG Msg; 993 RT_ZERO(Msg); 994 Msg.hdr.result = VERR_WRONG_ORDER; 995 Msg.hdr.u32ClientID = pCtx->uClientID; 996 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_CONNECT; 997 Msg.hdr.cParms = 2; 998 999 Msg.uProtocol.SetUInt32(pCtx->uProtocol); 1000 Msg.uFlags.SetUInt32(0); /* Unused at the moment. */ 1001 1002 int rc2 = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg)); 1003 if (RT_SUCCESS(rc2)) 1004 rc2 = Msg.hdr.result; /* Not fatal. */ 1005 1006 LogFlowFunc(("Connection request ended with rc=%Rrc\n", rc2)); 1007 } 1008 1009 LogFlowFunc(("uClient=%RU32, uProtocol=%RU32, rc=%Rrc\n", pCtx->uClientID, pCtx->uProtocol, rc)); 1010 return rc; 1011 } 1012 1013 VBGLR3DECL(int) VbglR3DnDDisconnect(PVBGLR3GUESTDNDCMDCTX pCtx) 1014 { 1015 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 1016 733 1017 VBoxGuestHGCMDisconnectInfo Info; 734 1018 Info.result = VERR_WRONG_ORDER; 735 Info.u32ClientID = u32ClientId; 736 737 /* Do request */ 1019 Info.u32ClientID = pCtx->uClientID; 1020 738 1021 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_DISCONNECT, &Info, sizeof(Info)); 739 1022 if (RT_SUCCESS(rc)) … … 743 1026 } 744 1027 745 VBGLR3DECL(int) VbglR3DnDProcessNextMessage(uint32_t u32ClientId, CPVBGLR3DNDHGCMEVENT pEvent) 746 { 1028 VBGLR3DECL(int) VbglR3DnDProcessNextMessage(PVBGLR3GUESTDNDCMDCTX pCtx, CPVBGLR3DNDHGCMEVENT pEvent) 1029 { 1030 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 747 1031 AssertPtrReturn(pEvent, VERR_INVALID_POINTER); 748 1032 … … 751 1035 const uint32_t ccbFormats = _64K; 752 1036 const uint32_t ccbData = _64K; 753 int rc = vbglR3DnDQueryNextHostMessageType( u32ClientId, &uMsg, &uNumParms,1037 int rc = vbglR3DnDQueryNextHostMessageType(pCtx, &uMsg, &uNumParms, 754 1038 true /* fWait */); 755 1039 if (RT_SUCCESS(rc)) 756 1040 { 1041 pEvent->uType = uMsg; 1042 757 1043 switch(uMsg) 758 1044 { … … 761 1047 case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED: 762 1048 { 763 pEvent->uType = uMsg;764 1049 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats)); 765 1050 if (!pEvent->pszFormats) … … 767 1052 768 1053 if (RT_SUCCESS(rc)) 769 rc = vbglR3DnDHGProcessActionMessage( u32ClientId,1054 rc = vbglR3DnDHGProcessActionMessage(pCtx, 770 1055 uMsg, 771 1056 &pEvent->uScreenId, … … 781 1066 case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE: 782 1067 { 783 pEvent->uType = uMsg; 784 rc = vbglR3DnDHGProcessLeaveMessage(u32ClientId); 1068 rc = vbglR3DnDHGProcessLeaveMessage(pCtx); 785 1069 break; 786 1070 } 787 1071 case DragAndDropSvc::HOST_DND_HG_SND_DATA: 788 1072 { 789 pEvent->uType = uMsg;790 1073 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats)); 791 1074 if (!pEvent->pszFormats) … … 799 1082 RTMemFree(pEvent->pszFormats); 800 1083 pEvent->pszFormats = NULL; 1084 801 1085 rc = VERR_NO_MEMORY; 802 1086 } … … 804 1088 805 1089 if (RT_SUCCESS(rc)) 806 rc = vbglR3DnDHGProcessSendDataMessage( u32ClientId,1090 rc = vbglR3DnDHGProcessSendDataMessage(pCtx, 807 1091 &pEvent->uScreenId, 808 1092 pEvent->pszFormats, … … 816 1100 case DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA: 817 1101 case DragAndDropSvc::HOST_DND_HG_SND_DIR: 818 case DragAndDropSvc::HOST_DND_HG_SND_FILE :1102 case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA: 819 1103 { 820 pEvent->uType = uMsg; 821 822 /* All messages in this case are handled internally 1104 /* 1105 * All messages in this case are handled internally 823 1106 * by vbglR3DnDHGProcessSendDataMessage() and must 824 * be specified by a preceding HOST_DND_HG_SND_DATA call. */ 1107 * be specified by a preceding HOST_DND_HG_SND_DATA call. 1108 */ 825 1109 rc = VERR_WRONG_ORDER; 826 1110 break; … … 828 1112 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL: 829 1113 { 830 pEvent->uType = uMsg; 831 rc = vbglR3DnDHGProcessCancelMessage(u32ClientId); 1114 rc = vbglR3DnDHGProcessCancelMessage(pCtx); 832 1115 break; 833 1116 } … … 835 1118 case DragAndDropSvc::HOST_DND_GH_REQ_PENDING: 836 1119 { 837 pEvent->uType = uMsg; 838 rc = vbglR3DnDGHProcessRequestPendingMessage(u32ClientId, 839 &pEvent->uScreenId); 1120 rc = vbglR3DnDGHProcessRequestPendingMessage(pCtx, &pEvent->uScreenId); 840 1121 break; 841 1122 } 842 1123 case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED: 843 1124 { 844 pEvent->uType = uMsg;845 1125 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats)); 846 1126 if (!pEvent->pszFormats) … … 848 1128 849 1129 if (RT_SUCCESS(rc)) 850 rc = vbglR3DnDGHProcessDroppedMessage( u32ClientId,1130 rc = vbglR3DnDGHProcessDroppedMessage(pCtx, 851 1131 pEvent->pszFormats, 852 1132 ccbFormats, … … 858 1138 default: 859 1139 { 860 pEvent->uType = uMsg;861 862 1140 rc = VERR_NOT_SUPPORTED; 863 1141 break; … … 869 1147 } 870 1148 871 VBGLR3DECL(int) VbglR3DnDHGAcknowledgeOperation(uint32_t u32ClientId, uint32_t uAction) 872 { 1149 VBGLR3DECL(int) VbglR3DnDHGAcknowledgeOperation(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uAction) 1150 { 1151 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 1152 873 1153 DragAndDropSvc::VBOXDNDHGACKOPMSG Msg; 874 1154 RT_ZERO(Msg); 875 1155 Msg.hdr.result = VERR_WRONG_ORDER; 876 Msg.hdr.u32ClientID = u32ClientId;1156 Msg.hdr.u32ClientID = pCtx->uClientID; 877 1157 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_ACK_OP; 878 1158 Msg.hdr.cParms = 1; … … 887 1167 } 888 1168 889 VBGLR3DECL(int) VbglR3DnDHGRequestData(uint32_t u32ClientId, const char* pcszFormat) 890 { 891 AssertPtrReturn(pcszFormat, VERR_INVALID_PARAMETER); 1169 VBGLR3DECL(int) VbglR3DnDHGRequestData(PVBGLR3GUESTDNDCMDCTX pCtx, const char* pcszFormat) 1170 { 1171 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 1172 AssertPtrReturn(pcszFormat, VERR_INVALID_POINTER); 892 1173 893 1174 DragAndDropSvc::VBOXDNDHGREQDATAMSG Msg; 894 1175 RT_ZERO(Msg); 895 1176 Msg.hdr.result = VERR_WRONG_ORDER; 896 Msg.hdr.u32ClientID = u32ClientId;1177 Msg.hdr.u32ClientID = pCtx->uClientID; 897 1178 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_REQ_DATA; 898 1179 Msg.hdr.cParms = 1; … … 907 1188 } 908 1189 1190 VBGLR3DECL(int) VbglR3DnDHGSetProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr) 1191 { 1192 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 1193 1194 DragAndDropSvc::VBOXDNDHGEVTPROGRESSMSG Msg; 1195 RT_ZERO(Msg); 1196 Msg.hdr.result = VERR_WRONG_ORDER; 1197 Msg.hdr.u32ClientID = pCtx->uClientID; 1198 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS; 1199 Msg.hdr.cParms = 3; 1200 1201 Msg.uStatus.SetUInt32(uStatus); 1202 Msg.uPercent.SetUInt32(uPercent); 1203 Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */ 1204 1205 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg)); 1206 if (RT_SUCCESS(rc)) 1207 rc = Msg.hdr.result; 1208 1209 return rc; 1210 } 1211 909 1212 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 910 VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending( uint32_t u32ClientId,911 uint32_t uDefAction, uint32_t uAllActions, 912 const char* pcszFormats) 913 { 1213 VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending(PVBGLR3GUESTDNDCMDCTX pCtx, 1214 uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats) 1215 { 1216 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 914 1217 AssertPtrReturn(pcszFormats, VERR_INVALID_POINTER); 915 1218 … … 917 1220 RT_ZERO(Msg); 918 1221 Msg.hdr.result = VERR_WRONG_ORDER; 919 Msg.hdr.u32ClientID = u32ClientId;1222 Msg.hdr.u32ClientID = pCtx->uClientID; 920 1223 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_ACK_PENDING; 921 1224 Msg.hdr.cParms = 3; … … 932 1235 } 933 1236 934 static int vbglR3DnDGHSendDataInternal( uint32_t u32ClientId,935 void *pvData, uint32_t cbData, 936 uint32_t cbAdditionalData) 937 { 1237 static int vbglR3DnDGHSendDataInternal(PVBGLR3GUESTDNDCMDCTX pCtx, 1238 void *pvData, uint32_t cbData, uint32_t cbAdditionalData) 1239 { 1240 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 938 1241 AssertPtrReturn(pvData, VERR_INVALID_POINTER); 939 AssertReturn(cbData, VERR_INVALID_PARAMETER); 1242 AssertReturn(cbData, VERR_INVALID_PARAMETER); 1243 /* cbAdditionalData is optional. */ 940 1244 941 1245 DragAndDropSvc::VBOXDNDGHSENDDATAMSG Msg; 942 1246 RT_ZERO(Msg); 943 1247 Msg.hdr.result = VERR_WRONG_ORDER; 944 Msg.hdr.u32ClientID = u32ClientId;1248 Msg.hdr.u32ClientID = pCtx->uClientID; 945 1249 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DATA; 946 1250 Msg.hdr.cParms = 2; … … 949 1253 Msg.cbTotalBytes.SetUInt32(cbData + cbAdditionalData); 950 1254 951 int rc; 952 1255 int rc = VINF_SUCCESS; 1256 1257 uint32_t cbCurChunk; 953 1258 uint32_t cbMaxChunk = _64K; /** @todo Transfer max. 64K chunks per message. Configurable? */ 954 1259 uint32_t cbSent = 0; … … 956 1261 while (cbSent < cbData) 957 1262 { 958 uint32_tcbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk);959 Msg.pvData.SetPtr(static_cast<uint8_t *>(pvData) + cbSent, cbCurChunk);1263 cbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk); 1264 Msg.pvData.SetPtr(static_cast<uint8_t *>(pvData) + cbSent, cbCurChunk); 960 1265 961 1266 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg)); … … 977 1282 } 978 1283 979 static int vbglR3DnDGHSendDir(uint32_t u32ClientId, DnDURIObject &obj) 980 { 1284 static int vbglR3DnDGHSendDir(PVBGLR3GUESTDNDCMDCTX pCtx, DnDURIObject &obj) 1285 { 1286 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 981 1287 AssertReturn(obj.GetType() == DnDURIObject::Directory, VERR_INVALID_PARAMETER); 982 1288 … … 984 1290 RT_ZERO(Msg); 985 1291 Msg.hdr.result = VERR_WRONG_ORDER; 986 Msg.hdr.u32ClientID = u32ClientId;1292 Msg.hdr.u32ClientID = pCtx->uClientID; 987 1293 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DIR; 988 1294 Msg.hdr.cParms = 3; … … 1004 1310 } 1005 1311 1006 static int vbglR3DnDGHSendFile(uint32_t u32ClientId, DnDURIObject &obj) 1007 { 1312 static int vbglR3DnDGHSendFile(PVBGLR3GUESTDNDCMDCTX pCtx, DnDURIObject &obj) 1313 { 1314 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 1008 1315 AssertReturn(obj.GetType() == DnDURIObject::File, VERR_INVALID_PARAMETER); 1009 1316 … … 1013 1320 return VERR_NO_MEMORY; 1014 1321 1015 DragAndDropSvc::VBOXDNDGHSENDFILEMSG Msg;1016 RT_ZERO(Msg);1017 Msg.hdr.result = VERR_WRONG_ORDER;1018 Msg.hdr.u32ClientID = u32ClientId;1019 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_FILE;1020 Msg.hdr.cParms = 5;1021 1022 1322 RTCString strPath = obj.GetDestPath(); 1023 LogFlowFunc(("strFile=%s (%zu), fMode=0x%x\n", 1024 strPath.c_str(), strPath.length(), obj.GetMode())); 1025 1026 Msg.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1)); 1027 Msg.cbName.SetUInt32((uint32_t)(strPath.length() + 1)); 1028 Msg.fMode.SetUInt32(obj.GetMode()); 1029 1030 int rc = VINF_SUCCESS; 1031 uint32_t cbData = obj.GetSize(); 1032 1033 do 1034 { 1035 uint32_t cbToRead = RT_MIN(cbData, cbBuf); 1036 uint32_t cbRead = 0; 1037 if (cbToRead) 1038 rc = obj.Read(pvBuf, cbToRead, &cbRead); 1323 LogFlowFunc(("strFile=%s (%zu), fMode=0x%x\n", strPath.c_str(), strPath.length(), obj.GetMode())); 1324 1325 int rc = obj.Open(DnDURIObject::Source, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE); 1326 if (RT_FAILURE(rc)) 1327 { 1328 LogFunc(("Opening file \"%s\" failed with rc=%Rrc\n", obj.GetSourcePath().c_str(), rc)); 1329 return rc; 1330 } 1331 1332 LogFlowFunc(("cbSize=%RU64, uProtocol=%RU32, uClientID=%RU32\n", obj.GetSize(), pCtx->uProtocol, pCtx->uClientID)); 1333 1334 if (pCtx->uProtocol >= 2) /* Protocol version 2 and up sends a file header first. */ 1335 { 1336 DragAndDropSvc::VBOXDNDGHSENDFILEHDRMSG MsgHdr; 1337 RT_ZERO(MsgHdr); 1338 MsgHdr.hdr.result = VERR_WRONG_ORDER; 1339 MsgHdr.hdr.u32ClientID = pCtx->uClientID; 1340 MsgHdr.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR; 1341 MsgHdr.hdr.cParms = 6; 1342 1343 MsgHdr.uContext.SetUInt32(0); /* Context ID; unused at the moment. */ 1344 MsgHdr.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1)); 1345 MsgHdr.cbName.SetUInt32((uint32_t)(strPath.length() + 1)); 1346 MsgHdr.uFlags.SetUInt32(0); /* Flags; unused at the moment. */ 1347 MsgHdr.fMode.SetUInt32(obj.GetMode()); 1348 MsgHdr.cbTotal.SetUInt64(obj.GetSize()); 1349 1350 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(MsgHdr)), &MsgHdr, sizeof(MsgHdr)); 1039 1351 if (RT_SUCCESS(rc)) 1040 { 1041 Msg.cbData.SetUInt32(cbRead); 1042 Msg.pvData.SetPtr(pvBuf, cbRead); 1043 1044 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg)); 1045 if (RT_SUCCESS(rc)) 1046 rc = Msg.hdr.result; 1047 } 1048 1049 if (RT_FAILURE(rc)) 1352 rc = MsgHdr.hdr.result; 1353 1354 LogFlowFunc(("Sending file header resulted in %Rrc\n", rc)); 1355 } 1356 else 1357 rc = VINF_SUCCESS; 1358 1359 if (RT_SUCCESS(rc)) 1360 { 1361 /* 1362 * Send the actual file data, chunk by chunk. 1363 */ 1364 DragAndDropSvc::VBOXDNDGHSENDFILEDATAMSG Msg; 1365 RT_ZERO(Msg); 1366 Msg.hdr.result = VERR_WRONG_ORDER; 1367 Msg.hdr.u32ClientID = pCtx->uClientID; 1368 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA; 1369 1370 if (pCtx->uProtocol <= 1) 1371 { 1372 Msg.hdr.cParms = 5; 1373 1374 Msg.u.v1.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1)); 1375 Msg.u.v1.cbName.SetUInt32((uint32_t)(strPath.length() + 1)); 1376 Msg.u.v1.fMode.SetUInt32(obj.GetMode()); 1377 } 1378 else 1379 { 1380 /* Only send context ID, file chunk + chunk size. */ 1381 Msg.hdr.cParms = 3; 1382 1383 Msg.u.v2.uContext.SetUInt32(0); /** @todo Set context ID. */ 1384 } 1385 1386 uint64_t cbToReadTotal = obj.GetSize(); 1387 uint64_t cbWrittenTotal = 0; 1388 while (cbToReadTotal) 1389 { 1390 uint32_t cbToRead = RT_MIN(cbToReadTotal, cbBuf); 1391 uint32_t cbRead = 0; 1392 if (cbToRead) 1393 rc = obj.Read(pvBuf, cbToRead, &cbRead); 1394 1395 LogFlowFunc(("cbToReadTotal=%RU64, cbToRead=%RU32, cbRead=%RU32, rc=%Rrc\n", 1396 cbToReadTotal, cbToRead, cbRead, rc)); 1397 1398 if ( RT_SUCCESS(rc) 1399 && cbRead) 1400 { 1401 if (pCtx->uProtocol <= 1) 1402 { 1403 Msg.u.v1.pvData.SetPtr(pvBuf, cbRead); 1404 Msg.u.v1.cbData.SetUInt32(cbRead); 1405 } 1406 else 1407 { 1408 Msg.u.v2.pvData.SetPtr(pvBuf, cbRead); 1409 Msg.u.v2.cbData.SetUInt32(cbRead); 1410 } 1411 1412 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg)); 1413 if (RT_SUCCESS(rc)) 1414 rc = Msg.hdr.result; 1415 } 1416 1417 if (RT_FAILURE(rc)) 1418 { 1419 LogFlowFunc(("Reading failed with rc=%Rrc\n", rc)); 1420 break; 1421 } 1422 1423 Assert(cbRead <= cbToReadTotal); 1424 cbToReadTotal -= cbRead; 1425 cbWrittenTotal += cbRead; 1426 1427 LogFlowFunc(("%RU64/%RU64 -- %RU8%%\n", cbWrittenTotal, obj.GetSize(), cbWrittenTotal * 100 / obj.GetSize())); 1428 }; 1429 } 1430 1431 RTMemFree(pvBuf); 1432 1433 LogFlowFuncLeaveRC(rc); 1434 return rc; 1435 } 1436 1437 static int vbglR3DnDGHSendURIObject(PVBGLR3GUESTDNDCMDCTX pCtx, DnDURIObject &obj) 1438 { 1439 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 1440 1441 int rc; 1442 1443 switch (obj.GetType()) 1444 { 1445 case DnDURIObject::Directory: 1446 rc = vbglR3DnDGHSendDir(pCtx, obj); 1050 1447 break; 1051 1448 1052 Assert(cbRead <= cbData); 1053 cbData -= cbRead; 1054 1055 } while (cbData); 1056 1057 RTMemFree(pvBuf); 1058 1059 LogFlowFuncLeaveRC(rc); 1060 return rc; 1061 } 1062 1063 static int vbglR3DnDGHSendURIObject(uint32_t u32ClientId, DnDURIObject &obj) 1064 { 1065 int rc; 1066 1067 switch (obj.GetType()) 1068 { 1069 case DnDURIObject::Directory: 1070 rc = vbglR3DnDGHSendDir(u32ClientId, obj); 1449 case DnDURIObject::File: 1450 rc = vbglR3DnDGHSendFile(pCtx, obj); 1071 1451 break; 1072 1452 1073 case DnDURIObject::File:1074 rc = vbglR3DnDGHSendFile(u32ClientId, obj);1075 break;1076 1077 1453 default: 1078 AssertMsgFailed(("Type %ld not implemented\n", 1079 obj.GetType())); 1454 AssertMsgFailed(("URI type %ld not implemented\n", obj.GetType())); 1080 1455 rc = VERR_NOT_IMPLEMENTED; 1081 1456 break; … … 1085 1460 } 1086 1461 1087 static int vbglR3DnDGHProcessURIMessages( uint32_t u32ClientId,1462 static int vbglR3DnDGHProcessURIMessages(PVBGLR3GUESTDNDCMDCTX pCtx, 1088 1463 const void *pvData, uint32_t cbData) 1089 1464 { 1465 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 1090 1466 AssertPtrReturn(pvData, VERR_INVALID_POINTER); 1091 AssertReturn(cbData, VERR_INVALID_PARAMETER);1467 AssertReturn(cbData, VERR_INVALID_PARAMETER); 1092 1468 1093 1469 RTCList<RTCString> lstPaths = … … 1106 1482 uint32_t cbToSend = (uint32_t)strRootDest.length() + 1; 1107 1483 1108 rc = vbglR3DnDGHSendDataInternal( u32ClientId, pvToSend, cbToSend,1484 rc = vbglR3DnDGHSendDataInternal(pCtx, pvToSend, cbToSend, 1109 1485 /* Include total bytes of all file paths, 1110 1486 * file sizes etc. */ … … 1118 1494 DnDURIObject &nextObj = lstURI.First(); 1119 1495 1120 rc = vbglR3DnDGHSendURIObject( u32ClientId, nextObj);1496 rc = vbglR3DnDGHSendURIObject(pCtx, nextObj); 1121 1497 if (RT_FAILURE(rc)) 1122 1498 break; … … 1129 1505 } 1130 1506 1131 VBGLR3DECL(int) VbglR3DnDGHSendData(uint32_t u32ClientId, 1132 const char *pszFormat, 1133 void *pvData, uint32_t cbData) 1134 { 1507 VBGLR3DECL(int) VbglR3DnDGHSendData(PVBGLR3GUESTDNDCMDCTX pCtx, const char *pszFormat, void *pvData, uint32_t cbData) 1508 { 1509 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 1135 1510 AssertPtrReturn(pszFormat, VERR_INVALID_POINTER); 1136 AssertPtrReturn(pvData, VERR_INVALID_POINTER); 1137 AssertReturn(cbData, VERR_INVALID_PARAMETER); 1511 AssertPtrReturn(pvData, VERR_INVALID_POINTER); 1512 AssertReturn(cbData, VERR_INVALID_PARAMETER); 1513 1514 LogFlowFunc(("pszFormat=%s, pvData=%p, cbData=%RU32\n", pszFormat, pvData, cbData)); 1138 1515 1139 1516 int rc; 1140 1517 if (DnDMIMEHasFileURLs(pszFormat, strlen(pszFormat))) 1141 1518 { 1142 rc = vbglR3DnDGHProcessURIMessages( u32ClientId, pvData, cbData);1519 rc = vbglR3DnDGHProcessURIMessages(pCtx, pvData, cbData); 1143 1520 } 1144 1521 else 1145 rc = vbglR3DnDGHSendDataInternal(u32ClientId, pvData, cbData, 1146 0 /* cbAdditionalData */); 1522 { 1523 rc = vbglR3DnDGHSendDataInternal(pCtx, pvData, cbData, 0 /* cbAdditionalData */); 1524 } 1525 1147 1526 if (RT_FAILURE(rc)) 1148 1527 { 1149 int rc2 = VbglR3DnDGHSendError(u32ClientId, rc); 1150 AssertRC(rc2); 1151 } 1152 1153 return rc; 1154 } 1155 1156 VBGLR3DECL(int) VbglR3DnDGHSendError(uint32_t u32ClientId, int rcErr) 1157 { 1528 int rc2 = VbglR3DnDGHSendError(pCtx, rc); 1529 if (RT_FAILURE(rc2)) 1530 LogFlowFunc(("Unable to send error (%Rrc) to host, rc=%Rrc\n", rc, rc2)); 1531 } 1532 1533 return rc; 1534 } 1535 1536 VBGLR3DECL(int) VbglR3DnDGHSendError(PVBGLR3GUESTDNDCMDCTX pCtx, int rcErr) 1537 { 1538 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 1539 1158 1540 DragAndDropSvc::VBOXDNDGHEVTERRORMSG Msg; 1159 1541 RT_ZERO(Msg); 1160 1542 Msg.hdr.result = VERR_WRONG_ORDER; 1161 Msg.hdr.u32ClientID = u32ClientId;1543 Msg.hdr.u32ClientID = pCtx->uClientID; 1162 1544 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_EVT_ERROR; 1163 1545 Msg.hdr.cParms = 1; 1164 1546 1165 Msg. uRC.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */1547 Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */ 1166 1548 1167 1549 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg)); … … 1173 1555 } 1174 1556 #endif /* VBOX_WITH_DRAG_AND_DROP_GH */ 1557 -
trunk/src/VBox/Additions/x11/VBoxClient/draganddrop.cpp
r55401 r55422 5 5 6 6 /* 7 * Copyright (C) 2011-201 4Oracle Corporation7 * Copyright (C) 2011-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 406 406 protected: 407 407 408 uint32_t m_uClientID; 409 DragAndDropService *m_pParent; 410 Display *m_pDisplay; 411 int m_screenId; 412 Screen *m_pScreen; 413 Window m_wndRoot; 414 Window m_wndProxy; 415 Window m_wndCur; 416 long m_curVer; 417 RTCList<Atom> m_formats; 418 RTCList<Atom> m_actions; 408 /** The instance's own DnD context. */ 409 VBGLR3GUESTDNDCMDCTX m_dndCtx; 410 DragAndDropService *m_pParent; 411 Display *m_pDisplay; 412 int m_screenId; 413 Screen *m_pScreen; 414 Window m_wndRoot; 415 Window m_wndProxy; 416 Window m_wndCur; 417 long m_curVer; 418 RTCList<Atom> m_formats; 419 RTCList<Atom> m_actions; 419 420 /** Deferred host to guest selection event for sending to the 420 421 * target window as soon as data from the host arrived. */ 421 XEvent m_eventHgSelection;422 XEvent m_eventHgSelection; 422 423 /** Current operation mode. */ 423 Mode m_mode;424 Mode m_mode; 424 425 /** Current state of operation mode. */ 425 State m_state;426 State m_state; 426 427 /** The instance's own X event queue. */ 427 RTCMTList<XEvent> m_eventQueue;428 RTCMTList<XEvent> m_eventQueue; 428 429 /** Critical section for providing serialized access to list 429 430 * event queue's contents. */ 430 RTCRITSECT m_eventQueueCS;431 RTCRITSECT m_eventQueueCS; 431 432 /** Event for notifying this instance in case of a new 432 433 * event. */ 433 RTSEMEVENT m_hEventSem;434 RTSEMEVENT m_hEventSem; 434 435 /** List of allowed formats. */ 435 RTCList<RTCString> m_lstAllowedFormats;436 RTCList<RTCString> m_lstAllowedFormats; 436 437 }; 437 438 … … 507 508 508 509 DragInstance::DragInstance(Display *pDisplay, DragAndDropService *pParent) 509 : m_uClientID(0) 510 , m_pParent(pParent) 511 , m_pDisplay(pDisplay) 512 , m_pScreen(0) 513 , m_wndRoot(0) 514 , m_wndProxy(0) 515 , m_wndCur(0) 516 , m_curVer(-1) 517 , m_mode(Unknown) 518 , m_state(Uninitialized) 510 : m_pParent(pParent) 511 , m_pDisplay(pDisplay) 512 , m_pScreen(0) 513 , m_wndRoot(0) 514 , m_wndProxy(0) 515 , m_wndCur(0) 516 , m_curVer(-1) 517 , m_mode(Unknown) 518 , m_state(Uninitialized) 519 519 { 520 520 uninit(); … … 527 527 XDestroyWindow(m_pDisplay, m_wndProxy); 528 528 529 if (m_uClientID) 530 { 531 VbglR3DnDDisconnect(m_uClientID); 532 m_uClientID = 0; 533 } 529 VbglR3DnDDisconnect(&m_dndCtx); 534 530 535 531 m_state = Uninitialized; … … 571 567 uninit(); 572 568 573 rc = VbglR3DnDConnect(&m_ uClientID);569 rc = VbglR3DnDConnect(&m_dndCtx); 574 570 if (RT_FAILURE(rc)) 575 571 break; … … 692 688 uAction = toHGCMAction(static_cast<Atom>(e.xclient.data.l[4])); 693 689 694 rc = VbglR3DnDHGAcknowledgeOperation( m_uClientID, uAction);690 rc = VbglR3DnDHGAcknowledgeOperation(&m_dndCtx, uAction); 695 691 } 696 692 else if (e.xclient.message_type == xAtom(XA_XdndFinished)) … … 859 855 RTCString strFormat = xAtomToString(e.xselectionrequest.target); 860 856 Assert(strFormat.isNotEmpty()); 861 rc = VbglR3DnDHGRequestData( m_uClientID, strFormat.c_str());857 rc = VbglR3DnDHGRequestData(&m_dndCtx, strFormat.c_str()); 862 858 LogFlowThisFunc(("Requesting data from host as \"%s\", rc=%Rrc\n", 863 859 strFormat.c_str(), rc)); … … 1221 1217 { 1222 1218 /* No window to process, so send a ignore ack event to the host. */ 1223 rc = VbglR3DnDHGAcknowledgeOperation( m_uClientID, DND_IGNORE_ACTION);1219 rc = VbglR3DnDHGAcknowledgeOperation(&m_dndCtx, DND_IGNORE_ACTION); 1224 1220 } 1225 1221 … … 1476 1472 uint32_t uAllActions = toHGCMActions(m_actions); 1477 1473 1478 rc = VbglR3DnDGHAcknowledgePending( m_uClientID, uDefAction, uAllActions, strFormats.c_str());1474 rc = VbglR3DnDGHAcknowledgePending(&m_dndCtx, uDefAction, uAllActions, strFormats.c_str()); 1479 1475 LogFlowThisFunc(("Acknowledging m_uClientID=%RU32, allActions=0x%x, strFormats=%s, rc=%Rrc\n", 1480 m_ uClientID, uAllActions, strFormats.c_str(), rc));1476 m_dndCtx.uClientID, uAllActions, strFormats.c_str(), rc)); 1481 1477 } 1482 1478 } … … 1587 1583 pvDataTmp[cbData++] = '\0'; 1588 1584 1589 rc = VbglR3DnDGHSendData(m_uClientID, strFormat.c_str(), 1590 pvDataTmp, cbData); 1585 rc = VbglR3DnDGHSendData(&m_dndCtx, strFormat.c_str(), pvDataTmp, cbData); 1591 1586 RTMemFree(pvDataTmp); 1592 1587 } … … 1597 1592 { 1598 1593 /* Send the raw data to the host. */ 1599 rc = VbglR3DnDGHSendData(m_uClientID, strFormat.c_str(), 1600 pcData, cbData); 1594 rc = VbglR3DnDGHSendData(&m_dndCtx, strFormat.c_str(), pcData, cbData); 1601 1595 } 1602 1596 1603 LogFlowThisFunc(("Sent strFormat=%s with rc=%Rrc\n", 1604 strFormat.c_str(), rc)); 1597 LogFlowThisFunc(("Sent strFormat=%s, rc=%Rrc\n", strFormat.c_str(), rc)); 1605 1598 1606 1599 if (RT_SUCCESS(rc)) … … 1679 1672 if (RT_FAILURE(rc)) 1680 1673 { 1681 int rc2 = VbglR3DnDGHSendError( m_uClientID, rc);1674 int rc2 = VbglR3DnDGHSendError(&m_dndCtx, rc); 1682 1675 AssertRC(rc2); 1683 1676 } … … 2253 2246 AssertPtr(pThis); 2254 2247 2255 uint32_t uClientID; 2256 int rc = VbglR3DnDConnect(&uClientID); 2248 /* This thread has an own DnD context, e.g. an own client ID. */ 2249 VBGLR3GUESTDNDCMDCTX dndCtx; 2250 2251 int rc = VbglR3DnDConnect(&dndCtx); 2257 2252 if (RT_FAILURE(rc)) 2258 2253 LogRel(("DnD: Unable to connect to drag and drop service, rc=%Rrc\n", rc)); … … 2271 2266 2272 2267 /* Wait for new events. */ 2273 rc = VbglR3DnDProcessNextMessage(uClientID, &e.hgcm); 2274 if (RT_SUCCESS(rc)) 2268 rc = VbglR3DnDProcessNextMessage(&dndCtx, &e.hgcm); 2269 if ( RT_SUCCESS(rc) 2270 || rc == VERR_CANCELLED) 2275 2271 { 2276 2272 cMsgSkippedInvalid = 0; /* Reset skipped messages count. */ … … 2285 2281 else 2286 2282 { 2283 LogFlowFunc(("Processing next message failed with rc=%Rrc\n", rc)); 2284 2287 2285 /* Old(er) hosts either are broken regarding DnD support or otherwise 2288 2286 * don't support the stuff we do on the guest side, so make sure we … … 2299 2297 } while (!ASMAtomicReadBool(&pThis->m_fSrvStopping)); 2300 2298 2301 VbglR3DnDDisconnect( uClientID);2299 VbglR3DnDDisconnect(&dndCtx); 2302 2300 2303 2301 LogFlowFuncLeaveRC(rc); -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.cpp
r55305 r55422 5 5 6 6 /* 7 * Copyright (C) 2006-201 4Oracle Corporation7 * Copyright (C) 2006-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 73 73 # ifdef VBOX_WITH_DRAG_AND_DROP 74 74 # include "CGuest.h" 75 # include "CDnDTarget.h" 75 76 # endif /* VBOX_WITH_DRAG_AND_DROP */ 76 77 … … 2394 2395 { 2395 2396 error(pParent, MessageType_Error, 2396 tr(" Failed to drop data."),2397 tr("Drag and drop operation failed."), 2397 2398 formatErrorInfo(guest)); 2398 2399 } … … 2401 2402 { 2402 2403 error(pParent, MessageType_Error, 2403 tr("Failed to dropdata."),2404 tr("Failed while dropping data."), 2404 2405 formatErrorInfo(progress)); 2406 } 2407 2408 void UIMessageCenter::cannotCancelDrop(const CDnDTarget &dndTarget, QWidget *pParent /* = 0*/) const 2409 { 2410 error(pParent, MessageType_Error, 2411 tr("Unable to cancel drag and drop operation."), 2412 formatErrorInfo(dndTarget)); 2405 2413 } 2406 2414 #endif /* VBOX_WITH_DRAG_AND_DROP */ -
trunk/src/VBox/Frontends/VirtualBox/src/globals/UIMessageCenter.h
r55401 r55422 351 351 void cannotDropData(const CGuest &guest, QWidget *pParent = 0) const; 352 352 void cannotDropData(const CProgress &progress, QWidget *pParent = 0) const; 353 void cannotCancelDrop(const CDnDTarget &dndTarget, QWidget *pParent = 0) const; 353 354 #endif /* VBOX_WITH_DRAG_AND_DROP */ 354 355 -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDHandler.cpp
r52730 r55422 5 5 6 6 /* 7 * Copyright (C) 2011-201 4Oracle Corporation7 * Copyright (C) 2011-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 43 43 #endif /* !VBOX_WITH_PRECOMPILED_HEADERS */ 44 44 45 #undef LOG_GROUP 45 #ifdef LOG_GROUP 46 #undef LOG_GROUP 47 #endif 46 48 #define LOG_GROUP LOG_GROUP_GUEST_DND 47 49 #include <VBox/log.h> 48 49 50 50 51 … … 127 128 && !format.isEmpty()) 128 129 { 129 /* Convert the actual MIME data to a vector (needed 130 * for the COM wrapper). */ 130 /* Convert the actual MIME data to a vector (needed for the COM wrapper). */ 131 131 QVector<uint8_t> dv(d.size()); 132 132 memcpy(dv.data(), d.constData(), d.size()); 133 133 134 134 CProgress progress = dndTarget.SendData(screenId, format, dv); 135 if (guest.isOk()) 135 136 if (progress.isOk()) 136 137 { 138 LogFlowFunc(("Transferring data to guest ...\n")); 139 137 140 msgCenter().showModalProgressDialog(progress, 138 141 tr("Dropping data ..."), ":/progress_dnd_hg_90px.png", 139 142 pParent); 140 if ( !progress.GetCanceled() 143 144 LogFlowFunc(("Transfer fCompleted=%RTbool, fCanceled=%RTbool, hr=%Rhrc\n", 145 progress.GetCompleted(), progress.GetCanceled(), progress.GetResultCode())); 146 147 BOOL fCanceled = progress.GetCanceled(); 148 149 /* Some error occurred? */ 150 if ( !fCanceled 141 151 && ( !progress.isOk() 142 152 || progress.GetResultCode() != 0)) … … 145 155 result = KDnDAction_Ignore; 146 156 } 157 #if 0 158 else if (fCanceled) /* Operation canceled by user? */ 159 { 160 Assert(progress.isOk()); 161 Assert(progress.GetResultCode() == 0); 162 163 /* Tell the guest. */ 164 BOOL fVeto = dndTarget.Cancel(); 165 if (fVeto) /* Cancelling vetoed by the target? Tell the user why. */ 166 msgCenter().cannotCancelDrop(dndTarget, pParent); 167 } 168 #endif 147 169 } 148 170 else -
trunk/src/VBox/GuestHost/DragAndDrop/DnDURIList.cpp
r50830 r55422 5 5 6 6 /* 7 * Copyright (C) 2014 Oracle Corporation7 * Copyright (C) 2014-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 33 33 34 34 #include <VBox/GuestHost/DragAndDrop.h> 35 36 DnDURIObject::DnDURIObject(Type type,37 const RTCString &strSrcPath,38 const RTCString &strDstPath,39 uint32_t fMode, uint64_t cbSize)40 : m_Type(type)41 , m_strSrcPath(strSrcPath)42 , m_strDstPath(strDstPath)43 , m_fMode(fMode)44 , m_cbSize(cbSize)45 , m_cbProcessed(0)46 {47 RT_ZERO(u);48 }49 50 DnDURIObject::~DnDURIObject(void)51 {52 closeInternal();53 }54 55 void DnDURIObject::closeInternal(void)56 {57 if (m_Type == File)58 {59 if (u.m_hFile)60 {61 RTFileClose(u.m_hFile);62 u.m_hFile = NULL;63 }64 }65 }66 67 bool DnDURIObject::IsComplete(void) const68 {69 bool fComplete = false;70 71 Assert(m_cbProcessed <= m_cbSize);72 if (m_cbProcessed == m_cbSize)73 fComplete = true;74 75 switch (m_Type)76 {77 case File:78 if (!fComplete)79 fComplete = !u.m_hFile;80 break;81 82 case Directory:83 fComplete = true;84 break;85 86 default:87 break;88 }89 90 return fComplete;91 }92 93 /* static */94 /** @todo Put this into an own class like DnDURIPath : public RTCString? */95 int DnDURIObject::RebaseURIPath(RTCString &strPath,96 const RTCString &strBaseOld,97 const RTCString &strBaseNew)98 {99 int rc;100 const char *pszPath = RTUriPath(strPath.c_str());101 if (pszPath)102 {103 const char *pszPathStart = pszPath;104 const char *pszBaseOld = strBaseOld.c_str();105 if ( pszBaseOld106 && RTPathStartsWith(pszPath, pszBaseOld))107 {108 pszPathStart += strlen(pszBaseOld);109 }110 111 rc = VINF_SUCCESS;112 113 if (RT_SUCCESS(rc))114 {115 char *pszPathNew = RTPathJoinA(strBaseNew.c_str(), pszPathStart);116 if (pszPathNew)117 {118 char *pszPathURI = RTUriCreate("file" /* pszScheme */, "/" /* pszAuthority */,119 pszPathNew /* pszPath */,120 NULL /* pszQuery */, NULL /* pszFragment */);121 if (pszPathURI)122 {123 #ifdef DEBUG_andy124 LogFlowFunc(("Rebasing \"%s\" to \"%s\"", strPath.c_str(), pszPathURI));125 #endif126 strPath = RTCString(pszPathURI) + "\r\n";127 RTStrFree(pszPathURI);128 129 rc = VINF_SUCCESS;130 }131 else132 rc = VERR_INVALID_PARAMETER;133 134 RTStrFree(pszPathNew);135 }136 else137 rc = VERR_NO_MEMORY;138 }139 }140 else141 rc = VERR_INVALID_PARAMETER;142 143 #ifdef DEBUG_andy144 LogFlowFuncLeaveRC(rc);145 #endif146 return rc;147 }148 149 int DnDURIObject::Read(void *pvBuf, uint32_t cbToRead, uint32_t *pcbRead)150 {151 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);152 AssertReturn(cbToRead, VERR_INVALID_PARAMETER);153 /* pcbRead is optional. */154 155 int rc;156 switch (m_Type)157 {158 case File:159 {160 if (!u.m_hFile)161 {162 /* Open files on the source with RTFILE_O_DENY_WRITE to prevent races163 * where the OS writes to the file while the destination side transfers164 * it over. */165 rc = RTFileOpen(&u.m_hFile, m_strSrcPath.c_str(),166 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);167 }168 else169 rc = VINF_SUCCESS;170 171 bool fDone = false;172 if (RT_SUCCESS(rc))173 {174 size_t cbRead;175 rc = RTFileRead(u.m_hFile, pvBuf, cbToRead, &cbRead);176 if (RT_SUCCESS(rc))177 {178 if (pcbRead)179 *pcbRead = (uint32_t)cbRead;180 181 m_cbProcessed += cbRead;182 Assert(m_cbProcessed <= m_cbSize);183 184 /* End of file reached or error occurred? */185 if ( m_cbProcessed == m_cbSize186 || RT_FAILURE(rc))187 {188 closeInternal();189 }190 }191 }192 193 break;194 }195 196 case Directory:197 {198 rc = VINF_SUCCESS;199 break;200 }201 202 default:203 rc = VERR_NOT_IMPLEMENTED;204 break;205 }206 207 LogFlowFunc(("Returning strSourcePath=%s, rc=%Rrc\n",208 m_strSrcPath.c_str(), rc));209 return rc;210 }211 212 /*** */213 35 214 36 DnDURIList::DnDURIList(void) … … 439 261 pszFilePath, pszFileName, pszRoot)); 440 262 #endif 441 rc = appendPathRecursive(pszFilePath, cbBase, 442 fFlags); 263 rc = appendPathRecursive(pszFilePath, cbBase, fFlags); 443 264 } 444 265 else … … 496 317 void DnDURIList::RemoveFirst(void) 497 318 { 319 if (m_lstTree.isEmpty()) 320 return; 321 498 322 DnDURIObject &curPath = m_lstTree.first(); 499 323 -
trunk/src/VBox/GuestHost/DragAndDrop/Makefile.kmk
r50468 r55422 1 1 # $Id$ 2 2 ## @file 3 # Sub-Makefile for the shared DnD code for both host and guest.3 # Sub-Makefile for the shared DnD code for both, host and guest. 4 4 # 5 5 6 6 # 7 # Copyright (C) 2014 Oracle Corporation7 # Copyright (C) 2014-2015 Oracle Corporation 8 8 # 9 9 # This file is part of VirtualBox Open Source Edition (OSE), as … … 23 23 DnDMIME.cpp \ 24 24 DnDPath.cpp \ 25 DnDURIList.cpp 25 DnDURIList.cpp \ 26 DnDURIObject.cpp 26 27 27 28 # -
trunk/src/VBox/HostServices/DragAndDrop/dndmanager.cpp
r50561 r55422 1 1 /* $Id$ */ 2 2 /** @file 3 * Drag and Drop manager .3 * Drag and Drop manager: Handling of DnD messages on the host side. 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2011-201 4Oracle Corporation7 * Copyright (C) 2011-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 34 34 35 35 /****************************************************************************** 36 * Private declarations *37 ******************************************************************************/38 39 typedef DECLCALLBACK(int) FNDNDPRIVATEPROGRESS(size_t cbDone, void *pvUser);40 typedef FNDNDPRIVATEPROGRESS *PFNDNDPRIVATEPROGRESS;41 42 /**43 * Internal DnD message class for informing the44 * guest about a new directory.45 *46 * @see DnDHGSendDataMessage47 */48 class DnDHGSendDirPrivate: public DnDMessage49 {50 public:51 52 DnDHGSendDirPrivate(DnDURIObject URIObject,53 PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser)54 : m_URIObject(URIObject)55 , m_pfnProgressCallback(pfnProgressCallback)56 , m_pvProgressUser(pvProgressUser)57 {58 RTCString strPath = m_URIObject.GetDestPath();59 LogFlowFunc(("strPath=%s (%zu)\n", strPath.c_str(), strPath.length()));60 61 VBOXHGCMSVCPARM paTmpParms[3];62 paTmpParms[0].setString(strPath.c_str());63 paTmpParms[1].setUInt32((uint32_t)(strPath.length() + 1));64 paTmpParms[2].setUInt32(m_URIObject.GetMode());65 66 m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_DIR, 3, paTmpParms);67 }68 69 public:70 71 int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])72 {73 int rc = DnDMessage::currentMessage(uMsg, cParms, paParms);74 /* Advance progress info */75 if ( RT_SUCCESS(rc)76 && m_pfnProgressCallback)77 rc = m_pfnProgressCallback(m_URIObject.GetSize(), m_pvProgressUser);78 79 return rc;80 }81 82 protected:83 84 DnDURIObject m_URIObject;85 86 /* Progress stuff. */87 PFNDNDPRIVATEPROGRESS m_pfnProgressCallback;88 void *m_pvProgressUser;89 };90 91 /**92 * Internal DnD message class for informing the guest about a new file.93 *94 * @see DnDHGSendDataMessage95 */96 class DnDHGSendFilePrivate: public DnDMessage97 {98 public:99 100 DnDHGSendFilePrivate(DnDURIObject URIObject,101 PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser);102 virtual ~DnDHGSendFilePrivate(void);103 104 public:105 106 int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);107 108 protected:109 110 DnDURIObject m_URIObject;111 /** Skeleton parameters for the next upcoming message in case112 * the file data didn't fit completely into the first one. */113 VBOXHGCMSVCPARM m_aSkelParms[5];114 115 /* Progress stuff. */116 PFNDNDPRIVATEPROGRESS m_pfnProgressCallback;117 void *m_pvProgressUser;118 };119 120 /**121 * Internal DnD message class for informing the guest about new drag & drop122 * data.123 *124 * @see DnDHGSendDataMessage125 */126 class DnDHGSendDataMessagePrivate: public DnDMessage127 {128 public:129 130 DnDHGSendDataMessagePrivate(uint32_t uMsg, uint32_t cParms,131 VBOXHGCMSVCPARM paParms[],132 PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser);133 int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);134 135 protected:136 size_t m_cbSize;137 size_t m_cbDone;138 139 /* Progress stuff. */140 PFNDNDPRIVATEPROGRESS m_pfnProgressCallback;141 void *m_pvProgressUser;142 };143 144 /******************************************************************************145 * Implementation *146 ******************************************************************************/147 148 /******************************************************************************149 * DnDHGSendFilePrivate *150 ******************************************************************************/151 152 DnDHGSendFilePrivate::DnDHGSendFilePrivate(DnDURIObject URIObject,153 PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser)154 : m_URIObject(URIObject)155 , m_pfnProgressCallback(pfnProgressCallback)156 , m_pvProgressUser(pvProgressUser)157 {158 LogFlowFunc(("strPath=%s (%zu)\n",159 m_URIObject.GetDestPath().c_str(), m_URIObject.GetDestPath().length()));160 161 m_aSkelParms[0].setString(m_URIObject.GetDestPath().c_str()); /* pvName */162 m_aSkelParms[1].setUInt32((uint32_t)(m_URIObject.GetDestPath().length() + 1)); /* cbName */163 m_aSkelParms[2].setPointer(NULL, 0); /* pvData */164 m_aSkelParms[3].setUInt32(0); /* cbData */165 m_aSkelParms[4].setUInt32(m_URIObject.GetMode()); /* fMode */166 167 m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_FILE, 5, m_aSkelParms);168 }169 170 DnDHGSendFilePrivate::~DnDHGSendFilePrivate(void)171 {172 }173 174 int DnDHGSendFilePrivate::currentMessage(uint32_t uMsg, uint32_t cParms,175 VBOXHGCMSVCPARM paParms[])176 {177 if (!m_pNextMsg)178 return VERR_NO_DATA;179 180 int rc = m_pNextMsg->getData(uMsg, cParms, paParms);181 clearNextMsg();182 if (RT_FAILURE(rc))183 return rc;184 185 uint32_t cbRead;186 if (RT_SUCCESS(rc))187 {188 /* Get buffer size + pointer to buffer from guest side. */189 uint32_t cbToRead = paParms[2].u.pointer.size; /* cbData */190 Assert(cbToRead);191 void *pvBuf = paParms[2].u.pointer.addr; /* pvData */192 AssertPtr(pvBuf);193 194 rc = m_URIObject.Read(pvBuf, cbToRead, &cbRead);195 LogFlowFunc(("Read %RU32 bytes (%RU32 bytes buffer) for \"%s\", rc=%Rrc\n",196 cbRead, cbToRead, m_URIObject.GetDestPath().c_str(), rc));197 198 if (RT_LIKELY(RT_SUCCESS(rc)))199 {200 /* Tell the guest the actual size read. */201 paParms[3].setUInt32((uint32_t)cbRead); /* cbData */202 }203 }204 205 if (RT_SUCCESS(rc))206 {207 if (!m_URIObject.IsComplete())208 {209 try210 {211 /* More data needed to send over. Prepare the next message. */212 m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_FILE, 5 /* cParms */,213 m_aSkelParms);214 }215 catch(std::bad_alloc &)216 {217 rc = VERR_NO_MEMORY;218 }219 }220 221 /* Advance progress info. */222 if ( RT_SUCCESS(rc)223 && m_pfnProgressCallback)224 {225 rc = m_pfnProgressCallback(cbRead, m_pvProgressUser);226 }227 }228 229 return rc;230 }231 232 /******************************************************************************233 * DnDHGSendDataMessagePrivate *234 ******************************************************************************/235 236 DnDHGSendDataMessagePrivate::DnDHGSendDataMessagePrivate(uint32_t uMsg, uint32_t cParms,237 VBOXHGCMSVCPARM paParms[],238 PFNDNDPRIVATEPROGRESS pfnProgressCallback,239 void *pvProgressUser)240 : m_cbSize(paParms[4].u.uint32)241 , m_cbDone(0)242 , m_pfnProgressCallback(pfnProgressCallback)243 , m_pvProgressUser(pvProgressUser)244 {245 /* Create the initial data message. This might throw246 * a bad_alloc exception. */247 m_pNextMsg = new HGCM::Message(uMsg, cParms, paParms);248 }249 250 int DnDHGSendDataMessagePrivate::currentMessage(uint32_t uMsg, uint32_t cParms,251 VBOXHGCMSVCPARM paParms[])252 {253 /** @todo Don't copy the data parts ... just move the data pointer in254 * the original data ptr. */255 if (!m_pNextMsg)256 return VERR_NO_DATA;257 258 int rc = VINF_SUCCESS;259 260 HGCM::Message *pCurMsg = m_pNextMsg;261 AssertPtr(pCurMsg);262 263 m_pNextMsg = 0;264 rc = pCurMsg->getData(uMsg, cParms, paParms);265 266 /* Depending on the current message, the data pointer is on a267 * different position (HOST_DND_HG_SND_DATA=3;268 * HOST_DND_HG_SND_MORE_DATA=0). */269 int iPos = uMsg == DragAndDropSvc::HOST_DND_HG_SND_DATA ? 3 : 0;270 m_cbDone += paParms[iPos + 1].u.uint32;271 272 /* Info + data send already? */273 if (rc == VERR_BUFFER_OVERFLOW)274 {275 paParms[iPos + 1].u.uint32 = paParms[iPos].u.pointer.size;276 VBOXHGCMSVCPARM paTmpParms[2];277 void *pvOldData;278 uint32_t cOldData;279 pCurMsg->getParmPtrInfo(iPos, &pvOldData, &cOldData);280 paTmpParms[0].setPointer(static_cast<uint8_t*>(pvOldData) + paParms[iPos].u.pointer.size, cOldData - paParms[iPos].u.pointer.size);281 paTmpParms[1].setUInt32(cOldData - paParms[iPos].u.pointer.size);282 283 try284 {285 m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA, 2, paTmpParms);286 }287 catch(std::bad_alloc &)288 {289 rc = VERR_NO_MEMORY;290 }291 }292 293 if (pCurMsg)294 delete pCurMsg;295 296 /* Advance progress info. */297 if ( RT_SUCCESS(rc)298 && m_pfnProgressCallback)299 {300 rc = m_pfnProgressCallback(m_cbDone, m_pvProgressUser);301 }302 303 return rc;304 }305 306 /******************************************************************************307 * DnDHGSendDataMessage *308 ******************************************************************************/309 310 /*311 * This class is a meta message class. It doesn't consist of any own message312 * data, but handle the meta info, the data itself as well as any files or313 * directories which have to be transfered to the guest.314 */315 DnDHGSendDataMessage::DnDHGSendDataMessage(uint32_t uMsg, uint32_t cParms,316 VBOXHGCMSVCPARM paParms[],317 PFNDNDPROGRESS pfnProgressCallback,318 void *pvProgressUser)319 : m_cbTotal(0)320 , m_cbTransfered(0)321 , m_pfnProgressCallback(pfnProgressCallback)322 , m_pvProgressUser(pvProgressUser)323 {324 if (cParms < 5) /* Paranoia. */325 return;326 327 const char *pszFormat = static_cast<const char*>(paParms[1].u.pointer.addr);328 uint32_t cbFormat = paParms[1].u.pointer.size;329 330 int rc = VINF_SUCCESS;331 RTCString strNewURIs;332 333 /* Do we need to build up a file tree? */334 if (DnDMIMEHasFileURLs(pszFormat, cbFormat))335 {336 const char *pszList = static_cast<const char*>(paParms[3].u.pointer.addr);337 AssertPtr(pszList);338 uint32_t cbList = paParms[3].u.pointer.size;339 Assert(cbList);340 341 LogFlowFunc(("Old data (%RU32 bytes): '%s'\n", cbList, pszList));342 343 /* The list is separated by newline (even if only one file is listed). */344 RTCList<RTCString> lstURIOrg345 = RTCString(pszList, cbList).split("\r\n");346 if (!lstURIOrg.isEmpty())347 {348 rc = m_lstURI.AppendURIPathsFromList(lstURIOrg, 0 /* fFlags */);349 if (RT_SUCCESS(rc))350 {351 /* Add the total size of all meta data + files transferred to352 * the message's total byte count. */353 m_cbTotal += m_lstURI.TotalBytes();354 355 /* We have to change the actual DnD data. Remove any host paths and356 * just decode the filename into the new data. The Guest Additions will357 * add the correct path again before sending the DnD drop event to358 * some window. */359 strNewURIs = m_lstURI.RootToString();360 361 /* Note: We don't delete the old pointer here, cause this is done362 * by the caller. We just use the RTString data, which has the363 * scope of this ctor. This is enough cause the data is copied in364 * the DnDHGSendDataMessagePrivate anyway. */365 paParms[3].u.pointer.addr = (void *)strNewURIs.c_str();366 paParms[3].u.pointer.size = (uint32_t)(strNewURIs.length() + 1);367 paParms[4].u.uint32 = (uint32_t)(strNewURIs.length() + 1);368 369 LogFlowFunc(("Set new data (%RU32 bytes): '%s'\n",370 paParms[3].u.pointer.size,371 (const char*)paParms[3].u.pointer.addr));372 }373 }374 }375 376 /* Add the size of the data to the todo list. */377 m_cbTotal += paParms[4].u.uint32;378 LogFlowFunc(("cbTotal=%zu\n", m_cbTotal));379 380 /* The first message is the meta info for the data and the data itself. */381 m_pNextPathMsg = new DnDHGSendDataMessagePrivate(uMsg, cParms, paParms,382 &DnDHGSendDataMessage::progressCallback, this);383 }384 385 DnDHGSendDataMessage::~DnDHGSendDataMessage(void)386 {387 if (m_pNextPathMsg)388 delete m_pNextPathMsg;389 }390 391 HGCM::Message* DnDHGSendDataMessage::nextHGCMMessage(void)392 {393 if (!m_pNextPathMsg)394 return NULL;395 396 return m_pNextPathMsg->nextHGCMMessage();397 }398 399 int DnDHGSendDataMessage::currentMessageInfo(uint32_t *puMsg, uint32_t *pcParms)400 {401 if (!m_pNextPathMsg)402 return VERR_NO_DATA;403 404 return m_pNextPathMsg->currentMessageInfo(puMsg, pcParms);405 }406 407 int DnDHGSendDataMessage::currentMessage(uint32_t uMsg,408 uint32_t cParms, VBOXHGCMSVCPARM paParms[])409 {410 if (!m_pNextPathMsg)411 return VERR_NO_DATA;412 413 /* Fill the data out of our current queued message. */414 int rc = m_pNextPathMsg->currentMessage(uMsg, cParms, paParms);415 /* Has this message more data to deliver? */416 if (!m_pNextPathMsg->isMessageWaiting())417 {418 delete m_pNextPathMsg;419 m_pNextPathMsg = NULL;420 }421 422 /* File/directory data to send? */423 if (!m_pNextPathMsg)424 {425 if (m_lstURI.IsEmpty())426 return rc;427 428 /* Create new messages based on our internal path list. Currently429 * this could be directories or regular files. */430 const DnDURIObject &nextObj = m_lstURI.First();431 try432 {433 uint32_t fMode = nextObj.GetMode();434 LogFlowFunc(("Processing srcPath=%s, dstPath=%s, fMode=0x%x, cbSize=%RU32, fIsDir=%RTbool, fIsFile=%RTbool\n",435 nextObj.GetSourcePath().c_str(), nextObj.GetDestPath().c_str(),436 fMode, nextObj.GetSize(),437 RTFS_IS_DIRECTORY(fMode), RTFS_IS_FILE(fMode)));438 439 if (RTFS_IS_DIRECTORY(fMode))440 m_pNextPathMsg = new DnDHGSendDirPrivate(nextObj,441 &DnDHGSendDataMessage::progressCallback /* pfnProgressCallback */,442 this /* pvProgressUser */);443 else if (RTFS_IS_FILE(fMode))444 m_pNextPathMsg = new DnDHGSendFilePrivate(nextObj,445 &DnDHGSendDataMessage::progressCallback /* pfnProgressCallback */,446 this /* pvProgressUser */);447 else448 AssertMsgFailedReturn(("fMode=0x%x is not supported for srcPath=%s, dstPath=%s\n",449 fMode, nextObj.GetSourcePath().c_str(), nextObj.GetDestPath().c_str()),450 VERR_NO_DATA);451 452 m_lstURI.RemoveFirst();453 }454 catch(std::bad_alloc &)455 {456 rc = VERR_NO_MEMORY;457 }458 }459 460 return rc;461 }462 463 int DnDHGSendDataMessage::progressCallback(size_t cbDone, void *pvUser)464 {465 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);466 467 DnDHGSendDataMessage *pSelf = static_cast<DnDHGSendDataMessage *>(pvUser);468 AssertPtr(pSelf);469 470 /* How many bytes are transfered already. */471 pSelf->m_cbTransfered += cbDone;472 473 /* Advance progress info. */474 int rc = VINF_SUCCESS;475 if ( pSelf->m_pfnProgressCallback476 && pSelf->m_cbTotal)477 {478 AssertMsg(pSelf->m_cbTransfered <= pSelf->m_cbTotal,479 ("More bytes transferred (%zu) than expected (%zu), cbDone=%zu\n",480 pSelf->m_cbTransfered, pSelf->m_cbTotal, cbDone));481 482 unsigned uPercentage = (unsigned)((uint64_t)pSelf->m_cbTransfered * 100 / pSelf->m_cbTotal);483 rc = pSelf->m_pfnProgressCallback(RT_MIN(uPercentage, 100),484 DragAndDropSvc::DND_PROGRESS_RUNNING,485 VINF_SUCCESS /* rc */, pSelf->m_pvProgressUser);486 }487 488 return rc;489 }490 491 /******************************************************************************492 36 * DnDManager * 493 37 ******************************************************************************/ 494 38 495 int DnDManager::addMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[] )39 int DnDManager::addMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool fAppend /* = true */) 496 40 { 497 41 int rc = VINF_SUCCESS; 498 42 43 LogFlowFunc(("uMsg=%RU32, cParms=%RU32, fAppend=%RTbool\n", uMsg, cParms, fAppend)); 44 499 45 try 500 46 { 47 DnDMessage *pMessage = NULL; 48 501 49 switch (uMsg) 502 50 { … … 505 53 clear(); 506 54 LogFlowFunc(("HOST_DND_HG_EVT_ENTER\n")); 507 508 /* Verify parameter count and types. */509 if ( cParms != 7510 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */511 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* x-pos */512 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* y-pos */513 || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* default action */514 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* allowed actions */515 || paParms[5].type != VBOX_HGCM_SVC_PARM_PTR /* data */516 || paParms[6].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)517 rc = VERR_INVALID_PARAMETER;518 else519 {520 m_fOpInProcess = true;521 DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);522 m_dndMessageQueue.append(pMessage);523 }524 55 break; 525 56 } … … 528 59 { 529 60 LogFlowFunc(("HOST_DND_HG_EVT_MOVE\n")); 530 531 /* Verify parameter count and types. */532 if ( cParms != 7533 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */534 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* x-pos */535 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* y-pos */536 || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* default action */537 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* allowed actions */538 || paParms[5].type != VBOX_HGCM_SVC_PARM_PTR /* data */539 || paParms[6].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)540 {541 rc = VERR_INVALID_PARAMETER;542 }543 else544 {545 m_fOpInProcess = true;546 DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);547 m_dndMessageQueue.append(pMessage);548 }549 61 break; 550 62 } … … 553 65 { 554 66 LogFlowFunc(("HOST_DND_HG_EVT_LEAVE\n")); 555 556 /* Verify parameter count and types. */557 if (cParms != 0)558 rc = VERR_INVALID_PARAMETER;559 else560 {561 DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);562 m_dndMessageQueue.append(pMessage);563 }564 565 m_fOpInProcess = false;566 67 break; 567 68 } … … 570 71 { 571 72 LogFlowFunc(("HOST_DND_HG_EVT_DROPPED\n")); 572 573 /* Verify parameter count and types. */ 574 if ( cParms != 7 575 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */ 576 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* x-pos */ 577 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* y-pos */ 578 || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* default action */ 579 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* allowed actions */ 580 || paParms[5].type != VBOX_HGCM_SVC_PARM_PTR /* data */ 581 || paParms[6].type != VBOX_HGCM_SVC_PARM_32BIT /* size */) 582 { 583 rc = VERR_INVALID_PARAMETER; 584 } 585 else 586 { 587 DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms); 588 m_dndMessageQueue.append(pMessage); 589 } 73 break; 74 } 75 76 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL: 77 { 78 LogFlowFunc(("HOST_DND_HG_EVT_CANCEL\n")); 79 80 pMessage = new DnDHGCancelMessage(); 590 81 break; 591 82 } … … 594 85 { 595 86 LogFlowFunc(("HOST_DND_HG_SND_DATA\n")); 596 597 /* Verify parameter count and types. */ 598 if ( cParms != 5 599 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */ 600 || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* format */ 601 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* format size */ 602 || paParms[3].type != VBOX_HGCM_SVC_PARM_PTR /* data */ 603 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* data size */) 604 { 605 rc = VERR_INVALID_PARAMETER; 606 } 607 else 608 { 609 DnDHGSendDataMessage *pMessage = 610 new DnDHGSendDataMessage(uMsg, cParms, paParms, 611 m_pfnProgressCallback, m_pvProgressUser); 612 m_dndMessageQueue.append(pMessage); 613 } 87 break; 88 } 89 90 case DragAndDropSvc::HOST_DND_HG_SND_DIR: 91 { 92 LogFlowFunc(("HOST_DND_HG_SND_DIR\n")); 93 break; 94 } 95 96 /* New since protocol version 2 (VBox 5.0). */ 97 case DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR: 98 { 99 LogFlowFunc(("HOST_DND_HG_SND_FILE_HDR\n")); 100 break; 101 } 102 103 case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA: 104 { 105 LogFlowFunc(("HOST_DND_HG_SND_FILE\n")); 106 107 /* No parameter verification here as, depending on the protocol version 108 * being used, the parameter count + types might change. */ 614 109 break; 615 110 } … … 625 120 { 626 121 rc = VERR_INVALID_PARAMETER; 627 }628 else629 {630 DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);631 m_dndMessageQueue.append(pMessage);632 122 } 633 123 break; … … 646 136 rc = VERR_INVALID_PARAMETER; 647 137 } 648 else649 {650 try651 {652 DnDGenericMessage *pMessage653 = new DnDGenericMessage(uMsg, cParms, paParms);654 m_dndMessageQueue.append(pMessage);655 }656 catch(std::bad_alloc &)657 {658 rc = VERR_NO_MEMORY;659 }660 }661 138 break; 662 139 } … … 667 144 break; 668 145 } 146 147 if (!pMessage) /* Generic message needed? */ 148 pMessage = new DnDGenericMessage(uMsg, cParms, paParms); 149 150 if (fAppend) 151 m_dndMessageQueue.append(pMessage); 152 else 153 m_dndMessageQueue.prepend(pMessage); 669 154 } 670 155 catch(std::bad_alloc &) … … 692 177 AssertPtrReturn(pcParms, VERR_INVALID_POINTER); 693 178 694 int rc = VINF_SUCCESS; 695 179 int rc; 696 180 if (m_pCurMsg) 697 181 rc = m_pCurMsg->currentMessageInfo(puMsg, pcParms); … … 699 183 { 700 184 if (m_dndMessageQueue.isEmpty()) 701 {702 185 rc = VERR_NO_DATA; 703 // if (m_pfnProgressCallback)704 // m_pfnProgressCallback(100.0, DragAndDropSvc::DND_OP_CANCELLED, m_pvProgressUser);705 }706 186 else 707 187 rc = m_dndMessageQueue.first()->currentMessageInfo(puMsg, pcParms); … … 743 223 * callback about our exit. 744 224 */ 745 if ( RT_FAILURE(rc) 746 && m_pfnProgressCallback) 225 if (RT_FAILURE(rc)) 747 226 { 748 227 /* Clear any pending messages. */ … … 754 233 try 755 234 { 235 if (rc == VERR_CANCELLED) 236 LogFlowFunc(("Operation was cancelled\n")); 237 756 238 Assert(!m_pCurMsg); 757 239 m_pCurMsg = new DnDHGCancelMessage(); 758 m_pfnProgressCallback(100 /* Percent */, 759 rc == VERR_CANCELLED 760 ? DragAndDropSvc::DND_PROGRESS_CANCELLED 761 : DragAndDropSvc::DND_PROGRESS_ERROR, rc, m_pvProgressUser); 240 241 if (m_pfnProgressCallback) 242 { 243 LogFlowFunc(("Notifying host about aborting operation (%Rrc) ...\n", rc)); 244 m_pfnProgressCallback( rc == VERR_CANCELLED 245 ? DragAndDropSvc::DND_PROGRESS_CANCELLED 246 : DragAndDropSvc::DND_PROGRESS_ERROR, 247 100 /* Percent */, rc, 248 m_pvProgressUser); 249 } 762 250 } 763 251 catch(std::bad_alloc &) … … 776 264 { 777 265 delete m_pCurMsg; 778 m_pCurMsg = 0;266 m_pCurMsg = NULL; 779 267 } 780 268 … … 786 274 } 787 275 276 /** 277 * Triggers a rescheduling of the manager's message queue by setting the first 278 * message available in the queue as the current one to process. 279 * 280 * @return IPRT status code. VERR_NO_DATA if not message to process is available at 281 * the time of calling. 282 */ 283 int DnDManager::doReschedule(void) 284 { 285 LogFlowFunc(("Rescheduling ...\n")); 286 287 if (!m_dndMessageQueue.isEmpty()) 288 { 289 m_pCurMsg = m_dndMessageQueue.first(); 290 m_dndMessageQueue.removeFirst(); 291 292 return VINF_SUCCESS; 293 } 294 295 return VERR_NO_DATA; 296 } 297 -
trunk/src/VBox/HostServices/DragAndDrop/dndmanager.h
r50460 r55422 4 4 5 5 /* 6 * Copyright (C) 2011-201 4Oracle Corporation6 * Copyright (C) 2011-2015 Oracle Corporation 7 7 * 8 8 * This file is part of VirtualBox Open Source Edition (OSE), as … … 25 25 #include <iprt/cpp/list.h> 26 26 27 typedef DECLCALLBACK(int) FNDNDPROGRESS(u nsigned uPercentage, uint32_t uState, int rc, void *pvUser);27 typedef DECLCALLBACK(int) FNDNDPROGRESS(uint32_t uState, uint32_t uPercentage, int rc, void *pvUser); 28 28 typedef FNDNDPROGRESS *PFNDNDPROGRESS; 29 29 … … 108 108 109 109 /** 110 * DnD message class for informing the guest about a new drop data event. 111 */ 112 class DnDHGSendDataMessage: public DnDMessage 113 { 114 public: 115 116 DnDHGSendDataMessage(uint32_t uMsg, uint32_t cParms, 117 VBOXHGCMSVCPARM paParms[], 118 PFNDNDPROGRESS pfnProgressCallback, void *pvProgressUser); 119 120 virtual ~DnDHGSendDataMessage(void); 121 122 HGCM::Message* nextHGCMMessage(void); 123 int currentMessageInfo(uint32_t *puMsg, uint32_t *pcParms); 124 int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 125 126 bool isMessageWaiting(void) const { return !!m_pNextPathMsg; } 127 128 protected: 129 130 static DECLCALLBACK(int) progressCallback(size_t cbDone, void *pvUser); 131 132 DnDMessage *m_pNextPathMsg; 133 134 DnDURIList m_lstURI; 135 /* Total message size (in bytes). */ 136 size_t m_cbTotal; 137 /* Transferred message size (in bytes). */ 138 size_t m_cbTransfered; 139 140 PFNDNDPROGRESS m_pfnProgressCallback; 141 void *m_pvProgressUser; 142 }; 143 144 /** 145 * DnD message class for informing the guest to cancel any currently and 146 * pending activities. 110 * DnD message class for informing the guest to cancel any current (and pending) activities. 147 111 */ 148 112 class DnDHGCancelMessage: public DnDMessage … … 167 131 168 132 DnDManager(PFNDNDPROGRESS pfnProgressCallback, void *pvProgressUser) 169 : m_pCurMsg(0) 170 , m_fOpInProcess(false) 133 : m_pCurMsg(NULL) 171 134 , m_pfnProgressCallback(pfnProgressCallback) 172 135 , m_pvProgressUser(pvProgressUser) … … 178 141 } 179 142 180 int addMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[] );143 int addMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool fAppend = true); 181 144 182 145 HGCM::Message *nextHGCMMessage(void); … … 185 148 186 149 void clear(void); 187 188 bool hasActiveOperation(void) const { return m_fOpInProcess; } 150 int doReschedule(void); 189 151 190 152 private: 191 153 DnDMessage *m_pCurMsg; 192 154 RTCList<DnDMessage*> m_dndMessageQueue; 193 194 bool m_fOpInProcess;195 155 196 156 /* Progress stuff */ -
trunk/src/VBox/HostServices/DragAndDrop/service.cpp
r50724 r55422 5 5 6 6 /* 7 * Copyright (C) 2011-201 4Oracle Corporation7 * Copyright (C) 2011-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 60 60 #define LOG_GROUP LOG_GROUP_GUEST_DND 61 61 62 #include <map> 63 62 64 #include "dndmanager.h" 63 65 … … 66 68 ******************************************************************************/ 67 69 70 /** Map holding pointers to HGCM clients. Key is the (unique) HGCM client ID. */ 71 typedef std::map<uint32_t, HGCM::Client*> DnDClientMap; 72 68 73 /** 69 74 * Specialized drag & drop service class. 70 75 */ 71 class DragAndDropService : public HGCM::AbstractService<DragAndDropService>76 class DragAndDropService : public HGCM::AbstractService<DragAndDropService> 72 77 { 73 78 public: … … 75 80 explicit DragAndDropService(PVBOXHGCMSVCHELPERS pHelpers) 76 81 : HGCM::AbstractService<DragAndDropService>(pHelpers) 77 , m_pManager(0) 78 , m_cClients(0) 79 {} 82 , m_pManager(NULL) {} 80 83 81 84 protected: 82 /* HGCM service implementation */ 85 83 86 int init(VBOXHGCMSVCFNTABLE *pTable); 84 int uninit( );87 int uninit(void); 85 88 int clientConnect(uint32_t u32ClientID, void *pvClient); 86 89 int clientDisconnect(uint32_t u32ClientID, void *pvClient); … … 88 91 int hostCall(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); 89 92 90 static DECLCALLBACK(int) progressCallback(uint32_t uPercentage, uint32_t uState, int rc, void *pvUser);91 93 int modeSet(uint32_t u32Mode); 92 94 inline uint32_t modeGet() { return m_u32Mode; }; 93 95 96 protected: 97 98 static DECLCALLBACK(int) progressCallback(uint32_t uStatus, uint32_t uPercentage, int rc, void *pvUser); 99 100 protected: 101 94 102 DnDManager *m_pManager; 95 96 uint32_t m_cClients; 103 /** Map of all connected clients. */ 104 DnDClientMap m_clientMap; 105 /** List of all clients which are queued up (deferred return) and ready 106 * to process new commands. */ 97 107 RTCList<HGCM::Client*> m_clientQueue; 98 108 uint32_t m_u32Mode; … … 114 124 modeSet(VBOX_DRAG_AND_DROP_MODE_OFF); 115 125 116 m_pManager = new DnDManager(&DragAndDropService::progressCallback, this); 126 int rc = VINF_SUCCESS; 127 128 try 129 { 130 m_pManager = new DnDManager(&DragAndDropService::progressCallback, this); 131 } 132 catch(std::bad_alloc &) 133 { 134 rc = VERR_NO_MEMORY; 135 } 136 137 LogFlowFuncLeaveRC(rc); 138 return rc; 139 } 140 141 int DragAndDropService::uninit(void) 142 { 143 if (m_pManager) 144 { 145 delete m_pManager; 146 m_pManager = NULL; 147 } 117 148 118 149 return VINF_SUCCESS; 119 150 } 120 151 121 int DragAndDropService::uninit(void) 122 { 123 delete m_pManager; 124 125 return VINF_SUCCESS; 152 int DragAndDropService::clientConnect(uint32_t u32ClientID, void *pvClient) 153 { 154 if (m_clientMap.size() >= UINT8_MAX) /* Don't allow too much clients at the same time. */ 155 { 156 AssertMsgFailed(("Maximum number of clients reached\n")); 157 return VERR_BUFFER_OVERFLOW; 158 } 159 160 int rc = VINF_SUCCESS; 161 162 /* 163 * Add client to our client map. 164 */ 165 if (m_clientMap.find(u32ClientID) != m_clientMap.end()) 166 rc = VERR_ALREADY_EXISTS; 167 168 if (RT_SUCCESS(rc)) 169 { 170 try 171 { 172 m_clientMap[u32ClientID] = new HGCM::Client(u32ClientID); 173 } 174 catch(std::bad_alloc &) 175 { 176 rc = VERR_NO_MEMORY; 177 } 178 179 if (RT_SUCCESS(rc)) 180 { 181 /* 182 * Clear the message queue as soon as a new clients connect 183 * to ensure that every client has the same state. 184 */ 185 if (m_pManager) 186 m_pManager->clear(); 187 } 188 } 189 190 LogFlowFunc(("Client %RU32 connected, rc=%Rrc\n", u32ClientID, rc)); 191 return rc; 126 192 } 127 193 128 int DragAndDropService::clientConnect(uint32_t u32ClientID, void *pvClient) 129 { 130 LogFlowFunc(("New client (%RU32) connected\n", u32ClientID)); 131 if (m_cClients < UINT32_MAX) 132 m_cClients++; 133 else 134 AssertMsgFailed(("Maximum number of clients reached\n")); 194 int DragAndDropService::clientDisconnect(uint32_t u32ClientID, void *pvClient) 195 { 196 /* Client not found? Bail out early. */ 197 DnDClientMap::iterator itClient = m_clientMap.find(u32ClientID); 198 if (itClient == m_clientMap.end()) 199 return VERR_NOT_FOUND; 135 200 136 201 /* 137 * Clear the message queue as soon as a new clients connect 138 * to ensure that every client has the same state. 202 * Remove from waiters queue. 139 203 */ 140 if (m_pManager) 141 m_pManager->clear(); 142 143 return VINF_SUCCESS; 144 } 145 146 int DragAndDropService::clientDisconnect(uint32_t u32ClientID, void *pvClient) 147 { 148 /* Remove all waiters with this u32ClientID. */ 149 for (size_t i = 0; i < m_clientQueue.size(); ) 204 for (size_t i = 0; i < m_clientQueue.size(); i++) 150 205 { 151 206 HGCM::Client *pClient = m_clientQueue.at(i); … … 157 212 m_clientQueue.removeAt(i); 158 213 delete pClient; 159 } 160 else 161 i++; 162 } 163 214 215 break; 216 } 217 } 218 219 /* 220 * Remove from client map and deallocate. 221 */ 222 AssertPtr(itClient->second); 223 delete itClient->second; 224 225 m_clientMap.erase(itClient); 226 227 LogFlowFunc(("Client %RU32 disconnected\n", u32ClientID)); 164 228 return VINF_SUCCESS; 165 229 } … … 197 261 { 198 262 case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG: 263 { 199 264 if (modeGet() != VBOX_DRAG_AND_DROP_MODE_OFF) 200 265 { … … 207 272 } 208 273 break; 274 } 275 276 /* Note: New since protocol version 2. */ 277 case DragAndDropSvc::GUEST_DND_CONNECT: 278 /* Fall through is intentional. */ 209 279 case DragAndDropSvc::GUEST_DND_HG_ACK_OP: 210 280 case DragAndDropSvc::GUEST_DND_HG_REQ_DATA: 281 case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS: 282 { 211 283 if ( modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL 212 284 || modeGet() == VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST) … … 217 289 LogFlowFunc(("Host -> Guest DnD mode disabled, ignoring request\n")); 218 290 break; 291 } 292 219 293 case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING: 220 294 case DragAndDropSvc::GUEST_DND_GH_SND_DATA: 221 295 case DragAndDropSvc::GUEST_DND_GH_SND_DIR: 222 case DragAndDropSvc::GUEST_DND_GH_SND_FILE: 296 case DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR: 297 case DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA: 223 298 case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR: 299 { 224 300 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 225 301 if ( modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL … … 232 308 LogFlowFunc(("Guest -> Host DnD mode disabled, ignoring request\n")); 233 309 break; 310 } 311 234 312 default: 235 313 /* Reach through to DnD manager. */ … … 244 322 if (rc == VINF_SUCCESS) /* Note: rc might be VINF_HGCM_ASYNC_EXECUTE! */ 245 323 { 324 DnDClientMap::iterator itClient = m_clientMap.find(u32ClientID); 325 Assert(itClient != m_clientMap.end()); 326 327 HGCM::Client *pClient = itClient->second; 328 AssertPtr(pClient); 329 246 330 switch (u32Function) 247 331 { 248 /* Note: Older VBox versions with enabled DnD guest->host support (< 4.4) 332 /* 333 * Note: Older VBox versions with enabled DnD guest->host support (< 5.0) 249 334 * used the same message ID (300) for GUEST_DND_GET_NEXT_HOST_MSG and 250 335 * HOST_DND_GH_REQ_PENDING, which led this service returning 251 336 * VERR_INVALID_PARAMETER when the guest wanted to actually 252 * handle HOST_DND_GH_REQ_PENDING. */ 337 * handle HOST_DND_GH_REQ_PENDING. 338 */ 253 339 case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG: 254 340 { … … 258 344 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* parameter count */ 259 345 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* blocking */) 260 rc = VERR_INVALID_PARAMETER; 261 else 262 { 263 rc = m_pManager->nextMessageInfo(&paParms[0].u.uint32, &paParms[1].u.uint32); 264 if ( RT_FAILURE(rc) 265 && paParms[2].u.uint32) /* Blocking? */ 346 { 347 rc = VERR_INVALID_PARAMETER; 348 } 349 else 350 { 351 rc = m_pManager->nextMessageInfo(&paParms[0].u.uint32 /* uMsg */, &paParms[1].u.uint32 /* cParms */); 352 if (RT_FAILURE(rc)) /* No queued messages available? */ 266 353 { 267 /* Defer client returning. */ 268 rc = VINF_HGCM_ASYNC_EXECUTE; 354 if (m_pfnHostCallback) /* Try asking the host. */ 355 { 356 DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSG data; 357 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG; 358 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data)); 359 if (RT_SUCCESS(rc)) 360 { 361 paParms[0].u.uint32 = data.uMsg; /* uMsg */ 362 paParms[1].u.uint32 = data.cParms; /* cParms */ 363 /* Note: paParms[2] was set by the guest as blocking flag. */ 364 } 365 } 366 else 367 rc = VERR_NOT_FOUND; 368 369 if (RT_FAILURE(rc)) 370 rc = m_pManager->nextMessage(u32Function, cParms, paParms); 371 372 /* Some error occurred? */ 373 if ( RT_FAILURE(rc) 374 && paParms[2].u.uint32) /* Blocking flag set? */ 375 { 376 /* Defer client returning. */ 377 rc = VINF_HGCM_ASYNC_EXECUTE; 378 } 269 379 } 380 } 381 break; 382 } 383 case DragAndDropSvc::GUEST_DND_CONNECT: 384 { 385 LogFlowFunc(("GUEST_DND_CONNECT\n")); 386 if ( cParms != 2 387 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* protocol version */ 388 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* additional connection flags */) 389 rc = VERR_INVALID_PARAMETER; 390 else 391 { 392 uint32_t uProtocol; 393 paParms[0].getUInt32(&uProtocol); /* Get protocol version. */ 394 395 rc = pClient->setProtocol(uProtocol); 396 if (RT_SUCCESS(rc)) 397 { 398 /** @todo Handle connection flags (paParms[1]). */ 399 } 400 401 /* Note: Does not reach the host; the client's protocol version 402 * is only kept in this service. */ 270 403 } 271 404 break; … … 304 437 break; 305 438 } 439 case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS: 440 { 441 LogFlowFunc(("GUEST_DND_HG_EVT_PROGRESS\n")); 442 if ( cParms != 3 443 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* status */ 444 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* percent */ 445 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* rc */) 446 rc = VERR_INVALID_PARAMETER; 447 else 448 { 449 DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA data; 450 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS; 451 paParms[0].getUInt32(&data.uStatus); 452 paParms[1].getUInt32(&data.uPercentage); 453 paParms[2].getUInt32(&data.rc); 454 if (m_pfnHostCallback) 455 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data)); 456 } 457 break; 458 } 306 459 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 307 460 case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING: … … 310 463 if ( cParms != 3 311 464 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* defaction */ 312 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* all actions */465 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* alloctions */ 313 466 || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR /* format */) 314 467 rc = VERR_INVALID_PARAMETER; … … 360 513 paParms[1].getUInt32(&data.cbPath); 361 514 paParms[2].getUInt32(&data.fMode); 362 #ifdef DEBUG_andy 363 LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x\n", 364 data.pszPath, data.cbPath, data.fMode)); 365 #endif 515 516 LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x\n", data.pszPath, data.cbPath, data.fMode)); 366 517 if (m_pfnHostCallback) 367 518 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data)); … … 369 520 break; 370 521 } 371 case DragAndDropSvc::GUEST_DND_GH_SND_FILE: 372 { 373 LogFlowFunc(("GUEST_DND_GH_SND_FILE\n")); 374 if ( cParms != 5 375 || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* file path */ 376 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* file path length */ 377 || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR /* file data */ 378 || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* file data length */ 379 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* creation mode */) 380 rc = VERR_INVALID_PARAMETER; 381 else 382 { 383 DragAndDropSvc::VBOXDNDCBSNDFILEDATA data; 384 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE; 522 /* Note: Since protocol v2 (>= VBox 5.0). */ 523 case DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR: 524 { 525 LogFlowFunc(("GUEST_DND_GH_SND_FILE_HDR\n")); 526 if ( cParms != 6 527 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* context ID */ 528 || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* file path */ 529 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* file path length */ 530 || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* flags */ 531 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* file mode */ 532 || paParms[5].type != VBOX_HGCM_SVC_PARM_64BIT /* file size */) 533 rc = VERR_INVALID_PARAMETER; 534 else 535 { 536 DragAndDropSvc::VBOXDNDCBSNDFILEHDRDATA data; 537 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_HDR; 385 538 uint32_t cTmp; 386 paParms[0].getPointer((void**)&data.pszFilePath, &cTmp);387 paParms[1].get UInt32(&data.cbFilePath);388 paParms[2].get Pointer((void**)&data.pvData, &data.cbData);389 /* paParms[3] is cbData. */539 /* paParms[0] is context ID; unused yet. */ 540 paParms[1].getPointer((void**)&data.pszFilePath, &cTmp); 541 paParms[2].getUInt32(&data.cbFilePath); 542 paParms[3].getUInt32(&data.fFlags); 390 543 paParms[4].getUInt32(&data.fMode); 391 #ifdef DEBUG_andy 392 LogFlowFunc(("pszFilePath=%s, cbData=%RU32, pvData=0x%p, fMode=0x%x\n", 393 data.pszFilePath, data.cbData, data.pvData, data.fMode)); 394 #endif 544 paParms[5].getUInt64(&data.cbSize); 545 546 LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x, cbSize=%RU64\n", 547 data.pszFilePath, data.cbFilePath, data.fMode, data.cbSize)); 548 395 549 if (m_pfnHostCallback) 396 550 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data)); 551 } 552 break; 553 } 554 case DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA: 555 { 556 LogFlowFunc(("GUEST_DND_GH_SND_FILE_DATA\n")); 557 558 switch (pClient->protocol()) 559 { 560 case 2: /* Protocol version 2 only sends the next data chunks to reduce traffic. */ 561 { 562 if ( cParms != 3 563 /* paParms[0] is context ID; unused yet. */ 564 || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* file data */ 565 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* file data length */) 566 { 567 rc = VERR_INVALID_PARAMETER; 568 } 569 else 570 { 571 DragAndDropSvc::VBOXDNDCBSNDFILEDATADATA data; 572 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_DATA; 573 /* paParms[0] is context ID; unused yet. */ 574 paParms[1].getPointer((void**)&data.pvData, &data.cbData); 575 paParms[2].getUInt32(&data.cbData); 576 577 LogFlowFunc(("cbData=%RU32, pvData=0x%p\n", data.cbData, data.pvData)); 578 579 if (m_pfnHostCallback) 580 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data)); 581 } 582 break; 583 } 584 default: 585 { 586 if ( cParms != 5 587 || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* file path */ 588 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* file path length */ 589 || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR /* file data */ 590 || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* file data length */ 591 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* creation mode */) 592 { 593 rc = VERR_INVALID_PARAMETER; 594 } 595 else 596 { 597 DragAndDropSvc::VBOXDNDCBSNDFILEDATADATA data; 598 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_DATA; 599 uint32_t cTmp; 600 paParms[0].getPointer((void**)&data.u.v1.pszFilePath, &cTmp); 601 paParms[1].getUInt32(&data.u.v1.cbFilePath); 602 paParms[2].getPointer((void**)&data.pvData, &cTmp); 603 paParms[3].getUInt32(&data.cbData); 604 paParms[4].getUInt32(&data.u.v1.fMode); 605 606 LogFlowFunc(("pszFilePath=%s, cbData=%RU32, pvData=0x%p, fMode=0x%x\n", 607 data.u.v1.pszFilePath, data.cbData, data.pvData, data.u.v1.fMode)); 608 609 if (m_pfnHostCallback) 610 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data)); 611 } 612 break; 613 } 397 614 } 398 615 break; … … 423 640 /* All other messages are handled by the DnD manager. */ 424 641 rc = m_pManager->nextMessage(u32Function, cParms, paParms); 425 break; 426 } 427 } 428 } 429 430 /* If async execution is requested, we didn't notify the guest yet about 642 if (rc == VERR_NO_DATA) /* Manager has no new messsages? Try asking the host. */ 643 { 644 if (m_pfnHostCallback) 645 { 646 DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSGDATA data; 647 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG_DATA; 648 data.uMsg = u32Function; 649 data.cParms = cParms; 650 data.paParms = paParms; 651 652 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data)); 653 if (RT_SUCCESS(rc)) 654 { 655 cParms = data.cParms; 656 paParms = data.paParms; 657 } 658 } 659 } 660 break; 661 } 662 } 663 } 664 665 /* 666 * If async execution is requested, we didn't notify the guest yet about 431 667 * completion. The client is queued into the waiters list and will be 432 * notified as soon as a new event is available. */ 668 * notified as soon as a new event is available. 669 */ 433 670 if (rc == VINF_HGCM_ASYNC_EXECUTE) 434 671 { … … 449 686 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) 450 687 { 451 LogFlowFunc(("u32Function=%RU32, cParms=%RU32\n", u32Function, cParms)); 688 LogFlowFunc(("u32Function=%RU32, cParms=%RU32, cClients=%zu, cQueue=%zu\n", 689 u32Function, cParms, m_clientMap.size(), m_clientQueue.size())); 452 690 453 691 int rc; … … 463 701 else if (modeGet() != VBOX_DRAG_AND_DROP_MODE_OFF) 464 702 { 465 if (!m_clientQueue.isEmpty()) /* At least one client on the guest connected? */ 466 { 467 rc = m_pManager->addMessage(u32Function, cParms, paParms); 703 if (m_clientMap.size()) /* At least one client on the guest connected? */ 704 { 705 /* 706 * Did the host call something which needs immediate processing? 707 * Prepend the message instead of appending to the command queue then. 708 */ 709 bool fAppend; 710 switch (u32Function) 711 { 712 /* Cancelling the drag'n drop operation has higher priority than 713 * processing already buffered messages. */ 714 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL: 715 fAppend = false; 716 break; 717 718 default: 719 fAppend = true; 720 break; 721 } 722 723 /* 724 * If we prepending the message (instead of appending) this mean we need 725 * to re-schedule the message queue in order to get the new command executed as 726 * soon as possible. 727 */ 728 bool fReschedule = !fAppend; 729 730 rc = m_pManager->addMessage(u32Function, cParms, paParms, fAppend); 731 if ( RT_SUCCESS(rc) 732 && fReschedule) 733 { 734 rc = m_pManager->doReschedule(); 735 } 736 468 737 if (RT_SUCCESS(rc)) 469 738 { 470 HGCM::Client *pClient = m_clientQueue.first(); 471 AssertPtr(pClient); 472 473 /* Check if this was a request for getting the next host 474 * message. If so, return the message id and the parameter 475 * count. The message itself has to be queued. */ 476 uint32_t uMsg = pClient->message(); 477 if (uMsg == DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG) 478 { 479 LogFlowFunc(("Client %RU32 is waiting for next host msg\n", pClient->clientId())); 480 481 uint32_t uMsg1; 482 uint32_t cParms1; 483 rc = m_pManager->nextMessageInfo(&uMsg1, &cParms1); 484 if (RT_SUCCESS(rc)) 739 if (m_clientQueue.size()) /* Any clients in our queue ready for processing the next command? */ 740 { 741 HGCM::Client *pClient = m_clientQueue.first(); 742 AssertPtr(pClient); 743 744 /* 745 * Check if this was a request for getting the next host 746 * message. If so, return the message ID and the parameter 747 * count. The message itself has to be queued. 748 */ 749 uint32_t uMsg = pClient->message(); 750 if (uMsg == DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG) 485 751 { 486 pClient->addMessageInfo(uMsg1, cParms1); 487 if (m_pHelpers) 488 m_pHelpers->pfnCallComplete(pClient->handle(), rc); 489 490 m_clientQueue.removeFirst(); 491 delete pClient; 752 LogFlowFunc(("Client %RU32 is waiting for next host msg\n", pClient->clientId())); 753 754 uint32_t uMsg1; 755 uint32_t cParms1; 756 rc = m_pManager->nextMessageInfo(&uMsg1, &cParms1); 757 if (RT_SUCCESS(rc)) 758 { 759 pClient->addMessageInfo(uMsg1, cParms1); 760 if ( m_pHelpers 761 && m_pHelpers->pfnCallComplete) 762 { 763 m_pHelpers->pfnCallComplete(pClient->handle(), rc); 764 } 765 766 m_clientQueue.removeFirst(); 767 768 delete pClient; 769 pClient = NULL; 770 } 771 else 772 AssertMsgFailed(("m_pManager::nextMessageInfo failed with rc=%Rrc\n", rc)); 492 773 } 493 774 else 494 AssertMsgFailed((" m_pManager::nextMessageInfo failed with rc=%Rrc\n", rc));495 }496 else497 AssertMsgFailed(("Client ID=%RU32 in wrong state with uMsg=%RU32\n",498 pClient->clientId(), uMsg));775 AssertMsgFailed(("Client ID=%RU32 in wrong state with uMsg=%RU32\n", 776 pClient->clientId(), uMsg)); 777 } 778 else 779 LogFlowFunc(("All clients busy; delaying execution\n")); 499 780 } 500 781 else … … 504 785 else 505 786 { 506 /* Tell the host that the guest does not support drag'n drop. 787 /* 788 * Tell the host that the guest does not support drag'n drop. 507 789 * This might happen due to not installed Guest Additions or 508 * not running VBoxTray/VBoxClient. */ 790 * not running VBoxTray/VBoxClient. 791 */ 509 792 rc = VERR_NOT_SUPPORTED; 510 793 } … … 516 799 } 517 800 518 LogFlowFunc (("rc=%Rrc\n", rc));801 LogFlowFuncLeaveRC(rc); 519 802 return rc; 520 803 } 521 804 522 DECLCALLBACK(int) DragAndDropService::progressCallback(uint32_t u Percentage, uint32_t uState, int rc, void *pvUser)805 DECLCALLBACK(int) DragAndDropService::progressCallback(uint32_t uStatus, uint32_t uPercentage, int rc, void *pvUser) 523 806 { 524 807 AssertPtrReturn(pvUser, VERR_INVALID_POINTER); … … 529 812 if (pSelf->m_pfnHostCallback) 530 813 { 531 LogFlowFunc(("GUEST_DND_HG_EVT_PROGRESS: uPercentage=%RU32, uState=%RU32, rc=%Rrc\n", 532 uPercentage, uState, rc)); 814 LogFlowFunc(("GUEST_DND_HG_EVT_PROGRESS: uStatus=%RU32, uPercentage=%RU32, rc=%Rrc\n", 815 uStatus, uPercentage, rc)); 816 533 817 DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA data; 534 818 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS; 535 819 data.uPercentage = RT_MIN(uPercentage, 100); 536 data.uStat e = uState;537 data.rc = rc; 820 data.uStatus = uStatus; 821 data.rc = rc; /** @todo uin32_t vs. int. */ 538 822 539 823 return pSelf->m_pfnHostCallback(pSelf->m_pvHostData, -
trunk/src/VBox/Main/Makefile.kmk
r55314 r55422 5 5 6 6 # 7 # Copyright (C) 2004-201 4Oracle Corporation7 # Copyright (C) 2004-2015 Oracle Corporation 8 8 # 9 9 # This file is part of VirtualBox Open Source Edition (OSE), as -
trunk/src/VBox/Main/idl/VirtualBox.xidl
r55405 r55422 2353 2353 in one of the formats supported by VirtualBox (see 2354 2354 <link to="ISystemProperties::mediumFormats" />). 2355 After the storage unit is successfully created and this method succeeds, 2355 After the storage unit is successfully created and this method succeeds, 2356 2356 if the medium is a base medium, it 2357 2357 will be added to the <link to="#hardDisks"/> array attribute. </li> … … 10460 10460 <interface 10461 10461 name="IDnDBase" extends="$unknown" 10462 uuid=" b15cf9ca-4078-4786-a1be-af773a36e19f"10462 uuid="a9630a67-7238-4b0e-9a58-364b1dd3d032" 10463 10463 wsmap="managed" 10464 10464 > 10465 10465 <desc>Base abstract interface for drag'n drop.</desc> 10466 10467 <attribute name="formats" type="wstring" safearray="yes" readonly="yes"> 10468 <desc>Returns all supported drag'n drop formats.</desc> 10469 </attribute> 10470 10471 <attribute name="protocolVersion" type="unsigned long" readonly="yes"> 10472 <desc>Returns the protocol version which is used to communicate 10473 with the guest.</desc> 10474 </attribute> 10466 10475 10467 10476 <method name="isFormatSupported" > … … 10494 10503 </param> 10495 10504 </method> 10496 10497 <attribute name="formats" type="wstring" safearray="yes" readonly="yes">10498 <desc>Returns all supported drag'n drop formats.</desc>10499 </attribute>10500 10505 10501 10506 </interface> … … 10583 10588 <interface 10584 10589 name="IDnDTarget" extends="IDnDBase" 10585 uuid="2 366c45c-4633-41a1-9fa6-0ef9f244434c"10590 uuid="25ac16fa-316d-4934-9a7f-fe02f6739bef" 10586 10591 wsmap="managed" 10587 10592 > … … 10700 10705 <method name="sendData"> 10701 10706 <desc> 10702 Sendsdata to the target.10707 Initiates sending data to the target. 10703 10708 10704 10709 <result name="VBOX_E_VM_ERROR"> … … 10718 10723 <param name="progress" type="IProgress" dir="return"> 10719 10724 <desc>Progress object to track the operation completion.</desc> 10725 </param> 10726 </method> 10727 10728 <method name="cancel"> 10729 <desc> 10730 Requests cancelling the current operation. The target can veto 10731 the request in case the operation is not cancelable at the moment. 10732 10733 <result name="VBOX_E_VM_ERROR"> 10734 VMM device is not available. 10735 </result> 10736 10737 </desc> 10738 10739 <param name="veto" type="boolean" dir="return"> 10740 <desc>Whether the target has vetoed cancelling the operation.</desc> 10720 10741 </param> 10721 10742 </method> -
trunk/src/VBox/Main/include/GuestDnDPrivate.h
r51556 r55422 6 6 7 7 /* 8 * Copyright (C) 2011-201 4Oracle Corporation8 * Copyright (C) 2011-2015 Oracle Corporation 9 9 * 10 10 * This file is part of VirtualBox Open Source Edition (OSE), as … … 21 21 22 22 #include "VBox/hgcmsvc.h" /* For PVBOXHGCMSVCPARM. */ 23 24 /* Forward prototype declarations. */ 23 #include "VBox/GuestHost/DragAndDrop.h" 24 25 /** 26 * Forward prototype declarations. 27 */ 25 28 class Guest; 29 class GuestDnDBase; 30 class GuestDnDResponse; 31 class GuestDnDSource; 32 class GuestDnDTarget; 26 33 class Progress; 27 34 28 /** 29 * Class for handling drag'n drop responses from 30 * the guest side. 31 */ 35 /** Array (vector) of guest DnD data. This might be an URI list, according 36 * to the format being set. */ 37 typedef std::vector<BYTE> GuestDnDData; 38 39 /** 40 * Context structure for sending data to the guest. 41 */ 42 typedef struct SENDDATACTX 43 { 44 /** Pointer to guest target class this context belongs to. */ 45 GuestDnDTarget *mpTarget; 46 /** Pointer to guest response class this context belongs to. */ 47 GuestDnDResponse *mpResp; 48 /** Flag indicating whether a file transfer is active and 49 * initiated by the host. */ 50 bool mIsActive; 51 /** Target (VM) screen ID. */ 52 uint32_t mScreenID; 53 /** Drag'n drop format to send. */ 54 com::Utf8Str mFormat; 55 /** Drag'n drop data to send. 56 * This can be arbitrary data or an URI list. */ 57 GuestDnDData mData; 58 /** Struct for keeping data required for URI list processing. */ 59 struct 60 { 61 /** List of all URI objects to send. */ 62 DnDURIList lstURI; 63 /** Event semaphore to notify in case of callback completion. */ 64 RTSEMEVENT SemEvent; 65 /** Overall size (in bytes) of data to send. */ 66 uint64_t cbToProcess; 67 /** Overall number of processed URI objects. */ 68 uint32_t cProcessed; 69 /** Overall size (in bytes) of processed file data. */ 70 uint64_t cbProcessed; 71 /** Pointer to scratch buffer to use for 72 * doing the actual chunk transfers. */ 73 void *pvScratchBuf; 74 /** Size (in bytes) of scratch buffer. */ 75 size_t cbScratchBuf; 76 } mURI; 77 78 } SENDDATACTX, *PSENDDATACTX; 79 80 /** 81 * Context structure for receiving data from the guest. 82 */ 83 typedef struct RECVDATACTX 84 { 85 /** Pointer to guest source class this context belongs to. */ 86 GuestDnDSource *mpSource; 87 /** Pointer to guest response class this context belongs to. */ 88 GuestDnDResponse *mpResp; 89 /** Flag indicating whether a file transfer is active and 90 * initiated by the host. */ 91 bool mIsActive; 92 /** Drag'n drop format to send. */ 93 com::Utf8Str mFormat; 94 /** Desired drop action to perform on the host. 95 * Needed to tell the guest if data has to be 96 * deleted e.g. when moving instead of copying. */ 97 uint32_t mAction; 98 /** Drag'n drop received from the guest. 99 * This can be arbitrary data or an URI list. */ 100 GuestDnDData mData; 101 /** Event semaphore to notify in case of callback completion. */ 102 RTSEMEVENT SemEvent; 103 /** Struct for keeping data required for URI list processing. */ 104 struct 105 { 106 /** Temporary drop directory on the host where to 107 * put the files sent from the guest. */ 108 com::Utf8Str strDropDir; 109 /** (Non-recursive) List of root URI objects to receive. */ 110 DnDURIList lstURI; 111 /** Current object to receive. */ 112 DnDURIObject objURI; 113 /** Overall size (in bytes) of data to send. */ 114 uint64_t cbToProcess; 115 /** Overall number of processed URI objects. */ 116 uint32_t cProcessed; 117 /** Overall size (in bytes) of processed file data. */ 118 uint64_t cbProcessed; 119 /** List for holding created directories in the case of a rollback. */ 120 RTCList<RTCString> lstDirs; 121 /** List for holding created files in the case of a rollback. */ 122 RTCList<RTCString> lstFiles; 123 124 } mURI; 125 126 } RECVDATACTX, *PRECVDATACTX; 127 128 /** 129 * Simple structure for a buffered guest DnD message. 130 */ 131 class GuestDnDMsg 132 { 133 public: 134 135 GuestDnDMsg(void) 136 : uMsg(0) 137 , cParms(0) 138 , cParmsAlloc(0) 139 , paParms(NULL) { } 140 141 virtual ~GuestDnDMsg(void) 142 { 143 if (paParms) 144 { 145 /* Remove deep copies. */ 146 for (uint32_t i = 0; i < cParms; i++) 147 { 148 if ( paParms[i].type == VBOX_HGCM_SVC_PARM_PTR 149 && paParms[i].u.pointer.addr) 150 { 151 RTMemFree(paParms[i].u.pointer.addr); 152 } 153 } 154 155 delete paParms; 156 } 157 } 158 159 public: 160 161 PVBOXHGCMSVCPARM getNextParam(void) 162 { 163 if (cParms >= cParmsAlloc) 164 { 165 paParms = (PVBOXHGCMSVCPARM)RTMemRealloc(paParms, (cParmsAlloc + 4) * sizeof(VBOXHGCMSVCPARM)); 166 if (!paParms) 167 throw VERR_NO_MEMORY; 168 RT_BZERO(&paParms[cParmsAlloc], 4 * sizeof(VBOXHGCMSVCPARM)); 169 cParmsAlloc += 4; 170 } 171 172 return &paParms[cParms++]; 173 } 174 175 uint32_t getCount(void) const { return cParms; } 176 PVBOXHGCMSVCPARM getParms(void) const { return paParms; } 177 uint32_t getType(void) const { return uMsg; } 178 179 int setNextPointer(void *pvBuf, uint32_t cbBuf) 180 { 181 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); 182 AssertReturn(cbBuf, VERR_INVALID_PARAMETER); 183 184 PVBOXHGCMSVCPARM pParm = getNextParam(); 185 if (!pParm) 186 return VERR_NO_MEMORY; 187 188 void *pvTmp = RTMemDup(pvBuf, cbBuf); 189 if (!pvTmp) 190 { 191 RTMemFree(pParm); 192 return VERR_NO_MEMORY; 193 } 194 195 pParm->setPointer(pvTmp, cbBuf); 196 return VINF_SUCCESS; 197 } 198 199 int setNextString(const char *pszString) 200 { 201 PVBOXHGCMSVCPARM pParm = getNextParam(); 202 if (!pParm) 203 return VERR_NO_MEMORY; 204 205 char *pszTemp = RTStrDup(pszString); 206 if (!pszTemp) 207 { 208 RTMemFree(pParm); 209 return VERR_NO_MEMORY; 210 } 211 212 pParm->setString(pszTemp); 213 return VINF_SUCCESS; 214 } 215 216 int setNextUInt32(uint32_t u32Val) 217 { 218 PVBOXHGCMSVCPARM pParm = getNextParam(); 219 if (!pParm) 220 return VERR_NO_MEMORY; 221 222 pParm->setUInt32(u32Val); 223 return VINF_SUCCESS; 224 } 225 226 int setNextUInt64(uint64_t u64Val) 227 { 228 PVBOXHGCMSVCPARM pParm = getNextParam(); 229 if (!pParm) 230 return VERR_NO_MEMORY; 231 232 pParm->setUInt64(u64Val); 233 return VINF_SUCCESS; 234 } 235 236 void setType(uint32_t uMsgType) { uMsg = uMsgType; } 237 238 protected: 239 240 /** Message type. */ 241 uint32_t uMsg; 242 /** Message parameters. */ 243 uint32_t cParms; 244 /** Size of array. */ 245 uint32_t cParmsAlloc; 246 /** Array of HGCM parameters */ 247 PVBOXHGCMSVCPARM paParms; 248 }; 249 250 /** Guest DnD callback function definition. */ 251 typedef DECLCALLBACKPTR(int, PFNGUESTDNDCALLBACK) (uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser); 252 253 /** 254 * Structure for keeping a guest DnD callback. 255 * Each callback can handle one HGCM message, however, multiple HGCM messages can be registered 256 * to the same callback (function). 257 */ 258 typedef struct GuestDnDCallback 259 { 260 GuestDnDCallback(void) 261 : uMessgage(0) 262 , pfnCallback(NULL) 263 , pvUser(NULL) { } 264 265 GuestDnDCallback(PFNGUESTDNDCALLBACK pvCB, uint32_t uMsg, void *pvUsr = NULL) 266 : uMessgage(uMsg) 267 , pfnCallback(pvCB) 268 , pvUser(pvUsr) { } 269 270 /** The HGCM message ID to handle. */ 271 uint32_t uMessgage; 272 /** Pointer to callback function. */ 273 PFNGUESTDNDCALLBACK pfnCallback; 274 /** Pointer to user-supplied data. */ 275 void *pvUser; 276 277 } GuestDnDCallback; 278 279 /** Contains registered callback pointers for specific HGCM message types. */ 280 typedef std::map<uint32_t, GuestDnDCallback> GuestDnDCallbackMap; 281 32 282 class GuestDnDResponse 33 283 { … … 36 286 37 287 GuestDnDResponse(const ComObjPtr<Guest>& pGuest); 38 39 288 virtual ~GuestDnDResponse(void); 40 289 41 290 public: 42 291 43 int notifyAboutGuestResponse(void); 44 int waitForGuestResponse(RTMSINTERVAL msTimeout = 500); 292 int notifyAboutGuestResponse(void) const; 293 int waitForGuestResponse(RTMSINTERVAL msTimeout = 500) const; 294 295 void setAllActions(uint32_t a) { m_allActions = a; } 296 uint32_t allActions(void) const { return m_allActions; } 45 297 46 298 void setDefAction(uint32_t a) { m_defAction = a; } 47 299 uint32_t defAction(void) const { return m_defAction; } 48 300 49 void set AllActions(uint32_t a) { m_allActions = a; }50 uint32_t allActions() const { return m_allActions; }301 void setDropDir(const Utf8Str &strDropDir) { m_strDropDir = strDropDir; } 302 Utf8Str dropDir(void) const { return m_strDropDir; } 51 303 52 304 void setFormat(const Utf8Str &strFormat) { m_strFormat = strFormat; } 53 305 Utf8Str format(void) const { return m_strFormat; } 54 306 55 void setDropDir(const Utf8Str &strDropDir) { m_strDropDir = strDropDir; }56 Utf8Str dropDir(void) const { return m_strDropDir; }57 58 307 int dataAdd(const void *pvData, uint32_t cbData, uint32_t *pcbCurSize); 59 308 int dataSetStatus(size_t cbDataAdd, size_t cbDataTotal = 0); 60 void reset(void);61 309 const void *data(void) { return m_pvData; } 62 310 size_t size(void) const { return m_cbData; } 63 311 312 void reset(void); 313 314 bool isProgressCanceled(void) const; 315 int setCallback(uint32_t uMsg, PFNGUESTDNDCALLBACK pfnCallback, void *pvUser = NULL); 64 316 int setProgress(unsigned uPercentage, uint32_t uState, int rcOp = VINF_SUCCESS); 65 317 HRESULT resetProgress(const ComObjPtr<Guest>& pParent); 66 318 HRESULT queryProgressTo(IProgress **ppProgress); 67 319 68 int writeToFile(const char *pszPath, size_t cbPath, void *pvData, size_t cbData, uint32_t fMode); 320 public: 321 322 /** @name HGCM callback handling. 323 @{ */ 324 int onDispatch(uint32_t u32Function, void *pvParms, uint32_t cbParms); 325 /** @} */ 69 326 70 327 public: … … 72 329 Utf8Str errorToString(const ComObjPtr<Guest>& pGuest, int guestRc); 73 330 74 private: 75 RTSEMEVENT m_EventSem; 76 uint32_t m_defAction; 77 uint32_t m_allActions; 78 Utf8Str m_strFormat; 331 protected: 332 333 /** Pointer to context this class is tied to. */ 334 void *m_pvCtx; 335 RTSEMEVENT m_EventSem; 336 uint32_t m_defAction; 337 uint32_t m_allActions; 338 Utf8Str m_strFormat; 79 339 80 340 /** The actual MIME data.*/ 81 void *m_pvData;341 void *m_pvData; 82 342 /** Size (in bytes) of MIME data. */ 83 uint32_t m_cbData;84 85 size_t m_cbDataCurrent;86 size_t m_cbDataTotal;343 uint32_t m_cbData; 344 345 size_t m_cbDataCurrent; 346 size_t m_cbDataTotal; 87 347 /** Dropped files directory on the host. */ 88 Utf8Str m_strDropDir; 89 /** The handle of the currently opened file being written to 90 * or read from. */ 91 RTFILE m_hFile; 92 Utf8Str m_strFile; 93 94 ComObjPtr<Guest> m_parent; 95 ComObjPtr<Progress> m_progress; 348 Utf8Str m_strDropDir; 349 /** URI object to use for reading/writing from/to files 350 * and handling directories. */ 351 DnDURIObject m_URIObj; 352 /** Pointer to IGuest parent object. */ 353 ComObjPtr<Guest> m_parent; 354 /** Pointer to associated progress object. Optional. */ 355 ComObjPtr<Progress> m_progress; 356 /** Callback map. */ 357 GuestDnDCallbackMap m_mapCallbacks; 96 358 }; 97 359 … … 172 434 /** @} */ 173 435 174 protected:175 176 #ifdef VBOX_WITH_DRAG_AND_DROP_GH177 /** @name Dispatch handlers for the HGCM callbacks.178 * @{ */179 int onGHSendData(GuestDnDResponse *pResp, const void *pvData, size_t cbData, size_t cbTotalSize);180 int onGHSendDir(GuestDnDResponse *pResp, const char *pszPath, size_t cbPath, uint32_t fMode);181 int onGHSendFile(GuestDnDResponse *pResp, const char *pszPath, size_t cbPath, void *pvData, size_t cbData, uint32_t fMode);182 /** @} */183 #endif /* VBOX_WITH_DRAG_AND_DROP_GH */184 185 436 private: 186 437 … … 192 443 #define GuestDnDInst() GuestDnD::getInstance() 193 444 445 /** List of pointers to guest DnD Messages. */ 446 typedef std::list<GuestDnDMsg *> GuestDnDMsgList; 447 194 448 /** 195 449 * IDnDBase class implementation for sharing code between … … 204 458 protected: 205 459 206 /** Shared IDnDBase method implementations. 207 * @{ */ 208 HRESULT isFormatSupported(const com::Utf8Str &aFormat, BOOL *aSupported); 209 HRESULT getFormats(std::vector<com::Utf8Str> &aFormats); 210 HRESULT addFormats(const std::vector<com::Utf8Str> &aFormats); 211 HRESULT removeFormats(const std::vector<com::Utf8Str> &aFormats); 460 /** Shared (internal) IDnDBase method implementations. 461 * @{ */ 462 HRESULT i_isFormatSupported(const com::Utf8Str &aFormat, BOOL *aSupported); 463 HRESULT i_getFormats(std::vector<com::Utf8Str> &aFormats); 464 HRESULT i_addFormats(const std::vector<com::Utf8Str> &aFormats); 465 HRESULT i_removeFormats(const std::vector<com::Utf8Str> &aFormats); 466 467 HRESULT i_getProtocolVersion(ULONG *puVersion); 468 /** @} */ 469 470 protected: 471 472 int getProtocolVersion(uint32_t *puVersion); 473 474 int addMsg(GuestDnDMsg *pMsg) 475 { 476 mData.m_lstOutgoing.push_back(pMsg); 477 return VINF_SUCCESS; 478 } 479 480 GuestDnDMsg *nextMsg(void) 481 { 482 if (mData.m_lstOutgoing.empty()) 483 return NULL; 484 return mData.m_lstOutgoing.front(); 485 } 486 487 void removeNext(void) 488 { 489 if (!mData.m_lstOutgoing.empty()) 490 { 491 GuestDnDMsg *pMsg = mData.m_lstOutgoing.front(); 492 if (pMsg) 493 delete pMsg; 494 mData.m_lstOutgoing.pop_front(); 495 } 496 } 497 498 /** Static callbacks. 499 * @{ */ 500 //static DECLCALLBACK(int) i_getNextMsgCallback(GuestDnDBase *pThis, uint32_t *puMsg, uint32_t *pcParms, PVBOXHGCMSVCPARM paParms); 212 501 /** @} */ 213 502 … … 217 506 * @{ */ 218 507 /** Pointer to guest implementation. */ 219 const ComObjPtr<Guest> m_pGuest;508 const ComObjPtr<Guest> m_pGuest; 220 509 /** List of supported MIME/Content-type formats. */ 221 std::vector<com::Utf8Str> m_strFormats; 222 /** @} */ 510 std::vector<com::Utf8Str> m_strFormats; 511 /** @} */ 512 513 struct 514 { 515 /** The DnD protocol version to use, depending on the 516 * installed Guest Additions. */ 517 uint32_t mProtocolVersion; 518 /** Outgoing message queue. */ 519 GuestDnDMsgList m_lstOutgoing; 520 } mData; 223 521 }; 224 522 -
trunk/src/VBox/Main/include/GuestDnDSourceImpl.h
r51556 r55422 5 5 6 6 /* 7 * Copyright (C) 2014 Oracle Corporation7 * Copyright (C) 2014-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 22 22 #include "GuestDnDPrivate.h" 23 23 24 struct RECVDATACTX; 25 typedef struct RECVDATACTX *PRECVDATACTX; 26 24 27 class ATL_NO_VTABLE GuestDnDSource : 25 28 public GuestDnDSourceWrap, 26 p rotectedGuestDnDBase29 public GuestDnDBase 27 30 { 28 31 public: … … 46 49 HRESULT addFormats(const std::vector<com::Utf8Str> &aFormats); 47 50 HRESULT removeFormats(const std::vector<com::Utf8Str> &aFormats); 51 52 HRESULT getProtocolVersion(ULONG *aProtocolVersion); 48 53 /** @} */ 49 54 … … 57 62 protected: 58 63 59 /** @name Attributes. 64 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 65 /** @name Dispatch handlers for the HGCM callbacks. 60 66 * @{ */ 61 /** Pointer to guest implementation. */ 62 const ComObjPtr<Guest> m_pGuest; 67 int i_onReceiveData(PRECVDATACTX pCtx, const void *pvData, uint32_t cbData, uint64_t cbTotalSize); 68 int i_onReceiveDir(PRECVDATACTX pCtx, const char *pszPath, uint32_t cbPath, uint32_t fMode); 69 int i_onReceiveFileHdr(PRECVDATACTX pCtx, const char *pszPath, uint32_t cbPath, uint64_t cbSize, uint32_t fMode, uint32_t fFlags); 70 int i_onReceiveFileData(PRECVDATACTX pCtx, const void *pvData, uint32_t cbData); 63 71 /** @} */ 72 #endif 73 74 protected: 75 76 static DECLCALLBACK(int) i_receiveDataThread(RTTHREAD Thread, void *pvUser); 77 78 /** @name Callbacks for dispatch handler. 79 * @{ */ 80 static DECLCALLBACK(int) i_receiveRawDataCallback(uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser); 81 static DECLCALLBACK(int) i_receiveURIDataCallback(uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser); 82 /** @} */ 83 84 protected: 85 86 int i_receiveData(PRECVDATACTX pCtx); 87 int i_receiveRawData(PRECVDATACTX pCtx); 88 int i_receiveURIData(PRECVDATACTX pCtx); 64 89 }; 65 90 -
trunk/src/VBox/Main/include/GuestDnDTargetImpl.h
r51556 r55422 5 5 6 6 /* 7 * Copyright (C) 2014 Oracle Corporation7 * Copyright (C) 2014-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 22 22 #include "GuestDnDPrivate.h" 23 23 24 #include <VBox/GuestHost/DragAndDrop.h> 25 #include <VBox/HostServices/DragAndDropSvc.h> 26 27 struct SENDDATACTX; 28 typedef struct SENDDATACTX *PSENDDATACTX; 29 24 30 class ATL_NO_VTABLE GuestDnDTarget : 25 31 public GuestDnDTargetWrap, 26 p rotectedGuestDnDBase32 public GuestDnDBase 27 33 { 28 34 public: … … 46 52 HRESULT addFormats(const std::vector<com::Utf8Str> &aFormats); 47 53 HRESULT removeFormats(const std::vector<com::Utf8Str> &aFormats); 54 55 HRESULT getProtocolVersion(ULONG *aProtocolVersion); 48 56 /** @} */ 49 57 … … 55 63 HRESULT drop(ULONG aScreenId, ULONG aX, ULONG aY, DnDAction_T aDefaultAction, const std::vector<DnDAction_T> &aAllowedActions, const std::vector<com::Utf8Str> &aFormats, com::Utf8Str &aFormat, DnDAction_T *aResultAction); 56 64 HRESULT sendData(ULONG aScreenId, const com::Utf8Str &aFormat, const std::vector<BYTE> &aData, ComPtr<IProgress> &aProgress); 65 HRESULT cancel(BOOL *aVeto); 57 66 /** @} */ 67 68 protected: 69 70 static DECLCALLBACK(int) i_sendDataThread(RTTHREAD Thread, void *pvUser); 71 static DECLCALLBACK(int) i_sendURIDataCallback(uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser); 72 73 protected: 74 75 int i_cancelOperation(void); 76 int i_sendData(PSENDDATACTX pCtx); 77 int i_sendDirectory(PSENDDATACTX pCtx, GuestDnDMsg *pMsg, DnDURIObject &aDirectory); 78 int i_sendFile(PSENDDATACTX pCtx, GuestDnDMsg *pMsg, DnDURIObject &aFile); 79 int i_sendFileData(PSENDDATACTX pCtx, GuestDnDMsg *pMsg, DnDURIObject &aFile); 80 int i_sendURIData(PSENDDATACTX pCtx); 81 int i_sendURIDataLoop(PSENDDATACTX pCtx, GuestDnDMsg *pMsg); 58 82 59 83 protected: … … 61 85 /** @name Attributes. 62 86 * @{ */ 63 /** Pointer to guest implementation. */64 const ComObjPtr<Guest> m_pGuest;87 /** Maximum data block size (in bytes) the target can handle. */ 88 uint32_t m_cbBlockSize; 65 89 /** @} */ 66 90 }; -
trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp
r55244 r55422 6 6 7 7 /* 8 * Copyright (C) 2011-201 4Oracle Corporation8 * Copyright (C) 2011-2015 Oracle Corporation 9 9 * 10 10 * This file is part of VirtualBox Open Source Edition (OSE), as … … 37 37 # include <VBox/GuestHost/DragAndDrop.h> 38 38 # include <VBox/HostServices/DragAndDropSvc.h> 39 # include <VBox/version.h> 39 40 40 41 # ifdef LOG_GROUP … … 167 168 , m_cbDataCurrent(0) 168 169 , m_cbDataTotal(0) 169 , m_hFile(NIL_RTFILE)170 170 , m_parent(pGuest) 171 171 { 172 172 int rc = RTSemEventCreate(&m_EventSem); 173 AssertRC(rc); 173 if (RT_FAILURE(rc)) 174 throw rc; 174 175 } 175 176 … … 242 243 } 243 244 244 int GuestDnDResponse::notifyAboutGuestResponse(void) 245 int GuestDnDResponse::notifyAboutGuestResponse(void) const 245 246 { 246 247 return RTSemEventSignal(m_EventSem); … … 262 263 m_pvData = NULL; 263 264 } 264 m_cbData = 0; 265 266 m_cbData = 0; 265 267 m_cbDataCurrent = 0; 266 m_cbDataTotal = 0; 267 268 if (m_hFile != NIL_RTFILE) 269 { 270 RTFileClose(m_hFile); 271 m_hFile = NIL_RTFILE; 272 } 273 m_strFile = ""; 268 m_cbDataTotal = 0; 274 269 } 275 270 … … 280 275 if (SUCCEEDED(rc)) 281 276 { 282 rc = m_progress->init(static_cast<IGuest *>(pParent),277 rc = m_progress->init(static_cast<IGuest *>(pParent), 283 278 Bstr(pParent->tr("Dropping data")).raw(), 284 FALSE /* fCancelable */);279 TRUE /* aCancelable */); 285 280 } 286 281 return rc; 287 282 } 288 283 284 bool GuestDnDResponse::isProgressCanceled(void) const 285 { 286 BOOL fCanceled; 287 if (!m_progress.isNull()) 288 { 289 HRESULT hr = m_progress->COMGETTER(Canceled)(&fCanceled); 290 AssertComRC(hr); 291 } 292 else fCanceled = TRUE; 293 294 return RT_BOOL(fCanceled); 295 } 296 297 int GuestDnDResponse::setCallback(uint32_t uMsg, PFNGUESTDNDCALLBACK pfnCallback, void *pvUser /* = NULL */) 298 { 299 GuestDnDCallbackMap::const_iterator it = m_mapCallbacks.find(uMsg); 300 301 /* Add. */ 302 if (pfnCallback) 303 { 304 if (it == m_mapCallbacks.end()) 305 { 306 m_mapCallbacks[uMsg] = GuestDnDCallback(pfnCallback, uMsg, pvUser); 307 return VINF_SUCCESS; 308 } 309 310 AssertMsgFailed(("Callback for message %RU32 already registered\n", uMsg)); 311 return VERR_ALREADY_EXISTS; 312 } 313 314 /* Remove. */ 315 if (it != m_mapCallbacks.end()) 316 m_mapCallbacks.erase(it); 317 318 return VINF_SUCCESS; 319 } 320 289 321 int GuestDnDResponse::setProgress(unsigned uPercentage, 290 uint32_t uStat e, int rcOp /* = VINF_SUCCESS */)291 { 292 LogFlowFunc(("u Percentage=%RU32, uState=%RU32, rcOp=%Rrc\n",293 u Percentage, uState, rcOp));322 uint32_t uStatus, int rcOp /* = VINF_SUCCESS */) 323 { 324 LogFlowFunc(("uStatus=%RU32, uPercentage=%RU32, rcOp=%Rrc\n", 325 uStatus, uPercentage, rcOp)); 294 326 295 327 int vrc = VINF_SUCCESS; … … 298 330 BOOL fCompleted; 299 331 HRESULT hr = m_progress->COMGETTER(Completed)(&fCompleted); 332 AssertComRC(hr); 333 334 BOOL fCanceled; 335 hr = m_progress->COMGETTER(Canceled)(&fCanceled); 336 AssertComRC(hr); 337 338 LogFlowFunc(("fCompleted=%RTbool, fCanceled=%RTbool\n", fCompleted, fCanceled)); 339 300 340 if (!fCompleted) 301 341 { 302 if (uState == DragAndDropSvc::DND_PROGRESS_ERROR)342 switch (uStatus) 303 343 { 304 hr = m_progress->i_notifyComplete(VBOX_E_IPRT_ERROR, 305 COM_IIDOF(IGuest), 306 m_parent->getComponentName(), 307 GuestDnDResponse::errorToString(m_parent, rcOp).c_str()); 308 reset(); 309 } 310 else if (uState == DragAndDropSvc::DND_PROGRESS_CANCELLED) 311 { 312 hr = m_progress->Cancel(); 313 if (SUCCEEDED(hr)) 314 vrc = VERR_CANCELLED; 315 316 reset(); 317 } 318 else /* uState == DragAndDropSvc::DND_PROGRESS_RUNNING */ 319 { 320 hr = m_progress->SetCurrentOperationProgress(uPercentage); 321 AssertComRC(hr); 322 if ( uState == DragAndDropSvc::DND_PROGRESS_COMPLETE 323 || uPercentage >= 100) 344 case DragAndDropSvc::DND_PROGRESS_ERROR: 345 { 346 hr = m_progress->i_notifyComplete(VBOX_E_IPRT_ERROR, 347 COM_IIDOF(IGuest), 348 m_parent->getComponentName(), 349 GuestDnDResponse::errorToString(m_parent, rcOp).c_str()); 350 reset(); 351 break; 352 } 353 354 case DragAndDropSvc::DND_PROGRESS_CANCELLED: 355 { 324 356 hr = m_progress->i_notifyComplete(S_OK); 357 AssertComRC(hr); 358 359 reset(); 360 break; 361 } 362 363 case DragAndDropSvc::DND_PROGRESS_RUNNING: 364 case DragAndDropSvc::DND_PROGRESS_COMPLETE: 365 { 366 if (!fCanceled) 367 { 368 hr = m_progress->SetCurrentOperationProgress(uPercentage); 369 AssertComRC(hr); 370 if ( uStatus == DragAndDropSvc::DND_PROGRESS_COMPLETE 371 || uPercentage >= 100) 372 { 373 hr = m_progress->i_notifyComplete(S_OK); 374 AssertComRC(hr); 375 } 376 } 377 break; 378 } 379 380 default: 381 break; 325 382 } 326 383 } 327 384 } 328 385 386 LogFlowFuncLeaveRC(vrc); 329 387 return vrc; 330 388 } … … 348 406 /** @todo Don't use anonymous enums (uint32_t). */ 349 407 uint32_t uStatus = DragAndDropSvc::DND_PROGRESS_RUNNING; 350 if (m_cbDataCurrent >= m_cbDataTotal) 351 uStatus = DragAndDropSvc::DND_PROGRESS_COMPLETE; 352 353 #ifdef DEBUG_andy 354 LogFlowFunc(("Updating transfer status (%zu/%zu), status=%ld\n", 355 m_cbDataCurrent, m_cbDataTotal, uStatus)); 356 #else 408 Assert(m_cbDataCurrent <= m_cbDataTotal); 409 if (m_cbDataCurrent >= m_cbDataTotal) uStatus = DragAndDropSvc::DND_PROGRESS_COMPLETE; 410 411 LogFlowFunc(("Updating transfer status (%zu/%zu), status=%ld\n", m_cbDataCurrent, m_cbDataTotal, uStatus)); 357 412 AssertMsg(m_cbDataCurrent <= m_cbDataTotal, 358 413 ("More data transferred (%zu) than initially announced (%zu), cbDataAdd=%zu\n", 359 m_cbDataCurrent, m_cbDataTotal, cbDataAdd));360 #endif 414 m_cbDataCurrent, m_cbDataTotal, cbDataAdd)); 415 361 416 int rc = setProgress(cPercentage, uStatus); 362 417 … … 364 419 * guest should first clean up stuff itself and than really confirm 365 420 * the cancel request by an extra message. */ 366 if (rc == VERR_CANCELLED) 367 rc = setProgress(100, DragAndDropSvc::DND_PROGRESS_CANCELLED); 421 if (rc == VERR_CANCELLED) rc = setProgress(100, DragAndDropSvc::DND_PROGRESS_CANCELLED); 368 422 369 423 LogFlowFuncLeaveRC(rc); … … 371 425 } 372 426 427 int GuestDnDResponse::onDispatch(uint32_t u32Function, void *pvParms, uint32_t cbParms) 428 { 429 LogFlowFunc(("u32Function=%RU32, pvParms=%p, cbParms=%RU32\n", u32Function, pvParms, cbParms)); 430 431 int rc = VERR_WRONG_ORDER; /* Play safe. */ 432 bool fTryCallbacks = false; 433 434 switch (u32Function) 435 { 436 case DragAndDropSvc::GUEST_DND_HG_ACK_OP: 437 { 438 DragAndDropSvc::PVBOXDNDCBHGACKOPDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGACKOPDATA>(pvParms); 439 AssertPtr(pCBData); 440 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGACKOPDATA) == cbParms, VERR_INVALID_PARAMETER); 441 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_ACK_OP == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); 442 443 setDefAction(pCBData->uAction); 444 rc = notifyAboutGuestResponse(); 445 break; 446 } 447 448 case DragAndDropSvc::GUEST_DND_HG_REQ_DATA: 449 { 450 DragAndDropSvc::PVBOXDNDCBHGREQDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGREQDATADATA>(pvParms); 451 AssertPtr(pCBData); 452 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGREQDATADATA) == cbParms, VERR_INVALID_PARAMETER); 453 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_REQ_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); 454 455 setFormat(pCBData->pszFormat); 456 rc = notifyAboutGuestResponse(); 457 break; 458 } 459 460 case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS: 461 { 462 DragAndDropSvc::PVBOXDNDCBHGEVTPROGRESSDATA pCBData = 463 reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGEVTPROGRESSDATA>(pvParms); 464 AssertPtr(pCBData); 465 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA) == cbParms, VERR_INVALID_PARAMETER); 466 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); 467 468 rc = setProgress(pCBData->uPercentage, pCBData->uStatus, pCBData->rc); 469 if (RT_SUCCESS(rc)) 470 rc = notifyAboutGuestResponse(); 471 break; 472 } 473 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 474 case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING: 475 { 476 DragAndDropSvc::PVBOXDNDCBGHACKPENDINGDATA pCBData = 477 reinterpret_cast<DragAndDropSvc::PVBOXDNDCBGHACKPENDINGDATA>(pvParms); 478 AssertPtr(pCBData); 479 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBGHACKPENDINGDATA) == cbParms, VERR_INVALID_PARAMETER); 480 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_ACK_PENDING == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); 481 482 setFormat (pCBData->pszFormat); 483 setDefAction (pCBData->uDefAction); 484 setAllActions(pCBData->uAllActions); 485 486 rc = notifyAboutGuestResponse(); 487 break; 488 } 489 #endif /* VBOX_WITH_DRAG_AND_DROP_GH */ 490 default: 491 /* * Try if the event is covered by a registered callback. */ 492 fTryCallbacks = true; 493 break; 494 } 495 496 /* 497 * Try the host's installed callbacks (if any). 498 */ 499 if (fTryCallbacks) 500 { 501 GuestDnDCallbackMap::const_iterator it = m_mapCallbacks.find(u32Function); 502 if (it != m_mapCallbacks.end()) 503 { 504 AssertPtr(it->second.pfnCallback); 505 rc = it->second.pfnCallback(u32Function, pvParms, cbParms, it->second.pvUser); 506 } 507 else 508 rc = VERR_NO_DATA; /* Tell the guest. */ 509 } 510 511 LogFlowFunc(("Returning rc=%Rrc\n", rc)); 512 return rc; 513 } 514 373 515 HRESULT GuestDnDResponse::queryProgressTo(IProgress **ppProgress) 374 516 { … … 376 518 } 377 519 378 int GuestDnDResponse::waitForGuestResponse(RTMSINTERVAL msTimeout /*= 500 */) 520 int GuestDnDResponse::waitForGuestResponse(RTMSINTERVAL msTimeout /*= 500 */) const 379 521 { 380 522 int rc = RTSemEventWait(m_EventSem, msTimeout); … … 382 524 LogFlowFunc(("msTimeout=%RU32, rc=%Rrc\n", msTimeout, rc)); 383 525 #endif 384 return rc;385 }386 387 int GuestDnDResponse::writeToFile(const char *pszPath, size_t cbPath,388 void *pvData, size_t cbData, uint32_t fMode)389 {390 /** @todo Support locking more than one file at a time! We391 * might want to have a table in DnDGuestImpl which392 * keeps those file pointers around, or extend the393 * actual protocol for explicit open calls.394 *395 * For now we only keep one file open at a time, so if396 * a client does alternating writes to different files397 * this function will close the old and re-open the new398 * file on every call. */399 int rc;400 if ( m_hFile == NIL_RTFILE401 || m_strFile != pszPath)402 {403 char *pszFile = RTPathJoinA(m_strDropDir.c_str(), pszPath);404 if (pszFile)405 {406 RTFILE hFile;407 /** @todo Respect fMode! */408 rc = RTFileOpen(&hFile, pszFile,409 RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE410 | RTFILE_O_WRITE | RTFILE_O_APPEND);411 if (RT_SUCCESS(rc))412 {413 LogFlowFunc(("Opening \"%s\" (fMode=0x%x) for writing ...\n",414 pszFile, fMode));415 416 m_hFile = hFile;417 m_strFile = pszPath;418 }419 420 RTStrFree(pszFile);421 }422 else423 rc = VERR_NO_MEMORY;424 }425 else426 rc = VINF_SUCCESS;427 428 if (RT_SUCCESS(rc))429 {430 rc = RTFileWrite(m_hFile, pvData, cbData,431 NULL /* No partial writes */);432 433 if (RT_SUCCESS(rc))434 rc = dataSetStatus(cbData);435 }436 437 526 return rc; 438 527 } … … 507 596 return VERR_COM_OBJECT_NOT_FOUND; 508 597 509 int rc = pVMMDev->hgcmHostCall("VBoxDragAndDropSvc", u32Function, 510 cParms, paParms); 511 LogFlowFunc(("uMsg=%RU32, cParms=%RU32, rc=%Rrc\n", 512 u32Function, cParms, rc)); 598 int rc = pVMMDev->hgcmHostCall("VBoxDragAndDropSvc", u32Function, cParms, paParms); 599 LogFlowFunc(("uMsg=%RU32, cParms=%RU32, rc=%Rrc\n", u32Function, cParms, rc)); 513 600 return rc; 514 601 } 602 603 /* static */ 604 DECLCALLBACK(int) GuestDnD::notifyDnDDispatcher(void *pvExtension, uint32_t u32Function, 605 void *pvParms, uint32_t cbParms) 606 { 607 LogFlowFunc(("pvExtension=%p, u32Function=%RU32, pvParms=%p, cbParms=%RU32\n", 608 pvExtension, u32Function, pvParms, cbParms)); 609 610 GuestDnD *pGuestDnD = reinterpret_cast<GuestDnD*>(pvExtension); 611 AssertPtrReturn(pGuestDnD, VERR_INVALID_POINTER); 612 613 /** @todo In case we need to handle multiple guest DnD responses at a time this 614 * would be the place to lookup and dispatch to those. For the moment we 615 * only have one response -- simple. */ 616 GuestDnDResponse *pResp = pGuestDnD->m_pResponse; 617 if (pResp) 618 return pResp->onDispatch(u32Function, pvParms, cbParms); 619 620 return VERR_NOT_SUPPORTED; 621 } 622 515 623 516 624 /* static */ … … 637 745 } 638 746 639 /* static */640 DECLCALLBACK(int) GuestDnD::notifyDnDDispatcher(void *pvExtension, uint32_t u32Function,641 void *pvParms, uint32_t cbParms)642 {643 LogFlowFunc(("pvExtension=%p, u32Function=%RU32, pvParms=%p, cbParms=%RU32\n",644 pvExtension, u32Function, pvParms, cbParms));645 646 GuestDnD *pGuestDnD = reinterpret_cast<GuestDnD*>(pvExtension);647 AssertPtrReturn(pGuestDnD, VERR_INVALID_POINTER);648 649 GuestDnDResponse *pResp = pGuestDnD->m_pResponse;650 AssertPtrReturn(pResp, VERR_INVALID_POINTER);651 652 int rc;653 switch (u32Function)654 {655 case DragAndDropSvc::GUEST_DND_HG_ACK_OP:656 {657 DragAndDropSvc::PVBOXDNDCBHGACKOPDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGACKOPDATA>(pvParms);658 AssertPtr(pCBData);659 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGACKOPDATA) == cbParms, VERR_INVALID_PARAMETER);660 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_ACK_OP == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);661 662 pResp->setDefAction(pCBData->uAction);663 664 rc = pResp->notifyAboutGuestResponse();665 break;666 }667 668 case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:669 {670 DragAndDropSvc::PVBOXDNDCBHGREQDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGREQDATADATA>(pvParms);671 AssertPtr(pCBData);672 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGREQDATADATA) == cbParms, VERR_INVALID_PARAMETER);673 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_REQ_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);674 675 pResp->setFormat(pCBData->pszFormat);676 677 rc = pResp->notifyAboutGuestResponse();678 break;679 }680 681 case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS:682 {683 DragAndDropSvc::PVBOXDNDCBHGEVTPROGRESSDATA pCBData =684 reinterpret_cast <DragAndDropSvc::PVBOXDNDCBHGEVTPROGRESSDATA>(pvParms);685 AssertPtr(pCBData);686 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA) == cbParms, VERR_INVALID_PARAMETER);687 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);688 689 rc = pResp->setProgress(pCBData->uPercentage, pCBData->uState, pCBData->rc);690 break;691 }692 693 # ifdef VBOX_WITH_DRAG_AND_DROP_GH694 case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:695 {696 DragAndDropSvc::PVBOXDNDCBGHACKPENDINGDATA pCBData =697 reinterpret_cast <DragAndDropSvc::PVBOXDNDCBGHACKPENDINGDATA>(pvParms);698 AssertPtr(pCBData);699 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBGHACKPENDINGDATA) == cbParms, VERR_INVALID_PARAMETER);700 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_ACK_PENDING == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);701 702 pResp->setFormat(pCBData->pszFormat);703 pResp->setDefAction(pCBData->uDefAction);704 pResp->setAllActions(pCBData->uAllActions);705 706 rc = pResp->notifyAboutGuestResponse();707 break;708 }709 710 case DragAndDropSvc::GUEST_DND_GH_SND_DATA:711 {712 DragAndDropSvc::PVBOXDNDCBSNDDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDDATADATA>(pvParms);713 AssertPtr(pCBData);714 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDDATADATA) == cbParms, VERR_INVALID_PARAMETER);715 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);716 717 rc = pGuestDnD->onGHSendData(pResp, pCBData->pvData, pCBData->cbData,718 pCBData->cbTotalSize);719 break;720 }721 722 case DragAndDropSvc::GUEST_DND_GH_SND_DIR:723 {724 DragAndDropSvc::PVBOXDNDCBSNDDIRDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDDIRDATA>(pvParms);725 AssertPtr(pCBData);726 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDDIRDATA) == cbParms, VERR_INVALID_PARAMETER);727 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DIR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);728 729 rc = pGuestDnD->onGHSendDir(pResp, pCBData->pszPath, pCBData->cbPath, pCBData->fMode);730 break;731 }732 733 case DragAndDropSvc::GUEST_DND_GH_SND_FILE:734 {735 DragAndDropSvc::PVBOXDNDCBSNDFILEDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDFILEDATA>(pvParms);736 AssertPtr(pCBData);737 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDFILEDATA) == cbParms, VERR_INVALID_PARAMETER);738 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);739 740 rc = pGuestDnD->onGHSendFile(pResp, pCBData->pszFilePath, pCBData->cbFilePath,741 pCBData->pvData, pCBData->cbData, pCBData->fMode);742 break;743 }744 745 case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:746 {747 DragAndDropSvc::PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBEVTERRORDATA>(pvParms);748 AssertPtr(pCBData);749 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER);750 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);751 752 /* Cleanup. */753 pResp->reset();754 rc = pResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, pCBData->rc);755 break;756 }757 # endif /* VBOX_WITH_DRAG_AND_DROP_GH */758 default:759 rc = VERR_NOT_SUPPORTED; /* Tell the guest. */760 break;761 }762 763 LogFlowFunc(("Returning rc=%Rrc\n", rc));764 return rc;765 }766 767 # ifdef VBOX_WITH_DRAG_AND_DROP_GH768 int GuestDnD::onGHSendData(GuestDnDResponse *pResp,769 const void *pvData, size_t cbData, size_t cbTotalSize)770 {771 AssertPtrReturn(pResp, VERR_INVALID_POINTER);772 AssertPtrReturn(pvData, VERR_INVALID_POINTER);773 AssertReturn(cbData, VERR_INVALID_PARAMETER);774 AssertReturn(cbTotalSize, VERR_INVALID_PARAMETER);775 776 int rc = pResp->dataAdd(pvData, cbData, NULL /* Current size */);777 if (RT_SUCCESS(rc))778 rc = pResp->dataSetStatus(cbData, cbTotalSize);779 780 LogFlowFuncLeaveRC(rc);781 return rc;782 }783 784 int GuestDnD::onGHSendDir(GuestDnDResponse *pResp,785 const char *pszPath, size_t cbPath, uint32_t fMode)786 {787 AssertPtrReturn(pResp, VERR_INVALID_POINTER);788 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);789 AssertReturn(cbPath, VERR_INVALID_PARAMETER);790 791 LogFlowFunc(("pszPath=%s, cbPath=%zu, fMode=0x%x\n",792 pszPath, cbPath, fMode));793 794 int rc;795 char *pszDir = RTPathJoinA(pResp->dropDir().c_str(), pszPath);796 if (pszDir)797 {798 rc = RTDirCreateFullPath(pszDir, fMode);799 RTStrFree(pszDir);800 }801 else802 rc = VERR_NO_MEMORY;803 804 if (RT_SUCCESS(rc))805 rc = pResp->dataSetStatus(cbPath);806 807 LogFlowFuncLeaveRC(rc);808 return rc;809 }810 811 int GuestDnD::onGHSendFile(GuestDnDResponse *pResp,812 const char *pszPath, size_t cbPath,813 void *pvData, size_t cbData, uint32_t fMode)814 {815 AssertPtrReturn(pResp, VERR_INVALID_POINTER);816 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);817 AssertReturn(cbPath, VERR_INVALID_PARAMETER);818 819 LogFlowFunc(("pszPath=%s, cbPath=%zu, fMode=0x%x\n",820 pszPath, cbPath, fMode));821 822 int rc = pResp->writeToFile(pszPath, cbPath,823 pvData, cbData, fMode);824 LogFlowFuncLeaveRC(rc);825 return rc;826 }827 # endif /* VBOX_WITH_DRAG_AND_DROP_GH */828 829 747 /////////////////////////////////////////////////////////////////////////////// 830 748 … … 834 752 } 835 753 836 HRESULT GuestDnDBase::i sFormatSupported(const com::Utf8Str &aFormat, BOOL *aSupported)754 HRESULT GuestDnDBase::i_isFormatSupported(const com::Utf8Str &aFormat, BOOL *aSupported) 837 755 { 838 756 *aSupported = std::find(m_strFormats.begin(), … … 842 760 } 843 761 844 HRESULT GuestDnDBase:: getFormats(std::vector<com::Utf8Str> &aFormats)762 HRESULT GuestDnDBase::i_getFormats(std::vector<com::Utf8Str> &aFormats) 845 763 { 846 764 aFormats = m_strFormats; … … 849 767 } 850 768 851 HRESULT GuestDnDBase:: addFormats(const std::vector<com::Utf8Str> &aFormats)769 HRESULT GuestDnDBase::i_addFormats(const std::vector<com::Utf8Str> &aFormats) 852 770 { 853 771 for (size_t i = 0; i < aFormats.size(); ++i) … … 864 782 } 865 783 866 HRESULT GuestDnDBase:: removeFormats(const std::vector<com::Utf8Str> &aFormats)784 HRESULT GuestDnDBase::i_removeFormats(const std::vector<com::Utf8Str> &aFormats) 867 785 { 868 786 for (size_t i = 0; i < aFormats.size(); ++i) … … 878 796 } 879 797 798 HRESULT GuestDnDBase::i_getProtocolVersion(ULONG *puVersion) 799 { 800 int rc = getProtocolVersion((uint32_t *)puVersion); 801 return RT_SUCCESS(rc) ? S_OK : E_FAIL; 802 } 803 804 int GuestDnDBase::getProtocolVersion(uint32_t *puVersion) 805 { 806 AssertPtrReturn(puVersion, VERR_INVALID_POINTER); 807 808 int rc; 809 810 uint32_t uVer, uVerAdditions = 0; 811 if ( m_pGuest 812 && (uVerAdditions = m_pGuest->i_getAdditionsVersion()) > 0) 813 { 814 uint32_t uVBoxMajor = VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions); 815 uint32_t uVBoxMinor = VBOX_FULL_VERSION_GET_MINOR(uVerAdditions); 816 817 #if 0 /*def DEBUG_andy*/ 818 /* Hardcode the to-used protocol version; nice for testing side effects. */ 819 uVer = 2; 820 #else 821 uVer = ( uVBoxMajor >= 5) 822 ? 2 /* VBox 5.0 and up: Protocol version 2. */ 823 : 1; /* VBox <= 4.3: Protocol version 1. */ 824 /* Build revision is ignored. */ 825 #endif 826 827 LogFlowThisFunc(("uVerAdditions=%RU32 (%RU32.%RU32)\n", uVerAdditions, uVBoxMajor, uVBoxMinor)); 828 rc = VINF_SUCCESS; 829 } 830 else 831 { 832 uVer = 1; /* Fallback. */ 833 rc = VERR_NOT_FOUND; 834 } 835 836 LogFlowThisFunc(("uVer=%RU32, uVerAdditions=%RU32, rc=%Rrc\n", uVer, uVerAdditions, rc)); 837 838 *puVersion = uVer; 839 return rc; 840 } 841 842 #if 0 843 /** 844 * Returns back information (message type + parameter count) of the current message in 845 * the local outgoing message queue. 846 * 847 * @return IPRT status code. 848 * @param pThis 849 * @param puMsg 850 * @param pcParms 851 * @param paParms 852 */ 853 /* static */ 854 DECLCALLBACK(int) GuestDnDBase::i_getNextMsgCallback(GuestDnDBase *pThis, uint32_t *puMsg, 855 uint32_t *pcParms, PVBOXHGCMSVCPARM paParms) 856 { 857 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 858 AssertPtrReturn(puMsg, VERR_INVALID_POINTER); 859 AssertPtrReturn(pcParms, VERR_INVALID_POINTER); 860 AssertPtrReturn(paParms, VERR_INVALID_POINTER); 861 862 if (pThis->mData.m_lstOutgoing.empty()) 863 return VERR_NO_DATA; 864 865 GuestDnDMsg *pMsg = pThis->mData.m_lstOutgoing.front(); 866 AssertPtr(pMsg); 867 868 *puMsg = pMsg->uMsg; 869 *pcParms = pMsg->cParms; 870 871 return VINF_SUCCESS; 872 } 873 #endif 880 874 #endif /* VBOX_WITH_DRAG_AND_DROP */ 881 875 -
trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp
r55180 r55422 5 5 6 6 /* 7 * Copyright (C) 2014 Oracle Corporation7 * Copyright (C) 2014-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 27 27 #include "AutoCaller.h" 28 28 29 #include <memory> /* For unique_ptr, seee #7179. */ 30 31 #include <iprt/dir.h> 32 #include <iprt/file.h> 33 #include <iprt/path.h> 34 29 35 #include <iprt/cpp/utils.h> /* For unconst(). */ 30 36 … … 39 45 #include <VBox/log.h> 40 46 47 /** 48 * Base class for a source task. 49 */ 50 class GuestDnDSourceTask 51 { 52 public: 53 54 GuestDnDSourceTask(GuestDnDSource *pSource) 55 : mSource(pSource), 56 mRC(VINF_SUCCESS) { } 57 58 virtual ~GuestDnDSourceTask(void) { } 59 60 int getRC(void) const { return mRC; } 61 bool isOk(void) const { return RT_SUCCESS(mRC); } 62 const ComObjPtr<GuestDnDSource> &getSource(void) const { return mSource; } 63 64 protected: 65 66 const ComObjPtr<GuestDnDSource> mSource; 67 int mRC; 68 }; 69 70 /** 71 * Task structure for receiving data from a source using 72 * a worker thread. 73 */ 74 class RecvDataTask : public GuestDnDSourceTask 75 { 76 public: 77 78 RecvDataTask(GuestDnDSource *pSource, PRECVDATACTX pCtx) 79 : GuestDnDSourceTask(pSource) 80 , mpCtx(pCtx) { } 81 82 virtual ~RecvDataTask(void) 83 { 84 if (mpCtx) 85 { 86 delete mpCtx; 87 mpCtx = NULL; 88 } 89 } 90 91 PRECVDATACTX getCtx(void) { return mpCtx; } 92 93 protected: 94 95 /** Pointer to receive data context. */ 96 PRECVDATACTX mpCtx; 97 }; 41 98 42 99 // constructor / destructor … … 95 152 ///////////////////////////////////////////////////////////////////////////// 96 153 97 HRESULT GuestDnDSource::isFormatSupported(const com::Utf8Str &aFormat, 98 BOOL *aSupported) 154 HRESULT GuestDnDSource::isFormatSupported(const com::Utf8Str &aFormat, BOOL *aSupported) 99 155 { 100 156 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH) … … 107 163 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 108 164 109 return GuestDnDBase::i sFormatSupported(aFormat, aSupported);165 return GuestDnDBase::i_isFormatSupported(aFormat, aSupported); 110 166 #endif /* VBOX_WITH_DRAG_AND_DROP */ 111 167 } … … 122 178 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 123 179 124 return GuestDnDBase:: getFormats(aFormats);180 return GuestDnDBase::i_getFormats(aFormats); 125 181 #endif /* VBOX_WITH_DRAG_AND_DROP */ 126 182 } … … 137 193 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 138 194 139 return GuestDnDBase:: addFormats(aFormats);195 return GuestDnDBase::i_addFormats(aFormats); 140 196 #endif /* VBOX_WITH_DRAG_AND_DROP */ 141 197 } … … 152 208 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 153 209 154 return GuestDnDBase::removeFormats(aFormats); 210 return GuestDnDBase::i_removeFormats(aFormats); 211 #endif /* VBOX_WITH_DRAG_AND_DROP */ 212 } 213 214 HRESULT GuestDnDSource::getProtocolVersion(ULONG *aProtocolVersion) 215 { 216 #if !defined(VBOX_WITH_DRAG_AND_DROP) 217 ReturnComNotImplemented(); 218 #else /* VBOX_WITH_DRAG_AND_DROP */ 219 220 AutoCaller autoCaller(this); 221 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 222 223 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 224 225 return GuestDnDBase::i_getProtocolVersion(aProtocolVersion); 155 226 #endif /* VBOX_WITH_DRAG_AND_DROP */ 156 227 } … … 171 242 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 172 243 244 /* Determine guest DnD protocol to use. */ 245 GuestDnDBase::getProtocolVersion(&mData.mProtocolVersion); 246 173 247 /* Default is ignoring the action. */ 174 248 DnDAction_T defaultAction = DnDAction_Ignore; … … 180 254 paParms[i++].setUInt32(uScreenId); 181 255 182 int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_GH_REQ_PENDING, 183 i, paParms); 256 int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_GH_REQ_PENDING, i, paParms); 184 257 if (RT_SUCCESS(rc)) 185 258 { … … 210 283 if (RT_FAILURE(rc)) 211 284 hr = setError(VBOX_E_IPRT_ERROR, 212 tr("Unable to retrieve pending status (%Rrc)\n"), rc);285 tr("Unable to retrieve drag'n drop pending status (%Rrc)\n"), rc); 213 286 214 287 LogFlowFunc(("hr=%Rhrc, defaultAction=0x%x\n", hr, defaultAction)); … … 238 311 HRESULT hr = S_OK; 239 312 240 const char *pcszFormat = aFormat.c_str(); 241 bool fNeedsDropDir = DnDMIMENeedsDropDir(pcszFormat, strlen(pcszFormat)); 242 LogFlowFunc(("strFormat=%s, uAction=0x%x, fNeedsDropDir=%RTbool\n", 243 pcszFormat, uAction, fNeedsDropDir)); 244 313 /* Note: At the moment we only support one response at a time. */ 245 314 GuestDnDResponse *pResp = GuestDnDInst()->response(); 246 315 if (pResp) 247 316 { 248 /* Reset any old data. */249 pResp->reset();250 317 pResp->resetProgress(m_pGuest); 251 318 252 /* Set the format we are going to retrieve to have it around 253 * when retrieving the data later. */ 254 pResp->setFormat(aFormat); 255 256 if (fNeedsDropDir) 257 { 258 char szDropDir[RTPATH_MAX]; 259 int rc = DnDDirCreateDroppedFiles(szDropDir, sizeof(szDropDir)); 260 LogFlowFunc(("rc=%Rrc, szDropDir=%s\n", rc, szDropDir)); 261 if (RT_FAILURE(rc)) 262 return setError(VBOX_E_IPRT_ERROR, 263 tr("Unable to create the temporary drag and drop directory \"%s\" (%Rrc)\n"), 264 szDropDir, rc); 265 266 pResp->setDropDir(szDropDir); 267 } 268 269 VBOXHGCMSVCPARM paParms[4]; 270 int i = 0; 271 paParms[i++].setPointer((void*)aFormat.c_str(), (uint32_t)aFormat.length() + 1); 272 paParms[i++].setUInt32((uint32_t)aFormat.length() + 1); 273 paParms[i++].setUInt32(uAction); 274 275 int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_GH_EVT_DROPPED, 276 i, paParms); 277 if (RT_SUCCESS(rc)) 278 { 279 /* Query the progress object to the caller. */ 280 pResp->queryProgressTo(aProgress.asOutParam()); 281 } 282 else 283 hr = setError(VBOX_E_IPRT_ERROR, 284 tr("Error signalling to drop data (%Rrc)\n"), rc); 285 } 319 int rc; 320 321 try 322 { 323 PRECVDATACTX pRecvCtx = new RECVDATACTX; 324 RT_BZERO(pRecvCtx, sizeof(RECVDATACTX)); 325 326 pRecvCtx->mpSource = this; 327 pRecvCtx->mpResp = pResp; 328 pRecvCtx->mFormat = aFormat; 329 330 std::unique_ptr <RecvDataTask> pTask(new RecvDataTask(this, pRecvCtx)); 331 AssertReturn(pTask->isOk(), pTask->getRC()); 332 333 rc = RTThreadCreate(NULL, GuestDnDSource::i_receiveDataThread, 334 (void *)pTask.get(), 0, RTTHREADTYPE_MAIN_WORKER, 0, "dndSrcRcvData"); 335 if (RT_SUCCESS(rc)) 336 { 337 hr = pResp->queryProgressTo(aProgress.asOutParam()); 338 ComAssertComRC(hr); 339 340 /* pTask is now owned by i_receiveDataThread(), so release it. */ 341 pTask.release(); 342 } 343 else if (pRecvCtx) 344 delete pRecvCtx; 345 } 346 catch(std::bad_alloc &) 347 { 348 rc = VERR_NO_MEMORY; 349 } 350 351 /*if (RT_FAILURE(vrc)) @todo SetError(...) */ 352 } 353 /** @todo SetError(...) */ 286 354 287 355 LogFlowFunc(("Returning hr=%Rhrc\n", hr)); … … 313 381 314 382 Utf8Str strFormat = pResp->format(); 315 LogFlowFunc(("strFormat=%s, cbData=%zu, pvData=0x%p\n", 316 strFormat.c_str(), cbData, pvData)); 383 LogFlowFunc(("strFormat=%s, cbData=%zu, pvData=0x%p\n", strFormat.c_str(), cbData, pvData)); 317 384 318 385 try … … 329 396 size_t cbURIs = strURIs.length(); 330 397 331 LogFlowFunc(("Found %zu root URIs (%zu bytes)\n", 332 lstURI.RootCount(), cbURIs)); 398 LogFlowFunc(("Found %zu root URIs (%zu bytes)\n", lstURI.RootCount(), cbURIs)); 333 399 334 400 aData.resize(cbURIs + 1 /* Include termination */); … … 362 428 } 363 429 430 // implementation of internal methods. 431 ///////////////////////////////////////////////////////////////////////////// 432 433 #ifdef VBOX_WITH_DRAG_AND_DROP_GH 434 int GuestDnDSource::i_onReceiveData(PRECVDATACTX pCtx, const void *pvData, uint32_t cbData, uint64_t cbTotalSize) 435 { 436 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 437 AssertPtrReturn(pvData, VERR_INVALID_POINTER); 438 AssertReturn(cbData, VERR_INVALID_PARAMETER); 439 AssertReturn(cbTotalSize, VERR_INVALID_PARAMETER); 440 441 LogFlowFunc(("cbData=%RU32, cbTotalSize=%RU64\n", cbData, cbTotalSize)); 442 443 int rc = VINF_SUCCESS; 444 445 try 446 { 447 if ( cbData > cbTotalSize 448 || cbData > _64K) /** @todo Make this configurable? */ 449 { 450 LogFlowFunc(("Data sizes invalid: cbData=%RU32, cbTotalSize=%RU64\n", cbData, cbTotalSize)); 451 rc = VERR_INVALID_PARAMETER; 452 } 453 else if (cbData < pCtx->mData.size()) 454 { 455 AssertMsgFailed(("New size (%RU64) is smaller than current size (%zu)\n", cbTotalSize, pCtx->mData.size())); 456 rc = VERR_INVALID_PARAMETER; 457 } 458 459 if (RT_SUCCESS(rc)) 460 { 461 pCtx->mData.insert(pCtx->mData.begin(), (BYTE *)pvData, (BYTE *)pvData + cbData); 462 463 LogFlowFunc(("mDataSize=%zu\n", pCtx->mData.size())); 464 465 /* Data transfer complete? */ 466 Assert(cbData <= pCtx->mData.size()); 467 if (cbData == pCtx->mData.size()) 468 { 469 bool fHasURIList = DnDMIMENeedsDropDir(pCtx->mFormat.c_str(), pCtx->mFormat.length()); 470 if (fHasURIList) 471 { 472 LogFlowFunc(("Parsing URI data ...\n")); 473 474 /* Try parsing the data as URI list. */ 475 rc = pCtx->mURI.lstURI.RootFromURIData(&pCtx->mData[0], pCtx->mData.size(), 0 /* uFlags */); 476 if (RT_SUCCESS(rc)) 477 { 478 pCtx->mURI.cbProcessed = 0; 479 pCtx->mURI.cbToProcess = cbTotalSize; 480 } 481 } 482 } 483 } 484 } 485 catch (std::bad_alloc &) 486 { 487 rc = VERR_NO_MEMORY; 488 } 489 490 LogFlowFuncLeaveRC(rc); 491 return rc; 492 } 493 494 int GuestDnDSource::i_onReceiveDir(PRECVDATACTX pCtx, const char *pszPath, uint32_t cbPath, uint32_t fMode) 495 { 496 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 497 AssertPtrReturn(pszPath, VERR_INVALID_POINTER); 498 AssertReturn(cbPath, VERR_INVALID_PARAMETER); 499 500 LogFlowFunc(("pszPath=%s, cbPath=%zu, fMode=0x%x\n", pszPath, cbPath, fMode)); 501 502 int rc; 503 char *pszDir = RTPathJoinA(pCtx->mURI.strDropDir.c_str(), pszPath); 504 if (pszDir) 505 { 506 rc = RTDirCreateFullPath(pszDir, fMode); 507 RTStrFree(pszDir); 508 } 509 else 510 rc = VERR_NO_MEMORY; 511 512 LogFlowFuncLeaveRC(rc); 513 return rc; 514 } 515 516 int GuestDnDSource::i_onReceiveFileHdr(PRECVDATACTX pCtx, const char *pszPath, uint32_t cbPath, 517 uint64_t cbSize, uint32_t fMode, uint32_t fFlags) 518 { 519 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 520 AssertPtrReturn(pszPath, VERR_INVALID_POINTER); 521 AssertReturn(cbPath, VERR_INVALID_PARAMETER); 522 AssertReturn(fMode, VERR_INVALID_PARAMETER); 523 /* fFlags are optional. */ 524 525 LogFlowFunc(("pszPath=%s, cbPath=%RU32, cbSize=%RU64, fMode=0x%x, fFlags=0x%x\n", pszPath, cbPath, cbSize, fMode, fFlags)); 526 527 int rc = VINF_SUCCESS; 528 529 do 530 { 531 if (!pCtx->mURI.objURI.IsComplete()) 532 { 533 LogFlowFunc(("Warning: Object \"%s\" not complete yet\n", pCtx->mURI.objURI.GetDestPath().c_str())); 534 rc = VERR_INVALID_PARAMETER; 535 break; 536 } 537 538 if (pCtx->mURI.objURI.IsOpen()) /* File already opened? */ 539 { 540 LogFlowFunc(("Warning: Current opened object is \"%s\"\n", pCtx->mURI.objURI.GetDestPath().c_str())); 541 rc = VERR_WRONG_ORDER; 542 break; 543 } 544 545 char pszPathAbs[RTPATH_MAX]; 546 rc = RTPathJoin(pszPathAbs, sizeof(pszPathAbs), pCtx->mURI.strDropDir.c_str(), pszPath); 547 if (RT_FAILURE(rc)) 548 { 549 LogFlowFunc(("Warning: Rebasing current file failed with rc=%Rrc\n", rc)); 550 break; 551 } 552 553 rc = DnDPathSanitize(pszPathAbs, sizeof(pszPathAbs)); 554 if (RT_FAILURE(rc)) 555 { 556 LogFlowFunc(("Warning: Rebasing current file failed with rc=%Rrc\n", rc)); 557 break; 558 } 559 560 LogFunc(("Rebased to: %s\n", pszPathAbs)); 561 562 /** @todo Add sparse file support based on fFlags? (Use Open(..., fFlags | SPARSE). */ 563 /** @todo Add fMode to opening flags. */ 564 rc = pCtx->mURI.objURI.OpenEx(pszPathAbs, DnDURIObject::File, DnDURIObject::Target, 565 RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE); 566 if (RT_SUCCESS(rc)) 567 { 568 /** @todo Unescpae path before printing. */ 569 LogRel2(("DnD: Transferring file to host: %s\n", pCtx->mURI.objURI.GetDestPath().c_str())); 570 571 /* Note: Protocol v1 does not send any file sizes, so always 0. */ 572 if (mData.mProtocolVersion >= 2) 573 rc = pCtx->mURI.objURI.SetSize(cbSize); 574 } 575 576 } while (0); 577 578 LogFlowFuncLeaveRC(rc); 579 return rc; 580 } 581 582 int GuestDnDSource::i_onReceiveFileData(PRECVDATACTX pCtx, const void *pvData, uint32_t cbData) 583 { 584 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 585 AssertPtrReturn(pvData, VERR_INVALID_POINTER); 586 AssertReturn(cbData, VERR_INVALID_PARAMETER); 587 588 int rc = VINF_SUCCESS; 589 590 do 591 { 592 if (pCtx->mURI.objURI.IsComplete()) 593 { 594 LogFlowFunc(("Warning: Object \"%s\" already completed\n", pCtx->mURI.objURI.GetDestPath().c_str())); 595 rc = VERR_WRONG_ORDER; 596 break; 597 } 598 599 if (!pCtx->mURI.objURI.IsOpen()) /* File opened on host? */ 600 { 601 LogFlowFunc(("Warning: Object \"%s\" not opened\n", pCtx->mURI.objURI.GetDestPath().c_str())); 602 rc = VERR_WRONG_ORDER; 603 break; 604 } 605 606 uint32_t cbWritten; 607 rc = pCtx->mURI.objURI.Write(pvData, cbData, &cbWritten); 608 if (RT_SUCCESS(rc)) 609 { 610 Assert(cbWritten <= cbData); 611 if (cbWritten < cbData) 612 { 613 /** @todo What to do when the host's disk is full? */ 614 rc = VERR_DISK_FULL; 615 } 616 } 617 618 if (RT_SUCCESS(rc)) 619 { 620 if (pCtx->mURI.objURI.IsComplete()) 621 { 622 LogRel2(("DnD: File transfer to host complete: %s", pCtx->mURI.objURI.GetDestPath().c_str())); 623 rc = VINF_EOF; 624 } 625 } 626 else 627 LogRel(("DnD: Error: Can't write guest file to host to \"%s\": %Rrc\n", pCtx->mURI.objURI.GetDestPath().c_str(), rc)); 628 629 } while (0); 630 631 LogFlowFuncLeaveRC(rc); 632 return rc; 633 } 634 #endif /* VBOX_WITH_DRAG_AND_DROP_GH */ 635 636 int GuestDnDSource::i_receiveData(PRECVDATACTX pCtx) 637 { 638 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 639 640 int rc; 641 642 GuestDnD *pInst = GuestDnDInst(); 643 if (!pInst) 644 return VERR_INVALID_POINTER; 645 646 GuestDnDResponse *pResp = pCtx->mpResp; 647 AssertPtr(pCtx->mpResp); 648 649 ASMAtomicWriteBool(&pCtx->mIsActive, true); 650 651 /* Create event semaphore. */ 652 pCtx->SemEvent = NIL_RTSEMEVENT; 653 rc = RTSemEventCreate(&pCtx->SemEvent); 654 if (RT_FAILURE(rc)) 655 return rc; 656 657 pCtx->mURI.cbToProcess = 0; 658 pCtx->mURI.cbProcessed = 0; 659 pCtx->mURI.cProcessed = 0; 660 661 do 662 { 663 /* Reset any old data. */ 664 pResp->reset(); 665 pResp->resetProgress(m_pGuest); 666 667 /* Set the format we are going to retrieve to have it around 668 * when retrieving the data later. */ 669 pResp->setFormat(pCtx->mFormat); 670 671 bool fHasURIList = DnDMIMENeedsDropDir(pCtx->mFormat.c_str(), pCtx->mFormat.length()); 672 LogFlowFunc(("strFormat=%s, uAction=0x%x, fHasURIList=%RTbool\n", pCtx->mFormat.c_str(), pCtx->mAction, fHasURIList)); 673 674 if (fHasURIList) 675 { 676 rc = i_receiveURIData(pCtx); 677 } 678 else 679 { 680 rc = i_receiveRawData(pCtx); 681 } 682 683 } while (0); 684 685 if (pCtx->SemEvent != NIL_RTSEMEVENT) 686 { 687 RTSemEventDestroy(pCtx->SemEvent); 688 pCtx->SemEvent = NIL_RTSEMEVENT; 689 } 690 691 ASMAtomicWriteBool(&pCtx->mIsActive, false); 692 693 LogFlowFuncLeaveRC(rc); 694 return rc; 695 } 696 697 /* static */ 698 DECLCALLBACK(int) GuestDnDSource::i_receiveDataThread(RTTHREAD Thread, void *pvUser) 699 { 700 LogFlowFunc(("pvUser=%p\n", pvUser)); 701 702 std::unique_ptr<RecvDataTask> pTask(static_cast<RecvDataTask*>(pvUser)); 703 AssertPtr(pTask.get()); 704 705 const ComObjPtr<GuestDnDSource> pTarget(pTask->getSource()); 706 Assert(!pTarget.isNull()); 707 708 AutoCaller autoCaller(pTarget); 709 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 710 711 int rc = pTarget->i_receiveData(pTask->getCtx()); 712 /* Nothing to do here anymore. */ 713 714 LogFlowFunc(("pSource=%p returning rc=%Rrc\n", (GuestDnDSource *)pTarget, rc)); 715 return rc; 716 } 717 718 int GuestDnDSource::i_receiveRawData(PRECVDATACTX pCtx) 719 { 720 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 721 722 int rc; 723 724 GuestDnDResponse *pResp = pCtx->mpResp; 725 AssertPtr(pCtx->mpResp); 726 727 GuestDnD *pInst = GuestDnDInst(); 728 if (!pInst) 729 return VERR_INVALID_POINTER; 730 731 #define REGISTER_CALLBACK(x) \ 732 rc = pResp->setCallback(x, i_receiveRawDataCallback, pCtx); \ 733 if (RT_FAILURE(rc)) \ 734 return rc; 735 736 #define UNREGISTER_CALLBACK(x) \ 737 rc = pCtx->mpResp->setCallback(x, NULL); \ 738 AssertRC(rc); 739 740 /* 741 * Register callbacks. 742 */ 743 /* Guest callbacks. */ 744 REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DATA); 745 746 do 747 { 748 /* 749 * Receive the raw data. 750 */ 751 GuestDnDMsg Msg; 752 Msg.setType(DragAndDropSvc::HOST_DND_GH_EVT_DROPPED); 753 Msg.setNextPointer((void*)pCtx->mFormat.c_str(), (uint32_t)pCtx->mFormat.length() + 1); 754 Msg.setNextUInt32((uint32_t)pCtx->mFormat.length() + 1); 755 Msg.setNextUInt32(pCtx->mAction); 756 757 /* Make the initial call to the guest by telling that we initiated the "dropped" event on 758 * the host and therefore now waiting for the actual raw data. */ 759 rc = pInst->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms()); 760 if (RT_SUCCESS(rc)) 761 { 762 /* 763 * Wait until our callback i_receiveRawDataCallback triggered the 764 * wait event. 765 */ 766 LogFlowFunc(("Waiting for raw data callback ...\n")); 767 rc = RTSemEventWait(pCtx->SemEvent, RT_INDEFINITE_WAIT); 768 LogFlowFunc(("Raw data callback done\n")); 769 } 770 771 } while (0); 772 773 /* 774 * Unregister callbacks. 775 */ 776 UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DATA); 777 778 #undef REGISTER_CALLBACK 779 #undef UNREGISTER_CALLBACK 780 781 LogFlowFuncLeaveRC(rc); 782 return rc; 783 } 784 785 int GuestDnDSource::i_receiveURIData(PRECVDATACTX pCtx) 786 { 787 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 788 789 int rc; 790 791 GuestDnDResponse *pResp = pCtx->mpResp; 792 AssertPtr(pCtx->mpResp); 793 794 GuestDnD *pInst = GuestDnDInst(); 795 if (!pInst) 796 return VERR_INVALID_POINTER; 797 798 #define REGISTER_CALLBACK(x) \ 799 rc = pResp->setCallback(x, i_receiveURIDataCallback, pCtx); \ 800 if (RT_FAILURE(rc)) \ 801 return rc; 802 803 #define UNREGISTER_CALLBACK(x) \ 804 rc = pResp->setCallback(x, NULL); \ 805 AssertRC(rc); 806 807 /* 808 * Register callbacks. 809 */ 810 /* Guest callbacks. */ 811 REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DATA); 812 REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DIR); 813 if (mData.mProtocolVersion >= 2) 814 REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR); 815 REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA); 816 817 do 818 { 819 char szDropDir[RTPATH_MAX]; 820 rc = DnDDirCreateDroppedFiles(szDropDir, sizeof(szDropDir)); 821 LogFlowFunc(("rc=%Rrc, szDropDir=%s\n", rc, szDropDir)); 822 if (RT_FAILURE(rc)) 823 break; 824 825 pCtx->mURI.strDropDir = szDropDir; /** @todo Keep directory handle open? */ 826 pResp->setDropDir(szDropDir); 827 828 /* 829 * Receive the URI list. 830 */ 831 GuestDnDMsg Msg; 832 Msg.setType(DragAndDropSvc::HOST_DND_GH_EVT_DROPPED); 833 Msg.setNextPointer((void*)pCtx->mFormat.c_str(), (uint32_t)pCtx->mFormat.length() + 1); 834 Msg.setNextUInt32((uint32_t)pCtx->mFormat.length() + 1); 835 Msg.setNextUInt32(pCtx->mAction); 836 837 /* Make the initial call to the guest by telling that we initiated the "dropped" event on 838 * the host and therefore now waiting for the actual URI actual data. */ 839 rc = pInst->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms()); 840 if (RT_SUCCESS(rc)) 841 { 842 /* 843 * Wait until our callback i_receiveURIDataCallback triggered the 844 * wait event. 845 */ 846 LogFlowFunc(("Waiting for URI callback ...\n")); 847 rc = RTSemEventWait(pCtx->SemEvent, RT_INDEFINITE_WAIT); 848 LogFlowFunc(("URI callback done, rc=%Rrc\n", rc)); 849 } 850 851 } while (0); 852 853 /* 854 * Unregister callbacks. 855 */ 856 UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DATA); 857 UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_DIR); 858 if (mData.mProtocolVersion >= 2) 859 UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR); 860 UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA); 861 862 #undef REGISTER_CALLBACK 863 #undef UNREGISTER_CALLBACK 864 865 if (RT_FAILURE(rc)) 866 { 867 LogFlowFunc(("Rolling back ...\n")); 868 869 /* Rollback by removing any stuff created. */ 870 for (size_t i = 0; i < pCtx->mURI.lstFiles.size(); ++i) 871 RTFileDelete(pCtx->mURI.lstFiles.at(i).c_str()); 872 for (size_t i = 0; i < pCtx->mURI.lstDirs.size(); ++i) 873 RTDirRemove(pCtx->mURI.lstDirs.at(i).c_str()); 874 } 875 876 /* Try removing (hopefully) empty drop directory in any case. */ 877 if (pCtx->mURI.strDropDir.isNotEmpty()) 878 RTDirRemove(pCtx->mURI.strDropDir.c_str()); 879 880 LogFlowFuncLeaveRC(rc); 881 return rc; 882 } 883 884 /* static */ 885 DECLCALLBACK(int) GuestDnDSource::i_receiveRawDataCallback(uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser) 886 { 887 PRECVDATACTX pCtx = (PRECVDATACTX)pvUser; 888 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 889 890 GuestDnDSource *pThis = pCtx->mpSource; 891 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 892 893 LogFlowFunc(("pThis=%p, uMsg=%RU32\n", pThis, uMsg)); 894 895 int rc = VINF_SUCCESS; 896 897 switch (uMsg) 898 { 899 case DragAndDropSvc::GUEST_DND_GH_SND_DATA: 900 { 901 DragAndDropSvc::PVBOXDNDCBSNDDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDDATADATA>(pvParms); 902 AssertPtr(pCBData); 903 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDDATADATA) == cbParms, VERR_INVALID_PARAMETER); 904 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); 905 906 rc = pThis->i_onReceiveData(pCtx, pCBData->pvData, pCBData->cbData, pCBData->cbTotalSize); 907 break; 908 } 909 case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR: 910 { 911 DragAndDropSvc::PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBEVTERRORDATA>(pvParms); 912 AssertPtr(pCBData); 913 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER); 914 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); 915 916 /* Cleanup. */ 917 pCtx->mpResp->reset(); 918 rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, pCBData->rc); 919 break; 920 } 921 default: 922 rc = VERR_NOT_SUPPORTED; 923 break; 924 } 925 926 if (RT_FAILURE(rc)) 927 { 928 if (pCtx->SemEvent != NIL_RTSEMEVENT) 929 { 930 LogFlowFunc(("Signalling ...\n")); 931 int rc2 = RTSemEventSignal(pCtx->SemEvent); 932 AssertRC(rc2); 933 } 934 } 935 936 LogFlowFuncLeaveRC(rc); 937 return rc; /* Tell the guest. */ 938 } 939 940 /* static */ 941 DECLCALLBACK(int) GuestDnDSource::i_receiveURIDataCallback(uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser) 942 { 943 PRECVDATACTX pCtx = (PRECVDATACTX)pvUser; 944 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 945 946 GuestDnDSource *pThis = pCtx->mpSource; 947 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 948 949 LogFlowFunc(("pThis=%p, uMsg=%RU32\n", pThis, uMsg)); 950 951 int rc = VINF_SUCCESS; 952 953 switch (uMsg) 954 { 955 case DragAndDropSvc::GUEST_DND_GH_SND_DATA: 956 { 957 DragAndDropSvc::PVBOXDNDCBSNDDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDDATADATA>(pvParms); 958 AssertPtr(pCBData); 959 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDDATADATA) == cbParms, VERR_INVALID_PARAMETER); 960 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); 961 962 rc = pThis->i_onReceiveData(pCtx, pCBData->pvData, pCBData->cbData, pCBData->cbTotalSize); 963 break; 964 } 965 case DragAndDropSvc::GUEST_DND_GH_SND_DIR: 966 { 967 DragAndDropSvc::PVBOXDNDCBSNDDIRDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDDIRDATA>(pvParms); 968 AssertPtr(pCBData); 969 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDDIRDATA) == cbParms, VERR_INVALID_PARAMETER); 970 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_DIR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); 971 972 rc = pThis->i_onReceiveDir(pCtx, pCBData->pszPath, pCBData->cbPath, pCBData->fMode); 973 break; 974 } 975 case DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR: 976 { 977 DragAndDropSvc::PVBOXDNDCBSNDFILEHDRDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDFILEHDRDATA>(pvParms); 978 AssertPtr(pCBData); 979 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDFILEHDRDATA) == cbParms, VERR_INVALID_PARAMETER); 980 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_HDR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); 981 982 rc = pThis->i_onReceiveFileHdr(pCtx, pCBData->pszFilePath, pCBData->cbFilePath, 983 pCBData->cbSize, pCBData->fMode, pCBData->fFlags); 984 break; 985 } 986 case DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA: 987 { 988 DragAndDropSvc::PVBOXDNDCBSNDFILEDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBSNDFILEDATADATA>(pvParms); 989 AssertPtr(pCBData); 990 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBSNDFILEDATADATA) == cbParms, VERR_INVALID_PARAMETER); 991 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); 992 993 if (pThis->mData.mProtocolVersion <= 1) 994 { 995 /** 996 * Notes for protocol v1 (< VBox 5.0): 997 * - Every time this command is being sent it includes the file header, 998 * so just process both calls here. 999 * - There was no information whatsoever about the total file size; the old code only 1000 * appended data to the desired file. So just pass 0 as cbSize. 1001 */ 1002 rc = pThis->i_onReceiveFileHdr(pCtx, 1003 pCBData->u.v1.pszFilePath, pCBData->u.v1.cbFilePath, 1004 0 /* cbSize */, pCBData->u.v1.fMode, 0 /* fFlags */); 1005 if (RT_SUCCESS(rc)) 1006 rc = pThis->i_onReceiveFileData(pCtx, pCBData->pvData, pCBData->cbData); 1007 } 1008 else /* Protocol v2 and up. */ 1009 rc = pThis->i_onReceiveFileData(pCtx, pCBData->pvData, pCBData->cbData); 1010 1011 /* Current file done? */ 1012 if (rc == VINF_EOF) 1013 { 1014 /* Remove it from the list. */ 1015 pCtx->mURI.lstURI.RemoveFirst(); 1016 1017 if (pCtx->mURI.lstURI.IsEmpty()) /* Current file processed? Check if there's more. */ 1018 { 1019 /* Let waiters know. */ 1020 if (pCtx->SemEvent != NIL_RTSEMEVENT) 1021 { 1022 LogFlowFunc(("Signalling ...\n")); 1023 int rc2 = RTSemEventSignal(pCtx->SemEvent); 1024 AssertRC(rc2); 1025 } 1026 } 1027 } 1028 break; 1029 } 1030 case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR: 1031 { 1032 DragAndDropSvc::PVBOXDNDCBEVTERRORDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBEVTERRORDATA>(pvParms); 1033 AssertPtr(pCBData); 1034 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBEVTERRORDATA) == cbParms, VERR_INVALID_PARAMETER); 1035 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); 1036 1037 /* Cleanup. */ 1038 pCtx->mpResp->reset(); 1039 rc = pCtx->mpResp->setProgress(100, DragAndDropSvc::DND_PROGRESS_ERROR, pCBData->rc); 1040 break; 1041 } 1042 default: 1043 rc = VERR_NOT_SUPPORTED; 1044 break; 1045 } 1046 1047 if (RT_FAILURE(rc)) 1048 { 1049 if (pCtx->SemEvent != NIL_RTSEMEVENT) 1050 { 1051 LogFlowFunc(("Signalling ...\n")); 1052 int rc2 = RTSemEventSignal(pCtx->SemEvent); 1053 AssertRC(rc2); 1054 } 1055 } 1056 1057 LogFlowFuncLeaveRC(rc); 1058 return rc; /* Tell the guest. */ 1059 } 1060 -
trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp
r55244 r55422 5 5 6 6 /* 7 * Copyright (C) 2014 Oracle Corporation7 * Copyright (C) 2014-2015 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 22 22 #include "GuestImpl.h" 23 23 #include "GuestDnDTargetImpl.h" 24 #include "VirtualBoxErrorInfoImpl.h" 24 25 25 26 #include "Global.h" … … 27 28 28 29 #include <algorithm> /* For std::find(). */ 30 #include <memory> /* For unique_ptr, see #7179. */ 31 32 #include <iprt/file.h> 33 #include <iprt/dir.h> 34 #include <iprt/path.h> 35 #include <iprt/uri.h> 29 36 #include <iprt/cpp/utils.h> /* For unconst(). */ 30 37 31 38 #include <VBox/com/array.h> 32 #include <VBox/HostServices/DragAndDropSvc.h> 39 40 #include <VBox/GuestHost/DragAndDrop.h> 41 #include <VBox/HostServices/Service.h> 33 42 34 43 #ifdef LOG_GROUP … … 39 48 40 49 50 /** 51 * Base class for a target task. 52 */ 53 class GuestDnDTargetTask 54 { 55 public: 56 57 GuestDnDTargetTask(GuestDnDTarget *pTarget) 58 : mTarget(pTarget), 59 mRC(VINF_SUCCESS) { } 60 61 virtual ~GuestDnDTargetTask(void) { } 62 63 int getRC(void) const { return mRC; } 64 bool isOk(void) const { return RT_SUCCESS(mRC); } 65 const ComObjPtr<GuestDnDTarget> &getTarget(void) const { return mTarget; } 66 67 protected: 68 69 const ComObjPtr<GuestDnDTarget> mTarget; 70 int mRC; 71 }; 72 73 /** 74 * Task structure for sending data to a target using 75 * a worker thread. 76 */ 77 class SendDataTask : public GuestDnDTargetTask 78 { 79 public: 80 81 SendDataTask(GuestDnDTarget *pTarget, PSENDDATACTX pCtx) 82 : GuestDnDTargetTask(pTarget), 83 mpCtx(pCtx) { } 84 85 virtual ~SendDataTask(void) 86 { 87 if (mpCtx) 88 { 89 delete mpCtx; 90 mpCtx = NULL; 91 } 92 } 93 94 95 PSENDDATACTX getCtx(void) { return mpCtx; } 96 97 protected: 98 99 /** Pointer to send data context. */ 100 PSENDDATACTX mpCtx; 101 }; 102 41 103 // constructor / destructor 42 104 ///////////////////////////////////////////////////////////////////////////// … … 46 108 HRESULT GuestDnDTarget::FinalConstruct(void) 47 109 { 110 /* Set the maximum block size our guests can handle to 64K. This always has 111 * been hardcoded until now. */ 112 /* Note: Never ever rely on information from the guest; the host dictates what and 113 * how to do something, so try to negogiate a sensible value here later. */ 114 m_cbBlockSize = _32K; /** @todo Make this configurable. */ 115 48 116 LogFlowThisFunc(("\n")); 49 117 return BaseFinalConstruct(); … … 94 162 ///////////////////////////////////////////////////////////////////////////// 95 163 96 HRESULT GuestDnDTarget::isFormatSupported(const com::Utf8Str &aFormat, 97 BOOL *aSupported) 98 { 99 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH) 164 HRESULT GuestDnDTarget::isFormatSupported(const com::Utf8Str &aFormat, BOOL *aSupported) 165 { 166 #if !defined(VBOX_WITH_DRAG_AND_DROP) 100 167 ReturnComNotImplemented(); 101 168 #else /* VBOX_WITH_DRAG_AND_DROP */ … … 106 173 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 107 174 108 return GuestDnDBase::i sFormatSupported(aFormat, aSupported);175 return GuestDnDBase::i_isFormatSupported(aFormat, aSupported); 109 176 #endif /* VBOX_WITH_DRAG_AND_DROP */ 110 177 } … … 112 179 HRESULT GuestDnDTarget::getFormats(std::vector<com::Utf8Str> &aFormats) 113 180 { 114 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)181 #if !defined(VBOX_WITH_DRAG_AND_DROP) 115 182 ReturnComNotImplemented(); 116 183 #else /* VBOX_WITH_DRAG_AND_DROP */ … … 121 188 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 122 189 123 return GuestDnDBase:: getFormats(aFormats);190 return GuestDnDBase::i_getFormats(aFormats); 124 191 #endif /* VBOX_WITH_DRAG_AND_DROP */ 125 192 } … … 127 194 HRESULT GuestDnDTarget::addFormats(const std::vector<com::Utf8Str> &aFormats) 128 195 { 129 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)196 #if !defined(VBOX_WITH_DRAG_AND_DROP) 130 197 ReturnComNotImplemented(); 131 198 #else /* VBOX_WITH_DRAG_AND_DROP */ … … 136 203 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 137 204 138 return GuestDnDBase:: addFormats(aFormats);205 return GuestDnDBase::i_addFormats(aFormats); 139 206 #endif /* VBOX_WITH_DRAG_AND_DROP */ 140 207 } … … 142 209 HRESULT GuestDnDTarget::removeFormats(const std::vector<com::Utf8Str> &aFormats) 143 210 { 144 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)211 #if !defined(VBOX_WITH_DRAG_AND_DROP) 145 212 ReturnComNotImplemented(); 146 213 #else /* VBOX_WITH_DRAG_AND_DROP */ … … 151 218 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); 152 219 153 return GuestDnDBase::removeFormats(aFormats); 220 return GuestDnDBase::i_removeFormats(aFormats); 221 #endif /* VBOX_WITH_DRAG_AND_DROP */ 222 } 223 224 HRESULT GuestDnDTarget::getProtocolVersion(ULONG *aProtocolVersion) 225 { 226 #if !defined(VBOX_WITH_DRAG_AND_DROP) 227 ReturnComNotImplemented(); 228 #else /* VBOX_WITH_DRAG_AND_DROP */ 229 230 AutoCaller autoCaller(this); 231 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 232 233 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); 234 235 return GuestDnDBase::i_getProtocolVersion(aProtocolVersion); 154 236 #endif /* VBOX_WITH_DRAG_AND_DROP */ 155 237 } … … 164 246 DnDAction_T *aResultAction) 165 247 { 166 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)248 #if !defined(VBOX_WITH_DRAG_AND_DROP) 167 249 ReturnComNotImplemented(); 168 250 #else /* VBOX_WITH_DRAG_AND_DROP */ … … 178 260 AutoCaller autoCaller(this); 179 261 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 262 263 /* Determine guest DnD protocol to use. */ 264 GuestDnDBase::getProtocolVersion(&mData.mProtocolVersion); 180 265 181 266 /* Default action is ignoring. */ … … 237 322 DnDAction_T *aResultAction) 238 323 { 239 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)324 #if !defined(VBOX_WITH_DRAG_AND_DROP) 240 325 ReturnComNotImplemented(); 241 326 #else /* VBOX_WITH_DRAG_AND_DROP */ … … 299 384 HRESULT GuestDnDTarget::leave(ULONG uScreenId) 300 385 { 301 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)386 #if !defined(VBOX_WITH_DRAG_AND_DROP) 302 387 ReturnComNotImplemented(); 303 388 #else /* VBOX_WITH_DRAG_AND_DROP */ … … 327 412 com::Utf8Str &aFormat, DnDAction_T *aResultAction) 328 413 { 329 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)414 #if !defined(VBOX_WITH_DRAG_AND_DROP) 330 415 ReturnComNotImplemented(); 331 416 #else /* VBOX_WITH_DRAG_AND_DROP */ … … 395 480 } 396 481 397 HRESULT GuestDnDTarget::sendData(ULONG aScreenId, 398 const com::Utf8Str &aFormat, 399 const std::vector<BYTE> &aData, 482 /* static */ 483 DECLCALLBACK(int) GuestDnDTarget::i_sendDataThread(RTTHREAD Thread, void *pvUser) 484 { 485 LogFlowFunc(("pvUser=%p\n", pvUser)); 486 487 std::unique_ptr<SendDataTask> pTask(static_cast<SendDataTask*>(pvUser)); 488 AssertPtr(pTask.get()); 489 490 const ComObjPtr<GuestDnDTarget> pTarget(pTask->getTarget()); 491 Assert(!pTarget.isNull()); 492 493 AutoCaller autoCaller(pTarget); 494 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 495 496 int rc = pTarget->i_sendData(pTask->getCtx()); 497 /* Nothing to do here anymore. */ 498 499 LogFlowFunc(("pTarget=%p returning rc=%Rrc\n", (GuestDnDTarget *)pTarget, rc)); 500 return rc; 501 } 502 503 /** 504 * Initiates a data transfer from the host to the guest. The source is the host whereas the target is the 505 * guest in this case. 506 * 507 * @return HRESULT 508 * @param aScreenId 509 * @param aFormat 510 * @param aData 511 * @param aProgress 512 */ 513 HRESULT GuestDnDTarget::sendData(ULONG aScreenId, const com::Utf8Str &aFormat, const std::vector<BYTE> &aData, 400 514 ComPtr<IProgress> &aProgress) 401 515 { 402 #if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)516 #if !defined(VBOX_WITH_DRAG_AND_DROP) 403 517 ReturnComNotImplemented(); 404 518 #else /* VBOX_WITH_DRAG_AND_DROP */ 405 519 406 /* Input validation*/407 520 /** @todo Add input validation. */ 521 /** @todo Check if another sendData() call currently is being processed. */ 408 522 409 523 AutoCaller autoCaller(this); 410 524 if (FAILED(autoCaller.rc())) return autoCaller.rc(); 411 525 412 HRESULT hr = S_OK; 413 414 VBOXHGCMSVCPARM paParms[8]; 415 int i = 0; 416 paParms[i++].setUInt32(aScreenId); 417 paParms[i++].setPointer((void *)aFormat.c_str(), (uint32_t)aFormat.length() + 1); 418 paParms[i++].setUInt32((uint32_t)aFormat.length() + 1); 419 paParms[i++].setPointer((void*)&aData.front(), (uint32_t)aData.size()); 420 paParms[i++].setUInt32((uint32_t)aData.size()); 421 526 HRESULT hr; 527 int vrc; 528 529 /* Note: At the moment we only support one response at a time. */ 422 530 GuestDnDResponse *pResp = GuestDnDInst()->response(); 423 531 if (pResp) 424 532 { 425 /* Reset any old progress status. */426 533 pResp->resetProgress(m_pGuest); 427 534 428 /* Note: The actual data transfer of files/directoies is performed by the 429 * DnD host service. */ 430 int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_HG_SND_DATA, 431 i, paParms); 432 if (RT_SUCCESS(rc)) 433 { 434 hr = pResp->queryProgressTo(aProgress.asOutParam()); 435 ComAssertComRC(hr); 436 } 437 } 535 try 536 { 537 PSENDDATACTX pSendCtx = new SENDDATACTX; 538 RT_BZERO(pSendCtx, sizeof(SENDDATACTX)); 539 540 pSendCtx->mpTarget = this; 541 pSendCtx->mpResp = pResp; 542 pSendCtx->mScreenID = aScreenId; 543 pSendCtx->mFormat = aFormat; 544 pSendCtx->mData = aData; 545 546 std::unique_ptr<SendDataTask> pTask(new SendDataTask(this, pSendCtx)); 547 AssertReturn(pTask->isOk(), pTask->getRC()); 548 549 vrc = RTThreadCreate(NULL, GuestDnDTarget::i_sendDataThread, 550 (void *)pTask.get(), 0, RTTHREADTYPE_MAIN_WORKER, 0, "dndTgtSndData"); 551 if (RT_SUCCESS(vrc)) 552 { 553 hr = pResp->queryProgressTo(aProgress.asOutParam()); 554 ComAssertComRC(hr); 555 556 /* pTask is now owned by i_sendDataThread(), so release it. */ 557 pTask.release(); 558 } 559 else if (pSendCtx) 560 delete pSendCtx; 561 } 562 catch(std::bad_alloc &) 563 { 564 vrc = VERR_NO_MEMORY; 565 } 566 567 /*if (RT_FAILURE(vrc)) ** @todo SetError(...) */ 568 } 569 /** @todo SetError(...) */ 438 570 439 571 return hr; … … 441 573 } 442 574 575 int GuestDnDTarget::i_cancelOperation(void) 576 { 577 /** @todo Check for pending cancel requests. */ 578 579 #if 0 /** @todo Later. */ 580 /* Cancel any outstanding waits for guest responses first. */ 581 if (pResp) 582 pResp->notifyAboutGuestResponse(); 583 #endif 584 585 LogFlowFunc(("Cancelling operation, telling guest ...\n")); 586 return GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_HG_EVT_CANCEL, 0 /* cParms */, NULL /*paParms*/); 587 } 588 589 int GuestDnDTarget::i_sendData(PSENDDATACTX pCtx) 590 { 591 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 592 593 #define DATA_IS_VALID_BREAK(x) \ 594 if (!x) \ 595 { \ 596 LogFlowFunc(("Invalid URI data value for \"" #x "\"\n")); \ 597 rc = VERR_INVALID_PARAMETER; \ 598 break; \ 599 } 600 601 GuestDnD *pInst = GuestDnDInst(); 602 if (!pInst) 603 return VERR_INVALID_POINTER; 604 605 int rc; 606 607 ASMAtomicWriteBool(&pCtx->mIsActive, true); 608 609 do 610 { 611 const char *pszFormat = pCtx->mFormat.c_str(); 612 DATA_IS_VALID_BREAK(pszFormat); 613 uint32_t cbFormat = pCtx->mFormat.length() + 1; 614 615 /* Do we need to build up a file tree? */ 616 bool fHasURIList = DnDMIMEHasFileURLs(pszFormat, cbFormat); 617 if (fHasURIList) 618 { 619 rc = i_sendURIData(pCtx); 620 } 621 else 622 { 623 GuestDnDMsg Msg; 624 625 size_t cbDataTotal = pCtx->mData.size(); 626 DATA_IS_VALID_BREAK(cbDataTotal); 627 628 /* Just copy over the raw data. */ 629 Msg.setType(DragAndDropSvc::HOST_DND_HG_SND_DATA); 630 Msg.setNextUInt32(pCtx->mScreenID); 631 Msg.setNextPointer((void *)pCtx->mFormat.c_str(), (uint32_t)pCtx->mFormat.length() + 1); 632 Msg.setNextUInt32((uint32_t)pCtx->mFormat.length() + 1); 633 Msg.setNextPointer((void*)&pCtx->mData.front(), (uint32_t)cbDataTotal); 634 Msg.setNextUInt32(cbDataTotal); 635 636 LogFlowFunc(("%zu total bytes of raw data to transfer\n", cbDataTotal)); 637 638 /* Make the initial call to the guest by sending the actual data. This might 639 * be an URI list which in turn can lead to more data to send afterwards. */ 640 rc = pInst->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms()); 641 if (RT_FAILURE(rc)) 642 break; 643 } 644 645 } while (0); 646 647 ASMAtomicWriteBool(&pCtx->mIsActive, false); 648 649 #undef DATA_IS_VALID_BREAK 650 651 LogFlowFuncLeaveRC(rc); 652 return rc; 653 } 654 655 int GuestDnDTarget::i_sendDirectory(PSENDDATACTX pCtx, GuestDnDMsg *pMsg, DnDURIObject &aDirectory) 656 { 657 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 658 659 RTCString strPath = aDirectory.GetDestPath(); 660 if (strPath.isEmpty()) 661 return VERR_INVALID_PARAMETER; 662 if (strPath.length() >= RTPATH_MAX) /* Note: Maximum is RTPATH_MAX on guest side. */ 663 return VERR_BUFFER_OVERFLOW; 664 665 LogFlowFunc(("Sending directory \"%s\" using protocol v%RU32 ...\n", strPath.c_str(), mData.mProtocolVersion)); 666 667 pMsg->setType(DragAndDropSvc::HOST_DND_HG_SND_DIR); 668 pMsg->setNextString(strPath.c_str()); /* path */ 669 pMsg->setNextUInt32((uint32_t)(strPath.length() + 1)); /* path length - note: Maximum is RTPATH_MAX on guest side. */ 670 pMsg->setNextUInt32(aDirectory.GetMode()); /* mode */ 671 672 return VINF_SUCCESS; 673 } 674 675 int GuestDnDTarget::i_sendFile(PSENDDATACTX pCtx, GuestDnDMsg *pMsg, DnDURIObject &aFile) 676 { 677 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 678 679 RTCString strPath = aFile.GetDestPath(); 680 if (strPath.isEmpty()) 681 return VERR_INVALID_PARAMETER; 682 683 int rc = VINF_SUCCESS; 684 685 LogFlowFunc(("Sending \"%s\" (%RU32 bytes buffer) using protocol v%RU32 ...\n", 686 aFile.GetDestPath().c_str(), m_cbBlockSize, mData.mProtocolVersion)); 687 688 bool fSendFileData = false; 689 if (mData.mProtocolVersion >= 2) 690 { 691 if (!aFile.IsOpen()) 692 { 693 rc = aFile.OpenEx(aFile.GetSourcePath(), DnDURIObject::Type::File, DnDURIObject::Dest::Source, 694 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE, 0 /* fFlags */); 695 if (RT_SUCCESS(rc)) 696 { 697 /* 698 * Since protocol v2 the file header and the actual file contents are 699 * separate messages, so send the file header first. 700 * The just registered callback will be called by the guest afterwards. 701 */ 702 pMsg->setType(DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR); 703 pMsg->setNextUInt32(0); /* context ID */ 704 pMsg->setNextString(strPath.c_str()); /* pvName */ 705 pMsg->setNextUInt32((uint32_t)(strPath.length() + 1)); /* cbName */ 706 pMsg->setNextUInt32(0); /* uFlags */ 707 pMsg->setNextUInt32(aFile.GetMode()); /* fMode */ 708 pMsg->setNextUInt64(aFile.GetSize()); /* uSize */ 709 710 LogFlowFunc(("Sending file header ...\n")); 711 } 712 } 713 else 714 { 715 /* File header was sent, so only send the actual file data. */ 716 fSendFileData = true; 717 } 718 } 719 else /* Protocol v1. */ 720 { 721 /* Always send the file data, every time. */ 722 fSendFileData = true; 723 } 724 725 if ( RT_SUCCESS(rc) 726 && fSendFileData) 727 { 728 rc = i_sendFileData(pCtx, pMsg, aFile); 729 } 730 731 LogFlowFuncLeaveRC(rc); 732 return rc; 733 } 734 735 int GuestDnDTarget::i_sendFileData(PSENDDATACTX pCtx, GuestDnDMsg *pMsg, DnDURIObject &aFile) 736 { 737 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 738 AssertPtrReturn(pMsg, VERR_INVALID_POINTER); 739 740 GuestDnDResponse *pResp = pCtx->mpResp; 741 AssertPtr(pResp); 742 743 /** @todo Don't allow concurrent reads per context! */ 744 745 /* Something to transfer? */ 746 if ( pCtx->mURI.lstURI.IsEmpty() 747 || !pCtx->mIsActive) 748 { 749 return VERR_WRONG_ORDER; 750 } 751 752 /* 753 * Start sending stuff. 754 */ 755 756 /* Set the message type. */ 757 pMsg->setType(DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA); 758 759 /* Protocol version 1 sends the file path *every* time with a new file chunk. 760 * In protocol version 2 we only do this once with HOST_DND_HG_SND_FILE_HDR. */ 761 if (mData.mProtocolVersion <= 1) 762 { 763 pMsg->setNextUInt32(0); /* context ID */ 764 pMsg->setNextString(aFile.GetSourcePath().c_str()); /* pvName */ 765 pMsg->setNextUInt32((uint32_t)(aFile.GetSourcePath().length() + 1)); /* cbName */ 766 } 767 768 uint32_t cbRead = 0; 769 770 int rc = aFile.Read(pCtx->mURI.pvScratchBuf, pCtx->mURI.cbScratchBuf, &cbRead); 771 if (RT_SUCCESS(rc)) 772 { 773 pCtx->mURI.cbProcessed += cbRead; 774 775 if (mData.mProtocolVersion <= 1) 776 { 777 pMsg->setNextPointer(pCtx->mURI.pvScratchBuf, cbRead); /* pvData */ 778 pMsg->setNextUInt32(cbRead); /* cbData */ 779 pMsg->setNextUInt32(aFile.GetMode()); /* fMode */ 780 } 781 else 782 { 783 pMsg->setNextPointer(pCtx->mURI.pvScratchBuf, cbRead); /* pvData */ 784 pMsg->setNextUInt32(cbRead); /* cbData */ 785 } 786 787 if (aFile.IsComplete()) /* Done reading? */ 788 { 789 LogFlowFunc(("File \"%s\" complete\n", aFile.GetSourcePath().c_str())); 790 rc = VINF_EOF; 791 } 792 } 793 794 LogFlowFuncLeaveRC(rc); 795 return rc; 796 } 797 798 /* static */ 799 DECLCALLBACK(int) GuestDnDTarget::i_sendURIDataCallback(uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser) 800 { 801 PSENDDATACTX pCtx = (PSENDDATACTX)pvUser; 802 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 803 804 GuestDnDTarget *pThis = pCtx->mpTarget; 805 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 806 807 LogFlowFunc(("pThis=%p, uMsg=%RU32\n", pThis, uMsg)); 808 809 int rc = VINF_SUCCESS; 810 811 switch (uMsg) 812 { 813 case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG: 814 { 815 DragAndDropSvc::PVBOXDNDCBHGGETNEXTHOSTMSG pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGGETNEXTHOSTMSG>(pvParms); 816 AssertPtr(pCBData); 817 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSG) == cbParms, VERR_INVALID_PARAMETER); 818 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); 819 820 GuestDnDMsg *pMsg; 821 try 822 { 823 pMsg = new GuestDnDMsg(); 824 rc = pThis->i_sendURIDataLoop(pCtx, pMsg); 825 if (RT_SUCCESS(rc)) 826 { 827 rc = pThis->addMsg(pMsg); 828 if (RT_SUCCESS(rc)) /* Return message type & required parameter count to the guest. */ 829 { 830 LogFlowFunc(("GUEST_DND_GET_NEXT_HOST_MSG -> %RU32 (%RU32 params)\n", pMsg->getType(), pMsg->getCount())); 831 pCBData->uMsg = pMsg->getType(); 832 pCBData->cParms = pMsg->getCount(); 833 } 834 } 835 836 if (RT_FAILURE(rc)) 837 { 838 if (rc == VERR_NO_DATA) /* All URI objects processed? */ 839 { 840 /* Unregister this callback. */ 841 AssertPtr(pCtx->mpResp); 842 int rc2 = pCtx->mpResp->setCallback(uMsg, NULL /* PFNGUESTDNDCALLBACK */); 843 if (RT_FAILURE(rc2)) 844 LogFlowFunc(("Error: Unable to unregister callback for message %RU32, rc=%Rrc\n", uMsg, rc2)); 845 } 846 847 delete pMsg; 848 } 849 } 850 catch(std::bad_alloc & /*e*/) 851 { 852 rc = VERR_NO_MEMORY; 853 } 854 break; 855 } 856 case DragAndDropSvc::HOST_DND_HG_SND_DIR: 857 case DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR: 858 case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA: 859 { 860 DragAndDropSvc::PVBOXDNDCBHGGETNEXTHOSTMSGDATA pCBData 861 = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGGETNEXTHOSTMSGDATA>(pvParms); 862 AssertPtr(pCBData); 863 AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSGDATA) == cbParms, VERR_INVALID_PARAMETER); 864 AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG_DATA == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER); 865 866 GuestDnDMsg *pMsg = pThis->nextMsg(); 867 if (pMsg) 868 { 869 /* 870 * Sanity checks. 871 */ 872 if ( pCBData->uMsg != uMsg 873 || pCBData->paParms == NULL 874 || pCBData->cParms != pMsg->getCount()) 875 { 876 rc = VERR_INVALID_PARAMETER; 877 } 878 879 if (RT_SUCCESS(rc)) 880 { 881 LogFlowFunc(("Sending uMsg=%RU32, cParms=%RU32 ...\n", uMsg, pCBData->cParms)); 882 rc = HGCM::Message::copyParms(pMsg->getCount(), pMsg->getParms(), pCBData->paParms); 883 if (RT_SUCCESS(rc)) 884 { 885 pCBData->cParms = pMsg->getCount(); 886 pThis->removeNext(); 887 } 888 } 889 } 890 else 891 rc = VERR_NO_DATA; 892 893 LogFlowFunc(("Returning msg %RU32, rc=%Rrc\n", uMsg, rc)); 894 break; 895 } 896 default: 897 rc = VERR_NOT_SUPPORTED; 898 break; 899 } 900 901 if (RT_FAILURE(rc)) 902 { 903 if (pCtx->mURI.SemEvent != NIL_RTSEMEVENT) 904 { 905 LogFlowFunc(("Signalling ...\n")); 906 int rc2 = RTSemEventSignal(pCtx->mURI.SemEvent); 907 AssertRC(rc2); 908 } 909 } 910 911 LogFlowFuncLeaveRC(rc); 912 return rc; /* Tell the guest. */ 913 } 914 915 int GuestDnDTarget::i_sendURIData(PSENDDATACTX pCtx) 916 { 917 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 918 AssertPtr(pCtx->mpResp); 919 920 #define URI_DATA_IS_VALID_BREAK(x) \ 921 if (!x) \ 922 { \ 923 LogFlowFunc(("Invalid URI data value for \"" #x "\"\n")); \ 924 rc = VERR_INVALID_PARAMETER; \ 925 break; \ 926 } 927 928 void *pvBuf = RTMemAlloc(m_cbBlockSize); 929 if (!pvBuf) 930 return VERR_NO_MEMORY; 931 932 int rc; 933 934 #define REGISTER_CALLBACK(x) \ 935 rc = pCtx->mpResp->setCallback(x, i_sendURIDataCallback, pCtx); \ 936 if (RT_FAILURE(rc)) \ 937 return rc; 938 939 #define UNREGISTER_CALLBACK(x) \ 940 rc = pCtx->mpResp->setCallback(x, NULL); \ 941 AssertRC(rc); 942 943 /* 944 * Register callbacks. 945 */ 946 /* Generic callbacks. */ 947 REGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG); 948 /* Host callbacks. */ 949 REGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_DIR); 950 if (mData.mProtocolVersion >= 2) 951 REGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR); 952 REGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA); 953 954 do 955 { 956 /* 957 * Set our scratch buffer. 958 */ 959 pCtx->mURI.pvScratchBuf = pvBuf; 960 pCtx->mURI.cbScratchBuf = m_cbBlockSize; 961 962 /* Create event semaphore. */ 963 pCtx->mURI.SemEvent = NIL_RTSEMEVENT; 964 rc = RTSemEventCreate(&pCtx->mURI.SemEvent); 965 if (RT_FAILURE(rc)) 966 break; 967 968 /* 969 * Extract URI list from byte data. 970 */ 971 DnDURIList &lstURI = pCtx->mURI.lstURI; /* Use the URI list from the context. */ 972 973 const char *pszList = (const char *)&pCtx->mData.front(); 974 URI_DATA_IS_VALID_BREAK(pszList); 975 976 uint32_t cbList = pCtx->mData.size(); 977 URI_DATA_IS_VALID_BREAK(cbList); 978 979 RTCList<RTCString> lstURIOrg = RTCString(pszList, cbList).split("\r\n"); 980 URI_DATA_IS_VALID_BREAK(!lstURIOrg.isEmpty()); 981 982 rc = lstURI.AppendURIPathsFromList(lstURIOrg, 0 /* fFlags */); 983 if (RT_SUCCESS(rc)) 984 LogFlowFunc(("URI root objects: %zu, total bytes (raw data to transfer): %zu\n", 985 lstURI.RootCount(), lstURI.TotalBytes())); 986 else 987 break; 988 989 /* 990 * The first message always is the meta info for the data. The meta 991 * info *only* contains the root elements of an URI list. 992 * 993 * After the meta data we generate the messages required to send the data itself. 994 */ 995 Assert(!lstURI.IsEmpty()); 996 RTCString strData = lstURI.RootToString().c_str(); 997 size_t cbData = strData.length() + 1; /* Include terminating zero. */ 998 999 GuestDnDMsg Msg; 1000 Msg.setType(DragAndDropSvc::HOST_DND_HG_SND_DATA); 1001 Msg.setNextUInt32(pCtx->mScreenID); 1002 Msg.setNextPointer((void *)pCtx->mFormat.c_str(), (uint32_t)pCtx->mFormat.length() + 1); 1003 Msg.setNextUInt32((uint32_t)pCtx->mFormat.length() + 1); 1004 Msg.setNextPointer((void*)strData.c_str(), (uint32_t)cbData); 1005 Msg.setNextUInt32((uint32_t)cbData); 1006 1007 rc = GuestDnDInst()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms()); 1008 if (RT_SUCCESS(rc)) 1009 { 1010 /* 1011 * Wait until our callback i_sendURIDataCallback triggered the 1012 * wait event. 1013 */ 1014 LogFlowFunc(("Waiting for URI callback ...\n")); 1015 rc = RTSemEventWait(pCtx->mURI.SemEvent, RT_INDEFINITE_WAIT); 1016 LogFlowFunc(("URI callback done\n")); 1017 } 1018 1019 } while (0); 1020 1021 if (pCtx->mURI.SemEvent != NIL_RTSEMEVENT) 1022 { 1023 RTSemEventDestroy(pCtx->mURI.SemEvent); 1024 pCtx->mURI.SemEvent = NIL_RTSEMEVENT; 1025 } 1026 1027 /* 1028 * Unregister callbacksagain. 1029 */ 1030 /* Guest callbacks. */ 1031 UNREGISTER_CALLBACK(DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG); 1032 /* Host callbacks. */ 1033 UNREGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_DIR); 1034 if (mData.mProtocolVersion >= 2) 1035 UNREGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR); 1036 UNREGISTER_CALLBACK(DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA); 1037 1038 #undef REGISTER_CALLBACK 1039 #undef UNREGISTER_CALLBACK 1040 1041 if (pvBuf) 1042 RTMemFree(pvBuf); 1043 1044 #undef URI_DATA_IS_VALID_BREAK 1045 1046 LogFlowFuncLeaveRC(rc); 1047 return rc; 1048 } 1049 1050 int GuestDnDTarget::i_sendURIDataLoop(PSENDDATACTX pCtx, GuestDnDMsg *pMsg) 1051 { 1052 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 1053 1054 DnDURIList &lstURI = pCtx->mURI.lstURI; 1055 1056 int rc; 1057 1058 uint64_t cbTotal = pCtx->mURI.lstURI.TotalBytes(); 1059 uint8_t uPercent = pCtx->mURI.cbProcessed * 100 / (cbTotal ? cbTotal : 1); 1060 Assert(uPercent <= 100); 1061 1062 LogFlowFunc(("%RU64 / %RU64 -- %RU8%%\n", pCtx->mURI.cbProcessed, cbTotal, uPercent)); 1063 1064 bool fComplete = (uPercent >= 100) || lstURI.IsEmpty(); 1065 1066 if (pCtx->mpResp) 1067 { 1068 int rc2 = pCtx->mpResp->setProgress(uPercent, 1069 fComplete 1070 ? DragAndDropSvc::DND_PROGRESS_COMPLETE 1071 : DragAndDropSvc::DND_PROGRESS_RUNNING); 1072 AssertRC(rc2); 1073 } 1074 1075 if (fComplete) 1076 { 1077 LogFlowFunc(("Last URI item processed, bailing out\n")); 1078 return VERR_NO_DATA; 1079 } 1080 1081 Assert(!lstURI.IsEmpty()); 1082 DnDURIObject &curObj = lstURI.First(); 1083 1084 uint32_t fMode = curObj.GetMode(); 1085 LogFlowFunc(("Processing srcPath=%s, dstPath=%s, fMode=0x%x, cbSize=%RU32, fIsDir=%RTbool, fIsFile=%RTbool\n", 1086 curObj.GetSourcePath().c_str(), curObj.GetDestPath().c_str(), 1087 fMode, curObj.GetSize(), 1088 RTFS_IS_DIRECTORY(fMode), RTFS_IS_FILE(fMode))); 1089 1090 if (RTFS_IS_DIRECTORY(fMode)) 1091 { 1092 rc = i_sendDirectory(pCtx, pMsg, curObj); 1093 } 1094 else if (RTFS_IS_FILE(fMode)) 1095 { 1096 rc = i_sendFile(pCtx, pMsg, curObj); 1097 } 1098 else 1099 { 1100 AssertMsgFailed(("fMode=0x%x is not supported for srcPath=%s, dstPath=%s\n", 1101 fMode, curObj.GetSourcePath().c_str(), curObj.GetDestPath().c_str())); 1102 rc = VERR_NOT_SUPPORTED; 1103 } 1104 1105 bool fRemove = false; /* Remove current entry? */ 1106 if ( curObj.IsComplete() 1107 || RT_FAILURE(rc)) 1108 { 1109 fRemove = true; 1110 } 1111 1112 if (fRemove) 1113 { 1114 LogFlowFunc(("Removing \"%s\" from list, rc=%Rrc\n", curObj.GetSourcePath().c_str(), rc)); 1115 lstURI.RemoveFirst(); 1116 } 1117 1118 if ( pCtx->mpResp 1119 && pCtx->mpResp->isProgressCanceled()) 1120 { 1121 LogFlowFunc(("Cancelling ...\n")); 1122 1123 rc = i_cancelOperation(); 1124 if (RT_SUCCESS(rc)) 1125 rc = VERR_CANCELLED; 1126 } 1127 1128 LogFlowFuncLeaveRC(rc); 1129 return rc; 1130 } 1131 1132 HRESULT GuestDnDTarget::cancel(BOOL *aVeto) 1133 { 1134 #if !defined(VBOX_WITH_DRAG_AND_DROP) 1135 ReturnComNotImplemented(); 1136 #else /* VBOX_WITH_DRAG_AND_DROP */ 1137 1138 int rc = i_cancelOperation(); 1139 1140 if (aVeto) 1141 *aVeto = FALSE; /** @todo */ 1142 1143 return RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR; 1144 #endif /* VBOX_WITH_DRAG_AND_DROP */ 1145 } 1146
Note:
See TracChangeset
for help on using the changeset viewer.