VirtualBox

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

Last change on this file since 78474 was 78474, 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: 16.7 KB
Line 
1/* $Id: ClipboardDataObjectImpl-win.cpp 78474 2019-05-13 07:44:15Z 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/path.h>
37#include <iprt/semaphore.h>
38#include <iprt/uri.h>
39#include <iprt/utf16.h>
40
41#include <VBox/err.h>
42#include <VBox/log.h>
43
44VBoxClipboardWinDataObject::VBoxClipboardWinDataObject(LPFORMATETC pFormatEtc, LPSTGMEDIUM pStgMed, ULONG cFormats)
45 : mStatus(Uninitialized)
46 , mRefCount(0)
47 , mcFormats(0)
48 , muClientID(0)
49{
50 HRESULT hr;
51
52 const ULONG cFixedFormats = 3; /* CFSTR_FILEDESCRIPTORA + CFSTR_FILEDESCRIPTORW + CFSTR_FILECONTENTS */
53 const ULONG cAllFormats = cFormats + cFixedFormats;
54
55 try
56 {
57 mpFormatEtc = new FORMATETC[cAllFormats];
58 RT_BZERO(mpFormatEtc, sizeof(FORMATETC) * cAllFormats);
59 mpStgMedium = new STGMEDIUM[cAllFormats];
60 RT_BZERO(mpStgMedium, sizeof(STGMEDIUM) * cAllFormats);
61
62 /** @todo Do we need CFSTR_FILENAME / CFSTR_SHELLIDLIST here? */
63
64 /*
65 * Register fixed formats.
66 */
67
68 /* IStream interface, implemented in ClipboardStreamImpl-win.cpp. */
69 registerFormat(&mpFormatEtc[FormatIndex_FileDescriptorA],
70 RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA));
71 registerFormat(&mpFormatEtc[FormatIndex_FileDescriptorW],
72 RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW));
73 registerFormat(&mpFormatEtc[FormatIndex_FileContents],
74 RegisterClipboardFormat(CFSTR_FILECONTENTS),
75 TYMED_ISTREAM, 0 /* lIndex */);
76
77 /*
78 * Registration of dynamic formats needed?
79 */
80 LogFlowFunc(("%RU32 dynamic formats\n", cFormats));
81 if (cFormats)
82 {
83 AssertPtr(pFormatEtc);
84 AssertPtr(pStgMed);
85
86 for (ULONG i = 0; i < cFormats; i++)
87 {
88 LogFlowFunc(("Format %RU32: cfFormat=%RI16, tyMed=%RU32, dwAspect=%RU32\n",
89 i, pFormatEtc[i].cfFormat, pFormatEtc[i].tymed, pFormatEtc[i].dwAspect));
90 mpFormatEtc[cFixedFormats + i] = pFormatEtc[i];
91 mpStgMedium[cFixedFormats + i] = pStgMed[i];
92 }
93 }
94
95 hr = S_OK;
96 }
97 catch (std::bad_alloc &)
98 {
99 hr = E_OUTOFMEMORY;
100 }
101
102 if (SUCCEEDED(hr))
103 {
104 mcFormats = cAllFormats;
105 mStatus = Initialized;
106 }
107
108 LogFlowFunc(("cAllFormats=%RU32, hr=%Rhrc\n", cAllFormats, hr));
109}
110
111VBoxClipboardWinDataObject::~VBoxClipboardWinDataObject(void)
112{
113 if (mpStream)
114 mpStream->Release();
115
116 if (mpFormatEtc)
117 delete[] mpFormatEtc;
118
119 if (mpStgMedium)
120 delete[] mpStgMedium;
121
122 LogFlowFunc(("mRefCount=%RI32\n", mRefCount));
123}
124
125/*
126 * IUnknown methods.
127 */
128
129STDMETHODIMP_(ULONG) VBoxClipboardWinDataObject::AddRef(void)
130{
131 LONG lCount = InterlockedIncrement(&mRefCount);
132 LogFlowFunc(("lCount=%RI32\n", lCount));
133 return lCount;
134}
135
136STDMETHODIMP_(ULONG) VBoxClipboardWinDataObject::Release(void)
137{
138 LONG lCount = InterlockedDecrement(&mRefCount);
139 LogFlowFunc(("lCount=%RI32\n", mRefCount));
140 if (lCount == 0)
141 {
142 delete this;
143 return 0;
144 }
145
146 return lCount;
147}
148
149STDMETHODIMP VBoxClipboardWinDataObject::QueryInterface(REFIID iid, void **ppvObject)
150{
151 AssertPtrReturn(ppvObject, E_INVALIDARG);
152
153 if ( iid == IID_IDataObject
154 || iid == IID_IUnknown)
155 {
156 AddRef();
157 *ppvObject = this;
158 return S_OK;
159 }
160
161 *ppvObject = 0;
162 return E_NOINTERFACE;
163}
164
165int VBoxClipboardWinDataObject::copyToHGlobal(const void *pvData, size_t cbData, UINT fFlags, HGLOBAL *phGlobal)
166{
167 AssertPtrReturn(phGlobal, VERR_INVALID_POINTER);
168
169 HGLOBAL hGlobal = GlobalAlloc(fFlags, cbData);
170 if (!hGlobal)
171 return VERR_NO_MEMORY;
172
173 void *pvAlloc = GlobalLock(hGlobal);
174 if (pvAlloc)
175 {
176 CopyMemory(pvAlloc, pvData, cbData);
177 GlobalUnlock(hGlobal);
178
179 *phGlobal = hGlobal;
180
181 return VINF_SUCCESS;
182 }
183
184 GlobalFree(hGlobal);
185 return VERR_ACCESS_DENIED;
186}
187
188int VBoxClipboardWinDataObject::createFileGroupDescriptor(const SharedClipboardURIList &URIList, HGLOBAL *phGlobal)
189{
190// AssertReturn(URIList.GetRootCount(), VERR_INVALID_PARAMETER);
191 AssertPtrReturn(phGlobal, VERR_INVALID_POINTER);
192
193 int rc;
194
195 const size_t cItems = 2; URIList.GetRootCount();
196 const size_t cbFGD = sizeof(FILEGROUPDESCRIPTOR) + sizeof(FILEDESCRIPTOR) * (cItems - 1);
197
198 LogFunc(("cItmes=%zu\n", cItems));
199
200 FILEGROUPDESCRIPTOR *pFGD = (FILEGROUPDESCRIPTOR *)RTMemAlloc(cbFGD);
201 if (pFGD)
202 {
203 pFGD->cItems = (UINT)cItems;
204
205
206 FILEDESCRIPTOR *pFD = &pFGD->fgd[0];
207 RT_BZERO(pFD, sizeof(FILEDESCRIPTOR));
208
209 RTStrPrintf(pFD->cFileName, sizeof(pFD->cFileName), "barbaz.txt\n");
210
211 #if 1
212 pFD->dwFlags = FD_ATTRIBUTES | FD_FILESIZE | FD_PROGRESSUI;
213 pFD->dwFileAttributes = FILE_ATTRIBUTE_NORMAL; // FILE_ATTRIBUTE_DIRECTORY;
214
215 uint64_t cbSize = _1M;
216
217 pFD->nFileSizeHigh = RT_HI_U32(cbSize);
218 pFD->nFileSizeLow = RT_LO_U32(cbSize);
219 #else
220 pFD->dwFlags = FD_ATTRIBUTES | FD_CREATETIME | FD_ACCESSTIME | FD_WRITESTIME | FD_FILESIZE;
221 pFD->dwFileAttributes =
222 pFD->ftCreationTime =
223 pFD->ftLastAccessTime =
224 pFD->ftLastWriteTime =
225 pFD->nFileSizeHigh =
226 pFD->nFileSizeLow =
227 #endif
228
229
230
231 pFD = &pFGD->fgd[1];
232 RT_BZERO(pFD, sizeof(FILEDESCRIPTOR));
233
234 RTStrPrintf(pFD->cFileName, sizeof(pFD->cFileName), "barbaz_dir\n");
235
236 #if 1
237 pFD->dwFlags = FD_ATTRIBUTES | FD_PROGRESSUI;
238 pFD->dwFileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY;
239 #else
240 pFD->dwFlags = FD_ATTRIBUTES | FD_CREATETIME | FD_ACCESSTIME | FD_WRITESTIME | FD_FILESIZE;
241 pFD->dwFileAttributes =
242 pFD->ftCreationTime =
243 pFD->ftLastAccessTime =
244 pFD->ftLastWriteTime =
245 pFD->nFileSizeHigh =
246 pFD->nFileSizeLow =
247 #endif
248
249
250 rc = copyToHGlobal(pFGD, cbFGD, GMEM_MOVEABLE, phGlobal);
251 }
252 else
253 rc = VERR_NO_MEMORY;
254
255 return rc;
256}
257
258/**
259 * Retrieves the data stored in this object and store the result in
260 * pMedium.
261 *
262 * @return IPRT status code.
263 * @return HRESULT
264 * @param pFormatEtc
265 * @param pMedium
266 */
267STDMETHODIMP VBoxClipboardWinDataObject::GetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium)
268{
269 AssertPtrReturn(pFormatEtc, DV_E_FORMATETC);
270 AssertPtrReturn(pMedium, DV_E_FORMATETC);
271
272 LogFlowFuncEnter();
273
274 ULONG lIndex;
275 if (!lookupFormatEtc(pFormatEtc, &lIndex)) /* Format supported? */
276 return DV_E_FORMATETC;
277 if (lIndex >= mcFormats) /* Paranoia. */
278 return DV_E_LINDEX;
279
280 LPFORMATETC pThisFormat = &mpFormatEtc[lIndex];
281 AssertPtr(pThisFormat);
282
283 LPSTGMEDIUM pThisMedium = &mpStgMedium[lIndex];
284 AssertPtr(pThisMedium);
285
286 LogFlowFunc(("Using pThisFormat=%p, pThisMedium=%p\n", pThisFormat, pThisMedium));
287
288 HRESULT hr = DV_E_FORMATETC; /* Play safe. */
289
290 LogRel3(("Clipboard: cfFormat=%RI16, sFormat=%s, tyMed=%RU32, dwAspect=%RU32 -> lIndex=%u\n",
291 pThisFormat->cfFormat, VBoxClipboardWinDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
292 pThisFormat->tymed, pThisFormat->dwAspect, lIndex));
293
294 /*
295 * Initialize default values.
296 */
297 pMedium->tymed = pThisFormat->tymed;
298 pMedium->pUnkForRelease = NULL; /* Caller is responsible for deleting the data. */
299
300 switch (lIndex)
301 {
302 case FormatIndex_FileDescriptorA:
303 {
304 LogFlowFunc(("FormatIndex_FileDescriptorA\n"));
305
306 SharedClipboardURIList mURIList;
307 // mURIList.AppendURIPath()
308
309 HGLOBAL hGlobal;
310 int rc = createFileGroupDescriptor(mURIList, &hGlobal);
311 if (RT_SUCCESS(rc))
312 {
313 pMedium->tymed = TYMED_HGLOBAL;
314 pMedium->hGlobal = hGlobal;
315
316 hr = S_OK;
317 }
318 break;
319 }
320
321 case FormatIndex_FileDescriptorW:
322 LogFlowFunc(("FormatIndex_FileDescriptorW\n"));
323 break;
324
325 case FormatIndex_FileContents:
326 {
327 LogFlowFunc(("FormatIndex_FileContents\n"));
328
329 hr = VBoxClipboardWinStreamImpl::Create(&mpStream);
330 if (SUCCEEDED(hr))
331 {
332 /* Hand over the stream to the caller. */
333 pMedium->tymed = TYMED_ISTREAM;
334 pMedium->pstm = mpStream;
335 }
336
337 break;
338 }
339
340 default:
341 break;
342 }
343
344 /* Error handling; at least return some basic data. */
345 if (FAILED(hr))
346 {
347 LogFunc(("Failed; copying medium ...\n"));
348
349 pMedium->tymed = pThisFormat->tymed;
350 pMedium->pUnkForRelease = NULL;
351 }
352
353 if (hr == DV_E_FORMATETC)
354 LogRel(("Clipboard: Error handling format\n"));
355
356 LogFlowFunc(("hr=%Rhrc\n", hr));
357 return hr;
358}
359
360/**
361 * Only required for IStream / IStorage interfaces.
362 *
363 * @return IPRT status code.
364 * @return HRESULT
365 * @param pFormatEtc
366 * @param pMedium
367 */
368STDMETHODIMP VBoxClipboardWinDataObject::GetDataHere(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium)
369{
370 RT_NOREF(pFormatEtc, pMedium);
371 LogFlowFunc(("\n"));
372 return E_NOTIMPL;
373}
374
375/**
376 * Query if this objects supports a specific format.
377 *
378 * @return IPRT status code.
379 * @return HRESULT
380 * @param pFormatEtc
381 */
382STDMETHODIMP VBoxClipboardWinDataObject::QueryGetData(LPFORMATETC pFormatEtc)
383{
384 LogFlowFunc(("\n"));
385 return (lookupFormatEtc(pFormatEtc, NULL /* puIndex */)) ? S_OK : DV_E_FORMATETC;
386}
387
388STDMETHODIMP VBoxClipboardWinDataObject::GetCanonicalFormatEtc(LPFORMATETC pFormatEtc, LPFORMATETC pFormatEtcOut)
389{
390 RT_NOREF(pFormatEtc);
391 LogFlowFunc(("\n"));
392
393 /* Set this to NULL in any case. */
394 pFormatEtcOut->ptd = NULL;
395 return E_NOTIMPL;
396}
397
398STDMETHODIMP VBoxClipboardWinDataObject::SetData(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium, BOOL fRelease)
399{
400 RT_NOREF(pFormatEtc, pMedium, fRelease);
401 LogFlowFunc(("\n"));
402
403 return E_NOTIMPL;
404}
405
406STDMETHODIMP VBoxClipboardWinDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc)
407{
408 LogFlowFunc(("dwDirection=%RI32, mcFormats=%RI32, mpFormatEtc=%p\n", dwDirection, mcFormats, mpFormatEtc));
409
410 HRESULT hr;
411 if (dwDirection == DATADIR_GET)
412 hr = VBoxClipboardWinEnumFormatEtc::CreateEnumFormatEtc(mcFormats, mpFormatEtc, ppEnumFormatEtc);
413 else
414 hr = E_NOTIMPL;
415
416 LogFlowFunc(("hr=%Rhrc\n", hr));
417 return hr;
418}
419
420STDMETHODIMP VBoxClipboardWinDataObject::DAdvise(LPFORMATETC pFormatEtc, DWORD fAdvise, IAdviseSink *pAdvSink, DWORD *pdwConnection)
421{
422 RT_NOREF(pFormatEtc, fAdvise, pAdvSink, pdwConnection);
423 return OLE_E_ADVISENOTSUPPORTED;
424}
425
426STDMETHODIMP VBoxClipboardWinDataObject::DUnadvise(DWORD dwConnection)
427{
428 RT_NOREF(dwConnection);
429 return OLE_E_ADVISENOTSUPPORTED;
430}
431
432STDMETHODIMP VBoxClipboardWinDataObject::EnumDAdvise(IEnumSTATDATA **ppEnumAdvise)
433{
434 RT_NOREF(ppEnumAdvise);
435 return OLE_E_ADVISENOTSUPPORTED;
436}
437
438#ifdef VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC
439/*
440 * IDataObjectAsyncCapability methods.
441 */
442
443STDMETHODIMP VBoxClipboardWinDataObject::EndOperation(HRESULT hResult, IBindCtx* pbcReserved, DWORD dwEffects)
444{
445 RT_NOREF(hResult, pbcReserved, dwEffects);
446 return E_NOTIMPL;
447}
448
449STDMETHODIMP VBoxClipboardWinDataObject::GetAsyncMode(BOOL* pfIsOpAsync)
450{
451 RT_NOREF(pfIsOpAsync);
452 return E_NOTIMPL;
453}
454
455STDMETHODIMP VBoxClipboardWinDataObject::InOperation(BOOL* pfInAsyncOp)
456{
457 RT_NOREF(pfInAsyncOp);
458 return E_NOTIMPL;
459}
460
461STDMETHODIMP VBoxClipboardWinDataObject::SetAsyncMode(BOOL fDoOpAsync)
462{
463 RT_NOREF(fDoOpAsync);
464 return E_NOTIMPL;
465}
466
467STDMETHODIMP VBoxClipboardWinDataObject::StartOperation(IBindCtx* pbcReserved)
468{
469 RT_NOREF(pbcReserved);
470 return E_NOTIMPL;
471}
472#endif /* VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC */
473
474/*
475 * Own stuff.
476 */
477
478int VBoxClipboardWinDataObject::Init(uint32_t idClient)
479{
480 muClientID = idClient;
481
482 LogFlowFuncLeaveRC(VINF_SUCCESS);
483 return VINF_SUCCESS;
484}
485
486/* static */
487const char* VBoxClipboardWinDataObject::ClipboardFormatToString(CLIPFORMAT fmt)
488{
489#if 0
490 char szFormat[128];
491 if (GetClipboardFormatName(fmt, szFormat, sizeof(szFormat)))
492 LogFlowFunc(("wFormat=%RI16, szName=%s\n", fmt, szFormat));
493#endif
494
495 switch (fmt)
496 {
497
498 case 1:
499 return "CF_TEXT";
500 case 2:
501 return "CF_BITMAP";
502 case 3:
503 return "CF_METAFILEPICT";
504 case 4:
505 return "CF_SYLK";
506 case 5:
507 return "CF_DIF";
508 case 6:
509 return "CF_TIFF";
510 case 7:
511 return "CF_OEMTEXT";
512 case 8:
513 return "CF_DIB";
514 case 9:
515 return "CF_PALETTE";
516 case 10:
517 return "CF_PENDATA";
518 case 11:
519 return "CF_RIFF";
520 case 12:
521 return "CF_WAVE";
522 case 13:
523 return "CF_UNICODETEXT";
524 case 14:
525 return "CF_ENHMETAFILE";
526 case 15:
527 return "CF_HDROP";
528 case 16:
529 return "CF_LOCALE";
530 case 17:
531 return "CF_DIBV5";
532 case 18:
533 return "CF_MAX";
534 case 49158:
535 return "FileName";
536 case 49159:
537 return "FileNameW";
538 case 49161:
539 return "DATAOBJECT";
540 case 49171:
541 return "Ole Private Data";
542 case 49314:
543 return "Shell Object Offsets";
544 case 49316:
545 return "File Contents";
546 case 49317:
547 return "File Group Descriptor";
548 case 49323:
549 return "Preferred Drop Effect";
550 case 49380:
551 return "Shell Object Offsets";
552 case 49382:
553 return "FileContents";
554 case 49383:
555 return "FileGroupDescriptor";
556 case 49389:
557 return "Preferred DropEffect";
558 case 49268:
559 return "Shell IDList Array";
560 case 49619:
561 return "RenPrivateFileAttachments";
562 default:
563 break;
564 }
565
566 return "unknown";
567}
568
569bool VBoxClipboardWinDataObject::lookupFormatEtc(LPFORMATETC pFormatEtc, ULONG *puIndex)
570{
571 AssertReturn(pFormatEtc, false);
572 /* puIndex is optional. */
573
574 for (ULONG i = 0; i < mcFormats; i++)
575 {
576 if( (pFormatEtc->tymed & mpFormatEtc[i].tymed)
577 && pFormatEtc->cfFormat == mpFormatEtc[i].cfFormat
578 && pFormatEtc->dwAspect == mpFormatEtc[i].dwAspect)
579 {
580 LogRel3(("Clipboard: Format found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32, ulIndex=%RU32\n",
581 pFormatEtc->tymed, pFormatEtc->cfFormat, VBoxClipboardWinDataObject::ClipboardFormatToString(mpFormatEtc[i].cfFormat),
582 pFormatEtc->dwAspect, i));
583 if (puIndex)
584 *puIndex = i;
585 return true;
586 }
587 }
588
589 LogRel3(("Clipboard: Format NOT found: tyMed=%RI32, cfFormat=%RI16, sFormats=%s, dwAspect=%RI32\n",
590 pFormatEtc->tymed, pFormatEtc->cfFormat, VBoxClipboardWinDataObject::ClipboardFormatToString(pFormatEtc->cfFormat),
591 pFormatEtc->dwAspect));
592
593 return false;
594}
595
596void VBoxClipboardWinDataObject::registerFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat,
597 TYMED tyMed, LONG lIndex, DWORD dwAspect,
598 DVTARGETDEVICE *pTargetDevice)
599{
600 AssertPtr(pFormatEtc);
601
602 pFormatEtc->cfFormat = clipFormat;
603 pFormatEtc->tymed = tyMed;
604 pFormatEtc->lindex = lIndex;
605 pFormatEtc->dwAspect = dwAspect;
606 pFormatEtc->ptd = pTargetDevice;
607
608 LogFlowFunc(("Registered format=%ld, sFormat=%s\n",
609 pFormatEtc->cfFormat, VBoxClipboardWinDataObject::ClipboardFormatToString(pFormatEtc->cfFormat)));
610}
611
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