VirtualBox

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

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