VirtualBox

source: vbox/trunk/include/VBox/GuestHost/SharedClipboard-win.h@ 100394

Last change on this file since 100394 was 100394, checked in by vboxsync, 22 months ago

Shared Clipboard: Also use the transfers callbacks for the Windows data object implementation. WIP. ​​bugref:9437

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.7 KB
Line 
1/** @file
2 * Shared Clipboard - Common Guest and Host Code, for Windows OSes.
3 */
4
5/*
6 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
7 *
8 * This file is part of VirtualBox base platform packages, as
9 * available from https://www.virtualbox.org.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation, in version 3 of the
14 * License.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <https://www.gnu.org/licenses>.
23 *
24 * The contents of this file may alternatively be used under the terms
25 * of the Common Development and Distribution License Version 1.0
26 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
27 * in the VirtualBox distribution, in which case the provisions of the
28 * CDDL are applicable instead of those of the GPL.
29 *
30 * You may elect to license modified versions of this file under the
31 * terms and conditions of either the GPL or the CDDL or both.
32 *
33 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
34 */
35
36#ifndef VBOX_INCLUDED_GuestHost_SharedClipboard_win_h
37#define VBOX_INCLUDED_GuestHost_SharedClipboard_win_h
38#ifndef RT_WITHOUT_PRAGMA_ONCE
39# pragma once
40#endif
41
42#include <iprt/critsect.h>
43#include <iprt/types.h>
44#include <iprt/req.h>
45#include <iprt/win/windows.h>
46
47#include <VBox/GuestHost/SharedClipboard.h>
48
49# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
50# include <vector>
51
52# include <iprt/cpp/ministring.h> /* For RTCString. */
53# include <iprt/win/shlobj.h> /* For DROPFILES and friends. */
54# include <VBox/com/string.h> /* For Utf8Str. */
55# include <oleidl.h>
56
57# include <VBox/GuestHost/SharedClipboard-transfers.h>
58
59using namespace com;
60# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
61
62#ifndef WM_CLIPBOARDUPDATE
63# define WM_CLIPBOARDUPDATE 0x031D
64#endif
65
66#define SHCL_WIN_WNDCLASS_NAME "VBoxSharedClipboardClass"
67
68/** See: https://docs.microsoft.com/en-us/windows/desktop/dataxchg/html-clipboard-format
69 * Do *not* change the name, as this will break compatbility with other (legacy) applications! */
70#define SHCL_WIN_REGFMT_HTML "HTML Format"
71
72/** Default timeout (in ms) for passing down messages down the clipboard chain. */
73#define SHCL_WIN_CBCHAIN_TIMEOUT_MS 5000
74
75/** Reports clipboard formats. */
76#define SHCL_WIN_WM_REPORT_FORMATS WM_USER
77/** Reads data from the clipboard and sends it to the destination. */
78#define SHCL_WIN_WM_READ_DATA WM_USER + 1
79#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
80/** Starts a transfer on the guest.
81 * This creates the necessary IDataObject in the matching window thread. */
82# define SHCL_WIN_WM_TRANSFER_START WM_USER + 2
83#endif
84
85/* Dynamically load clipboard functions from User32.dll. */
86typedef BOOL WINAPI FNADDCLIPBOARDFORMATLISTENER(HWND);
87typedef FNADDCLIPBOARDFORMATLISTENER *PFNADDCLIPBOARDFORMATLISTENER;
88
89typedef BOOL WINAPI FNREMOVECLIPBOARDFORMATLISTENER(HWND);
90typedef FNREMOVECLIPBOARDFORMATLISTENER *PFNREMOVECLIPBOARDFORMATLISTENER;
91
92/**
93 * Structure for keeping function pointers for the new clipboard API.
94 * If the new API is not available, those function pointer are NULL.
95 */
96typedef struct _SHCLWINAPINEW
97{
98 PFNADDCLIPBOARDFORMATLISTENER pfnAddClipboardFormatListener;
99 PFNREMOVECLIPBOARDFORMATLISTENER pfnRemoveClipboardFormatListener;
100} SHCLWINAPINEW, *PSHCLWINAPINEW;
101
102/**
103 * Structure for keeping variables which are needed to drive the old clipboard API.
104 */
105typedef struct _SHCLWINAPIOLD
106{
107 /** Timer ID for the refresh timer. */
108 UINT timerRefresh;
109 /** Whether "pinging" the clipboard chain currently is in progress or not. */
110 bool fCBChainPingInProcess;
111} SHCLWINAPIOLD, *PSHCLWINAPIOLD;
112
113#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
114/** Forward declaration for the Windows data object. */
115class SharedClipboardWinDataObject;
116#endif
117
118/**
119 * Structure for maintaining a Shared Clipboard context on Windows platforms.
120 */
121typedef struct _SHCLWINCTX
122{
123 /** Critical section to serialize access. */
124 RTCRITSECT CritSect;
125 /** Window handle of our (invisible) clipbaord window. */
126 HWND hWnd;
127 /** Window handle which is next to us in the clipboard chain. */
128 HWND hWndNextInChain;
129 /** Window handle of the clipboard owner *if* we are the owner.
130 * @todo r=bird: Ignore the misleading statement above. This is only set to
131 * NULL by the initialization code and then it's set to the clipboard owner
132 * after we announce data to the clipboard. So, essentially this will be our
133 * windows handle or NULL. End of story. */
134 HWND hWndClipboardOwnerUs;
135 /** Structure for maintaining the new clipboard API. */
136 SHCLWINAPINEW newAPI;
137 /** Structure for maintaining the old clipboard API. */
138 SHCLWINAPIOLD oldAPI;
139#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
140 /** The "in-flight" data object for file transfers.
141 * This is the current data object which has been created and sent to the Windows clipboard.
142 * That way Windows knows that a potential file transfer is available, but the actual transfer
143 * hasn't been started yet.
144 * Can be NULL if currently not being used / no current "in-flight" transfer present. */
145 SharedClipboardWinDataObject
146 *pDataObjInFlight;
147#endif
148 /** Request queue.
149 * Needed for processing HGCM requests within the HGCM (main) thread from the Windows event thread. */
150 RTREQQUEUE hReqQ;
151} SHCLWINCTX, *PSHCLWINCTX;
152
153int SharedClipboardWinOpen(HWND hWnd);
154int SharedClipboardWinClose(void);
155int SharedClipboardWinClear(void);
156
157int SharedClipboardWinCtxInit(PSHCLWINCTX pWinCtx);
158void SharedClipboardWinCtxDestroy(PSHCLWINCTX pWinCtx);
159
160int SharedClipboardWinCheckAndInitNewAPI(PSHCLWINAPINEW pAPI);
161bool SharedClipboardWinIsNewAPI(PSHCLWINAPINEW pAPI);
162
163int SharedClipboardWinDataWrite(UINT cfFormat, void *pvData, uint32_t cbData);
164
165int SharedClipboardWinChainAdd(PSHCLWINCTX pCtx);
166int SharedClipboardWinChainRemove(PSHCLWINCTX pCtx);
167VOID CALLBACK SharedClipboardWinChainPingProc(HWND hWnd, UINT uMsg, ULONG_PTR dwData, LRESULT lResult) RT_NOTHROW_DEF;
168LRESULT SharedClipboardWinChainPassToNext(PSHCLWINCTX pWinCtx, UINT msg, WPARAM wParam, LPARAM lParam);
169
170SHCLFORMAT SharedClipboardWinClipboardFormatToVBox(UINT uFormat);
171int SharedClipboardWinGetFormats(PSHCLWINCTX pCtx, PSHCLFORMATS pfFormats);
172
173int SharedClipboardWinGetCFHTMLHeaderValue(const char *pszSrc, const char *pszOption, uint32_t *puValue);
174bool SharedClipboardWinIsCFHTML(const char *pszSource);
175int SharedClipboardWinConvertCFHTMLToMIME(const char *pszSource, const uint32_t cch, char **ppszOutput, uint32_t *pcbOutput);
176int SharedClipboardWinConvertMIMEToCFHTML(const char *pszSource, size_t cb, char **ppszOutput, uint32_t *pcbOutput);
177
178LRESULT SharedClipboardWinHandleWMChangeCBChain(PSHCLWINCTX pWinCtx, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
179int SharedClipboardWinHandleWMDestroy(PSHCLWINCTX pWinCtx);
180int SharedClipboardWinHandleWMRenderAllFormats(PSHCLWINCTX pWinCtx, HWND hWnd);
181int SharedClipboardWinHandleWMTimer(PSHCLWINCTX pWinCtx);
182
183int SharedClipboardWinClearAndAnnounceFormats(PSHCLWINCTX pWinCtx, SHCLFORMATS fFormats, HWND hWnd);
184
185#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
186class SharedClipboardTransferList;
187# ifndef FILEGROUPDESCRIPTOR
188class FILEGROUPDESCRIPTOR;
189# endif
190
191/**
192 * Generic Windows class implementing IDataObject for Shared Clipboard data transfers.
193 */
194class SharedClipboardWinDataObject : public IDataObject //, public IDataObjectAsyncCapability
195{
196public:
197
198 /**
199 * Structure for keeping a data object callback context.
200 */
201 struct CALLBACKCTX
202 {
203 /** Pointer to the data object of this callback. */
204 SharedClipboardWinDataObject *pThis;
205 /** User-supplied pointer to more context data. */
206 void *pvUser;
207 };
208 /** Pointer to a Shared Clipboard Windows data object callback table. */
209 typedef CALLBACKCTX *PCALLBACKCTX;
210
211 /**
212 * @name Shared Clipboard Windows data object callback table.
213 */
214 struct CALLBACKS
215 {
216 /**
217 * Called by the data object if a transfer needs to be started.
218 *
219 * @returns VBox status code.
220 * @param pCbCtx Pointer to callback context.
221 */
222 DECLCALLBACKMEMBER(int, pfnTransferStart, (PCALLBACKCTX pCbCtx));
223 };
224 /** Pointer to a Shared Clipboard Windows data object callback table. */
225 typedef CALLBACKS *PCALLBACKS;
226
227 enum Status
228 {
229 /** The object is uninitialized (not ready). */
230 Uninitialized = 0,
231 /** The object is initialized and ready to use.
232 * A transfer is *not* running yet! */
233 Initialized,
234 /** Transfer is running. */
235 Running,
236 /** The operation has been successfully completed. */
237 Completed,
238 /** The operation has been canceled. */
239 Canceled,
240 /** An (unrecoverable) error occurred. */
241 Error
242 };
243
244public:
245
246 SharedClipboardWinDataObject(void);
247 virtual ~SharedClipboardWinDataObject(void);
248
249public:
250
251 int Init(PSHCLCONTEXT pCtx, SharedClipboardWinDataObject::PCALLBACKS pCallbacks, LPFORMATETC pFormatEtc = NULL, LPSTGMEDIUM pStgMed = NULL, ULONG cFormats = 0);
252 void Destroy(void);
253
254public: /* IUnknown methods. */
255
256 STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject);
257 STDMETHOD_(ULONG, AddRef)(void);
258 STDMETHOD_(ULONG, Release)(void);
259
260public: /* IDataObject methods. */
261
262 STDMETHOD(GetData)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium);
263 STDMETHOD(GetDataHere)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium);
264 STDMETHOD(QueryGetData)(LPFORMATETC pFormatEtc);
265 STDMETHOD(GetCanonicalFormatEtc)(LPFORMATETC pFormatEct, LPFORMATETC pFormatEtcOut);
266 STDMETHOD(SetData)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium, BOOL fRelease);
267 STDMETHOD(EnumFormatEtc)(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc);
268 STDMETHOD(DAdvise)(LPFORMATETC pFormatEtc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
269 STDMETHOD(DUnadvise)(DWORD dwConnection);
270 STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppEnumAdvise);
271
272#ifdef VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC
273public: /* IDataObjectAsyncCapability methods. */
274
275 STDMETHOD(EndOperation)(HRESULT hResult, IBindCtx* pbcReserved, DWORD dwEffects);
276 STDMETHOD(GetAsyncMode)(BOOL* pfIsOpAsync);
277 STDMETHOD(InOperation)(BOOL* pfInAsyncOp);
278 STDMETHOD(SetAsyncMode)(BOOL fDoOpAsync);
279 STDMETHOD(StartOperation)(IBindCtx* pbcReserved);
280#endif /* VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC */
281
282public:
283
284 int SetTransfer(PSHCLTRANSFER pTransfer);
285 int SetStatus(Status enmStatus, int rcSts = VINF_SUCCESS);
286
287public:
288
289 static DECLCALLBACK(int) readThread(RTTHREAD ThreadSelf, void *pvUser);
290
291 static void logFormat(CLIPFORMAT fmt);
292
293protected:
294
295 static int Thread(RTTHREAD hThread, void *pvUser);
296
297 int readDir(PSHCLTRANSFER pTransfer, const Utf8Str &strPath);
298
299 int copyToHGlobal(const void *pvData, size_t cbData, UINT fFlags, HGLOBAL *phGlobal);
300 int createFileGroupDescriptorFromTransfer(PSHCLTRANSFER pTransfer,
301 bool fUnicode, HGLOBAL *phGlobal);
302
303 bool lookupFormatEtc(LPFORMATETC pFormatEtc, ULONG *puIndex);
304 void registerFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat, TYMED tyMed = TYMED_HGLOBAL,
305 LONG lindex = -1, DWORD dwAspect = DVASPECT_CONTENT, DVTARGETDEVICE *pTargetDevice = NULL);
306 int setStatusLocked(Status enmStatus, int rc = VINF_SUCCESS);
307
308protected:
309
310 /**
311 * Structure for keeping a single file system object entry.
312 */
313 struct FSOBJENTRY
314 {
315 /** Relative path of the object. */
316 char *pszPath;
317 /** Related (cached) object information. */
318 SHCLFSOBJINFO objInfo;
319 };
320
321 /** Vector containing file system objects with its (cached) objection information. */
322 typedef std::vector<FSOBJENTRY> FsObjEntryList;
323
324 /** Shared Clipboard context to use. */
325 PSHCLCONTEXT m_pCtx;
326 /** The object's current status. */
327 Status m_enmStatus;
328 /** Data object callback table to use. */
329 CALLBACKS m_Callbacks;
330 /** Data object callback table context to use. */
331 CALLBACKCTX m_CallbackCtx;
332 /** The object's current reference count. */
333 LONG m_lRefCount;
334 /** How many formats have been registered. */
335 ULONG m_cFormats;
336 LPFORMATETC m_pFormatEtc;
337 LPSTGMEDIUM m_pStgMedium;
338 /** Pointer to the associated transfer object being handled. */
339 PSHCLTRANSFER m_pTransfer;
340 /** Current stream object being used. */
341 IStream *m_pStream;
342 /** Current object index being handled by the data object.
343 * This is needed to create the next IStream object for e.g. the next upcoming file/dir/++ in the transfer. */
344 ULONG m_uObjIdx;
345 /** List of (cached) file system objects. */
346 FsObjEntryList m_lstEntries;
347 /** Critical section to serialize access. */
348 RTCRITSECT m_CritSect;
349 /** Whether the transfer thread is running. */
350 bool m_fThreadRunning;
351 /** Event being triggered when reading the transfer list been completed. */
352 RTSEMEVENT m_EventListComplete;
353 /** Event being triggered when the transfer status has been changed. */
354 RTSEMEVENT m_EventStatusChanged;
355 /** Registered format for CFSTR_FILEDESCRIPTORA. */
356 UINT m_cfFileDescriptorA;
357 /** Registered format for CFSTR_FILEDESCRIPTORW. */
358 UINT m_cfFileDescriptorW;
359 /** Registered format for CFSTR_FILECONTENTS. */
360 UINT m_cfFileContents;
361 /** Registered format for CFSTR_PERFORMEDDROPEFFECT. */
362 UINT m_cfPerformedDropEffect;
363};
364
365/**
366 * Generic Windows class implementing IEnumFORMATETC for Shared Clipboard data transfers.
367 */
368class SharedClipboardWinEnumFormatEtc : public IEnumFORMATETC
369{
370public:
371
372 SharedClipboardWinEnumFormatEtc(void);
373 virtual ~SharedClipboardWinEnumFormatEtc(void);
374
375public:
376
377 int Init(LPFORMATETC pFormatEtc, ULONG cFormats);
378 void Destroy(void);
379
380public: /* IUnknown methods. */
381
382 STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject);
383 STDMETHOD_(ULONG, AddRef)(void);
384 STDMETHOD_(ULONG, Release)(void);
385
386public: /* IEnumFORMATETC methods. */
387
388 STDMETHOD(Next)(ULONG cFormats, LPFORMATETC pFormatEtc, ULONG *pcFetched);
389 STDMETHOD(Skip)(ULONG cFormats);
390 STDMETHOD(Reset)(void);
391 STDMETHOD(Clone)(IEnumFORMATETC **ppEnumFormatEtc);
392
393public:
394
395 static void CopyFormat(LPFORMATETC pFormatDest, LPFORMATETC pFormatSource);
396 static HRESULT CreateEnumFormatEtc(UINT cFormats, LPFORMATETC pFormatEtc, IEnumFORMATETC **ppEnumFormatEtc);
397
398private:
399
400 LONG m_lRefCount;
401 ULONG m_nIndex;
402 ULONG m_nNumFormats;
403 LPFORMATETC m_pFormatEtc;
404};
405
406/**
407 * Generic Windows class implementing IStream for Shared Clipboard data transfers.
408 */
409class SharedClipboardWinStreamImpl : public IStream
410{
411public:
412
413 SharedClipboardWinStreamImpl(SharedClipboardWinDataObject *pParent, PSHCLTRANSFER pTransfer,
414 const Utf8Str &strPath, PSHCLFSOBJINFO pObjInfo);
415 virtual ~SharedClipboardWinStreamImpl(void);
416
417public: /* IUnknown methods. */
418
419 STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject);
420 STDMETHOD_(ULONG, AddRef)(void);
421 STDMETHOD_(ULONG, Release)(void);
422
423public: /* IStream methods. */
424
425 STDMETHOD(Clone)(IStream** ppStream);
426 STDMETHOD(Commit)(DWORD dwFrags);
427 STDMETHOD(CopyTo)(IStream* pDestStream, ULARGE_INTEGER nBytesToCopy, ULARGE_INTEGER* nBytesRead, ULARGE_INTEGER* nBytesWritten);
428 STDMETHOD(LockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes,DWORD dwFlags);
429 STDMETHOD(Read)(void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead);
430 STDMETHOD(Revert)(void);
431 STDMETHOD(Seek)(LARGE_INTEGER nMove, DWORD dwOrigin, ULARGE_INTEGER* nNewPos);
432 STDMETHOD(SetSize)(ULARGE_INTEGER nNewSize);
433 STDMETHOD(Stat)(STATSTG* statstg, DWORD dwFlags);
434 STDMETHOD(UnlockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes, DWORD dwFlags);
435 STDMETHOD(Write)(const void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead);
436
437public: /* Own methods. */
438
439 static HRESULT Create(SharedClipboardWinDataObject *pParent, PSHCLTRANSFER pTransfer, const Utf8Str &strPath,
440 PSHCLFSOBJINFO pObjInfo, IStream **ppStream);
441private:
442
443 /** Pointer to the parent data object. */
444 SharedClipboardWinDataObject *m_pParent;
445 /** The stream object's current reference count. */
446 LONG m_lRefCount;
447 /** Pointer to the associated Shared Clipboard transfer. */
448 PSHCLTRANSFER m_pTransfer;
449 /** The object handle to use. */
450 SHCLOBJHANDLE m_hObj;
451 /** Object path. */
452 Utf8Str m_strPath;
453 /** (Cached) object information. */
454 SHCLFSOBJINFO m_objInfo;
455 /** Number of bytes already processed. */
456 uint64_t m_cbProcessed;
457 /** Whether this object already is in completed state or not. */
458 bool m_fIsComplete;
459};
460
461/**
462 * Class for Windows-specifics for maintaining a single Shared Clipboard transfer.
463 * Set as pvUser / cbUser in SHCLTRANSFERCTX.
464 */
465class SharedClipboardWinTransferCtx
466{
467public:
468 SharedClipboardWinTransferCtx()
469 : pDataObj(NULL) { }
470
471 virtual ~SharedClipboardWinTransferCtx()
472 {
473 if (pDataObj)
474 delete pDataObj;
475 }
476
477 /** Pointer to data object to use for this transfer.
478 * Can be NULL if not being used. */
479 SharedClipboardWinDataObject *pDataObj;
480};
481
482int SharedClipboardWinTransferGetRoots(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
483int SharedClipboardWinTransferDropFilesToStringList(DROPFILES *pDropFiles, char **papszList, uint32_t *pcbList);
484int SharedClipboardWinTransferGetRootsFromClipboard(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
485
486int SharedClipboardWinTransferCreate(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
487void SharedClipboardWinTransferDestroy(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
488
489int SharedClipboardWinTransferCreateAndSetDataObject(PSHCLWINCTX pWinCtx, PSHCLCONTEXT pCtx, SharedClipboardWinDataObject::PCALLBACKS pCallbacks);
490# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
491#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_win_h */
492
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette