VirtualBox

source: vbox/trunk/src/VBox/Main/include/GuestDnDPrivate.h@ 85334

Last change on this file since 85334 was 85121, checked in by vboxsync, 5 years ago

iprt/cdefs.h: Refactored the typedef use of DECLCALLBACK as well as DECLCALLBACKMEMBER to wrap the whole expression, similar to the DECLR?CALLBACKMEMBER macros. This allows adding a throw() at the end when compiling with the VC++ compiler to indicate that the callbacks won't throw anything, so we can stop supressing the C5039 warning about passing functions that can potential throw C++ exceptions to extern C code that can't necessarily cope with such (unwind,++). Introduced a few _EX variations that allows specifying different/no calling convention too, as that's handy when dynamically resolving host APIs. Fixed numerous places missing DECLCALLBACK and such. Left two angry @todos regarding use of CreateThread. bugref:9794

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.5 KB
Line 
1/* $Id: GuestDnDPrivate.h 85121 2020-07-08 19:33:26Z vboxsync $ */
2/** @file
3 * Private guest drag and drop code, used by GuestDnDTarget +
4 * GuestDnDSource.
5 */
6
7/*
8 * Copyright (C) 2011-2020 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#ifndef MAIN_INCLUDED_GuestDnDPrivate_h
20#define MAIN_INCLUDED_GuestDnDPrivate_h
21#ifndef RT_WITHOUT_PRAGMA_ONCE
22# pragma once
23#endif
24
25#include <iprt/dir.h>
26#include <iprt/file.h>
27#include <iprt/path.h>
28
29#include <VBox/hgcmsvc.h> /* For PVBOXHGCMSVCPARM. */
30#include <VBox/GuestHost/DragAndDrop.h>
31#include <VBox/GuestHost/DragAndDropDefs.h>
32#include <VBox/HostServices/DragAndDropSvc.h>
33
34/**
35 * Forward prototype declarations.
36 */
37class Guest;
38class GuestDnDBase;
39class GuestDnDResponse;
40class GuestDnDSource;
41class GuestDnDTarget;
42class Progress;
43
44/**
45 * Type definitions.
46 */
47
48/** List (vector) of MIME types. */
49typedef std::vector<com::Utf8Str> GuestDnDMIMEList;
50
51/*
52 ** @todo Put most of the implementations below in GuestDnDPrivate.cpp!
53 */
54
55class GuestDnDCallbackEvent
56{
57public:
58
59 GuestDnDCallbackEvent(void)
60 : mSemEvent(NIL_RTSEMEVENT)
61 , mRc(VINF_SUCCESS) { }
62
63 virtual ~GuestDnDCallbackEvent(void);
64
65public:
66
67 int Reset(void);
68
69 int Notify(int rc = VINF_SUCCESS);
70
71 int Result(void) const { return mRc; }
72
73 int Wait(RTMSINTERVAL msTimeout);
74
75protected:
76
77 /** Event semaphore to notify on error/completion. */
78 RTSEMEVENT mSemEvent;
79 /** Callback result. */
80 int mRc;
81};
82
83/**
84 * Class for handling the (raw) meta data.
85 */
86class GuestDnDMetaData
87{
88public:
89
90 GuestDnDMetaData(void)
91 : pvData(NULL)
92 , cbData(0)
93 , cbDataUsed(0) { }
94
95 virtual ~GuestDnDMetaData(void)
96 {
97 reset();
98 }
99
100public:
101
102 uint32_t add(const void *pvDataAdd, uint32_t cbDataAdd)
103 {
104 LogFlowThisFunc(("pvDataAdd=%p, cbDataAdd=%zu\n", pvDataAdd, cbDataAdd));
105
106 if (!cbDataAdd)
107 return 0;
108 AssertPtrReturn(pvDataAdd, 0);
109
110 int rc = resize(cbData + cbDataAdd);
111 if (RT_FAILURE(rc))
112 return 0;
113
114 Assert(cbData >= cbDataUsed + cbDataAdd);
115 memcpy((uint8_t *)pvData + cbDataUsed, pvDataAdd, cbDataAdd);
116
117 cbDataUsed += cbDataAdd;
118
119 return cbDataAdd;
120 }
121
122 uint32_t add(const std::vector<BYTE> &vecAdd)
123 {
124 if (!vecAdd.size())
125 return 0;
126
127 if (vecAdd.size() > UINT32_MAX) /* Paranoia. */
128 return 0;
129
130 return add(&vecAdd.front(), (uint32_t)vecAdd.size());
131 }
132
133 void reset(void)
134 {
135 if (pvData)
136 {
137 Assert(cbData);
138 RTMemFree(pvData);
139 pvData = NULL;
140 }
141
142 cbData = 0;
143 cbDataUsed = 0;
144 }
145
146 const void *getData(void) const { return pvData; }
147
148 void *getDataMutable(void) { return pvData; }
149
150 uint32_t getSize(void) const { return cbDataUsed; }
151
152public:
153
154 int fromString(const RTCString &strData)
155 {
156 int rc = VINF_SUCCESS;
157
158 if (strData.isNotEmpty())
159 {
160 const uint32_t cbStrData = (uint32_t)strData.length() + 1; /* Include terminating zero. */
161 rc = resize(cbStrData);
162 if (RT_SUCCESS(rc))
163 memcpy(pvData, strData.c_str(), cbStrData);
164 }
165
166 return rc;
167 }
168
169 int fromURIList(const DnDURIList &lstURI)
170 {
171 return fromString(lstURI.GetRootEntries());
172 }
173
174protected:
175
176 int resize(uint32_t cbSize)
177 {
178 if (!cbSize)
179 {
180 reset();
181 return VINF_SUCCESS;
182 }
183
184 if (cbSize == cbData)
185 return VINF_SUCCESS;
186
187 if (cbSize > _32M) /* Meta data can be up to 32MB. */
188 return VERR_INVALID_PARAMETER;
189
190 void *pvTmp = NULL;
191 if (!cbData)
192 {
193 Assert(cbDataUsed == 0);
194 pvTmp = RTMemAllocZ(cbSize);
195 }
196 else
197 {
198 AssertPtr(pvData);
199 pvTmp = RTMemRealloc(pvData, cbSize);
200 RT_BZERO(pvTmp, cbSize);
201 }
202
203 if (pvTmp)
204 {
205 pvData = pvTmp;
206 cbData = cbSize;
207 return VINF_SUCCESS;
208 }
209
210 return VERR_NO_MEMORY;
211 }
212
213protected:
214
215 void *pvData;
216 uint32_t cbData;
217 uint32_t cbDataUsed;
218};
219
220/**
221 * Class for keeping drag and drop (meta) data
222 * to be sent/received.
223 */
224class GuestDnDData
225{
226public:
227
228 GuestDnDData(void)
229 : cbEstTotal(0)
230 , cbEstMeta(0)
231 , cbProcessed(0)
232 {
233 RT_ZERO(dataHdr);
234 }
235
236 virtual ~GuestDnDData(void)
237 {
238 reset();
239 }
240
241public:
242
243 uint64_t addProcessed(uint32_t cbDataAdd)
244 {
245 const uint64_t cbTotal = getTotal(); NOREF(cbTotal);
246 Assert(cbProcessed + cbDataAdd <= cbTotal);
247 cbProcessed += cbDataAdd;
248 return cbProcessed;
249 }
250
251 bool isComplete(void) const
252 {
253 const uint64_t cbTotal = getTotal();
254 LogFlowFunc(("cbProcessed=%RU64, cbTotal=%RU64\n", cbProcessed, cbTotal));
255 Assert(cbProcessed <= cbTotal);
256 return (cbProcessed == cbTotal);
257 }
258
259 void *getChkSumMutable(void) { return dataHdr.pvChecksum; }
260
261 uint32_t getChkSumSize(void) const { return dataHdr.cbChecksum; }
262
263 void *getFmtMutable(void) { return dataHdr.pvMetaFmt; }
264
265 uint32_t getFmtSize(void) const { return dataHdr.cbMetaFmt; }
266
267 GuestDnDMetaData &getMeta(void) { return dataMeta; }
268
269 uint8_t getPercentComplete(void) const
270 {
271 int64_t cbTotal = RT_MAX(getTotal(), 1);
272 return (uint8_t)(cbProcessed * 100 / cbTotal);
273 }
274
275 uint64_t getProcessed(void) const { return cbProcessed; }
276
277 uint64_t getRemaining(void) const
278 {
279 const uint64_t cbTotal = getTotal();
280 Assert(cbProcessed <= cbTotal);
281 return cbTotal - cbProcessed;
282 }
283
284 uint64_t getTotal(void) const { return cbEstTotal; }
285
286 void reset(void)
287 {
288 clearFmt();
289 clearChkSum();
290
291 RT_ZERO(dataHdr);
292
293 dataMeta.reset();
294
295 cbEstTotal = 0;
296 cbEstMeta = 0;
297 cbProcessed = 0;
298 }
299
300 int setFmt(const void *pvFmt, uint32_t cbFmt)
301 {
302 if (cbFmt)
303 {
304 AssertPtrReturn(pvFmt, VERR_INVALID_POINTER);
305 void *pvFmtTmp = RTMemAlloc(cbFmt);
306 if (!pvFmtTmp)
307 return VERR_NO_MEMORY;
308
309 clearFmt();
310
311 memcpy(pvFmtTmp, pvFmt, cbFmt);
312
313 dataHdr.pvMetaFmt = pvFmtTmp;
314 dataHdr.cbMetaFmt = cbFmt;
315 }
316 else
317 clearFmt();
318
319 return VINF_SUCCESS;
320 }
321
322 void setEstimatedSize(uint64_t cbTotal, uint32_t cbMeta)
323 {
324 Assert(cbMeta <= cbTotal);
325
326 LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU32\n", cbTotal, cbMeta));
327
328 cbEstTotal = cbTotal;
329 cbEstMeta = cbMeta;
330 }
331
332protected:
333
334 void clearChkSum(void)
335 {
336 if (dataHdr.pvChecksum)
337 {
338 Assert(dataHdr.cbChecksum);
339 RTMemFree(dataHdr.pvChecksum);
340 dataHdr.pvChecksum = NULL;
341 }
342
343 dataHdr.cbChecksum = 0;
344 }
345
346 void clearFmt(void)
347 {
348 if (dataHdr.pvMetaFmt)
349 {
350 Assert(dataHdr.cbMetaFmt);
351 RTMemFree(dataHdr.pvMetaFmt);
352 dataHdr.pvMetaFmt = NULL;
353 }
354
355 dataHdr.cbMetaFmt = 0;
356 }
357
358protected:
359
360 /** The data header. */
361 VBOXDNDDATAHDR dataHdr;
362 /** For storing the actual meta data.
363 * This might be an URI list or just plain raw data,
364 * according to the format being sent. */
365 GuestDnDMetaData dataMeta;
366 /** Estimated total data size when receiving data. */
367 uint64_t cbEstTotal;
368 /** Estimated meta data size when receiving data. */
369 uint32_t cbEstMeta;
370 /** Overall size (in bytes) of processed data. */
371 uint64_t cbProcessed;
372};
373
374/** Initial object context state / no state set. */
375#define DND_OBJCTX_STATE_NONE 0
376/** The header was received / sent. */
377#define DND_OBJCTX_STATE_HAS_HDR RT_BIT(0)
378/** Validation mask for object context state. */
379#define DND_OBJCTX_STATE_VALID_MASK UINT32_C(0x00000001)
380
381/**
382 * Structure for keeping a DnDURIObject context around.
383 */
384class GuestDnDURIObjCtx
385{
386public:
387
388 GuestDnDURIObjCtx(void)
389 : pObjURI(NULL)
390 , fIntermediate(false)
391 , fState(DND_OBJCTX_STATE_NONE) { }
392
393 virtual ~GuestDnDURIObjCtx(void)
394 {
395 destroy();
396 }
397
398public:
399
400 int createIntermediate(DnDURIObject::Type enmType)
401 {
402 reset();
403
404 int rc;
405
406 try
407 {
408 pObjURI = new DnDURIObject(enmType);
409 fIntermediate = true;
410
411 rc = VINF_SUCCESS;
412 }
413 catch (std::bad_alloc &)
414 {
415 rc = VERR_NO_MEMORY;
416 }
417
418 LogThisFunc(("Returning %Rrc\n", rc));
419 return rc;
420 }
421
422 void destroy(void)
423 {
424 LogFlowThisFuncEnter();
425
426 if ( pObjURI
427 && fIntermediate)
428 {
429 delete pObjURI;
430 }
431
432 pObjURI = NULL;
433 fIntermediate = false;
434 }
435
436 DnDURIObject *getObj(void) const { return pObjURI; }
437
438 bool isIntermediate(void) { return fIntermediate; }
439
440 bool isValid(void) const { return (pObjURI != NULL); }
441
442 /** Returns the current state. */
443 uint32_t getState(void) const { return fState; }
444
445 void reset(void)
446 {
447 LogFlowThisFuncEnter();
448
449 destroy();
450
451 fIntermediate = false;
452 fState = DND_OBJCTX_STATE_NONE;
453 }
454
455 void setObj(DnDURIObject *pObj)
456 {
457 LogFlowThisFunc(("%p\n", pObj));
458
459 destroy();
460
461 pObjURI = pObj;
462 }
463
464 /**
465 * Sets the new state.
466 *
467 * @returns The new state, if set.
468 * @param fStateNew New state to set.
469 */
470 uint32_t setState(uint32_t fStateNew)
471 {
472 AssertReturn(!(fStateNew & ~DND_OBJCTX_STATE_VALID_MASK), fState /* Return old state */);
473 fState = fStateNew;
474 return fState;
475 }
476
477protected:
478
479 /** Pointer to current object being handled. */
480 DnDURIObject *pObjURI;
481 /** Flag whether pObjURI needs deletion after use. */
482 bool fIntermediate;
483 /** Internal context state, corresponding to DND_OBJCTX_STATE_XXX. */
484 uint32_t fState;
485 /** @todo Add more statistics / information here. */
486};
487
488/**
489 * Structure for keeping around an URI (data) transfer.
490 */
491class GuestDnDURIData
492{
493
494public:
495
496 GuestDnDURIData(void)
497 : cObjToProcess(0)
498 , cObjProcessed(0)
499 , pvScratchBuf(NULL)
500 , cbScratchBuf(0) { }
501
502 virtual ~GuestDnDURIData(void)
503 {
504 reset();
505
506 if (pvScratchBuf)
507 {
508 Assert(cbScratchBuf);
509 RTMemFree(pvScratchBuf);
510 pvScratchBuf = NULL;
511 }
512 cbScratchBuf = 0;
513 }
514
515 DnDDroppedFiles &getDroppedFiles(void) { return droppedFiles; }
516
517 DnDURIList &getURIList(void) { return lstURI; }
518
519 int init(size_t cbBuf = _64K)
520 {
521 reset();
522
523 pvScratchBuf = RTMemAlloc(cbBuf);
524 if (!pvScratchBuf)
525 return VERR_NO_MEMORY;
526
527 cbScratchBuf = cbBuf;
528 return VINF_SUCCESS;
529 }
530
531 bool isComplete(void) const
532 {
533 LogFlowFunc(("cObjProcessed=%RU64, cObjToProcess=%RU64\n", cObjProcessed, cObjToProcess));
534
535 if (!cObjToProcess) /* Always return true if we don't have an object count. */
536 return true;
537
538 Assert(cObjProcessed <= cObjToProcess);
539 return (cObjProcessed == cObjToProcess);
540 }
541
542 const void *getBuffer(void) const { return pvScratchBuf; }
543
544 void *getBufferMutable(void) { return pvScratchBuf; }
545
546 size_t getBufferSize(void) const { return cbScratchBuf; }
547
548 GuestDnDURIObjCtx &getObj(uint64_t uID = 0)
549 {
550 RT_NOREF(uID);
551 AssertMsg(uID == 0, ("Other objects than object 0 is not supported yet\n"));
552 return objCtx;
553 }
554
555 GuestDnDURIObjCtx &getObjCurrent(void)
556 {
557 DnDURIObject *pCurObj = lstURI.First();
558 if ( !lstURI.IsEmpty()
559 && pCurObj)
560 {
561 /* Point the context object to the current DnDURIObject to process. */
562 objCtx.setObj(pCurObj);
563 }
564 else
565 objCtx.reset();
566
567 return objCtx;
568 }
569
570 uint64_t getObjToProcess(void) const { return cObjToProcess; }
571
572 uint64_t getObjProcessed(void) const { return cObjProcessed; }
573
574 int processObject(const DnDURIObject &Obj)
575 {
576 int rc;
577
578 /** @todo Find objct in lstURI first! */
579 switch (Obj.GetType())
580 {
581 case DnDURIObject::Type_Directory:
582 case DnDURIObject::Type_File:
583 rc = VINF_SUCCESS;
584 break;
585
586 default:
587 rc = VERR_NOT_IMPLEMENTED;
588 break;
589 }
590
591 if (RT_SUCCESS(rc))
592 {
593 if (cObjToProcess)
594 {
595 cObjProcessed++;
596 Assert(cObjProcessed <= cObjToProcess);
597 }
598 }
599
600 return rc;
601 }
602
603 void removeObjCurrent(void)
604 {
605 if (cObjToProcess)
606 {
607 cObjProcessed++;
608 Assert(cObjProcessed <= cObjToProcess);
609 }
610
611 lstURI.RemoveFirst();
612 objCtx.reset();
613 }
614
615 void reset(void)
616 {
617 LogFlowFuncEnter();
618
619 cObjToProcess = 0;
620 cObjProcessed = 0;
621
622 droppedFiles.Close();
623
624 lstURI.Clear();
625 objCtx.reset();
626 }
627
628 void setEstimatedObjects(uint64_t cObjs)
629 {
630 Assert(cObjToProcess == 0);
631 cObjToProcess = cObjs;
632 LogFlowFunc(("cObjToProcess=%RU64\n", cObjs));
633 }
634
635public:
636
637 int fromLocalMetaData(const GuestDnDMetaData &Data)
638 {
639 reset();
640
641 if (!Data.getSize())
642 return VINF_SUCCESS;
643
644 char *pszList;
645 int rc = RTStrCurrentCPToUtf8(&pszList, (const char *)Data.getData());
646 if (RT_FAILURE(rc))
647 {
648 LogFlowThisFunc(("String conversion failed with rc=%Rrc\n", rc));
649 return rc;
650 }
651
652 const size_t cbList = Data.getSize();
653 LogFlowThisFunc(("metaData=%p, cbList=%zu\n", &Data, cbList));
654
655 if (cbList)
656 {
657 RTCList<RTCString> lstURIOrg = RTCString(pszList, cbList).split("\r\n");
658 if (!lstURIOrg.isEmpty())
659 {
660 /* Note: All files to be transferred will be kept open during the entire DnD
661 * operation, also to keep the accounting right. */
662 rc = lstURI.AppendURIPathsFromList(lstURIOrg, DNDURILIST_FLAGS_KEEP_OPEN);
663 if (RT_SUCCESS(rc))
664 cObjToProcess = lstURI.GetTotalCount();
665 }
666 }
667
668 RTStrFree(pszList);
669 return rc;
670 }
671
672 int fromRemoteMetaData(const GuestDnDMetaData &Data)
673 {
674 LogFlowFuncEnter();
675
676 int rc = lstURI.SetFromURIData(Data.getData(), Data.getSize(), 0 /* uFlags */);
677 if (RT_SUCCESS(rc))
678 {
679 const size_t cRootCount = lstURI.GetRootCount();
680 LogFlowFunc(("cRootCount=%zu, cObjToProcess=%RU64\n", cRootCount, cObjToProcess));
681 if (cRootCount > cObjToProcess)
682 rc = VERR_INVALID_PARAMETER;
683 }
684
685 return rc;
686 }
687
688 int toMetaData(std::vector<BYTE> &vecData)
689 {
690 const char *pszDroppedFilesDir = droppedFiles.GetDirAbs();
691
692 Utf8Str strURIs = lstURI.GetRootEntries(RTCString(pszDroppedFilesDir));
693 size_t cbData = strURIs.length();
694
695 LogFlowFunc(("%zu root URIs (%zu bytes)\n", lstURI.GetRootCount(), cbData));
696
697 int rc;
698
699 try
700 {
701 vecData.resize(cbData + 1 /* Include termination */);
702 memcpy(&vecData.front(), strURIs.c_str(), cbData);
703
704 rc = VINF_SUCCESS;
705 }
706 catch (std::bad_alloc &)
707 {
708 rc = VERR_NO_MEMORY;
709 }
710
711 return rc;
712 }
713
714protected:
715
716 int processDirectory(const char *pszPath, uint32_t fMode)
717 {
718 /** @todo Find directory in lstURI first! */
719 int rc;
720
721 const char *pszDroppedFilesDir = droppedFiles.GetDirAbs();
722 char *pszDir = RTPathJoinA(pszDroppedFilesDir, pszPath);
723 if (pszDir)
724 {
725 rc = RTDirCreateFullPath(pszDir, fMode);
726 if (cObjToProcess)
727 {
728 cObjProcessed++;
729 Assert(cObjProcessed <= cObjToProcess);
730 }
731
732 RTStrFree(pszDir);
733 }
734 else
735 rc = VERR_NO_MEMORY;
736
737 return rc;
738 }
739
740protected:
741
742 /** Number of objects to process. */
743 uint64_t cObjToProcess;
744 /** Number of objects already processed. */
745 uint64_t cObjProcessed;
746 /** Handles all drop files for this operation. */
747 DnDDroppedFiles droppedFiles;
748 /** (Non-recursive) List of URI objects to handle. */
749 DnDURIList lstURI;
750 /** Context to current object being handled.
751 * As we currently do all transfers one after another we
752 * only have one context at a time. */
753 GuestDnDURIObjCtx objCtx;
754 /** Pointer to an optional scratch buffer to use for
755 * doing the actual chunk transfers. */
756 void *pvScratchBuf;
757 /** Size (in bytes) of scratch buffer. */
758 size_t cbScratchBuf;
759};
760
761/**
762 * Context structure for sending data to the guest.
763 */
764struct GuestDnDSendCtx
765{
766 /** Pointer to guest target class this context belongs to. */
767 GuestDnDTarget *mpTarget;
768 /** Pointer to guest response class this context belongs to. */
769 GuestDnDResponse *mpResp;
770 /** Flag indicating whether a file transfer is active and
771 * initiated by the host. */
772 bool mIsActive;
773 /** Target (VM) screen ID. */
774 uint32_t mScreenID;
775 /** Drag'n drop format requested by the guest. */
776 com::Utf8Str mFmtReq;
777 /** Drag'n drop data to send.
778 * This can be arbitrary data or an URI list. */
779 GuestDnDData mData;
780 /** URI data structure. */
781 GuestDnDURIData mURI;
782 /** Callback event to use. */
783 GuestDnDCallbackEvent mCBEvent;
784};
785
786/**
787 * Context structure for receiving data from the guest.
788 */
789struct GuestDnDRecvCtx
790{
791 /** Pointer to guest source class this context belongs to. */
792 GuestDnDSource *mpSource;
793 /** Pointer to guest response class this context belongs to. */
794 GuestDnDResponse *mpResp;
795 /** Flag indicating whether a file transfer is active and
796 * initiated by the host. */
797 bool mIsActive;
798 /** Formats offered by the guest (and supported by the host). */
799 GuestDnDMIMEList mFmtOffered;
800 /** Original drop format requested to receive from the guest. */
801 com::Utf8Str mFmtReq;
802 /** Intermediate drop format to be received from the guest.
803 * Some original drop formats require a different intermediate
804 * drop format:
805 *
806 * Receiving a file link as "text/plain" requires still to
807 * receive the file from the guest as "text/uri-list" first,
808 * then pointing to the file path on the host with the data
809 * in "text/plain" format returned. */
810 com::Utf8Str mFmtRecv;
811 /** Desired drop action to perform on the host.
812 * Needed to tell the guest if data has to be
813 * deleted e.g. when moving instead of copying. */
814 VBOXDNDACTION mAction;
815 /** Drag'n drop received from the guest.
816 * This can be arbitrary data or an URI list. */
817 GuestDnDData mData;
818 /** URI data structure. */
819 GuestDnDURIData mURI;
820 /** Callback event to use. */
821 GuestDnDCallbackEvent mCBEvent;
822};
823
824/**
825 * Simple structure for a buffered guest DnD message.
826 */
827class GuestDnDMsg
828{
829public:
830
831 GuestDnDMsg(void)
832 : uMsg(0)
833 , cParms(0)
834 , cParmsAlloc(0)
835 , paParms(NULL) { }
836
837 virtual ~GuestDnDMsg(void)
838 {
839 reset();
840 }
841
842public:
843
844 PVBOXHGCMSVCPARM getNextParam(void)
845 {
846 if (cParms >= cParmsAlloc)
847 {
848 if (!paParms)
849 paParms = (PVBOXHGCMSVCPARM)RTMemAlloc(4 * sizeof(VBOXHGCMSVCPARM));
850 else
851 paParms = (PVBOXHGCMSVCPARM)RTMemRealloc(paParms, (cParmsAlloc + 4) * sizeof(VBOXHGCMSVCPARM));
852 if (!paParms)
853 throw VERR_NO_MEMORY;
854 RT_BZERO(&paParms[cParmsAlloc], 4 * sizeof(VBOXHGCMSVCPARM));
855 cParmsAlloc += 4;
856 }
857
858 return &paParms[cParms++];
859 }
860
861 uint32_t getCount(void) const { return cParms; }
862 PVBOXHGCMSVCPARM getParms(void) const { return paParms; }
863 uint32_t getType(void) const { return uMsg; }
864
865 void reset(void)
866 {
867 if (paParms)
868 {
869 /* Remove deep copies. */
870 for (uint32_t i = 0; i < cParms; i++)
871 {
872 if ( paParms[i].type == VBOX_HGCM_SVC_PARM_PTR
873 && paParms[i].u.pointer.size)
874 {
875 AssertPtr(paParms[i].u.pointer.addr);
876 RTMemFree(paParms[i].u.pointer.addr);
877 }
878 }
879
880 RTMemFree(paParms);
881 paParms = NULL;
882 }
883
884 uMsg = cParms = cParmsAlloc = 0;
885 }
886
887 int setNextPointer(void *pvBuf, uint32_t cbBuf)
888 {
889 PVBOXHGCMSVCPARM pParm = getNextParam();
890 if (!pParm)
891 return VERR_NO_MEMORY;
892
893 void *pvTmp = NULL;
894 if (pvBuf)
895 {
896 Assert(cbBuf);
897 pvTmp = RTMemDup(pvBuf, cbBuf);
898 if (!pvTmp)
899 return VERR_NO_MEMORY;
900 }
901
902 HGCMSvcSetPv(pParm, pvTmp, cbBuf);
903 return VINF_SUCCESS;
904 }
905
906 int setNextString(const char *pszString)
907 {
908 PVBOXHGCMSVCPARM pParm = getNextParam();
909 if (!pParm)
910 return VERR_NO_MEMORY;
911
912 char *pszTemp = RTStrDup(pszString);
913 if (!pszTemp)
914 return VERR_NO_MEMORY;
915
916 HGCMSvcSetStr(pParm, pszTemp);
917 return VINF_SUCCESS;
918 }
919
920 int setNextUInt32(uint32_t u32Val)
921 {
922 PVBOXHGCMSVCPARM pParm = getNextParam();
923 if (!pParm)
924 return VERR_NO_MEMORY;
925
926 HGCMSvcSetU32(pParm, u32Val);
927 return VINF_SUCCESS;
928 }
929
930 int setNextUInt64(uint64_t u64Val)
931 {
932 PVBOXHGCMSVCPARM pParm = getNextParam();
933 if (!pParm)
934 return VERR_NO_MEMORY;
935
936 HGCMSvcSetU64(pParm, u64Val);
937 return VINF_SUCCESS;
938 }
939
940 void setType(uint32_t uMsgType) { uMsg = uMsgType; }
941
942protected:
943
944 /** Message type. */
945 uint32_t uMsg;
946 /** Message parameters. */
947 uint32_t cParms;
948 /** Size of array. */
949 uint32_t cParmsAlloc;
950 /** Array of HGCM parameters */
951 PVBOXHGCMSVCPARM paParms;
952};
953
954/** Guest DnD callback function definition. */
955typedef DECLCALLBACKPTR(int, PFNGUESTDNDCALLBACK,(uint32_t uMsg, void *pvParms, size_t cbParms, void *pvUser));
956
957/**
958 * Structure for keeping a guest DnD callback.
959 * Each callback can handle one HGCM message, however, multiple HGCM messages can be registered
960 * to the same callback (function).
961 */
962typedef struct GuestDnDCallback
963{
964 GuestDnDCallback(void)
965 : uMessgage(0)
966 , pfnCallback(NULL)
967 , pvUser(NULL) { }
968
969 GuestDnDCallback(PFNGUESTDNDCALLBACK pvCB, uint32_t uMsg, void *pvUsr = NULL)
970 : uMessgage(uMsg)
971 , pfnCallback(pvCB)
972 , pvUser(pvUsr) { }
973
974 /** The HGCM message ID to handle. */
975 uint32_t uMessgage;
976 /** Pointer to callback function. */
977 PFNGUESTDNDCALLBACK pfnCallback;
978 /** Pointer to user-supplied data. */
979 void *pvUser;
980
981} GuestDnDCallback;
982
983/** Contains registered callback pointers for specific HGCM message types. */
984typedef std::map<uint32_t, GuestDnDCallback> GuestDnDCallbackMap;
985
986/** @todo r=andy This class needs to go, as this now is too inflexible when it comes to all
987 * the callback handling/dispatching. It's part of the initial code and only adds
988 * unnecessary complexity. */
989class GuestDnDResponse
990{
991
992public:
993
994 GuestDnDResponse(const ComObjPtr<Guest>& pGuest);
995 virtual ~GuestDnDResponse(void);
996
997public:
998
999 int notifyAboutGuestResponse(void) const;
1000 int waitForGuestResponse(RTMSINTERVAL msTimeout = 500) const;
1001
1002 void setActionsAllowed(VBOXDNDACTIONLIST a) { m_dndLstActionsAllowed = a; }
1003 VBOXDNDACTIONLIST getActionsAllowed(void) const { return m_dndLstActionsAllowed; }
1004
1005 void setActionDefault(VBOXDNDACTION a) { m_dndActionDefault = a; }
1006 VBOXDNDACTION getActionDefault(void) const { return m_dndActionDefault; }
1007
1008 void setFormats(const GuestDnDMIMEList &lstFormats) { m_lstFormats = lstFormats; }
1009 GuestDnDMIMEList formats(void) const { return m_lstFormats; }
1010
1011 void reset(void);
1012
1013 bool isProgressCanceled(void) const;
1014 int setCallback(uint32_t uMsg, PFNGUESTDNDCALLBACK pfnCallback, void *pvUser = NULL);
1015 int setProgress(unsigned uPercentage, uint32_t uState, int rcOp = VINF_SUCCESS, const Utf8Str &strMsg = "");
1016 HRESULT resetProgress(const ComObjPtr<Guest>& pParent);
1017 HRESULT queryProgressTo(IProgress **ppProgress);
1018
1019public:
1020
1021 /** @name HGCM callback handling.
1022 @{ */
1023 int onDispatch(uint32_t u32Function, void *pvParms, uint32_t cbParms);
1024 /** @} */
1025
1026protected:
1027
1028 /** Pointer to context this class is tied to. */
1029 void *m_pvCtx;
1030 /** Event for waiting for response. */
1031 RTSEMEVENT m_EventSem;
1032 /** Default action to perform in case of a
1033 * successful drop. */
1034 VBOXDNDACTION m_dndActionDefault;
1035 /** Actions supported by the guest in case of a successful drop. */
1036 VBOXDNDACTIONLIST m_dndLstActionsAllowed;
1037 /** Format(s) requested/supported from the guest. */
1038 GuestDnDMIMEList m_lstFormats;
1039 /** Pointer to IGuest parent object. */
1040 ComObjPtr<Guest> m_pParent;
1041 /** Pointer to associated progress object. Optional. */
1042 ComObjPtr<Progress> m_pProgress;
1043 /** Callback map. */
1044 GuestDnDCallbackMap m_mapCallbacks;
1045};
1046
1047/**
1048 * Private singleton class for the guest's DnD
1049 * implementation. Can't be instanciated directly, only via
1050 * the factory pattern.
1051 *
1052 ** @todo Move this into GuestDnDBase.
1053 */
1054class GuestDnD
1055{
1056public:
1057
1058 static GuestDnD *createInstance(const ComObjPtr<Guest>& pGuest)
1059 {
1060 Assert(NULL == GuestDnD::s_pInstance);
1061 GuestDnD::s_pInstance = new GuestDnD(pGuest);
1062 return GuestDnD::s_pInstance;
1063 }
1064
1065 static void destroyInstance(void)
1066 {
1067 if (GuestDnD::s_pInstance)
1068 {
1069 delete GuestDnD::s_pInstance;
1070 GuestDnD::s_pInstance = NULL;
1071 }
1072 }
1073
1074 static inline GuestDnD *getInstance(void)
1075 {
1076 AssertPtr(GuestDnD::s_pInstance);
1077 return GuestDnD::s_pInstance;
1078 }
1079
1080protected:
1081
1082 GuestDnD(const ComObjPtr<Guest>& pGuest);
1083 virtual ~GuestDnD(void);
1084
1085public:
1086
1087 /** @name Public helper functions.
1088 * @{ */
1089 HRESULT adjustScreenCoordinates(ULONG uScreenId, ULONG *puX, ULONG *puY) const;
1090 int hostCall(uint32_t u32Function, uint32_t cParms, PVBOXHGCMSVCPARM paParms) const;
1091 GuestDnDResponse *response(void) { return m_pResponse; }
1092 GuestDnDMIMEList defaultFormats(void) const { return m_strDefaultFormats; }
1093 /** @} */
1094
1095public:
1096
1097 /** @name Static low-level HGCM callback handler.
1098 * @{ */
1099 static DECLCALLBACK(int) notifyDnDDispatcher(void *pvExtension, uint32_t u32Function, void *pvParms, uint32_t cbParms);
1100 /** @} */
1101
1102 /** @name Static helper methods.
1103 * @{ */
1104 static bool isFormatInFormatList(const com::Utf8Str &strFormat, const GuestDnDMIMEList &lstFormats);
1105 static GuestDnDMIMEList toFormatList(const com::Utf8Str &strFormats);
1106 static com::Utf8Str toFormatString(const GuestDnDMIMEList &lstFormats);
1107 static GuestDnDMIMEList toFilteredFormatList(const GuestDnDMIMEList &lstFormatsSupported, const GuestDnDMIMEList &lstFormatsWanted);
1108 static GuestDnDMIMEList toFilteredFormatList(const GuestDnDMIMEList &lstFormatsSupported, const com::Utf8Str &strFormatsWanted);
1109 static DnDAction_T toMainAction(VBOXDNDACTION dndAction);
1110 static std::vector<DnDAction_T> toMainActions(VBOXDNDACTIONLIST dndActionList);
1111 static VBOXDNDACTION toHGCMAction(DnDAction_T enmAction);
1112 static void toHGCMActions(DnDAction_T enmDefAction, VBOXDNDACTION *pDefAction, const std::vector<DnDAction_T> vecAllowedActions, VBOXDNDACTIONLIST *pLstAllowedActions);
1113 /** @} */
1114
1115protected:
1116
1117 /** @name Singleton properties.
1118 * @{ */
1119 /** List of supported default MIME/Content-type formats. */
1120 GuestDnDMIMEList m_strDefaultFormats;
1121 /** Pointer to guest implementation. */
1122 const ComObjPtr<Guest> m_pGuest;
1123 /** The current (last) response from the guest. At the
1124 * moment we only support only response a time (ARQ-style). */
1125 GuestDnDResponse *m_pResponse;
1126 /** @} */
1127
1128private:
1129
1130 /** Staic pointer to singleton instance. */
1131 static GuestDnD *s_pInstance;
1132};
1133
1134/** Access to the GuestDnD's singleton instance. */
1135#define GUESTDNDINST() GuestDnD::getInstance()
1136
1137/** List of pointers to guest DnD Messages. */
1138typedef std::list<GuestDnDMsg *> GuestDnDMsgList;
1139
1140/**
1141 * IDnDBase class implementation for sharing code between
1142 * IGuestDnDSource and IGuestDnDTarget implementation.
1143 */
1144class GuestDnDBase
1145{
1146protected:
1147
1148 GuestDnDBase(void);
1149
1150protected:
1151
1152 /** Shared (internal) IDnDBase method implementations.
1153 * @{ */
1154 HRESULT i_isFormatSupported(const com::Utf8Str &aFormat, BOOL *aSupported);
1155 HRESULT i_getFormats(GuestDnDMIMEList &aFormats);
1156 HRESULT i_addFormats(const GuestDnDMIMEList &aFormats);
1157 HRESULT i_removeFormats(const GuestDnDMIMEList &aFormats);
1158
1159 HRESULT i_getProtocolVersion(ULONG *puVersion);
1160 /** @} */
1161
1162protected:
1163
1164 int getProtocolVersion(uint32_t *puVersion);
1165
1166 /** @name Functions for handling a simple host HGCM message queue.
1167 * @{ */
1168 int msgQueueAdd(GuestDnDMsg *pMsg);
1169 GuestDnDMsg *msgQueueGetNext(void);
1170 void msgQueueRemoveNext(void);
1171 void msgQueueClear(void);
1172 /** @} */
1173
1174 int sendCancel(void);
1175 int updateProgress(GuestDnDData *pData, GuestDnDResponse *pResp, uint32_t cbDataAdd = 0);
1176 int waitForEvent(GuestDnDCallbackEvent *pEvent, GuestDnDResponse *pResp, RTMSINTERVAL msTimeout);
1177
1178protected:
1179
1180 /** @name Public attributes (through getters/setters).
1181 * @{ */
1182 /** Pointer to guest implementation. */
1183 const ComObjPtr<Guest> m_pGuest;
1184 /** List of supported MIME types by the source. */
1185 GuestDnDMIMEList m_lstFmtSupported;
1186 /** List of offered MIME types to the counterpart. */
1187 GuestDnDMIMEList m_lstFmtOffered;
1188 /** @} */
1189
1190 /**
1191 * Internal stuff.
1192 */
1193 struct
1194 {
1195 /** Number of active transfers (guest->host or host->guest). */
1196 uint32_t m_cTransfersPending;
1197 /** The DnD protocol version to use, depending on the
1198 * installed Guest Additions. See DragAndDropSvc.h for
1199 * a protocol changelog. */
1200 uint32_t m_uProtocolVersion;
1201 /** Outgoing message queue (FIFO). */
1202 GuestDnDMsgList m_lstMsgOut;
1203 } mDataBase;
1204};
1205#endif /* !MAIN_INCLUDED_GuestDnDPrivate_h */
1206
Note: See TracBrowser for help on using the repository browser.

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