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
Line 
1/* $Id: VBoxDnDDataObject.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * VBoxDnDDataObject.cpp - IDataObject implementation.
4 */
5
6/*
7 * Copyright (C) 2013-2023 Oracle and/or its affiliates.
8 *
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
26 */
27
28
29#define LOG_GROUP LOG_GROUP_GUEST_DND
30#include <VBox/log.h>
31
32#include <iprt/win/windows.h>
33#include <new> /* For bad_alloc. */
34#include <iprt/win/shlobj.h>
35
36#include <iprt/path.h>
37#include <iprt/semaphore.h>
38#include <iprt/uri.h>
39#include <iprt/utf16.h>
40
41#include "VBoxTray.h"
42#include "VBoxHelpers.h"
43#include "VBoxDnD.h"
44
45
46/** @todo Implement IDataObjectAsyncCapability interface? */
47
48VBoxDnDDataObject::VBoxDnDDataObject(LPFORMATETC pFormatEtc, LPSTGMEDIUM pStgMed, ULONG cFormats)
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)
57{
58 int rc2 = Init(pFormatEtc, pStgMed, cFormats);
59 AssertRC(rc2);
60}
61
62VBoxDnDDataObject::~VBoxDnDDataObject(void)
63{
64 int rc2 = Destroy();
65 AssertRC(rc2);
66}
67
68/*
69 * IUnknown methods.
70 */
71
72STDMETHODIMP_(ULONG) VBoxDnDDataObject::AddRef(void)
73{
74 AssertReturn(m_cRefs < 32, m_cRefs); /* Paranoia. */
75 return InterlockedIncrement(&m_cRefs);
76}
77
78STDMETHODIMP_(ULONG) VBoxDnDDataObject::Release(void)
79{
80 AssertReturn(m_cRefs > 0, 0);
81 LONG lCount = InterlockedDecrement(&m_cRefs);
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
107STDMETHODIMP VBoxDnDDataObject::GetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium)
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;
115 if (lIndex >= m_cFormats) /* Paranoia. */
116 return DV_E_FORMATETC;
117
118 LPFORMATETC pThisFormat = &m_paFormatEtc[lIndex];
119 AssertPtr(pThisFormat);
120
121 LPSTGMEDIUM pThisMedium = &m_paStgMedium[lIndex];
122 AssertPtr(pThisMedium);
123
124 LogFlowFunc(("Using pThisFormat=%p, pThisMedium=%p\n", pThisFormat, pThisMedium));
125
126 HRESULT hr = DV_E_FORMATETC; /* Play safe. */
127
128 LogFlowFunc(("mStatus=%ld\n", m_enmStatus));
129 if (m_enmStatus == Status_Dropping)
130 {
131 LogRel2(("DnD: Waiting for drop event ...\n"));
132 int rc2 = RTSemEventWait(m_EvtDropped, RT_INDEFINITE_WAIT);
133 LogFlowFunc(("rc2=%Rrc, mStatus=%ld\n", rc2, m_enmStatus)); RT_NOREF(rc2);
134 }
135
136 if (m_enmStatus == Status_Dropped)
137 {
138 LogRel2(("DnD: Drop event received\n"));
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",
143 m_strFormat.c_str(), m_pvData, m_cbData));
144
145 /*
146 * Initialize default values.
147 */
148 pMedium->tymed = pThisFormat->tymed;
149 pMedium->pUnkForRelease = NULL;
150
151 /*
152 * URI list handling.
153 */
154 if (DnDMIMEHasFileURLs(m_strFormat.c_str(), RTSTR_MAX))
155 {
156 char **papszFiles;
157 size_t cFiles;
158 int rc = RTStrSplit((const char *)m_pvData, m_cbData, DND_PATH_SEPARATOR_STR, &papszFiles, &cFiles);
159 if ( RT_SUCCESS(rc)
160 && cFiles)
161 {
162 LogRel2(("DnD: Files (%zu)\n", cFiles));
163 for (size_t i = 0; i < cFiles; i++)
164 LogRel2(("\tDnD: File '%s'\n", papszFiles[i]));
165
166#if 0
167 if ( (pFormatEtc->tymed & TYMED_ISTREAM)
168 && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
169 && (pFormatEtc->cfFormat == CF_FILECONTENTS))
170 {
171
172 }
173 else if ( (pFormatEtc->tymed & TYMED_HGLOBAL)
174 && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
175 && (pFormatEtc->cfFormat == CF_FILEDESCRIPTOR))
176 {
177
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);
187
188 pMedium->hGlobal = hData;
189 pMedium->tymed = TYMED_HGLOBAL;
190 }
191 else
192#endif
193 if ( (pFormatEtc->tymed & TYMED_HGLOBAL)
194 && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
195 && (pFormatEtc->cfFormat == CF_TEXT))
196 {
197 pMedium->hGlobal = GlobalAlloc(GHND, m_cbData + 1);
198 if (pMedium->hGlobal)
199 {
200 char *pcDst = (char *)GlobalLock(pMedium->hGlobal);
201 memcpy(pcDst, m_pvData, m_cbData);
202 pcDst[m_cbData] = '\0';
203 GlobalUnlock(pMedium->hGlobal);
204
205 hr = S_OK;
206 }
207 }
208 else if ( (pFormatEtc->tymed & TYMED_HGLOBAL)
209 && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
210 && (pFormatEtc->cfFormat == CF_HDROP))
211 {
212 size_t cchFiles = 0; /* Number of ASCII characters. */
213 for (size_t i = 0; i < cFiles; i++)
214 {
215 cchFiles += strlen(papszFiles[i]);
216 cchFiles += 1; /* Terminating '\0'. */
217 }
218
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. */
225
226 uint8_t *pCurFile = (uint8_t *)pBuf + pBuf->pFiles;
227 AssertPtr(pCurFile);
228
229 for (size_t i = 0; i < cFiles && RT_SUCCESS(rc); i++)
230 {
231 size_t cchCurFile;
232 PRTUTF16 pwszFile;
233 rc = RTStrToUtf16(papszFiles[i], &pwszFile);
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;
243
244 pCurFile += cchCurFile * sizeof(RTUTF16);
245
246 /* Terminate current file name. */
247 *pCurFile = L'\0';
248 pCurFile += sizeof(RTUTF16);
249 }
250
251 if (RT_SUCCESS(rc))
252 {
253 *pCurFile = L'\0'; /* Final list terminator. */
254
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)
261 {
262 LPVOID pMem = GlobalLock(pMedium->hGlobal);
263 if (pMem)
264 {
265 memcpy(pMem, pBuf, cbBuf);
266 GlobalUnlock(pMedium->hGlobal);
267
268 hr = S_OK;
269 }
270 }
271 }
272
273 RTMemFree(pBuf);
274 }
275 else
276 rc = VERR_NO_MEMORY;
277 }
278
279 for (size_t i = 0; i < cFiles; ++i)
280 RTStrFree(papszFiles[i]);
281 RTMemFree(papszFiles);
282 }
283
284 if (RT_FAILURE(rc))
285 hr = DV_E_FORMATETC;
286 }
287 /*
288 * Plain text handling.
289 */
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"))
298 {
299 pMedium->hGlobal = GlobalAlloc(GHND, m_cbData + 1);
300 if (pMedium->hGlobal)
301 {
302 char *pcDst = (char *)GlobalLock(pMedium->hGlobal);
303 memcpy(pcDst, m_pvData, m_cbData);
304 pcDst[m_cbData] = '\0';
305 GlobalUnlock(pMedium->hGlobal);
306
307 hr = S_OK;
308 }
309 }
310 else
311 LogRel(("DnD: Error: Format '%s' not implemented\n", m_strFormat.c_str()));
312 }
313
314 /* Error handling; at least return some basic data. */
315 if (FAILED(hr))
316 {
317 LogFlowFunc(("Copying medium ...\n"));
318 switch (pThisMedium->tymed)
319 {
320
321 case TYMED_HGLOBAL:
322 pMedium->hGlobal = (HGLOBAL)OleDuplicateData(pThisMedium->hGlobal,
323 pThisFormat->cfFormat, NULL);
324 break;
325
326 default:
327 break;
328 }
329
330 pMedium->tymed = pThisFormat->tymed;
331 pMedium->pUnkForRelease = NULL;
332 }
333
334 if (hr == DV_E_FORMATETC)
335 LogRel(("DnD: Error handling format '%s' (%RU32 bytes)\n", m_strFormat.c_str(), m_cbData));
336
337 LogFlowFunc(("hr=%Rhrc\n", hr));
338 return hr;
339}
340
341STDMETHODIMP VBoxDnDDataObject::GetDataHere(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium)
342{
343 RT_NOREF(pFormatEtc, pMedium);
344 LogFlowFunc(("\n"));
345 return DATA_E_FORMATETC;
346}
347
348STDMETHODIMP VBoxDnDDataObject::QueryGetData(LPFORMATETC pFormatEtc)
349{
350 LogFlowFunc(("\n"));
351 return (LookupFormatEtc(pFormatEtc, NULL /* puIndex */)) ? S_OK : DV_E_FORMATETC;
352}
353
354STDMETHODIMP VBoxDnDDataObject::GetCanonicalFormatEtc(LPFORMATETC pFormatEtc, LPFORMATETC pFormatEtcOut)
355{
356 RT_NOREF(pFormatEtc);
357 LogFlowFunc(("\n"));
358
359 /* Set this to NULL in any case. */
360 pFormatEtcOut->ptd = NULL;
361 return E_NOTIMPL;
362}
363
364STDMETHODIMP VBoxDnDDataObject::SetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium, BOOL fRelease)
365{
366 RT_NOREF(pFormatEtc, pMedium, fRelease);
367 return E_NOTIMPL;
368}
369
370STDMETHODIMP VBoxDnDDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc)
371{
372 LogFlowFunc(("dwDirection=%RI32, mcFormats=%RI32, mpFormatEtc=%p\n", dwDirection, m_cFormats, m_paFormatEtc));
373
374 HRESULT hr;
375 if (dwDirection == DATADIR_GET)
376 hr = VBoxDnDEnumFormatEtc::CreateEnumFormatEtc(m_cFormats, m_paFormatEtc, ppEnumFormatEtc);
377 else
378 hr = E_NOTIMPL;
379
380 LogFlowFunc(("hr=%Rhrc\n", hr));
381 return hr;
382}
383
384STDMETHODIMP VBoxDnDDataObject::DAdvise(LPFORMATETC pFormatEtc, DWORD fAdvise, IAdviseSink *pAdvSink, DWORD *pdwConnection)
385{
386 RT_NOREF(pFormatEtc, fAdvise, pAdvSink, pdwConnection);
387 return OLE_E_ADVISENOTSUPPORTED;
388}
389
390STDMETHODIMP VBoxDnDDataObject::DUnadvise(DWORD dwConnection)
391{
392 RT_NOREF(dwConnection);
393 return OLE_E_ADVISENOTSUPPORTED;
394}
395
396STDMETHODIMP VBoxDnDDataObject::EnumDAdvise(IEnumSTATDATA **ppEnumAdvise)
397{
398 RT_NOREF(ppEnumAdvise);
399 return OLE_E_ADVISENOTSUPPORTED;
400}
401
402/*
403 * Own stuff.
404 */
405
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
514/**
515 * Aborts waiting for data being "dropped".
516 *
517 * @returns VBox status code.
518 */
519int VBoxDnDDataObject::Abort(void)
520{
521 LogFlowFunc(("Aborting ...\n"));
522 if (m_enmStatus == Status_Dropping)
523 {
524 m_enmStatus = Status_Aborted;
525 return RTSemEventSignal(m_EvtDropped);
526 }
527
528 return VINF_SUCCESS;
529}
530
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 */
537/* static */
538const char* VBoxDnDDataObject::ClipboardFormatToString(CLIPFORMAT fmt)
539{
540#if 0
541 char szFormat[128];
542 if (GetClipboardFormatName(fmt, szFormat, sizeof(szFormat)))
543 LogFlowFunc(("wFormat=%RI16, szName=%s\n", fmt, szFormat));
544#endif
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
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 */
627bool VBoxDnDDataObject::LookupFormatEtc(LPFORMATETC pFormatEtc, ULONG *puIndex)
628{
629 AssertReturn(pFormatEtc, false);
630 /* puIndex is optional. */
631
632 for (ULONG i = 0; i < m_cFormats; i++)
633 {
634 if( (pFormatEtc->tymed & m_paFormatEtc[i].tymed)
635 && pFormatEtc->cfFormat == m_paFormatEtc[i].cfFormat
636 && pFormatEtc->dwAspect == m_paFormatEtc[i].dwAspect)
637 {
638 LogRel3(("DnD: Format found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32, ulIndex=%RU32\n",
639 pFormatEtc->tymed, pFormatEtc->cfFormat, VBoxDnDDataObject::ClipboardFormatToString(m_paFormatEtc[i].cfFormat),
640 pFormatEtc->dwAspect, i));
641 if (puIndex)
642 *puIndex = i;
643 return true;
644 }
645 }
646
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
651 return false;
652}
653
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 */
664void VBoxDnDDataObject::RegisterFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat,
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
680/**
681 * Sets the current status of this data object.
682 *
683 * @param status New status to set.
684 */
685void VBoxDnDDataObject::SetStatus(Status status)
686{
687 LogFlowFunc(("Setting status to %ld\n", status));
688 m_enmStatus = status;
689}
690
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 */
699int VBoxDnDDataObject::Signal(const RTCString &strFormat,
700 const void *pvData, size_t cbData)
701{
702 int rc;
703
704 if (cbData)
705 {
706 m_pvData = RTMemAlloc(cbData);
707 if (m_pvData)
708 {
709 memcpy(m_pvData, pvData, cbData);
710 m_cbData = cbData;
711 rc = VINF_SUCCESS;
712 }
713 else
714 rc = VERR_NO_MEMORY;
715 }
716 else
717 rc = VINF_SUCCESS;
718
719 if (RT_SUCCESS(rc))
720 {
721 m_enmStatus = Status_Dropped;
722 m_strFormat = strFormat;
723 }
724 else
725 {
726 m_enmStatus = Status_Aborted;
727 }
728
729 /* Signal in any case. */
730 LogRel2(("DnD: Signalling drop event\n"));
731
732 int rc2 = RTSemEventSignal(m_EvtDropped);
733 if (RT_SUCCESS(rc))
734 rc = rc2;
735
736 LogFunc(("mStatus=%RU32, rc=%Rrc\n", m_enmStatus, rc));
737 return rc;
738}
739
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use