VirtualBox

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

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

Shared Clipboard/URI: More work on context IDs and entry list handling.

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