VirtualBox

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

Last change on this file since 95734 was 95734, checked in by vboxsync, 2 years ago

VBoxTray/DnD: Make the code build w/o exceptions enabled. bugref:10261

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