VirtualBox

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

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

Shared Clipboard: Use a dedicated worker thread wrapper for transfer threads, so that we have more control for the thread creation / destruction. bugref:9437

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.9 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.215389.xyz.
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 Uninit(void);
253 void Destroy(void);
254
255public: /* IUnknown methods. */
256
257 STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject);
258 STDMETHOD_(ULONG, AddRef)(void);
259 STDMETHOD_(ULONG, Release)(void);
260
261public: /* IDataObject methods. */
262
263 STDMETHOD(GetData)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium);
264 STDMETHOD(GetDataHere)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium);
265 STDMETHOD(QueryGetData)(LPFORMATETC pFormatEtc);
266 STDMETHOD(GetCanonicalFormatEtc)(LPFORMATETC pFormatEct, LPFORMATETC pFormatEtcOut);
267 STDMETHOD(SetData)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium, BOOL fRelease);
268 STDMETHOD(EnumFormatEtc)(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc);
269 STDMETHOD(DAdvise)(LPFORMATETC pFormatEtc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
270 STDMETHOD(DUnadvise)(DWORD dwConnection);
271 STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppEnumAdvise);
272
273#ifdef VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC
274public: /* IDataObjectAsyncCapability methods. */
275
276 STDMETHOD(EndOperation)(HRESULT hResult, IBindCtx* pbcReserved, DWORD dwEffects);
277 STDMETHOD(GetAsyncMode)(BOOL* pfIsOpAsync);
278 STDMETHOD(InOperation)(BOOL* pfInAsyncOp);
279 STDMETHOD(SetAsyncMode)(BOOL fDoOpAsync);
280 STDMETHOD(StartOperation)(IBindCtx* pbcReserved);
281#endif /* VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC */
282
283public:
284
285 int SetTransfer(PSHCLTRANSFER pTransfer);
286 int SetStatus(Status enmStatus, int rcSts = VINF_SUCCESS);
287
288public:
289
290 static DECLCALLBACK(int) readThread(PSHCLTRANSFER pTransfer, void *pvUser);
291
292 static void logFormat(CLIPFORMAT fmt);
293
294protected:
295
296 void uninitInternal(void);
297
298 static int Thread(RTTHREAD hThread, void *pvUser);
299
300 inline int lock(void);
301 inline int unlock(void);
302
303 int readDir(PSHCLTRANSFER pTransfer, const Utf8Str &strPath);
304
305 int copyToHGlobal(const void *pvData, size_t cbData, UINT fFlags, HGLOBAL *phGlobal);
306 int createFileGroupDescriptorFromTransfer(PSHCLTRANSFER pTransfer,
307 bool fUnicode, HGLOBAL *phGlobal);
308
309 bool lookupFormatEtc(LPFORMATETC pFormatEtc, ULONG *puIndex);
310 void registerFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat, TYMED tyMed = TYMED_HGLOBAL,
311 LONG lindex = -1, DWORD dwAspect = DVASPECT_CONTENT, DVTARGETDEVICE *pTargetDevice = NULL);
312 int setTransferLocked(PSHCLTRANSFER pTransfer);
313 int setStatusLocked(Status enmStatus, int rc = VINF_SUCCESS);
314
315protected:
316
317 /**
318 * Structure for keeping a single file system object entry.
319 */
320 struct FSOBJENTRY
321 {
322 /** Relative path of the object. */
323 char *pszPath;
324 /** Related (cached) object information. */
325 SHCLFSOBJINFO objInfo;
326 };
327
328 /** Vector containing file system objects with its (cached) objection information. */
329 typedef std::vector<FSOBJENTRY> FsObjEntryList;
330
331 /** Shared Clipboard context to use. */
332 PSHCLCONTEXT m_pCtx;
333 /** The object's current status. */
334 Status m_enmStatus;
335 /** Last (IPRT-style) error set in conjunction with the status. */
336 int m_rcStatus;
337 /** Data object callback table to use. */
338 CALLBACKS m_Callbacks;
339 /** Data object callback table context to use. */
340 CALLBACKCTX m_CallbackCtx;
341 /** The object's current reference count. */
342 ULONG m_lRefCount;
343 /** How many formats have been registered. */
344 ULONG m_cFormats;
345 LPFORMATETC m_pFormatEtc;
346 LPSTGMEDIUM m_pStgMedium;
347 /** Pointer to the associated transfer object being handled. */
348 PSHCLTRANSFER m_pTransfer;
349 /** Current stream object being used. */
350 IStream *m_pStream;
351 /** Current object index being handled by the data object.
352 * This is needed to create the next IStream object for e.g. the next upcoming file/dir/++ in the transfer. */
353 ULONG m_uObjIdx;
354 /** List of (cached) file system objects. */
355 FsObjEntryList m_lstEntries;
356 /** Critical section to serialize access. */
357 RTCRITSECT m_CritSect;
358 /** Event being triggered when reading the transfer list been completed. */
359 RTSEMEVENT m_EventListComplete;
360 /** Event being triggered when the object status has been changed. */
361 RTSEMEVENT m_EventStatusChanged;
362 /** Registered format for CFSTR_FILEDESCRIPTORA. */
363 UINT m_cfFileDescriptorA;
364 /** Registered format for CFSTR_FILEDESCRIPTORW. */
365 UINT m_cfFileDescriptorW;
366 /** Registered format for CFSTR_FILECONTENTS. */
367 UINT m_cfFileContents;
368 /** Registered format for CFSTR_PERFORMEDDROPEFFECT. */
369 UINT m_cfPerformedDropEffect;
370};
371
372/**
373 * Generic Windows class implementing IEnumFORMATETC for Shared Clipboard data transfers.
374 */
375class SharedClipboardWinEnumFormatEtc : public IEnumFORMATETC
376{
377public:
378
379 SharedClipboardWinEnumFormatEtc(void);
380 virtual ~SharedClipboardWinEnumFormatEtc(void);
381
382public:
383
384 int Init(LPFORMATETC pFormatEtc, ULONG cFormats);
385 void Destroy(void);
386
387public: /* IUnknown methods. */
388
389 STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject);
390 STDMETHOD_(ULONG, AddRef)(void);
391 STDMETHOD_(ULONG, Release)(void);
392
393public: /* IEnumFORMATETC methods. */
394
395 STDMETHOD(Next)(ULONG cFormats, LPFORMATETC pFormatEtc, ULONG *pcFetched);
396 STDMETHOD(Skip)(ULONG cFormats);
397 STDMETHOD(Reset)(void);
398 STDMETHOD(Clone)(IEnumFORMATETC **ppEnumFormatEtc);
399
400public:
401
402 static void CopyFormat(LPFORMATETC pFormatDest, LPFORMATETC pFormatSource);
403 static HRESULT CreateEnumFormatEtc(UINT cFormats, LPFORMATETC pFormatEtc, IEnumFORMATETC **ppEnumFormatEtc);
404
405private:
406
407 LONG m_lRefCount;
408 ULONG m_nIndex;
409 ULONG m_nNumFormats;
410 LPFORMATETC m_pFormatEtc;
411};
412
413/**
414 * Generic Windows class implementing IStream for Shared Clipboard data transfers.
415 */
416class SharedClipboardWinStreamImpl : public IStream
417{
418public:
419
420 SharedClipboardWinStreamImpl(SharedClipboardWinDataObject *pParent, PSHCLTRANSFER pTransfer,
421 const Utf8Str &strPath, PSHCLFSOBJINFO pObjInfo);
422 virtual ~SharedClipboardWinStreamImpl(void);
423
424public: /* IUnknown methods. */
425
426 STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject);
427 STDMETHOD_(ULONG, AddRef)(void);
428 STDMETHOD_(ULONG, Release)(void);
429
430public: /* IStream methods. */
431
432 STDMETHOD(Clone)(IStream** ppStream);
433 STDMETHOD(Commit)(DWORD dwFrags);
434 STDMETHOD(CopyTo)(IStream* pDestStream, ULARGE_INTEGER nBytesToCopy, ULARGE_INTEGER* nBytesRead, ULARGE_INTEGER* nBytesWritten);
435 STDMETHOD(LockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes,DWORD dwFlags);
436 STDMETHOD(Read)(void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead);
437 STDMETHOD(Revert)(void);
438 STDMETHOD(Seek)(LARGE_INTEGER nMove, DWORD dwOrigin, ULARGE_INTEGER* nNewPos);
439 STDMETHOD(SetSize)(ULARGE_INTEGER nNewSize);
440 STDMETHOD(Stat)(STATSTG* statstg, DWORD dwFlags);
441 STDMETHOD(UnlockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes, DWORD dwFlags);
442 STDMETHOD(Write)(const void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead);
443
444public: /* Own methods. */
445
446 static HRESULT Create(SharedClipboardWinDataObject *pParent, PSHCLTRANSFER pTransfer, const Utf8Str &strPath,
447 PSHCLFSOBJINFO pObjInfo, IStream **ppStream);
448private:
449
450 /** Pointer to the parent data object. */
451 SharedClipboardWinDataObject *m_pParent;
452 /** The stream object's current reference count. */
453 LONG m_lRefCount;
454 /** Pointer to the associated Shared Clipboard transfer. */
455 PSHCLTRANSFER m_pTransfer;
456 /** The object handle to use. */
457 SHCLOBJHANDLE m_hObj;
458 /** Object path. */
459 Utf8Str m_strPath;
460 /** (Cached) object information. */
461 SHCLFSOBJINFO m_objInfo;
462 /** Number of bytes already processed. */
463 uint64_t m_cbProcessed;
464 /** Whether this object already is in completed state or not. */
465 bool m_fIsComplete;
466};
467
468/**
469 * Class for Windows-specifics for maintaining a single Shared Clipboard transfer.
470 * Set as pvUser / cbUser for SHCLTRANSFER on Windows hosts / guests.
471 */
472class SharedClipboardWinTransferCtx
473{
474public:
475 SharedClipboardWinTransferCtx()
476 : pDataObj(NULL) { }
477
478 virtual ~SharedClipboardWinTransferCtx() { }
479
480 /** Pointer to data object to use for this transfer. Not owned.
481 * Can be NULL if not being used. */
482 SharedClipboardWinDataObject *pDataObj;
483};
484
485int SharedClipboardWinTransferGetRoots(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
486int SharedClipboardWinTransferDropFilesToStringList(DROPFILES *pDropFiles, char **papszList, uint32_t *pcbList);
487int SharedClipboardWinTransferGetRootsFromClipboard(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
488
489int SharedClipboardWinTransferCreate(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
490void SharedClipboardWinTransferDestroy(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
491
492int SharedClipboardWinTransferCreateAndSetDataObject(PSHCLWINCTX pWinCtx, PSHCLCONTEXT pCtx, SharedClipboardWinDataObject::PCALLBACKS pCallbacks);
493# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
494#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_win_h */
495
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