VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use