VirtualBox

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

Last change on this file since 106501 was 106411, checked in by vboxsync, 3 months ago

Additions/VBoxTray: Implemented ability for easier user-controllable logging (also via verbose levels), support for running in foreground mode (with a console window attached to) and selective starting of sub services to easier pinpoint errors in release builds. Cleaned up initialization / termination code a little. See command line help for new options. bugref:10763

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