VirtualBox

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

Last change on this file since 79644 was 79630, checked in by vboxsync, 6 years ago

Shared Clipboard/URI: Update.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.3 KB
Line 
1/* $Id: ClipboardDataObjectImpl-win.cpp 79630 2019-07-09 08:14:01Z 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 VBOXCLIPBOARDLISTOPENPARMS openParmsList;
252 rc = SharedClipboardURIListOpenParmsInit(&openParmsList);
253 if (RT_SUCCESS(rc))
254 {
255 SHAREDCLIPBOARDLISTHANDLE hList;
256 rc = SharedClipboardURITransferListOpen(pTransfer, &openParmsList, &hList);
257 if (RT_SUCCESS(rc))
258 {
259 LogFlowFunc(("hList=%RU64\n", hList));
260
261 VBOXCLIPBOARDLISTHDR hdrList;
262 rc = SharedClipboardURITransferListGetHeader(pTransfer, hList, &hdrList);
263 if (RT_SUCCESS(rc))
264 {
265 LogFlowFunc(("cTotalObjects=%RU64, cbTotalSize=%RU64\n\n",
266 hdrList.cTotalObjects, hdrList.cbTotalSize));
267
268 for (uint64_t i = 0; i < hdrList.cTotalObjects; i++)
269 {
270 VBOXCLIPBOARDLISTENTRY entryList;
271 rc = SharedClipboardURITransferListRead(pTransfer, hList, &entryList);
272 if (RT_SUCCESS(rc))
273 {
274 }
275 else
276 break;
277
278 if (pTransfer->Thread.fStop)
279 break;
280 }
281
282 if (RT_SUCCESS(rc))
283 {
284 /*
285 * Signal the "list complete" event so that this data object can return (valid) data via ::GetData().
286 * This in turn then will create IStream instances (by the OS) for each file system object to handle.
287 */
288 int rc2 = RTSemEventSignal(pThis->m_EventListComplete);
289 AssertRC(rc2);
290
291 LogFlowFunc(("Waiting for transfer to complete ...\n"));
292
293 /* Transferring stuff can take a while, so don't use any timeout here. */
294 rc2 = RTSemEventWait(pThis->m_EventTransferComplete, RT_INDEFINITE_WAIT);
295 AssertRC(rc2);
296 }
297 }
298
299 SharedClipboardURITransferListClose(pTransfer, hList);
300 }
301
302 SharedClipboardURIListOpenParmsDestroy(&openParmsList);
303 }
304
305 SharedClipboardURITransferClose(pTransfer);
306 }
307
308 LogFlowFuncLeaveRC(rc);
309 return rc;
310}
311
312/**
313 * Creates a FILEGROUPDESCRIPTOR object from a given URI transfer and stores the result into an HGLOBAL object.
314 *
315 * @returns VBox status code.
316 * @param pTransfer URI transfer to create file grou desciprtor for.
317 * @param fUnicode Whether the FILEGROUPDESCRIPTOR object shall contain Unicode data or not.
318 * @param phGlobal Where to store the allocated HGLOBAL object on success.
319 */
320int VBoxClipboardWinDataObject::createFileGroupDescriptorFromTransfer(PSHAREDCLIPBOARDURITRANSFER pTransfer,
321 bool fUnicode, HGLOBAL *phGlobal)
322{
323 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
324 AssertPtrReturn(phGlobal, VERR_INVALID_POINTER);
325
326 LogFlowFuncEnter();
327
328 const size_t cbFileGroupDescriptor = fUnicode ? sizeof(FILEGROUPDESCRIPTORW) : sizeof(FILEGROUPDESCRIPTORA);
329 const size_t cbFileDescriptor = fUnicode ? sizeof(FILEDESCRIPTORW) : sizeof(FILEDESCRIPTORA);
330
331 const UINT cItems = (UINT)0; /** @todo UINT vs. uint64_t */
332 if (!cItems)
333 return VERR_NOT_FOUND;
334
335 const size_t cbFGD = cbFileGroupDescriptor + (cbFileDescriptor * (cItems - 1));
336
337 LogFunc(("fUnicode=%RTbool, cItems=%u, cbFileDescriptor=%zu\n", fUnicode, cItems, cbFileDescriptor));
338
339 /* FILEGROUPDESCRIPTORA / FILEGROUPDESCRIPTOR matches except the cFileName member (TCHAR vs. WCHAR). */
340 FILEGROUPDESCRIPTOR *pFGD = (FILEGROUPDESCRIPTOR *)RTMemAlloc(cbFGD);
341 if (!pFGD)
342 return VERR_NO_MEMORY;
343
344 int rc = VINF_SUCCESS;
345
346 pFGD->cItems = cItems;
347
348 char *pszFileSpec = NULL;
349#if 0
350 for (UINT i = 0; i < cItems; i++)
351 {
352 FILEDESCRIPTOR *pFD = &pFGD->fgd[i];
353 RT_BZERO(pFD, cbFileDescriptor);
354
355 const SharedClipboardURIObject *pObj = pURIList->At(i);
356 AssertPtr(pObj);
357 const char *pszFile = pObj->GetSourcePathAbs().c_str();
358 AssertPtr(pszFile);
359
360 pszFileSpec = RTStrDup(pszFile);
361 AssertBreakStmt(pszFileSpec != NULL, rc = VERR_NO_MEMORY);
362
363 if (fUnicode)
364 {
365 PRTUTF16 pwszFileSpec;
366 rc = RTStrToUtf16(pszFileSpec, &pwszFileSpec);
367 if (RT_SUCCESS(rc))
368 {
369 rc = RTUtf16CopyEx((PRTUTF16 )pFD->cFileName, sizeof(pFD->cFileName) / sizeof(WCHAR),
370 pwszFileSpec, RTUtf16Len(pwszFileSpec));
371 RTUtf16Free(pwszFileSpec);
372 }
373 }
374 else
375 rc = RTStrCopy(pFD->cFileName, sizeof(pFD->cFileName), pszFileSpec);
376
377 RTStrFree(pszFileSpec);
378 pszFileSpec = NULL;
379
380 if (RT_FAILURE(rc))
381 break;
382
383 pFD->dwFlags = FD_PROGRESSUI | FD_ATTRIBUTES;
384 if (fUnicode) /** @todo Only >= Vista. */
385 pFD->dwFlags |= FD_UNICODE;
386 pFD->dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
387
388 switch (pObj->GetType())
389 {
390 case SharedClipboardURIObject::Type_Directory:
391 pFD->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
392
393 LogFunc(("pszDir=%s\n", pszFile));
394 break;
395
396 case SharedClipboardURIObject::Type_File:
397 {
398 pFD->dwFlags |= FD_FILESIZE;
399
400 const uint64_t cbObjSize = pObj->GetSize();
401
402 pFD->nFileSizeHigh = RT_HI_U32(cbObjSize);
403 pFD->nFileSizeLow = RT_LO_U32(cbObjSize);
404
405 LogFunc(("pszFile=%s, cbObjSize=%RU64\n", pszFile, cbObjSize));
406 break;
407 }
408
409 default:
410 AssertFailed();
411 break;
412 }
413#if 0
414 pFD->dwFlags = FD_ATTRIBUTES | FD_CREATETIME | FD_ACCESSTIME | FD_WRITESTIME | FD_FILESIZE; /** @todo Implement this. */
415 pFD->dwFileAttributes =
416 pFD->ftCreationTime =
417 pFD->ftLastAccessTime =
418 pFD->ftLastWriteTime =
419#endif
420 }
421#endif
422
423 if (pszFileSpec)
424 RTStrFree(pszFileSpec);
425
426 if (RT_SUCCESS(rc))
427 {
428 rc = copyToHGlobal(pFGD, cbFGD, GMEM_MOVEABLE, phGlobal);
429 }
430 else
431 {
432 RTMemFree(pFGD);
433 }
434
435 LogFlowFuncLeaveRC(rc);
436 return rc;
437}
438
439/**
440 * Retrieves the data stored in this object and store the result in
441 * pMedium.
442 *
443 * @return IPRT status code.
444 * @return HRESULT
445 * @param pFormatEtc
446 * @param pMedium
447 */
448STDMETHODIMP VBoxClipboardWinDataObject::GetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium)
449{
450 AssertPtrReturn(pFormatEtc, DV_E_FORMATETC);
451 AssertPtrReturn(pMedium, DV_E_FORMATETC);
452
453 LogFlowFuncEnter();
454
455 ULONG lIndex;
456 if (!lookupFormatEtc(pFormatEtc, &lIndex)) /* Format supported? */
457 return DV_E_FORMATETC;
458 if (lIndex >= m_cFormats) /* Paranoia. */
459 return DV_E_LINDEX;
460
461 LPFORMATETC pThisFormat = &m_pFormatEtc[lIndex];
462 AssertPtr(pThisFormat);
463
464 LPSTGMEDIUM pThisMedium = &m_pStgMedium[lIndex];
465 AssertPtr(pThisMedium);
466
467 LogFlowFunc(("Using pThisFormat=%p, pThisMedium=%p\n", pThisFormat, pThisMedium));
468
469 HRESULT hr = DV_E_FORMATETC; /* Play safe. */
470
471 LogRel2(("Shared Clipboard: cfFormat=%RI16, sFormat=%s, tyMed=%RU32, dwAspect=%RU32 -> lIndex=%u\n",
472 pThisFormat->cfFormat, VBoxClipboardWinDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
473 pThisFormat->tymed, pThisFormat->dwAspect, lIndex));
474
475 /*
476 * Initialize default values.
477 */
478 pMedium->tymed = pThisFormat->tymed;
479 pMedium->pUnkForRelease = NULL; /* Caller is responsible for deleting the data. */
480
481 switch (lIndex)
482 {
483 case FormatIndex_FileDescriptorA: /* ANSI */
484#ifdef VBOX_CLIPBOARD_WITH_UNICODE_SUPPORT
485 RT_FALL_THROUGH();
486 case FormatIndex_FileDescriptorW: /* Unicode */
487#endif
488 {
489 const bool fUnicode = lIndex == FormatIndex_FileDescriptorW;
490
491 LogFlowFunc(("FormatIndex_FileDescriptor%s\n", fUnicode ? "W" : "A"));
492
493 int rc;
494
495 /* The caller can call GetData() several times, so make sure we don't do the same transfer multiple times. */
496 if (SharedClipboardURITransferGetStatus(m_pTransfer) == SHAREDCLIPBOARDURITRANSFERSTATUS_NONE)
497 {
498 rc = SharedClipboardURITransferPrepare(m_pTransfer);
499 if (RT_SUCCESS(rc))
500 {
501 /* Start the transfer asynchronously in a separate thread. */
502 rc = SharedClipboardURITransferRun(m_pTransfer, &VBoxClipboardWinDataObject::readThread, this);
503 if (RT_SUCCESS(rc))
504 {
505 /* Don't block for too long here, as this also will screw other apps running on the OS. */
506 LogFunc(("Waiting for listing to arrive ...\n"));
507 rc = RTSemEventWait(m_EventListComplete, 10 * 1000 /* 10s timeout */);
508 if (RT_SUCCESS(rc))
509 {
510 LogFunc(("Listing complete\n"));
511
512 HGLOBAL hGlobal;
513 rc = createFileGroupDescriptorFromTransfer(m_pTransfer, fUnicode, &hGlobal);
514 if (RT_SUCCESS(rc))
515 {
516 pMedium->tymed = TYMED_HGLOBAL;
517 pMedium->hGlobal = hGlobal;
518 /* Note: hGlobal now is being owned by pMedium / the caller. */
519
520 hr = S_OK;
521 }
522 }
523 }
524 }
525 }
526 else
527 rc = VERR_ALREADY_EXISTS;
528
529 if (RT_FAILURE(rc))
530 LogRel(("Shared Clipboard: Data object unable to get data, rc=%Rrc\n", rc));
531
532 break;
533 }
534
535 case FormatIndex_FileContents:
536 {
537 LogFlowFunc(("FormatIndex_FileContents: m_uObjIdx=%u\n", m_uObjIdx));
538
539 SHAREDCLIPBOARDOBJHANDLE hObj = 0; /** @todo */
540
541 /* Hand-in the provider so that our IStream implementation can continue working with it. */
542 hr = VBoxClipboardWinStreamImpl::Create(this /* pParent */, m_pTransfer, hObj, &m_pStream);
543 if (SUCCEEDED(hr))
544 {
545 /* Hand over the stream to the caller. */
546 pMedium->tymed = TYMED_ISTREAM;
547 pMedium->pstm = m_pStream;
548
549 /* Handle next object. */
550 m_uObjIdx++;
551 }
552 break;
553 }
554
555 default:
556 break;
557 }
558
559 /* Error handling; at least return some basic data. */
560 if (FAILED(hr))
561 {
562 LogFunc(("Failed; copying medium ...\n"));
563
564 pMedium->tymed = pThisFormat->tymed;
565 pMedium->pUnkForRelease = NULL;
566 }
567
568 if (hr == DV_E_FORMATETC)
569 LogRel(("Shared Clipboard: Error handling format\n"));
570
571 LogFlowFunc(("hr=%Rhrc\n", hr));
572 return hr;
573}
574
575/**
576 * Only required for IStream / IStorage interfaces.
577 *
578 * @return IPRT status code.
579 * @return HRESULT
580 * @param pFormatEtc
581 * @param pMedium
582 */
583STDMETHODIMP VBoxClipboardWinDataObject::GetDataHere(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium)
584{
585 RT_NOREF(pFormatEtc, pMedium);
586 LogFlowFunc(("\n"));
587 return E_NOTIMPL;
588}
589
590/**
591 * Query if this objects supports a specific format.
592 *
593 * @return IPRT status code.
594 * @return HRESULT
595 * @param pFormatEtc
596 */
597STDMETHODIMP VBoxClipboardWinDataObject::QueryGetData(LPFORMATETC pFormatEtc)
598{
599 LogFlowFunc(("\n"));
600 return (lookupFormatEtc(pFormatEtc, NULL /* puIndex */)) ? S_OK : DV_E_FORMATETC;
601}
602
603STDMETHODIMP VBoxClipboardWinDataObject::GetCanonicalFormatEtc(LPFORMATETC pFormatEtc, LPFORMATETC pFormatEtcOut)
604{
605 RT_NOREF(pFormatEtc);
606 LogFlowFunc(("\n"));
607
608 /* Set this to NULL in any case. */
609 pFormatEtcOut->ptd = NULL;
610 return E_NOTIMPL;
611}
612
613STDMETHODIMP VBoxClipboardWinDataObject::SetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium, BOOL fRelease)
614{
615 RT_NOREF(pFormatEtc, pMedium, fRelease);
616 LogFlowFunc(("\n"));
617
618 return E_NOTIMPL;
619}
620
621STDMETHODIMP VBoxClipboardWinDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc)
622{
623 LogFlowFunc(("dwDirection=%RI32, mcFormats=%RI32, mpFormatEtc=%p\n", dwDirection, m_cFormats, m_pFormatEtc));
624
625 HRESULT hr;
626 if (dwDirection == DATADIR_GET)
627 hr = VBoxClipboardWinEnumFormatEtc::CreateEnumFormatEtc(m_cFormats, m_pFormatEtc, ppEnumFormatEtc);
628 else
629 hr = E_NOTIMPL;
630
631 LogFlowFunc(("hr=%Rhrc\n", hr));
632 return hr;
633}
634
635STDMETHODIMP VBoxClipboardWinDataObject::DAdvise(LPFORMATETC pFormatEtc, DWORD fAdvise, IAdviseSink *pAdvSink, DWORD *pdwConnection)
636{
637 RT_NOREF(pFormatEtc, fAdvise, pAdvSink, pdwConnection);
638 return OLE_E_ADVISENOTSUPPORTED;
639}
640
641STDMETHODIMP VBoxClipboardWinDataObject::DUnadvise(DWORD dwConnection)
642{
643 RT_NOREF(dwConnection);
644 return OLE_E_ADVISENOTSUPPORTED;
645}
646
647STDMETHODIMP VBoxClipboardWinDataObject::EnumDAdvise(IEnumSTATDATA **ppEnumAdvise)
648{
649 RT_NOREF(ppEnumAdvise);
650 return OLE_E_ADVISENOTSUPPORTED;
651}
652
653#ifdef VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC
654/*
655 * IDataObjectAsyncCapability methods.
656 */
657
658STDMETHODIMP VBoxClipboardWinDataObject::EndOperation(HRESULT hResult, IBindCtx *pbcReserved, DWORD dwEffects)
659{
660 RT_NOREF(hResult, pbcReserved, dwEffects);
661 return E_NOTIMPL;
662}
663
664STDMETHODIMP VBoxClipboardWinDataObject::GetAsyncMode(BOOL *pfIsOpAsync)
665{
666 RT_NOREF(pfIsOpAsync);
667 return E_NOTIMPL;
668}
669
670STDMETHODIMP VBoxClipboardWinDataObject::InOperation(BOOL *pfInAsyncOp)
671{
672 RT_NOREF(pfInAsyncOp);
673 return E_NOTIMPL;
674}
675
676STDMETHODIMP VBoxClipboardWinDataObject::SetAsyncMode(BOOL fDoOpAsync)
677{
678 RT_NOREF(fDoOpAsync);
679 return E_NOTIMPL;
680}
681
682STDMETHODIMP VBoxClipboardWinDataObject::StartOperation(IBindCtx *pbcReserved)
683{
684 RT_NOREF(pbcReserved);
685 return E_NOTIMPL;
686}
687#endif /* VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC */
688
689/*
690 * Own stuff.
691 */
692
693int VBoxClipboardWinDataObject::Init(void)
694{
695 LogFlowFuncLeaveRC(VINF_SUCCESS);
696 return VINF_SUCCESS;
697}
698
699void VBoxClipboardWinDataObject::OnTransferComplete(int rc /* = VINF_SUCESS */)
700{
701 RT_NOREF(rc);
702
703 LogFlowFuncLeaveRC(rc);
704}
705
706void VBoxClipboardWinDataObject::OnTransferCanceled(void)
707{
708 LogFlowFuncLeave();
709}
710
711/* static */
712const char* VBoxClipboardWinDataObject::ClipboardFormatToString(CLIPFORMAT fmt)
713{
714#if 0
715 char szFormat[128];
716 if (GetClipboardFormatName(fmt, szFormat, sizeof(szFormat)))
717 LogFlowFunc(("wFormat=%RI16, szName=%s\n", fmt, szFormat));
718#endif
719
720 switch (fmt)
721 {
722
723 case 1:
724 return "CF_TEXT";
725 case 2:
726 return "CF_BITMAP";
727 case 3:
728 return "CF_METAFILEPICT";
729 case 4:
730 return "CF_SYLK";
731 case 5:
732 return "CF_DIF";
733 case 6:
734 return "CF_TIFF";
735 case 7:
736 return "CF_OEMTEXT";
737 case 8:
738 return "CF_DIB";
739 case 9:
740 return "CF_PALETTE";
741 case 10:
742 return "CF_PENDATA";
743 case 11:
744 return "CF_RIFF";
745 case 12:
746 return "CF_WAVE";
747 case 13:
748 return "CF_UNICODETEXT";
749 case 14:
750 return "CF_ENHMETAFILE";
751 case 15:
752 return "CF_HDROP";
753 case 16:
754 return "CF_LOCALE";
755 case 17:
756 return "CF_DIBV5";
757 case 18:
758 return "CF_MAX";
759 case 49158:
760 return "FileName";
761 case 49159:
762 return "FileNameW";
763 case 49161:
764 return "DATAOBJECT";
765 case 49171:
766 return "Ole Private Data";
767 case 49314:
768 return "Shell Object Offsets";
769 case 49316:
770 return "File Contents";
771 case 49317:
772 return "File Group Descriptor";
773 case 49323:
774 return "Preferred Drop Effect";
775 case 49380:
776 return "Shell Object Offsets";
777 case 49382:
778 return "FileContents";
779 case 49383:
780 return "FileGroupDescriptor";
781 case 49389:
782 return "Preferred DropEffect";
783 case 49268:
784 return "Shell IDList Array";
785 case 49619:
786 return "RenPrivateFileAttachments";
787 default:
788 break;
789 }
790
791 return "unknown";
792}
793
794bool VBoxClipboardWinDataObject::lookupFormatEtc(LPFORMATETC pFormatEtc, ULONG *puIndex)
795{
796 AssertReturn(pFormatEtc, false);
797 /* puIndex is optional. */
798
799 for (ULONG i = 0; i < m_cFormats; i++)
800 {
801 if( (pFormatEtc->tymed & m_pFormatEtc[i].tymed)
802 && pFormatEtc->cfFormat == m_pFormatEtc[i].cfFormat)
803 /* Note: Do *not* compare dwAspect here, as this can be dynamic, depending on how the object should be represented. */
804 //&& pFormatEtc->dwAspect == m_pFormatEtc[i].dwAspect)
805 {
806 LogRel3(("Shared Clipboard: Format found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32, ulIndex=%RU32\n",
807 pFormatEtc->tymed, pFormatEtc->cfFormat, VBoxClipboardWinDataObject::ClipboardFormatToString(m_pFormatEtc[i].cfFormat),
808 pFormatEtc->dwAspect, i));
809 if (puIndex)
810 *puIndex = i;
811 return true;
812 }
813 }
814
815 LogRel3(("Shared Clipboard: Format NOT found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32\n",
816 pFormatEtc->tymed, pFormatEtc->cfFormat, VBoxClipboardWinDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
817 pFormatEtc->dwAspect));
818
819 return false;
820}
821
822void VBoxClipboardWinDataObject::registerFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat,
823 TYMED tyMed, LONG lIndex, DWORD dwAspect,
824 DVTARGETDEVICE *pTargetDevice)
825{
826 AssertPtr(pFormatEtc);
827
828 pFormatEtc->cfFormat = clipFormat;
829 pFormatEtc->tymed = tyMed;
830 pFormatEtc->lindex = lIndex;
831 pFormatEtc->dwAspect = dwAspect;
832 pFormatEtc->ptd = pTargetDevice;
833
834 LogFlowFunc(("Registered format=%ld, sFormat=%s\n",
835 pFormatEtc->cfFormat, VBoxClipboardWinDataObject::ClipboardFormatToString(pFormatEtc->cfFormat)));
836}
837
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