VirtualBox

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

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

Shared Clipboard/URI: Update; more work on root list handling.

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