VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIDnDDataObject_win.cpp

Last change on this file was 106061, checked in by vboxsync, 4 weeks ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.7 KB
Line 
1/* $Id: UIDnDDataObject_win.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIDnDDrag class implementation (implements IDataObject).
4 */
5
6/*
7 * Copyright (C) 2014-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#define LOG_GROUP LOG_GROUP_GUEST_DND
29#include <VBox/log.h>
30
31#include <iprt/win/windows.h>
32#include <new> /* For bad_alloc. */
33#include <iprt/win/shlobj.h>
34
35#include <iprt/mem.h>
36#include <iprt/errcore.h>
37#include <iprt/path.h>
38#include <iprt/semaphore.h>
39#include <iprt/string.h>
40#include <iprt/uri.h>
41#include <iprt/utf16.h>
42
43#include <QStringList>
44
45#include "UIDnDHandler.h"
46#include "UIDnDDataObject_win.h"
47#include "UIDnDEnumFormat_win.h"
48
49
50UIDnDDataObject::UIDnDDataObject(UIDnDHandler *pDnDHandler, const QStringList &lstFormats)
51 : m_pDnDHandler(pDnDHandler)
52 , m_enmStatus(Status_Uninitialized)
53 , m_cRefs(1)
54 , m_cFormats(0)
55 , m_pFormatEtc(NULL)
56 , m_pStgMedium(NULL)
57 , m_SemEvent(NIL_RTSEMEVENT)
58 , m_fDataRetrieved(false)
59 , m_pvData(NULL)
60 , m_cbData(0)
61{
62 HRESULT hr;
63
64 int cMaxFormats = 16; /* Maximum number of registered formats. */
65 ULONG cRegisteredFormats = 0;
66
67 try
68 {
69 m_pFormatEtc = new FORMATETC[cMaxFormats];
70 RT_BZERO(m_pFormatEtc, sizeof(FORMATETC) * cMaxFormats);
71 m_pStgMedium = new STGMEDIUM[cMaxFormats];
72 RT_BZERO(m_pStgMedium, sizeof(STGMEDIUM) * cMaxFormats);
73
74 for (int i = 0; i < lstFormats.size() && i < cMaxFormats; i++)
75 {
76 const QString &strFormat = lstFormats.at(i);
77 if (m_lstFormats.contains(strFormat))
78 continue;
79
80 /* URI data ("text/uri-list"). */
81 if (strFormat.contains("text/uri-list", Qt::CaseInsensitive))
82 {
83 RegisterFormat(&m_pFormatEtc[cRegisteredFormats], CF_TEXT);
84 m_pStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
85 RegisterFormat(&m_pFormatEtc[cRegisteredFormats], CF_UNICODETEXT);
86 m_pStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
87 RegisterFormat(&m_pFormatEtc[cRegisteredFormats], CF_HDROP);
88 m_pStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
89
90 m_lstFormats << strFormat;
91 }
92 /* Plain text ("text/plain"). */
93 if (strFormat.contains("text/plain", Qt::CaseInsensitive))
94 {
95 RegisterFormat(&m_pFormatEtc[cRegisteredFormats], CF_TEXT);
96 m_pStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
97 RegisterFormat(&m_pFormatEtc[cRegisteredFormats], CF_UNICODETEXT);
98 m_pStgMedium[cRegisteredFormats++].tymed = TYMED_HGLOBAL;
99
100 m_lstFormats << strFormat;
101 }
102 }
103
104 LogRel3(("DnD: Total registered native formats: %RU32 (for %d formats from guest)\n",
105 cRegisteredFormats, lstFormats.size()));
106 hr = S_OK;
107 }
108 catch (std::bad_alloc &)
109 {
110 hr = E_OUTOFMEMORY;
111 }
112
113 if (SUCCEEDED(hr))
114 {
115 int rc2 = RTSemEventCreate(&m_SemEvent);
116 AssertRC(rc2);
117
118 /*
119 * Other (not so common) formats.
120 */
121#if 0
122 /* IStream. */
123 RegisterFormat(&mpFormatEtc[cFormats++],
124 RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR));
125 RegisterFormat(&mpFormatEtc[cFormats++],
126 RegisterClipboardFormat(CFSTR_FILECONTENTS),
127 TYMED_ISTREAM, 0 /* lIndex */);
128
129 /* Required for e.g. Windows Media Player. */
130 RegisterFormat(&mpFormatEtc[cFormats++],
131 RegisterClipboardFormat(CFSTR_FILENAME));
132 RegisterFormat(&mpFormatEtc[cFormats++],
133 RegisterClipboardFormat(CFSTR_FILENAMEW));
134 RegisterFormat(&mpFormatEtc[cFormats++],
135 RegisterClipboardFormat(CFSTR_SHELLIDLIST));
136 RegisterFormat(&mpFormatEtc[cFormats++],
137 RegisterClipboardFormat(CFSTR_SHELLIDLISTOFFSET));
138#endif
139 m_cFormats = cRegisteredFormats;
140 m_enmStatus = Status_Dropping;
141 }
142
143 LogFlowFunc(("hr=%Rhrc\n", hr));
144}
145
146UIDnDDataObject::~UIDnDDataObject(void)
147{
148 if (m_pFormatEtc)
149 delete[] m_pFormatEtc;
150
151 if (m_pStgMedium)
152 delete[] m_pStgMedium;
153
154 if (m_pvData)
155 RTMemFree(m_pvData);
156
157 if (m_SemEvent != NIL_RTSEMEVENT)
158 RTSemEventDestroy(m_SemEvent);
159
160 LogFlowFunc(("mRefCount=%RI32\n", m_cRefs));
161}
162
163/*
164 * IUnknown methods.
165 */
166
167STDMETHODIMP_(ULONG) UIDnDDataObject::AddRef(void)
168{
169 return InterlockedIncrement(&m_cRefs);
170}
171
172STDMETHODIMP_(ULONG) UIDnDDataObject::Release(void)
173{
174 LONG lCount = InterlockedDecrement(&m_cRefs);
175 if (lCount == 0)
176 {
177 delete this;
178 return 0;
179 }
180
181 return lCount;
182}
183
184STDMETHODIMP UIDnDDataObject::QueryInterface(REFIID iid, void **ppvObject)
185{
186 AssertPtrReturn(ppvObject, E_INVALIDARG);
187
188 if ( iid == IID_IDataObject
189 || iid == IID_IUnknown)
190 {
191 AddRef();
192 *ppvObject = this;
193 return S_OK;
194 }
195
196 *ppvObject = 0;
197 return E_NOINTERFACE;
198}
199
200STDMETHODIMP UIDnDDataObject::GetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium)
201{
202 AssertPtrReturn(pFormatEtc, DV_E_FORMATETC);
203 AssertPtrReturn(pMedium, DV_E_FORMATETC);
204
205 HRESULT hr = DV_E_FORMATETC;
206
207 LPFORMATETC pThisFormat = NULL;
208 LPSTGMEDIUM pThisMedium = NULL;
209
210 LogFlowThisFunc(("\n"));
211
212 /* Format supported? */
213 ULONG lIndex;
214 if ( LookupFormatEtc(pFormatEtc, &lIndex)
215 && lIndex < m_cFormats) /* Paranoia. */
216 {
217 pThisMedium = &m_pStgMedium[lIndex];
218 AssertPtr(pThisMedium);
219 pThisFormat = &m_pFormatEtc[lIndex];
220 AssertPtr(pThisFormat);
221
222 LogFlowThisFunc(("pThisMedium=%p, pThisFormat=%p\n", pThisMedium, pThisFormat));
223 LogFlowThisFunc(("mStatus=%RU32\n", m_enmStatus));
224 switch (m_enmStatus)
225 {
226 case Status_Dropping:
227 {
228#if 0
229 LogRel3(("DnD: Dropping\n"));
230 LogFlowFunc(("Waiting for event ...\n"));
231 int rc2 = RTSemEventWait(m_SemEvent, RT_INDEFINITE_WAIT);
232 LogFlowFunc(("rc=%Rrc, mStatus=%RU32\n", rc2, m_enmStatus));
233#endif
234 break;
235 }
236
237 case Status_Dropped:
238 {
239 LogRel3(("DnD: Dropped\n"));
240 LogRel3(("DnD: cfFormat=%RI16, sFormat=%s, tyMed=%RU32, dwAspect=%RU32\n",
241 pThisFormat->cfFormat, UIDnDDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
242 pThisFormat->tymed, pThisFormat->dwAspect));
243 LogRel3(("DnD: Got strFormat=%s, pvData=%p, cbData=%RU32\n",
244 m_strFormat.toUtf8().constData(), m_pvData, m_cbData));
245
246 QMetaType::Type vaType = QMetaType::UnknownType; /* MSC: Might be used uninitialized otherwise! */
247 QString strMIMEType;
248 if ( (pFormatEtc->tymed & TYMED_HGLOBAL)
249 && pFormatEtc->dwAspect == DVASPECT_CONTENT
250 && ( pFormatEtc->cfFormat == CF_TEXT
251 || pFormatEtc->cfFormat == CF_UNICODETEXT)
252 )
253 {
254 /* Use UTF-8, always. */
255 strMIMEType = "text/plain;charset=utf-8";
256 vaType = QMetaType::QString;
257 }
258 else if ( (pFormatEtc->tymed & TYMED_HGLOBAL)
259 && pFormatEtc->dwAspect == DVASPECT_CONTENT
260 && pFormatEtc->cfFormat == CF_HDROP)
261 {
262 strMIMEType = "text/uri-list";
263 vaType = QMetaType::QStringList;
264 }
265#if 0 /* More formats; not needed right now. */
266 else if ( (pFormatEtc->tymed & TYMED_ISTREAM)
267 && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
268 && (pFormatEtc->cfFormat == CF_FILECONTENTS))
269 {
270
271 }
272 else if ( (pFormatEtc->tymed & TYMED_HGLOBAL)
273 && (pFormatEtc->dwAspect == DVASPECT_CONTENT)
274 && (pFormatEtc->cfFormat == CF_FILEDESCRIPTOR))
275 {
276
277 }
278 else if ( (pFormatEtc->tymed & TYMED_HGLOBAL)
279 && (pFormatEtc->cfFormat == CF_PREFERREDDROPEFFECT))
280 {
281 HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, sizeof(DWORD));
282 DWORD *pdwEffect = (DWORD *)GlobalLock(hData);
283 AssertPtr(pdwEffect);
284 *pdwEffect = DROPEFFECT_COPY;
285 GlobalUnlock(hData);
286
287 pMedium->hGlobal = hData;
288 pMedium->tymed = TYMED_HGLOBAL;
289 }
290#endif
291 LogRel3(("DnD: strMIMEType=%s\n", strMIMEType.toUtf8().constData()));
292
293 int rc;
294
295 if (!m_fDataRetrieved)
296 {
297 if (m_pDnDHandler)
298 rc = m_pDnDHandler->retrieveData(Qt::CopyAction, strMIMEType, vaType, m_vaData);
299 else
300 rc = VERR_NOT_FOUND;
301
302 m_fDataRetrieved = true;
303 LogFlowFunc(("Retrieving data ended with %Rrc\n", rc));
304 }
305 else /* Data already been retrieved. */
306 rc = VINF_SUCCESS;
307
308 if ( RT_SUCCESS(rc)
309 && m_vaData.isValid())
310 {
311 if ( strMIMEType.startsWith("text/uri-list")
312 /* One item. */
313 && ( m_vaData.canConvert(QMetaType::QString)
314 /* Multiple items. */
315 || m_vaData.canConvert(QMetaType::QStringList))
316 )
317 {
318 QStringList lstFilesURI = m_vaData.toStringList();
319 QStringList lstFiles;
320 for (int i = 0; i < lstFilesURI.size(); i++)
321 {
322 char *pszFilePath = RTUriFilePath(lstFilesURI.at(i).toUtf8().constData());
323 if (pszFilePath)
324 {
325 lstFiles.append(pszFilePath);
326 RTStrFree(pszFilePath);
327 }
328 else /* Unable to parse -- refuse entire request. */
329 {
330 lstFiles.clear();
331 rc = VERR_INVALID_PARAMETER;
332 break;
333 }
334 }
335
336 int cFiles = lstFiles.size();
337 LogFlowThisFunc(("Files (%d)\n", cFiles));
338 if ( RT_SUCCESS(rc)
339 && cFiles)
340 {
341 size_t cchFiles = 0; /* Number of characters. */
342 for (int i = 0; i < cFiles; i++)
343 {
344 const char *pszFile = lstFiles.at(i).toUtf8().constData();
345 cchFiles += strlen(pszFile);
346 cchFiles += 1; /* Terminating '\0'. */
347 LogFlowThisFunc(("\tFile: %s (cchFiles=%zu)\n", pszFile, cchFiles));
348 }
349
350 /* List termination with '\0'. */
351 cchFiles++;
352
353 size_t cbBuf = sizeof(DROPFILES) + (cchFiles * sizeof(RTUTF16));
354 DROPFILES *pDropFiles = (DROPFILES *)RTMemAllocZ(cbBuf);
355 if (pDropFiles)
356 {
357 /* Put the files list right after our DROPFILES structure. */
358 pDropFiles->pFiles = sizeof(DROPFILES); /* Offset to file list. */
359 pDropFiles->fWide = 1; /* We use Unicode. Always. */
360
361 uint8_t *pCurFile = (uint8_t *)pDropFiles + pDropFiles->pFiles;
362 AssertPtr(pCurFile);
363
364 LogFlowThisFunc(("Encoded:\n"));
365 for (int i = 0; i < cFiles; i++)
366 {
367 const char *pszFile = lstFiles.at(i).toUtf8().constData();
368 Assert(strlen(pszFile));
369
370 size_t cchCurFile;
371 PRTUTF16 pwszFile;
372 rc = RTStrToUtf16(pszFile, &pwszFile);
373 if (RT_SUCCESS(rc))
374 {
375 cchCurFile = RTUtf16Len(pwszFile);
376 Assert(cchCurFile);
377 memcpy(pCurFile, pwszFile, cchCurFile * sizeof(RTUTF16));
378 RTUtf16Free(pwszFile);
379 }
380 else
381 break;
382
383 pCurFile += cchCurFile * sizeof(RTUTF16);
384
385 /* Terminate current file name. */
386 *pCurFile = L'\0';
387 pCurFile += sizeof(RTUTF16);
388
389 LogFlowThisFunc(("\t#%d: cchCurFile=%zu\n", i, cchCurFile));
390 }
391
392 if (RT_SUCCESS(rc))
393 {
394 *pCurFile = L'\0'; /* Final list terminator. */
395
396 /*
397 * Fill out the medium structure we're going to report back.
398 */
399 pMedium->tymed = TYMED_HGLOBAL;
400 pMedium->pUnkForRelease = NULL;
401 pMedium->hGlobal = GlobalAlloc( GMEM_ZEROINIT
402 | GMEM_MOVEABLE
403 | GMEM_DDESHARE, cbBuf);
404 if (pMedium->hGlobal)
405 {
406 LPVOID pvMem = GlobalLock(pMedium->hGlobal);
407 if (pvMem)
408 {
409 memcpy(pvMem, pDropFiles, cbBuf);
410 GlobalUnlock(pMedium->hGlobal);
411
412 hr = S_OK;
413 }
414 else
415 rc = VERR_ACCESS_DENIED;
416 }
417 else
418 rc = VERR_NO_MEMORY;
419
420 LogFlowThisFunc(("Copying to TYMED_HGLOBAL (%zu bytes): %Rrc\n", cbBuf, rc));
421 }
422
423 RTMemFree(pDropFiles);
424 }
425 else
426 rc = VERR_NO_MEMORY;
427
428 if (RT_FAILURE(rc))
429 LogFlowThisFunc(("Failed with %Rrc\n", rc));
430 }
431 }
432 else if ( strMIMEType.startsWith("text/plain;charset=utf-8") /* Use UTF-8, always. */
433 && m_vaData.canConvert(QMetaType::QString))
434 {
435 const bool fUnicode = pFormatEtc->cfFormat == CF_UNICODETEXT;
436 const size_t cbCh = fUnicode
437 ? sizeof(WCHAR) : sizeof(char);
438
439 QString strText = m_vaData.toString();
440 size_t cbSrc = strText.length() * cbCh;
441 LPCVOID pvSrc = fUnicode
442 ? (void *)strText.unicode()
443 : (void *)strText.toUtf8().constData();
444
445 AssertMsg(cbSrc, ("pvSrc=0x%p, cbSrc=%zu, cbCh=%zu\n", pvSrc, cbSrc, cbCh));
446 AssertPtr(pvSrc);
447
448 LogFlowFunc(("pvSrc=0x%p, cbSrc=%zu, cbCh=%zu, fUnicode=%RTbool\n",
449 pvSrc, cbSrc, cbCh, fUnicode));
450
451 pMedium->tymed = TYMED_HGLOBAL;
452 pMedium->pUnkForRelease = NULL;
453 pMedium->hGlobal = GlobalAlloc(GHND | GMEM_SHARE, cbSrc);
454 if (pMedium->hGlobal)
455 {
456 LPVOID pvDst = GlobalLock(pMedium->hGlobal);
457 if (pvDst)
458 {
459 memcpy(pvDst, pvSrc, cbSrc);
460 GlobalUnlock(pMedium->hGlobal);
461 }
462 else
463 rc = VERR_ACCESS_DENIED;
464
465 hr = S_OK;
466 }
467 else
468 hr = VERR_NO_MEMORY;
469 }
470 else
471 LogRel2(("DnD: MIME type '%s' not supported\n", strMIMEType.toUtf8().constData()));
472
473 LogFlowThisFunc(("Handling formats ended with rc=%Rrc\n", rc));
474 }
475
476 break;
477 }
478
479 default:
480 break;
481 }
482 }
483
484 /*
485 * Fallback in error case.
486 */
487 if (FAILED(hr))
488 {
489 if (pThisMedium)
490 {
491 switch (pThisMedium->tymed)
492 {
493
494 case TYMED_HGLOBAL:
495 pMedium->hGlobal = (HGLOBAL)OleDuplicateData(pThisMedium->hGlobal,
496 pThisFormat->cfFormat,
497 0 /* Flags */);
498 break;
499
500 default:
501 break;
502 }
503 }
504
505 if (pFormatEtc)
506 pMedium->tymed = pFormatEtc->tymed;
507
508 pMedium->pUnkForRelease = NULL;
509 }
510
511 LogFlowThisFunc(("Returning hr=%Rhrc\n", hr));
512 return hr;
513}
514
515STDMETHODIMP UIDnDDataObject::GetDataHere(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium)
516{
517 RT_NOREF(pFormatEtc, pMedium);
518 LogFlowFunc(("\n"));
519 return DATA_E_FORMATETC;
520}
521
522STDMETHODIMP UIDnDDataObject::QueryGetData(LPFORMATETC pFormatEtc)
523{
524 return LookupFormatEtc(pFormatEtc, NULL /* puIndex */) ? S_OK : DV_E_FORMATETC;
525}
526
527STDMETHODIMP UIDnDDataObject::GetCanonicalFormatEtc(LPFORMATETC pFormatEtc, LPFORMATETC pFormatEtcOut)
528{
529 RT_NOREF(pFormatEtc);
530 LogFlowFunc(("\n"));
531
532 /* Set this to NULL in any case. */
533 pFormatEtcOut->ptd = NULL;
534 return E_NOTIMPL;
535}
536
537STDMETHODIMP UIDnDDataObject::SetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium, BOOL fRelease)
538{
539 RT_NOREF(pFormatEtc, pMedium, fRelease);
540 return E_NOTIMPL;
541}
542
543STDMETHODIMP UIDnDDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc)
544{
545 LogFlowFunc(("dwDirection=%RI32, mcFormats=%RI32, mpFormatEtc=%p\n",
546 dwDirection, m_cFormats, m_pFormatEtc));
547
548 HRESULT hr;
549 if (dwDirection == DATADIR_GET)
550 {
551 hr = UIDnDEnumFormatEtc::CreateEnumFormatEtc(m_cFormats, m_pFormatEtc, ppEnumFormatEtc);
552 }
553 else
554 hr = E_NOTIMPL;
555
556 LogFlowFunc(("hr=%Rhrc\n", hr));
557 return hr;
558}
559
560STDMETHODIMP UIDnDDataObject::DAdvise(LPFORMATETC pFormatEtc, DWORD fAdvise, IAdviseSink *pAdvSink, DWORD *pdwConnection)
561{
562 RT_NOREF(pFormatEtc, fAdvise, pAdvSink, pdwConnection);
563 return OLE_E_ADVISENOTSUPPORTED;
564}
565
566STDMETHODIMP UIDnDDataObject::DUnadvise(DWORD dwConnection)
567{
568 RT_NOREF(dwConnection);
569 return OLE_E_ADVISENOTSUPPORTED;
570}
571
572STDMETHODIMP UIDnDDataObject::EnumDAdvise(IEnumSTATDATA **ppEnumAdvise)
573{
574 RT_NOREF(ppEnumAdvise);
575 return OLE_E_ADVISENOTSUPPORTED;
576}
577
578/*
579 * Own stuff.
580 */
581
582/**
583 * Aborts waiting for data being "dropped".
584 *
585 * @returns VBox status code.
586 */
587int UIDnDDataObject::Abort(void)
588{
589 LogFlowFunc(("Aborting ...\n"));
590 m_enmStatus = Status_Aborted;
591 return RTSemEventSignal(m_SemEvent);
592}
593
594/**
595 * Static helper function to convert a CLIPFORMAT to a string and return it.
596 *
597 * @returns Pointer to converted stringified CLIPFORMAT, or "unknown" if not found / invalid.
598 * @param fmt CLIPFORMAT to return string for.
599 */
600/* static */
601const char* UIDnDDataObject::ClipboardFormatToString(CLIPFORMAT fmt)
602{
603 WCHAR wszFormat[128];
604 if (GetClipboardFormatNameW(fmt, wszFormat, sizeof(wszFormat) / sizeof(WCHAR)))
605 LogFlowFunc(("wFormat=%RI16, szName=%ls\n", fmt, wszFormat));
606
607 switch (fmt)
608 {
609
610 case 1:
611 return "CF_TEXT";
612 case 2:
613 return "CF_BITMAP";
614 case 3:
615 return "CF_METAFILEPICT";
616 case 4:
617 return "CF_SYLK";
618 case 5:
619 return "CF_DIF";
620 case 6:
621 return "CF_TIFF";
622 case 7:
623 return "CF_OEMTEXT";
624 case 8:
625 return "CF_DIB";
626 case 9:
627 return "CF_PALETTE";
628 case 10:
629 return "CF_PENDATA";
630 case 11:
631 return "CF_RIFF";
632 case 12:
633 return "CF_WAVE";
634 case 13:
635 return "CF_UNICODETEXT";
636 case 14:
637 return "CF_ENHMETAFILE";
638 case 15:
639 return "CF_HDROP";
640 case 16:
641 return "CF_LOCALE";
642 case 17:
643 return "CF_DIBV5";
644 case 18:
645 return "CF_MAX";
646 case 49158:
647 return "FileName";
648 case 49159:
649 return "FileNameW";
650 case 49161:
651 return "DATAOBJECT";
652 case 49171:
653 return "Ole Private Data";
654 case 49314:
655 return "Shell Object Offsets";
656 case 49316:
657 return "File Contents";
658 case 49317:
659 return "File Group Descriptor";
660 case 49323:
661 return "Preferred Drop Effect";
662 case 49380:
663 return "Shell Object Offsets";
664 case 49382:
665 return "FileContents";
666 case 49383:
667 return "FileGroupDescriptor";
668 case 49389:
669 return "Preferred DropEffect";
670 case 49268:
671 return "Shell IDList Array";
672 case 49619:
673 return "RenPrivateFileAttachments";
674 default:
675 break;
676 }
677
678 return "unknown";
679}
680
681/**
682 * Checks whether a given FORMATETC is supported by this data object and returns its index.
683 *
684 * @returns \c true if format is supported, \c false if not.
685 * @param pFormatEtc Pointer to FORMATETC to check for.
686 * @param puIndex Where to store the index if format is supported.
687 */
688bool UIDnDDataObject::LookupFormatEtc(LPFORMATETC pFormatEtc, ULONG *puIndex)
689{
690 AssertReturn(pFormatEtc, false);
691 /* puIndex is optional. */
692
693 for (ULONG i = 0; i < m_cFormats; i++)
694 {
695 if( (pFormatEtc->tymed & m_pFormatEtc[i].tymed)
696 && pFormatEtc->cfFormat == m_pFormatEtc[i].cfFormat
697 && pFormatEtc->dwAspect == m_pFormatEtc[i].dwAspect)
698 {
699 LogRel3(("DnD: Format found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32, ulIndex=%RU32\n",
700 pFormatEtc->tymed, pFormatEtc->cfFormat, UIDnDDataObject::ClipboardFormatToString(m_pFormatEtc[i].cfFormat),
701 pFormatEtc->dwAspect, i));
702
703 if (puIndex)
704 *puIndex = i;
705 return true;
706 }
707 }
708
709#if 0
710 LogRel3(("DnD: Format NOT found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32\n",
711 pFormatEtc->tymed, pFormatEtc->cfFormat, UIDnDDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
712 pFormatEtc->dwAspect));
713#endif
714
715 return false;
716}
717
718/**
719 * Registers a new format with this data object.
720 *
721 * @param pFormatEtc Where to store the new format into.
722 * @param clipFormat Clipboard format to register.
723 * @param tyMed Format medium type to register.
724 * @param lIndex Format index to register.
725 * @param dwAspect Format aspect to register.
726 * @param pTargetDevice Format target device to register.
727 */
728void UIDnDDataObject::RegisterFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat,
729 TYMED tyMed, LONG lIndex, DWORD dwAspect,
730 DVTARGETDEVICE *pTargetDevice)
731{
732 AssertPtr(pFormatEtc);
733
734 pFormatEtc->cfFormat = clipFormat;
735 pFormatEtc->tymed = tyMed;
736 pFormatEtc->lindex = lIndex;
737 pFormatEtc->dwAspect = dwAspect;
738 pFormatEtc->ptd = pTargetDevice;
739
740 LogFlowFunc(("Registered format=%ld, sFormat=%s\n",
741 pFormatEtc->cfFormat, UIDnDDataObject::ClipboardFormatToString(pFormatEtc->cfFormat)));
742}
743
744/**
745 * Sets the current status of this data object.
746 *
747 * @param enmStatus New status to set.
748 */
749void UIDnDDataObject::SetStatus(Status enmStatus)
750{
751 LogFlowFunc(("Setting status to %RU32\n", enmStatus));
752 m_enmStatus = enmStatus;
753}
754
755/**
756 * Signals that data has been "dropped".
757 */
758void UIDnDDataObject::Signal(void)
759{
760 SetStatus(Status_Dropped);
761}
762
763/**
764 * Signals that data has been "dropped".
765 *
766 * @returns VBox status code.
767 * @param strFormat Format of data (MIME string).
768 * @param pvData Pointer to data.
769 * @param cbData Size (in bytes) of data.
770 */
771int UIDnDDataObject::Signal(const QString &strFormat,
772 const void *pvData, uint32_t cbData)
773{
774 LogFlowFunc(("Signalling ...\n"));
775
776 int rc;
777
778 if (cbData)
779 {
780 m_pvData = RTMemAlloc(cbData);
781 if (m_pvData)
782 {
783 memcpy(m_pvData, pvData, cbData);
784 m_cbData = cbData;
785 rc = VINF_SUCCESS;
786 }
787 else
788 rc = VERR_NO_MEMORY;
789 }
790 else
791 rc = VINF_SUCCESS;
792
793 if (RT_SUCCESS(rc))
794 {
795 m_strFormat = strFormat;
796 SetStatus(Status_Dropped);
797 }
798 else
799 SetStatus(Status_Aborted);
800
801 /* Signal in any case. */
802 int rc2 = RTSemEventSignal(m_SemEvent);
803 if (RT_SUCCESS(rc))
804 rc = rc2;
805
806 return rc;
807}
808
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