VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxDnDDataObject.cpp@ 85800

Last change on this file since 85800 was 85746, checked in by vboxsync, 4 years ago

DnD: Renaming -- DND_FORMATS_SEPARATOR -> DND_FORMATS_SEPARATOR_STR and DND_PATH_SEPARATOR -> DND_PATH_SEPARATOR_STR.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.1 KB
Line 
1/* $Id: VBoxDnDDataObject.cpp 85746 2020-08-13 08:47:12Z vboxsync $ */
2/** @file
3 * VBoxDnDDataObject.cpp - IDataObject implementation.
4 */
5
6/*
7 * Copyright (C) 2013-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19#define LOG_GROUP LOG_GROUP_GUEST_DND
20#include <iprt/win/windows.h>
21#include <new> /* For bad_alloc. */
22#include <iprt/win/shlobj.h>
23
24#include <iprt/path.h>
25#include <iprt/semaphore.h>
26#include <iprt/uri.h>
27#include <iprt/utf16.h>
28
29#include <VBox/log.h>
30
31#include "VBoxTray.h"
32#include "VBoxHelpers.h"
33#include "VBoxDnD.h"
34
35#ifdef DEBUG
36 /* Enable the following line to get much more debug output about
37 * (un)known clipboard formats. */
38//# define VBOX_DND_DEBUG_FORMATS
39#endif
40
41/** @todo Implement IDataObjectAsyncCapability interface? */
42
43VBoxDnDDataObject::VBoxDnDDataObject(LPFORMATETC pFormatEtc, LPSTGMEDIUM pStgMed, ULONG cFormats)
44 : m_enmStatus(Status_Uninitialized),
45 m_cRefs(1),
46 m_cFormats(0),
47 m_pvData(NULL),
48 m_cbData(0)
49{
50 HRESULT hr;
51
52 ULONG cFixedFormats = 1;
53 ULONG cAllFormats = cFormats + cFixedFormats;
54
55 try
56 {
57 m_paFormatEtc = new FORMATETC[cAllFormats];
58 RT_BZERO(m_paFormatEtc, sizeof(FORMATETC) * cAllFormats);
59 m_paStgMedium = new STGMEDIUM[cAllFormats];
60 RT_BZERO(m_paStgMedium, sizeof(STGMEDIUM) * cAllFormats);
61
62 /*
63 * Registration of dynamic formats needed?
64 */
65 LogFlowFunc(("%RU32 dynamic formats\n", cFormats));
66 if (cFormats)
67 {
68 AssertPtr(pFormatEtc);
69 AssertPtr(pStgMed);
70
71 for (ULONG i = 0; i < cFormats; i++)
72 {
73 LogFlowFunc(("Format %RU32: cfFormat=%RI16, tyMed=%RU32, dwAspect=%RU32\n",
74 i, pFormatEtc[i].cfFormat, pFormatEtc[i].tymed, pFormatEtc[i].dwAspect));
75 m_paFormatEtc[i] = pFormatEtc[i];
76 m_paStgMedium[i] = pStgMed[i];
77 }
78 }
79
80 hr = S_OK;
81 }
82 catch (std::bad_alloc &)
83 {
84 hr = E_OUTOFMEMORY;
85 }
86
87 if (SUCCEEDED(hr))
88 {
89 int rc2 = RTSemEventCreate(&m_EvtDropped);
90 AssertRC(rc2);
91
92 /*
93 * Register fixed formats.
94 */
95#if 0
96 /* CF_HDROP. */
97 RegisterFormat(&mpFormatEtc[cFormats], CF_HDROP);
98 mpStgMedium[cFormats++].tymed = TYMED_HGLOBAL;
99
100 /* IStream. */
101 RegisterFormat(&mpFormatEtc[cFormats++],
102 RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR));
103 RegisterFormat(&mpFormatEtc[cFormats++],
104 RegisterClipboardFormat(CFSTR_FILECONTENTS),
105 TYMED_ISTREAM, 0 /* lIndex */);
106
107 /* Required for e.g. Windows Media Player. */
108 RegisterFormat(&mpFormatEtc[cFormats++],
109 RegisterClipboardFormat(CFSTR_FILENAME));
110 RegisterFormat(&mpFormatEtc[cFormats++],
111 RegisterClipboardFormat(CFSTR_FILENAMEW));
112 RegisterFormat(&mpFormatEtc[cFormats++],
113 RegisterClipboardFormat(CFSTR_SHELLIDLIST));
114 RegisterFormat(&mpFormatEtc[cFormats++],
115 RegisterClipboardFormat(CFSTR_SHELLIDLISTOFFSET));
116#endif
117 m_cFormats = cFormats;
118 m_enmStatus = Status_Initialized;
119 }
120
121 LogFlowFunc(("cFormats=%RU32, hr=%Rhrc\n", cFormats, hr));
122}
123
124VBoxDnDDataObject::~VBoxDnDDataObject(void)
125{
126 if (m_paFormatEtc)
127 delete[] m_paFormatEtc;
128
129 if (m_paStgMedium)
130 delete[] m_paStgMedium;
131
132 if (m_pvData)
133 RTMemFree(m_pvData);
134
135 LogFlowFunc(("mRefCount=%RI32\n", m_cRefs));
136}
137
138/*
139 * IUnknown methods.
140 */
141
142STDMETHODIMP_(ULONG) VBoxDnDDataObject::AddRef(void)
143{
144 return InterlockedIncrement(&m_cRefs);
145}
146
147STDMETHODIMP_(ULONG) VBoxDnDDataObject::Release(void)
148{
149 LONG lCount = InterlockedDecrement(&m_cRefs);
150 if (lCount == 0)
151 {
152 delete this;
153 return 0;
154 }
155
156 return lCount;
157}
158
159STDMETHODIMP VBoxDnDDataObject::QueryInterface(REFIID iid, void **ppvObject)
160{
161 AssertPtrReturn(ppvObject, E_INVALIDARG);
162
163 if ( iid == IID_IDataObject
164 || iid == IID_IUnknown)
165 {
166 AddRef();
167 *ppvObject = this;
168 return S_OK;
169 }
170
171 *ppvObject = 0;
172 return E_NOINTERFACE;
173}
174
175STDMETHODIMP VBoxDnDDataObject::GetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium)
176{
177 AssertPtrReturn(pFormatEtc, DV_E_FORMATETC);
178 AssertPtrReturn(pMedium, DV_E_FORMATETC);
179
180 ULONG lIndex;
181 if (!LookupFormatEtc(pFormatEtc, &lIndex)) /* Format supported? */
182 return DV_E_FORMATETC;
183 if (lIndex >= m_cFormats) /* Paranoia. */
184 return DV_E_FORMATETC;
185
186 LPFORMATETC pThisFormat = &m_paFormatEtc[lIndex];
187 AssertPtr(pThisFormat);
188
189 LPSTGMEDIUM pThisMedium = &m_paStgMedium[lIndex];
190 AssertPtr(pThisMedium);
191
192 LogFlowFunc(("Using pThisFormat=%p, pThisMedium=%p\n", pThisFormat, pThisMedium));
193
194 HRESULT hr = DV_E_FORMATETC; /* Play safe. */
195
196 LogFlowFunc(("mStatus=%ld\n", m_enmStatus));
197 if (m_enmStatus == Status_Dropping)
198 {
199 LogRel2(("DnD: Waiting for drop event ...\n"));
200 int rc2 = RTSemEventWait(m_EvtDropped, RT_INDEFINITE_WAIT);
201 LogFlowFunc(("rc2=%Rrc, mStatus=%ld\n", rc2, m_enmStatus)); RT_NOREF(rc2);
202 }
203
204 if (m_enmStatus == Status_Dropped)
205 {
206 LogRel2(("DnD: Drop event received\n"));
207 LogRel3(("DnD: cfFormat=%RI16, sFormat=%s, tyMed=%RU32, dwAspect=%RU32\n",
208 pThisFormat->cfFormat, VBoxDnDDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
209 pThisFormat->tymed, pThisFormat->dwAspect));
210 LogRel3(("DnD: Got strFormat=%s, pvData=%p, cbData=%RU32\n",
211 m_strFormat.c_str(), m_pvData, m_cbData));
212
213 /*
214 * Initialize default values.
215 */
216 pMedium->tymed = pThisFormat->tymed;
217 pMedium->pUnkForRelease = NULL;
218
219 /*
220 * URI list handling.
221 */
222 if (DnDMIMEHasFileURLs(m_strFormat.c_str(), RTSTR_MAX))
223 {
224 char **papszFiles;
225 size_t cFiles;
226 int rc = RTStrSplit((const char *)m_pvData, m_cbData, DND_PATH_SEPARATOR_STR, &papszFiles, &cFiles);
227 if ( RT_SUCCESS(rc)
228 && cFiles)
229 {
230 LogRel2(("DnD: Files (%zu)\n", cFiles));
231 for (size_t i = 0; i < cFiles; i++)
232 LogRel2(("\tDnD: File '%s'\n", papszFiles[i]));
233
234#if 0
235 if ( (pFormatEtc->tymed & TYMED_ISTREAM)
236 && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
237 && (pFormatEtc->cfFormat == CF_FILECONTENTS))
238 {
239
240 }
241 else if ( (pFormatEtc->tymed & TYMED_HGLOBAL)
242 && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
243 && (pFormatEtc->cfFormat == CF_FILEDESCRIPTOR))
244 {
245
246 }
247 else if ( (pFormatEtc->tymed & TYMED_HGLOBAL)
248 && (pFormatEtc->cfFormat == CF_PREFERREDDROPEFFECT))
249 {
250 HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, sizeof(DWORD));
251 DWORD *pdwEffect = (DWORD *)GlobalLock(hData);
252 AssertPtr(pdwEffect);
253 *pdwEffect = DROPEFFECT_COPY;
254 GlobalUnlock(hData);
255
256 pMedium->hGlobal = hData;
257 pMedium->tymed = TYMED_HGLOBAL;
258 }
259 else
260#endif
261 if ( (pFormatEtc->tymed & TYMED_HGLOBAL)
262 && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
263 && (pFormatEtc->cfFormat == CF_TEXT))
264 {
265 pMedium->hGlobal = GlobalAlloc(GHND, m_cbData + 1);
266 if (pMedium->hGlobal)
267 {
268 char *pcDst = (char *)GlobalLock(pMedium->hGlobal);
269 memcpy(pcDst, m_pvData, m_cbData);
270 pcDst[m_cbData] = '\0';
271 GlobalUnlock(pMedium->hGlobal);
272
273 hr = S_OK;
274 }
275 }
276 else if ( (pFormatEtc->tymed & TYMED_HGLOBAL)
277 && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
278 && (pFormatEtc->cfFormat == CF_HDROP))
279 {
280 size_t cchFiles = 0; /* Number of ASCII characters. */
281 for (size_t i = 0; i < cFiles; i++)
282 {
283 cchFiles += strlen(papszFiles[i]);
284 cchFiles += 1; /* Terminating '\0'. */
285 }
286
287 size_t cbBuf = sizeof(DROPFILES) + ((cchFiles + 1) * sizeof(RTUTF16));
288 DROPFILES *pBuf = (DROPFILES *)RTMemAllocZ(cbBuf);
289 if (pBuf)
290 {
291 pBuf->pFiles = sizeof(DROPFILES);
292 pBuf->fWide = 1; /* We use unicode. Always. */
293
294 uint8_t *pCurFile = (uint8_t *)pBuf + pBuf->pFiles;
295 AssertPtr(pCurFile);
296
297 for (size_t i = 0; i < cFiles && RT_SUCCESS(rc); i++)
298 {
299 size_t cchCurFile;
300 PRTUTF16 pwszFile;
301 rc = RTStrToUtf16(papszFiles[i], &pwszFile);
302 if (RT_SUCCESS(rc))
303 {
304 cchCurFile = RTUtf16Len(pwszFile);
305 Assert(cchCurFile);
306 memcpy(pCurFile, pwszFile, cchCurFile * sizeof(RTUTF16));
307 RTUtf16Free(pwszFile);
308 }
309 else
310 break;
311
312 pCurFile += cchCurFile * sizeof(RTUTF16);
313
314 /* Terminate current file name. */
315 *pCurFile = L'\0';
316 pCurFile += sizeof(RTUTF16);
317 }
318
319 if (RT_SUCCESS(rc))
320 {
321 *pCurFile = L'\0'; /* Final list terminator. */
322
323 pMedium->tymed = TYMED_HGLOBAL;
324 pMedium->pUnkForRelease = NULL;
325 pMedium->hGlobal = GlobalAlloc( GMEM_ZEROINIT
326 | GMEM_MOVEABLE
327 | GMEM_DDESHARE, cbBuf);
328 if (pMedium->hGlobal)
329 {
330 LPVOID pMem = GlobalLock(pMedium->hGlobal);
331 if (pMem)
332 {
333 memcpy(pMem, pBuf, cbBuf);
334 GlobalUnlock(pMedium->hGlobal);
335
336 hr = S_OK;
337 }
338 }
339 }
340
341 RTMemFree(pBuf);
342 }
343 else
344 rc = VERR_NO_MEMORY;
345 }
346
347 for (size_t i = 0; i < cFiles; ++i)
348 RTStrFree(papszFiles[i]);
349 RTMemFree(papszFiles);
350 }
351
352 if (RT_FAILURE(rc))
353 hr = DV_E_FORMATETC;
354 }
355 /*
356 * Plain text handling.
357 */
358 else if ( m_strFormat.equalsIgnoreCase("text/plain")
359 || m_strFormat.equalsIgnoreCase("text/html")
360 || m_strFormat.equalsIgnoreCase("text/plain;charset=utf-8")
361 || m_strFormat.equalsIgnoreCase("text/plain;charset=utf-16")
362 || m_strFormat.equalsIgnoreCase("text/richtext")
363 || m_strFormat.equalsIgnoreCase("UTF8_STRING")
364 || m_strFormat.equalsIgnoreCase("TEXT")
365 || m_strFormat.equalsIgnoreCase("STRING"))
366 {
367 pMedium->hGlobal = GlobalAlloc(GHND, m_cbData + 1);
368 if (pMedium->hGlobal)
369 {
370 char *pcDst = (char *)GlobalLock(pMedium->hGlobal);
371 memcpy(pcDst, m_pvData, m_cbData);
372 pcDst[m_cbData] = '\0';
373 GlobalUnlock(pMedium->hGlobal);
374
375 hr = S_OK;
376 }
377 }
378 else
379 LogRel(("DnD: Error: Format '%s' not implemented\n", m_strFormat.c_str()));
380 }
381
382 /* Error handling; at least return some basic data. */
383 if (FAILED(hr))
384 {
385 LogFlowFunc(("Copying medium ...\n"));
386 switch (pThisMedium->tymed)
387 {
388
389 case TYMED_HGLOBAL:
390 pMedium->hGlobal = (HGLOBAL)OleDuplicateData(pThisMedium->hGlobal,
391 pThisFormat->cfFormat, NULL);
392 break;
393
394 default:
395 break;
396 }
397
398 pMedium->tymed = pThisFormat->tymed;
399 pMedium->pUnkForRelease = NULL;
400 }
401
402 if (hr == DV_E_FORMATETC)
403 LogRel(("DnD: Error handling format '%s' (%RU32 bytes)\n", m_strFormat.c_str(), m_cbData));
404
405 LogFlowFunc(("hr=%Rhrc\n", hr));
406 return hr;
407}
408
409STDMETHODIMP VBoxDnDDataObject::GetDataHere(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium)
410{
411 RT_NOREF(pFormatEtc, pMedium);
412 LogFlowFunc(("\n"));
413 return DATA_E_FORMATETC;
414}
415
416STDMETHODIMP VBoxDnDDataObject::QueryGetData(LPFORMATETC pFormatEtc)
417{
418 LogFlowFunc(("\n"));
419 return (LookupFormatEtc(pFormatEtc, NULL /* puIndex */)) ? S_OK : DV_E_FORMATETC;
420}
421
422STDMETHODIMP VBoxDnDDataObject::GetCanonicalFormatEtc(LPFORMATETC pFormatEtc, LPFORMATETC pFormatEtcOut)
423{
424 RT_NOREF(pFormatEtc);
425 LogFlowFunc(("\n"));
426
427 /* Set this to NULL in any case. */
428 pFormatEtcOut->ptd = NULL;
429 return E_NOTIMPL;
430}
431
432STDMETHODIMP VBoxDnDDataObject::SetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium, BOOL fRelease)
433{
434 RT_NOREF(pFormatEtc, pMedium, fRelease);
435 return E_NOTIMPL;
436}
437
438STDMETHODIMP VBoxDnDDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc)
439{
440 LogFlowFunc(("dwDirection=%RI32, mcFormats=%RI32, mpFormatEtc=%p\n", dwDirection, m_cFormats, m_paFormatEtc));
441
442 HRESULT hr;
443 if (dwDirection == DATADIR_GET)
444 hr = VBoxDnDEnumFormatEtc::CreateEnumFormatEtc(m_cFormats, m_paFormatEtc, ppEnumFormatEtc);
445 else
446 hr = E_NOTIMPL;
447
448 LogFlowFunc(("hr=%Rhrc\n", hr));
449 return hr;
450}
451
452STDMETHODIMP VBoxDnDDataObject::DAdvise(LPFORMATETC pFormatEtc, DWORD fAdvise, IAdviseSink *pAdvSink, DWORD *pdwConnection)
453{
454 RT_NOREF(pFormatEtc, fAdvise, pAdvSink, pdwConnection);
455 return OLE_E_ADVISENOTSUPPORTED;
456}
457
458STDMETHODIMP VBoxDnDDataObject::DUnadvise(DWORD dwConnection)
459{
460 RT_NOREF(dwConnection);
461 return OLE_E_ADVISENOTSUPPORTED;
462}
463
464STDMETHODIMP VBoxDnDDataObject::EnumDAdvise(IEnumSTATDATA **ppEnumAdvise)
465{
466 RT_NOREF(ppEnumAdvise);
467 return OLE_E_ADVISENOTSUPPORTED;
468}
469
470/*
471 * Own stuff.
472 */
473
474/**
475 * Aborts waiting for data being "dropped".
476 *
477 * @returns VBox status code.
478 */
479int VBoxDnDDataObject::Abort(void)
480{
481 LogFlowFunc(("Aborting ...\n"));
482 m_enmStatus = Status_Aborted;
483 return RTSemEventSignal(m_EvtDropped);
484}
485
486/**
487 * Static helper function to convert a CLIPFORMAT to a string and return it.
488 *
489 * @returns Pointer to converted stringified CLIPFORMAT, or "unknown" if not found / invalid.
490 * @param fmt CLIPFORMAT to return string for.
491 */
492/* static */
493const char* VBoxDnDDataObject::ClipboardFormatToString(CLIPFORMAT fmt)
494{
495#if 0
496 char szFormat[128];
497 if (GetClipboardFormatName(fmt, szFormat, sizeof(szFormat)))
498 LogFlowFunc(("wFormat=%RI16, szName=%s\n", fmt, szFormat));
499#endif
500
501 switch (fmt)
502 {
503
504 case 1:
505 return "CF_TEXT";
506 case 2:
507 return "CF_BITMAP";
508 case 3:
509 return "CF_METAFILEPICT";
510 case 4:
511 return "CF_SYLK";
512 case 5:
513 return "CF_DIF";
514 case 6:
515 return "CF_TIFF";
516 case 7:
517 return "CF_OEMTEXT";
518 case 8:
519 return "CF_DIB";
520 case 9:
521 return "CF_PALETTE";
522 case 10:
523 return "CF_PENDATA";
524 case 11:
525 return "CF_RIFF";
526 case 12:
527 return "CF_WAVE";
528 case 13:
529 return "CF_UNICODETEXT";
530 case 14:
531 return "CF_ENHMETAFILE";
532 case 15:
533 return "CF_HDROP";
534 case 16:
535 return "CF_LOCALE";
536 case 17:
537 return "CF_DIBV5";
538 case 18:
539 return "CF_MAX";
540 case 49158:
541 return "FileName";
542 case 49159:
543 return "FileNameW";
544 case 49161:
545 return "DATAOBJECT";
546 case 49171:
547 return "Ole Private Data";
548 case 49314:
549 return "Shell Object Offsets";
550 case 49316:
551 return "File Contents";
552 case 49317:
553 return "File Group Descriptor";
554 case 49323:
555 return "Preferred Drop Effect";
556 case 49380:
557 return "Shell Object Offsets";
558 case 49382:
559 return "FileContents";
560 case 49383:
561 return "FileGroupDescriptor";
562 case 49389:
563 return "Preferred DropEffect";
564 case 49268:
565 return "Shell IDList Array";
566 case 49619:
567 return "RenPrivateFileAttachments";
568 default:
569 break;
570 }
571
572 return "unknown";
573}
574
575/**
576 * Checks whether a given FORMATETC is supported by this data object and returns its index.
577 *
578 * @returns \c true if format is supported, \c false if not.
579 * @param pFormatEtc Pointer to FORMATETC to check for.
580 * @param puIndex Where to store the index if format is supported.
581 */
582bool VBoxDnDDataObject::LookupFormatEtc(LPFORMATETC pFormatEtc, ULONG *puIndex)
583{
584 AssertReturn(pFormatEtc, false);
585 /* puIndex is optional. */
586
587 for (ULONG i = 0; i < m_cFormats; i++)
588 {
589 if( (pFormatEtc->tymed & m_paFormatEtc[i].tymed)
590 && pFormatEtc->cfFormat == m_paFormatEtc[i].cfFormat
591 && pFormatEtc->dwAspect == m_paFormatEtc[i].dwAspect)
592 {
593 LogRel3(("DnD: Format found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32, ulIndex=%RU32\n",
594 pFormatEtc->tymed, pFormatEtc->cfFormat, VBoxDnDDataObject::ClipboardFormatToString(m_paFormatEtc[i].cfFormat),
595 pFormatEtc->dwAspect, i));
596 if (puIndex)
597 *puIndex = i;
598 return true;
599 }
600 }
601
602 LogRel3(("DnD: Format NOT found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32\n",
603 pFormatEtc->tymed, pFormatEtc->cfFormat, VBoxDnDDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
604 pFormatEtc->dwAspect));
605
606 return false;
607}
608
609/**
610 * Registers a new format with this data object.
611 *
612 * @param pFormatEtc Where to store the new format into.
613 * @param clipFormat Clipboard format to register.
614 * @param tyMed Format medium type to register.
615 * @param lIndex Format index to register.
616 * @param dwAspect Format aspect to register.
617 * @param pTargetDevice Format target device to register.
618 */
619void VBoxDnDDataObject::RegisterFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat,
620 TYMED tyMed, LONG lIndex, DWORD dwAspect,
621 DVTARGETDEVICE *pTargetDevice)
622{
623 AssertPtr(pFormatEtc);
624
625 pFormatEtc->cfFormat = clipFormat;
626 pFormatEtc->tymed = tyMed;
627 pFormatEtc->lindex = lIndex;
628 pFormatEtc->dwAspect = dwAspect;
629 pFormatEtc->ptd = pTargetDevice;
630
631 LogFlowFunc(("Registered format=%ld, sFormat=%s\n",
632 pFormatEtc->cfFormat, VBoxDnDDataObject::ClipboardFormatToString(pFormatEtc->cfFormat)));
633}
634
635/**
636 * Sets the current status of this data object.
637 *
638 * @param status New status to set.
639 */
640void VBoxDnDDataObject::SetStatus(Status status)
641{
642 LogFlowFunc(("Setting status to %ld\n", status));
643 m_enmStatus = status;
644}
645
646/**
647 * Signals that data has been "dropped".
648 *
649 * @returns VBox status code.
650 * @param strFormat Format of data (MIME string).
651 * @param pvData Pointer to data.
652 * @param cbData Size (in bytes) of data.
653 */
654int VBoxDnDDataObject::Signal(const RTCString &strFormat,
655 const void *pvData, size_t cbData)
656{
657 int rc;
658
659 if (cbData)
660 {
661 m_pvData = RTMemAlloc(cbData);
662 if (m_pvData)
663 {
664 memcpy(m_pvData, pvData, cbData);
665 m_cbData = cbData;
666 rc = VINF_SUCCESS;
667 }
668 else
669 rc = VERR_NO_MEMORY;
670 }
671 else
672 rc = VINF_SUCCESS;
673
674 if (RT_SUCCESS(rc))
675 {
676 m_enmStatus = Status_Dropped;
677 m_strFormat = strFormat;
678 }
679 else
680 {
681 m_enmStatus = Status_Aborted;
682 }
683
684 /* Signal in any case. */
685 LogRel2(("DnD: Signalling drop event\n"));
686
687 int rc2 = RTSemEventSignal(m_EvtDropped);
688 if (RT_SUCCESS(rc))
689 rc = rc2;
690
691 LogFunc(("mStatus=%RU32, rc=%Rrc\n", m_enmStatus, rc));
692 return rc;
693}
694
Note: See TracBrowser for help on using the repository browser.

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