VirtualBox

source: vbox/trunk/src/VBox/GuestHost/SharedClipboard/ClipboardDataObjectImpl-win.cpp@ 79497

Last change on this file since 79497 was 79497, checked in by vboxsync, 5 years ago

Shared Clipboard/URI: Update.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.7 KB
Line 
1/* $Id: ClipboardDataObjectImpl-win.cpp 79497 2019-07-03 13:28:33Z vboxsync $ */
2/** @file
3 * ClipboardDataObjectImpl-win.cpp - Shared Clipboard IDataObject implementation.
4 */
5
6/*
7 * Copyright (C) 2019 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/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
23#include <VBox/GuestHost/SharedClipboard-win.h>
24#include <VBox/GuestHost/SharedClipboard-uri.h>
25
26/** !!! HACK ALERT !!! Dynamically resolve functions! */
27#ifdef _WIN32_IE
28#undef _WIN32_IE
29#define _WIN32_IE 0x0501
30#endif
31
32#include <iprt/win/windows.h>
33#include <iprt/win/shlobj.h>
34#include <iprt/win/shlwapi.h>
35
36#include <iprt/err.h>
37#include <iprt/path.h>
38#include <iprt/semaphore.h>
39#include <iprt/uri.h>
40#include <iprt/utf16.h>
41
42#include <iprt/errcore.h>
43#include <VBox/log.h>
44
45/** Also handle Unicode entries. */
46#define VBOX_CLIPBOARD_WITH_UNICODE_SUPPORT 1
47
48VBoxClipboardWinDataObject::VBoxClipboardWinDataObject(PSHAREDCLIPBOARDURITRANSFER pTransfer,
49 LPFORMATETC pFormatEtc, LPSTGMEDIUM pStgMed, ULONG cFormats)
50 : m_enmStatus(Uninitialized)
51 , m_lRefCount(1)
52 , m_cFormats(0)
53 , m_pTransfer(pTransfer)
54 , m_pStream(NULL)
55 , m_uObjIdx(0)
56{
57 AssertPtr(m_pTransfer);
58
59 HRESULT hr;
60
61 ULONG cFixedFormats = 2; /* CFSTR_FILEDESCRIPTORA + CFSTR_FILECONTENTS */
62#ifdef VBOX_CLIPBOARD_WITH_UNICODE_SUPPORT
63 cFixedFormats++; /* CFSTR_FILEDESCRIPTORW */
64#endif
65 const ULONG cAllFormats = cFormats + cFixedFormats;
66
67 try
68 {
69 m_pFormatEtc = new FORMATETC[cAllFormats];
70 RT_BZERO(m_pFormatEtc, sizeof(FORMATETC) * cAllFormats);
71 m_pStgMedium = new STGMEDIUM[cAllFormats];
72 RT_BZERO(m_pStgMedium, sizeof(STGMEDIUM) * cAllFormats);
73
74 /** @todo Do we need CFSTR_FILENAME / CFSTR_SHELLIDLIST here? */
75
76 /*
77 * Register fixed formats.
78 */
79
80 LogFlowFunc(("Registering CFSTR_FILEDESCRIPTORA ...\n"));
81 registerFormat(&m_pFormatEtc[FormatIndex_FileDescriptorA],
82 RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA));
83#ifdef VBOX_CLIPBOARD_WITH_UNICODE_SUPPORT
84 LogFlowFunc(("Registering CFSTR_FILEDESCRIPTORW ...\n"));
85 registerFormat(&m_pFormatEtc[FormatIndex_FileDescriptorW],
86 RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW));
87#endif
88 /* IStream interface, implemented in ClipboardStreamImpl-win.cpp. */
89 LogFlowFunc(("Registering CFSTR_FILECONTENTS ...\n"));
90 registerFormat(&m_pFormatEtc[FormatIndex_FileContents],
91 RegisterClipboardFormat(CFSTR_FILECONTENTS),
92 TYMED_ISTREAM, 0 /* lIndex */);
93
94 /*
95 * Registration of dynamic formats needed?
96 */
97 LogFlowFunc(("%RU32 dynamic formats\n", cFormats));
98 if (cFormats)
99 {
100 AssertPtr(pFormatEtc);
101 AssertPtr(pStgMed);
102
103 for (ULONG i = 0; i < cFormats; i++)
104 {
105 LogFlowFunc(("Format %RU32: cfFormat=%RI16, tyMed=%RU32, dwAspect=%RU32\n",
106 i, pFormatEtc[i].cfFormat, pFormatEtc[i].tymed, pFormatEtc[i].dwAspect));
107 m_pFormatEtc[cFixedFormats + i] = pFormatEtc[i];
108 m_pStgMedium[cFixedFormats + i] = pStgMed[i];
109 }
110 }
111
112 hr = S_OK;
113 }
114 catch (std::bad_alloc &)
115 {
116 hr = E_OUTOFMEMORY;
117 }
118
119 if (SUCCEEDED(hr))
120 {
121 m_cFormats = cAllFormats;
122 m_enmStatus = Initialized;
123
124 int rc2 = RTSemEventCreate(&m_EventListComplete);
125 AssertRC(rc2);
126 rc2 = RTSemEventCreate(&m_EventTransferComplete);
127 AssertRC(rc2);
128 }
129
130 LogFlowFunc(("cAllFormats=%RU32, hr=%Rhrc\n", cAllFormats, hr));
131}
132
133VBoxClipboardWinDataObject::~VBoxClipboardWinDataObject(void)
134{
135 RTSemEventDestroy(m_EventListComplete);
136 RTSemEventDestroy(m_EventTransferComplete);
137
138 if (m_pStream)
139 m_pStream->Release();
140
141 if (m_pFormatEtc)
142 delete[] m_pFormatEtc;
143
144 if (m_pStgMedium)
145 delete[] m_pStgMedium;
146
147 LogFlowFunc(("mRefCount=%RI32\n", m_lRefCount));
148}
149
150/*
151 * IUnknown methods.
152 */
153
154STDMETHODIMP_(ULONG) VBoxClipboardWinDataObject::AddRef(void)
155{
156 LONG lCount = InterlockedIncrement(&m_lRefCount);
157 LogFlowFunc(("lCount=%RI32\n", lCount));
158 return lCount;
159}
160
161STDMETHODIMP_(ULONG) VBoxClipboardWinDataObject::Release(void)
162{
163 LONG lCount = InterlockedDecrement(&m_lRefCount);
164 LogFlowFunc(("lCount=%RI32\n", m_lRefCount));
165 if (lCount == 0)
166 {
167 delete this;
168 return 0;
169 }
170
171 return lCount;
172}
173
174STDMETHODIMP VBoxClipboardWinDataObject::QueryInterface(REFIID iid, void **ppvObject)
175{
176 AssertPtrReturn(ppvObject, E_INVALIDARG);
177
178 if ( iid == IID_IDataObject
179 || iid == IID_IUnknown)
180 {
181 AddRef();
182 *ppvObject = this;
183 return S_OK;
184 }
185
186 *ppvObject = 0;
187 return E_NOINTERFACE;
188}
189
190/**
191 * Copies a chunk of data into a HGLOBAL object.
192 *
193 * @returns VBox status code.
194 * @param pvData Data to copy.
195 * @param cbData Size (in bytes) to copy.
196 * @param fFlags GlobalAlloc flags, used for allocating the HGLOBAL block.
197 * @param phGlobal Where to store the allocated HGLOBAL object.
198 */
199int VBoxClipboardWinDataObject::copyToHGlobal(const void *pvData, size_t cbData, UINT fFlags, HGLOBAL *phGlobal)
200{
201 AssertPtrReturn(phGlobal, VERR_INVALID_POINTER);
202
203 HGLOBAL hGlobal = GlobalAlloc(fFlags, cbData);
204 if (!hGlobal)
205 return VERR_NO_MEMORY;
206
207 void *pvAlloc = GlobalLock(hGlobal);
208 if (pvAlloc)
209 {
210 CopyMemory(pvAlloc, pvData, cbData);
211 GlobalUnlock(hGlobal);
212
213 *phGlobal = hGlobal;
214
215 return VINF_SUCCESS;
216 }
217
218 GlobalFree(hGlobal);
219 return VERR_ACCESS_DENIED;
220}
221
222/* static */
223
224/**
225 * Thread for reading URI data.
226 * The data object needs the (high level, root) URI listing at the time of ::GetData(), so we need
227 * to block and wait until we have this data (via this thread) and continue.
228 *
229 * @returns VBox status code.
230 * @param ThreadSelf Thread handle. Unused at the moment.
231 * @param pvUser Pointer to user-provided data. Of type VBoxClipboardWinDataObject.
232 */
233DECLCALLBACK(int) VBoxClipboardWinDataObject::readThread(RTTHREAD ThreadSelf, void *pvUser)
234{
235 RT_NOREF(ThreadSelf);
236
237 LogFlowFuncEnter();
238
239 VBoxClipboardWinDataObject *pThis = (VBoxClipboardWinDataObject *)pvUser;
240
241 PSHAREDCLIPBOARDURITRANSFER pTransfer = pThis->m_pTransfer;
242 AssertPtr(pTransfer);
243
244 pTransfer->Thread.fStarted = true;
245
246 RTThreadUserSignal(RTThreadSelf());
247
248 int rc = SharedClipboardURITransferOpen(pTransfer);
249 if (RT_SUCCESS(rc))
250 {
251 VBOXCLIPBOARDLISTHDR Hdr;
252 rc = SharedClipboardURIListHdrInit(&Hdr);
253 if (RT_SUCCESS(rc))
254 {
255 VBOXCLIPBOARDLISTHANDLE hList;
256 rc = SharedClipboardURITransferListOpen(pTransfer, &Hdr, &hList);
257 if (RT_SUCCESS(rc))
258 {
259 LogFlowFunc(("hList=%RU64, cTotalObjects=%RU64, cbTotalSize=%RU64\n\n",
260 hList, Hdr.cTotalObjects, Hdr.cbTotalSize));
261
262 for (uint64_t i = 0; i < Hdr.cTotalObjects; i++)
263 {
264 VBOXCLIPBOARDLISTENTRY Entry;
265 rc = SharedClipboardURITransferListRead(pTransfer, hList, &Entry);
266 if (RT_SUCCESS(rc))
267 {
268
269 }
270 else
271 break;
272
273 if (pTransfer->Thread.fStop)
274 break;
275 }
276
277 if (RT_SUCCESS(rc))
278 {
279 /*
280 * Signal the "list complete" event so that this data object can return (valid) data via ::GetData().
281 * This in turn then will create IStream instances (by the OS) for each file system object to handle.
282 */
283 int rc2 = RTSemEventSignal(pThis->m_EventListComplete);
284 AssertRC(rc2);
285
286 LogFlowFunc(("Waiting for transfer to complete ...\n"));
287
288 /* Transferring stuff can take a while, so don't use any timeout here. */
289 rc2 = RTSemEventWait(pThis->m_EventTransferComplete, RT_INDEFINITE_WAIT);
290 AssertRC(rc2);
291 }
292
293 SharedClipboardURITransferListClose(pTransfer, hList);
294 }
295
296 SharedClipboardURIListHdrDestroy(&Hdr);
297 }
298
299 SharedClipboardURITransferClose(pTransfer);
300 }
301
302 LogFlowFuncLeaveRC(rc);
303 return rc;
304}
305
306/**
307 * Creates a FILEGROUPDESCRIPTOR object from a given URI transfer and stores the result into an HGLOBAL object.
308 *
309 * @returns VBox status code.
310 * @param pTransfer URI transfer to create file grou desciprtor for.
311 * @param fUnicode Whether the FILEGROUPDESCRIPTOR object shall contain Unicode data or not.
312 * @param phGlobal Where to store the allocated HGLOBAL object on success.
313 */
314int VBoxClipboardWinDataObject::createFileGroupDescriptorFromTransfer(PSHAREDCLIPBOARDURITRANSFER pTransfer,
315 bool fUnicode, HGLOBAL *phGlobal)
316{
317 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
318 AssertPtrReturn(phGlobal, VERR_INVALID_POINTER);
319
320 LogFlowFuncEnter();
321
322 const size_t cbFileGroupDescriptor = fUnicode ? sizeof(FILEGROUPDESCRIPTORW) : sizeof(FILEGROUPDESCRIPTORA);
323 const size_t cbFileDescriptor = fUnicode ? sizeof(FILEDESCRIPTORW) : sizeof(FILEDESCRIPTORA);
324
325 const UINT cItems = (UINT)0; /** @todo UINT vs. uint64_t */
326 if (!cItems)
327 return VERR_NOT_FOUND;
328
329 const size_t cbFGD = cbFileGroupDescriptor + (cbFileDescriptor * (cItems - 1));
330
331 LogFunc(("fUnicode=%RTbool, cItems=%u, cbFileDescriptor=%zu\n", fUnicode, cItems, cbFileDescriptor));
332
333 /* FILEGROUPDESCRIPTORA / FILEGROUPDESCRIPTOR matches except the cFileName member (TCHAR vs. WCHAR). */
334 FILEGROUPDESCRIPTOR *pFGD = (FILEGROUPDESCRIPTOR *)RTMemAlloc(cbFGD);
335 if (!pFGD)
336 return VERR_NO_MEMORY;
337
338 int rc = VINF_SUCCESS;
339
340 pFGD->cItems = cItems;
341
342 char *pszFileSpec = NULL;
343#if 0
344 for (UINT i = 0; i < cItems; i++)
345 {
346 FILEDESCRIPTOR *pFD = &pFGD->fgd[i];
347 RT_BZERO(pFD, cbFileDescriptor);
348
349 const SharedClipboardURIObject *pObj = pURIList->At(i);
350 AssertPtr(pObj);
351 const char *pszFile = pObj->GetSourcePathAbs().c_str();
352 AssertPtr(pszFile);
353
354 pszFileSpec = RTStrDup(pszFile);
355 AssertBreakStmt(pszFileSpec != NULL, rc = VERR_NO_MEMORY);
356
357 if (fUnicode)
358 {
359 PRTUTF16 pwszFileSpec;
360 rc = RTStrToUtf16(pszFileSpec, &pwszFileSpec);
361 if (RT_SUCCESS(rc))
362 {
363 rc = RTUtf16CopyEx((PRTUTF16 )pFD->cFileName, sizeof(pFD->cFileName) / sizeof(WCHAR),
364 pwszFileSpec, RTUtf16Len(pwszFileSpec));
365 RTUtf16Free(pwszFileSpec);
366 }
367 }
368 else
369 rc = RTStrCopy(pFD->cFileName, sizeof(pFD->cFileName), pszFileSpec);
370
371 RTStrFree(pszFileSpec);
372 pszFileSpec = NULL;
373
374 if (RT_FAILURE(rc))
375 break;
376
377 pFD->dwFlags = FD_PROGRESSUI | FD_ATTRIBUTES;
378 if (fUnicode) /** @todo Only >= Vista. */
379 pFD->dwFlags |= FD_UNICODE;
380 pFD->dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
381
382 switch (pObj->GetType())
383 {
384 case SharedClipboardURIObject::Type_Directory:
385 pFD->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
386
387 LogFunc(("pszDir=%s\n", pszFile));
388 break;
389
390 case SharedClipboardURIObject::Type_File:
391 {
392 pFD->dwFlags |= FD_FILESIZE;
393
394 const uint64_t cbObjSize = pObj->GetSize();
395
396 pFD->nFileSizeHigh = RT_HI_U32(cbObjSize);
397 pFD->nFileSizeLow = RT_LO_U32(cbObjSize);
398
399 LogFunc(("pszFile=%s, cbObjSize=%RU64\n", pszFile, cbObjSize));
400 break;
401 }
402
403 default:
404 AssertFailed();
405 break;
406 }
407#if 0
408 pFD->dwFlags = FD_ATTRIBUTES | FD_CREATETIME | FD_ACCESSTIME | FD_WRITESTIME | FD_FILESIZE; /** @todo Implement this. */
409 pFD->dwFileAttributes =
410 pFD->ftCreationTime =
411 pFD->ftLastAccessTime =
412 pFD->ftLastWriteTime =
413#endif
414 }
415#endif
416
417 if (pszFileSpec)
418 RTStrFree(pszFileSpec);
419
420 if (RT_SUCCESS(rc))
421 {
422 rc = copyToHGlobal(pFGD, cbFGD, GMEM_MOVEABLE, phGlobal);
423 }
424 else
425 {
426 RTMemFree(pFGD);
427 }
428
429 LogFlowFuncLeaveRC(rc);
430 return rc;
431}
432
433/**
434 * Retrieves the data stored in this object and store the result in
435 * pMedium.
436 *
437 * @return IPRT status code.
438 * @return HRESULT
439 * @param pFormatEtc
440 * @param pMedium
441 */
442STDMETHODIMP VBoxClipboardWinDataObject::GetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium)
443{
444 AssertPtrReturn(pFormatEtc, DV_E_FORMATETC);
445 AssertPtrReturn(pMedium, DV_E_FORMATETC);
446
447 LogFlowFuncEnter();
448
449 ULONG lIndex;
450 if (!lookupFormatEtc(pFormatEtc, &lIndex)) /* Format supported? */
451 return DV_E_FORMATETC;
452 if (lIndex >= m_cFormats) /* Paranoia. */
453 return DV_E_LINDEX;
454
455 LPFORMATETC pThisFormat = &m_pFormatEtc[lIndex];
456 AssertPtr(pThisFormat);
457
458 LPSTGMEDIUM pThisMedium = &m_pStgMedium[lIndex];
459 AssertPtr(pThisMedium);
460
461 LogFlowFunc(("Using pThisFormat=%p, pThisMedium=%p\n", pThisFormat, pThisMedium));
462
463 HRESULT hr = DV_E_FORMATETC; /* Play safe. */
464
465 LogRel2(("Shared Clipboard: cfFormat=%RI16, sFormat=%s, tyMed=%RU32, dwAspect=%RU32 -> lIndex=%u\n",
466 pThisFormat->cfFormat, VBoxClipboardWinDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
467 pThisFormat->tymed, pThisFormat->dwAspect, lIndex));
468
469 /*
470 * Initialize default values.
471 */
472 pMedium->tymed = pThisFormat->tymed;
473 pMedium->pUnkForRelease = NULL; /* Caller is responsible for deleting the data. */
474
475 switch (lIndex)
476 {
477 case FormatIndex_FileDescriptorA: /* ANSI */
478#ifdef VBOX_CLIPBOARD_WITH_UNICODE_SUPPORT
479 RT_FALL_THROUGH();
480 case FormatIndex_FileDescriptorW: /* Unicode */
481#endif
482 {
483 const bool fUnicode = lIndex == FormatIndex_FileDescriptorW;
484
485 LogFlowFunc(("FormatIndex_FileDescriptor%s\n", fUnicode ? "W" : "A"));
486
487 int rc;
488
489 /* The caller can call GetData() several times, so make sure we don't do the same transfer multiple times. */
490 if (SharedClipboardURITransferGetStatus(m_pTransfer) == SHAREDCLIPBOARDURITRANSFERSTATUS_NONE)
491 {
492 rc = SharedClipboardURITransferPrepare(m_pTransfer);
493 if (RT_SUCCESS(rc))
494 {
495 /* Start the transfer asynchronously in a separate thread. */
496 rc = SharedClipboardURITransferRun(m_pTransfer, &VBoxClipboardWinDataObject::readThread, this);
497 if (RT_SUCCESS(rc))
498 {
499 LogFunc(("Waiting for listing to arrive ...\n"));
500 rc = RTSemEventWait(m_EventListComplete, 5 * 60 * 1000 /* 5 min timeout */);
501 if (RT_SUCCESS(rc))
502 {
503 LogFunc(("Listing complete\n"));
504
505 HGLOBAL hGlobal;
506 rc = createFileGroupDescriptorFromTransfer(m_pTransfer, fUnicode, &hGlobal);
507 if (RT_SUCCESS(rc))
508 {
509 pMedium->tymed = TYMED_HGLOBAL;
510 pMedium->hGlobal = hGlobal;
511 /* Note: hGlobal now is being owned by pMedium / the caller. */
512
513 hr = S_OK;
514 }
515 }
516 }
517 }
518 }
519 else
520 rc = VERR_ALREADY_EXISTS;
521
522 if (RT_FAILURE(rc))
523 LogRel(("Shared Clipboard: Data object unable to get data, rc=%Rrc\n", rc));
524
525 break;
526 }
527
528 case FormatIndex_FileContents:
529 {
530 LogFlowFunc(("FormatIndex_FileContents: m_uObjIdx=%u\n", m_uObjIdx));
531
532 /* Hand-in the provider so that our IStream implementation can continue working with it. */
533 hr = VBoxClipboardWinStreamImpl::Create(this /* pParent */, m_pTransfer, m_uObjIdx, &m_pStream);
534 if (SUCCEEDED(hr))
535 {
536 /* Hand over the stream to the caller. */
537 pMedium->tymed = TYMED_ISTREAM;
538 pMedium->pstm = m_pStream;
539
540 /* Handle next object. */
541 m_uObjIdx++;
542 }
543 break;
544 }
545
546 default:
547 break;
548 }
549
550 /* Error handling; at least return some basic data. */
551 if (FAILED(hr))
552 {
553 LogFunc(("Failed; copying medium ...\n"));
554
555 pMedium->tymed = pThisFormat->tymed;
556 pMedium->pUnkForRelease = NULL;
557 }
558
559 if (hr == DV_E_FORMATETC)
560 LogRel(("Shared Clipboard: Error handling format\n"));
561
562 LogFlowFunc(("hr=%Rhrc\n", hr));
563 return hr;
564}
565
566/**
567 * Only required for IStream / IStorage interfaces.
568 *
569 * @return IPRT status code.
570 * @return HRESULT
571 * @param pFormatEtc
572 * @param pMedium
573 */
574STDMETHODIMP VBoxClipboardWinDataObject::GetDataHere(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium)
575{
576 RT_NOREF(pFormatEtc, pMedium);
577 LogFlowFunc(("\n"));
578 return E_NOTIMPL;
579}
580
581/**
582 * Query if this objects supports a specific format.
583 *
584 * @return IPRT status code.
585 * @return HRESULT
586 * @param pFormatEtc
587 */
588STDMETHODIMP VBoxClipboardWinDataObject::QueryGetData(LPFORMATETC pFormatEtc)
589{
590 LogFlowFunc(("\n"));
591 return (lookupFormatEtc(pFormatEtc, NULL /* puIndex */)) ? S_OK : DV_E_FORMATETC;
592}
593
594STDMETHODIMP VBoxClipboardWinDataObject::GetCanonicalFormatEtc(LPFORMATETC pFormatEtc, LPFORMATETC pFormatEtcOut)
595{
596 RT_NOREF(pFormatEtc);
597 LogFlowFunc(("\n"));
598
599 /* Set this to NULL in any case. */
600 pFormatEtcOut->ptd = NULL;
601 return E_NOTIMPL;
602}
603
604STDMETHODIMP VBoxClipboardWinDataObject::SetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium, BOOL fRelease)
605{
606 RT_NOREF(pFormatEtc, pMedium, fRelease);
607 LogFlowFunc(("\n"));
608
609 return E_NOTIMPL;
610}
611
612STDMETHODIMP VBoxClipboardWinDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc)
613{
614 LogFlowFunc(("dwDirection=%RI32, mcFormats=%RI32, mpFormatEtc=%p\n", dwDirection, m_cFormats, m_pFormatEtc));
615
616 HRESULT hr;
617 if (dwDirection == DATADIR_GET)
618 hr = VBoxClipboardWinEnumFormatEtc::CreateEnumFormatEtc(m_cFormats, m_pFormatEtc, ppEnumFormatEtc);
619 else
620 hr = E_NOTIMPL;
621
622 LogFlowFunc(("hr=%Rhrc\n", hr));
623 return hr;
624}
625
626STDMETHODIMP VBoxClipboardWinDataObject::DAdvise(LPFORMATETC pFormatEtc, DWORD fAdvise, IAdviseSink *pAdvSink, DWORD *pdwConnection)
627{
628 RT_NOREF(pFormatEtc, fAdvise, pAdvSink, pdwConnection);
629 return OLE_E_ADVISENOTSUPPORTED;
630}
631
632STDMETHODIMP VBoxClipboardWinDataObject::DUnadvise(DWORD dwConnection)
633{
634 RT_NOREF(dwConnection);
635 return OLE_E_ADVISENOTSUPPORTED;
636}
637
638STDMETHODIMP VBoxClipboardWinDataObject::EnumDAdvise(IEnumSTATDATA **ppEnumAdvise)
639{
640 RT_NOREF(ppEnumAdvise);
641 return OLE_E_ADVISENOTSUPPORTED;
642}
643
644#ifdef VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC
645/*
646 * IDataObjectAsyncCapability methods.
647 */
648
649STDMETHODIMP VBoxClipboardWinDataObject::EndOperation(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects)
650{
651 RT_NOREF(hResult, pbcReserved, dwEffects);
652 return E_NOTIMPL;
653}
654
655STDMETHODIMP VBoxClipboardWinDataObject::GetAsyncMode(BOOL *pfIsOpAsync)
656{
657 RT_NOREF(pfIsOpAsync);
658 return E_NOTIMPL;
659}
660
661STDMETHODIMP VBoxClipboardWinDataObject::InOperation(BOOL *pfInAsyncOp)
662{
663 RT_NOREF(pfInAsyncOp);
664 return E_NOTIMPL;
665}
666
667STDMETHODIMP VBoxClipboardWinDataObject::SetAsyncMode(BOOL fDoOpAsync)
668{
669 RT_NOREF(fDoOpAsync);
670 return E_NOTIMPL;
671}
672
673STDMETHODIMP VBoxClipboardWinDataObject::StartOperation(IBindCtx *pbcReserved)
674{
675 RT_NOREF(pbcReserved);
676 return E_NOTIMPL;
677}
678#endif /* VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC */
679
680/*
681 * Own stuff.
682 */
683
684int VBoxClipboardWinDataObject::Init(void)
685{
686 LogFlowFuncLeaveRC(VINF_SUCCESS);
687 return VINF_SUCCESS;
688}
689
690void VBoxClipboardWinDataObject::OnTransferComplete(int rc /* = VINF_SUCESS */)
691{
692 RT_NOREF(rc);
693
694 LogFlowFuncLeaveRC(rc);
695}
696
697void VBoxClipboardWinDataObject::OnTransferCanceled(void)
698{
699 LogFlowFuncLeave();
700}
701
702/* static */
703const char* VBoxClipboardWinDataObject::ClipboardFormatToString(CLIPFORMAT fmt)
704{
705#if 0
706 char szFormat[128];
707 if (GetClipboardFormatName(fmt, szFormat, sizeof(szFormat)))
708 LogFlowFunc(("wFormat=%RI16, szName=%s\n", fmt, szFormat));
709#endif
710
711 switch (fmt)
712 {
713
714 case 1:
715 return "CF_TEXT";
716 case 2:
717 return "CF_BITMAP";
718 case 3:
719 return "CF_METAFILEPICT";
720 case 4:
721 return "CF_SYLK";
722 case 5:
723 return "CF_DIF";
724 case 6:
725 return "CF_TIFF";
726 case 7:
727 return "CF_OEMTEXT";
728 case 8:
729 return "CF_DIB";
730 case 9:
731 return "CF_PALETTE";
732 case 10:
733 return "CF_PENDATA";
734 case 11:
735 return "CF_RIFF";
736 case 12:
737 return "CF_WAVE";
738 case 13:
739 return "CF_UNICODETEXT";
740 case 14:
741 return "CF_ENHMETAFILE";
742 case 15:
743 return "CF_HDROP";
744 case 16:
745 return "CF_LOCALE";
746 case 17:
747 return "CF_DIBV5";
748 case 18:
749 return "CF_MAX";
750 case 49158:
751 return "FileName";
752 case 49159:
753 return "FileNameW";
754 case 49161:
755 return "DATAOBJECT";
756 case 49171:
757 return "Ole Private Data";
758 case 49314:
759 return "Shell Object Offsets";
760 case 49316:
761 return "File Contents";
762 case 49317:
763 return "File Group Descriptor";
764 case 49323:
765 return "Preferred Drop Effect";
766 case 49380:
767 return "Shell Object Offsets";
768 case 49382:
769 return "FileContents";
770 case 49383:
771 return "FileGroupDescriptor";
772 case 49389:
773 return "Preferred DropEffect";
774 case 49268:
775 return "Shell IDList Array";
776 case 49619:
777 return "RenPrivateFileAttachments";
778 default:
779 break;
780 }
781
782 return "unknown";
783}
784
785bool VBoxClipboardWinDataObject::lookupFormatEtc(LPFORMATETC pFormatEtc, ULONG *puIndex)
786{
787 AssertReturn(pFormatEtc, false);
788 /* puIndex is optional. */
789
790 for (ULONG i = 0; i < m_cFormats; i++)
791 {
792 if( (pFormatEtc->tymed & m_pFormatEtc[i].tymed)
793 && pFormatEtc->cfFormat == m_pFormatEtc[i].cfFormat)
794 /* Note: Do *not* compare dwAspect here, as this can be dynamic, depending on how the object should be represented. */
795 //&& pFormatEtc->dwAspect == m_pFormatEtc[i].dwAspect)
796 {
797 LogRel3(("Shared Clipboard: Format found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32, ulIndex=%RU32\n",
798 pFormatEtc->tymed, pFormatEtc->cfFormat, VBoxClipboardWinDataObject::ClipboardFormatToString(m_pFormatEtc[i].cfFormat),
799 pFormatEtc->dwAspect, i));
800 if (puIndex)
801 *puIndex = i;
802 return true;
803 }
804 }
805
806 LogRel3(("Shared Clipboard: Format NOT found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32\n",
807 pFormatEtc->tymed, pFormatEtc->cfFormat, VBoxClipboardWinDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
808 pFormatEtc->dwAspect));
809
810 return false;
811}
812
813void VBoxClipboardWinDataObject::registerFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat,
814 TYMED tyMed, LONG lIndex, DWORD dwAspect,
815 DVTARGETDEVICE *pTargetDevice)
816{
817 AssertPtr(pFormatEtc);
818
819 pFormatEtc->cfFormat = clipFormat;
820 pFormatEtc->tymed = tyMed;
821 pFormatEtc->lindex = lIndex;
822 pFormatEtc->dwAspect = dwAspect;
823 pFormatEtc->ptd = pTargetDevice;
824
825 LogFlowFunc(("Registered format=%ld, sFormat=%s\n",
826 pFormatEtc->cfFormat, VBoxClipboardWinDataObject::ClipboardFormatToString(pFormatEtc->cfFormat)));
827}
828
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