VirtualBox

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

Last change on this file since 105381 was 103631, checked in by vboxsync, 10 months ago

Shared Clipboard: More cleanups (renaming Windows parts to match the other platforms). 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.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 ShClWinDataObject;
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 ShClWinDataObject *pDataObjInFlight;
146#endif
147 /** Request queue.
148 * Needed for processing HGCM requests within the HGCM (main) thread from the Windows event thread. */
149 RTREQQUEUE hReqQ;
150} SHCLWINCTX, *PSHCLWINCTX;
151
152int ShClWinOpen(HWND hWnd);
153int ShClWinClose(void);
154int ShClWinClear(void);
155
156int ShClWinCtxInit(PSHCLWINCTX pWinCtx);
157void ShClWinCtxDestroy(PSHCLWINCTX pWinCtx);
158
159int ShClWinCheckAndInitNewAPI(PSHCLWINAPINEW pAPI);
160bool ShClWinIsNewAPI(PSHCLWINAPINEW pAPI);
161
162int ShClWinDataWrite(UINT cfFormat, void *pvData, uint32_t cbData);
163
164int ShClWinChainAdd(PSHCLWINCTX pCtx);
165int ShClWinChainRemove(PSHCLWINCTX pCtx);
166VOID CALLBACK ShClWinChainPingProc(HWND hWnd, UINT uMsg, ULONG_PTR dwData, LRESULT lResult) RT_NOTHROW_DEF;
167LRESULT ShClWinChainPassToNext(PSHCLWINCTX pWinCtx, UINT msg, WPARAM wParam, LPARAM lParam);
168
169SHCLFORMAT ShClWinClipboardFormatToVBox(UINT uFormat);
170int ShClWinGetFormats(PSHCLWINCTX pCtx, PSHCLFORMATS pfFormats);
171
172int ShClWinGetCFHTMLHeaderValue(const char *pszSrc, const char *pszOption, uint32_t *puValue);
173bool ShClWinIsCFHTML(const char *pszSource);
174int ShClWinConvertCFHTMLToMIME(const char *pszSource, const uint32_t cch, char **ppszOutput, uint32_t *pcbOutput);
175int ShClWinConvertMIMEToCFHTML(const char *pszSource, size_t cb, char **ppszOutput, uint32_t *pcbOutput);
176
177LRESULT ShClWinHandleWMChangeCBChain(PSHCLWINCTX pWinCtx, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
178int ShClWinHandleWMDestroy(PSHCLWINCTX pWinCtx);
179int ShClWinHandleWMRenderAllFormats(PSHCLWINCTX pWinCtx, HWND hWnd);
180int ShClWinHandleWMTimer(PSHCLWINCTX pWinCtx);
181
182int ShClWinClearAndAnnounceFormats(PSHCLWINCTX pWinCtx, SHCLFORMATS fFormats, HWND hWnd);
183
184#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
185class SharedClipboardTransferList;
186# ifndef FILEGROUPDESCRIPTOR
187class FILEGROUPDESCRIPTOR;
188# endif
189
190/**
191 * Shared CLipboard Windows class implementing IDataObject for Shared Clipboard data transfers.
192 */
193class ShClWinDataObject : public IDataObject //, public IDataObjectAsyncCapability
194{
195public:
196
197 /**
198 * Structure for keeping a data object callback context.
199 */
200 struct CALLBACKCTX
201 {
202 /** Pointer to the data object of this callback. */
203 ShClWinDataObject *pThis;
204 /** User-supplied pointer to more context data. */
205 void *pvUser;
206 };
207 /** Pointer to a Shared Clipboard Windows data object callback table. */
208 typedef CALLBACKCTX *PCALLBACKCTX;
209
210 /**
211 * @name Shared Clipboard Windows data object callback table.
212 */
213 struct CALLBACKS
214 {
215 /**
216 * Called by the data object if a transfer needs to be started.
217 *
218 * @returns VBox status code.
219 * @param pCbCtx Pointer to callback context.
220 */
221 DECLCALLBACKMEMBER(int, pfnTransferBegin, (PCALLBACKCTX pCbCtx));
222 /**
223 * Called by the data object if a transfer has been ended (succeeded or failed).
224 *
225 * @returns VBox status code.
226 * @param pCbCtx Pointer to callback context.
227 * @param pTransfer Pointer to transfer being completed.
228 * @param rcTransfer Result (IPRT-style) code.
229 */
230 DECLCALLBACKMEMBER(int, pfnTransferEnd, (PCALLBACKCTX pCbCtx, PSHCLTRANSFER pTransfer, int rcTransfer));
231 };
232 /** Pointer to a Shared Clipboard Windows data object callback table. */
233 typedef CALLBACKS *PCALLBACKS;
234
235 enum Status
236 {
237 /** The object is uninitialized (not ready). */
238 Uninitialized = 0,
239 /** The object is initialized and ready to use.
240 * A transfer is *not* running yet! */
241 Initialized,
242 /** Transfer is running. */
243 Running,
244 /** The operation has been successfully completed. */
245 Completed,
246 /** The operation has been canceled. */
247 Canceled,
248 /** An (unrecoverable) error occurred. */
249 Error
250 };
251
252public:
253
254 ShClWinDataObject(void);
255 virtual ~ShClWinDataObject(void);
256
257public:
258
259 int Init(PSHCLCONTEXT pCtx, ShClWinDataObject::PCALLBACKS pCallbacks, LPFORMATETC pFormatEtc = NULL, LPSTGMEDIUM pStgMed = NULL, ULONG cFormats = 0);
260 void Uninit(void);
261 void Destroy(void);
262
263public: /* IUnknown methods. */
264
265 STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject);
266 STDMETHOD_(ULONG, AddRef)(void);
267 STDMETHOD_(ULONG, Release)(void);
268
269public: /* IDataObject methods. */
270
271 STDMETHOD(GetData)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium);
272 STDMETHOD(GetDataHere)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium);
273 STDMETHOD(QueryGetData)(LPFORMATETC pFormatEtc);
274 STDMETHOD(GetCanonicalFormatEtc)(LPFORMATETC pFormatEct, LPFORMATETC pFormatEtcOut);
275 STDMETHOD(SetData)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium, BOOL fRelease);
276 STDMETHOD(EnumFormatEtc)(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc);
277 STDMETHOD(DAdvise)(LPFORMATETC pFormatEtc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
278 STDMETHOD(DUnadvise)(DWORD dwConnection);
279 STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppEnumAdvise);
280
281#ifdef VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC
282public: /* IDataObjectAsyncCapability methods. */
283
284 STDMETHOD(EndOperation)(HRESULT hResult, IBindCtx* pbcReserved, DWORD dwEffects);
285 STDMETHOD(GetAsyncMode)(BOOL* pfIsOpAsync);
286 STDMETHOD(InOperation)(BOOL* pfInAsyncOp);
287 STDMETHOD(SetAsyncMode)(BOOL fDoOpAsync);
288 STDMETHOD(StartOperation)(IBindCtx* pbcReserved);
289#endif /* VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC */
290
291public:
292
293 int SetTransfer(PSHCLTRANSFER pTransfer);
294 int SetStatus(Status enmStatus, int rcSts = VINF_SUCCESS);
295
296public:
297
298 static DECLCALLBACK(int) readThread(PSHCLTRANSFER pTransfer, void *pvUser);
299
300 static void logFormat(CLIPFORMAT fmt);
301
302protected:
303
304 void uninitInternal(void);
305
306 static int Thread(RTTHREAD hThread, void *pvUser);
307
308 inline int lock(void);
309 inline int unlock(void);
310
311 int readDir(PSHCLTRANSFER pTransfer, const Utf8Str &strPath);
312
313 int copyToHGlobal(const void *pvData, size_t cbData, UINT fFlags, HGLOBAL *phGlobal);
314 int createFileGroupDescriptorFromTransfer(PSHCLTRANSFER pTransfer,
315 bool fUnicode, HGLOBAL *phGlobal);
316
317 bool lookupFormatEtc(LPFORMATETC pFormatEtc, ULONG *puIndex);
318 void registerFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat, TYMED tyMed = TYMED_HGLOBAL,
319 LONG lindex = -1, DWORD dwAspect = DVASPECT_CONTENT, DVTARGETDEVICE *pTargetDevice = NULL);
320 int setTransferLocked(PSHCLTRANSFER pTransfer);
321 int setStatusLocked(Status enmStatus, int rc = VINF_SUCCESS);
322
323protected:
324
325 /**
326 * Structure for keeping a single file system object entry.
327 */
328 struct FSOBJENTRY
329 {
330 /** Relative path of the object. */
331 char *pszPath;
332 /** Related (cached) object information. */
333 SHCLFSOBJINFO objInfo;
334 };
335
336 /** Vector containing file system objects with its (cached) objection information. */
337 typedef std::vector<FSOBJENTRY> FsObjEntryList;
338
339 /** Shared Clipboard context to use. */
340 PSHCLCONTEXT m_pCtx;
341 /** The object's current status. */
342 Status m_enmStatus;
343 /** Last (IPRT-style) error set in conjunction with the status. */
344 int m_rcStatus;
345 /** Data object callback table to use. */
346 CALLBACKS m_Callbacks;
347 /** Data object callback table context to use. */
348 CALLBACKCTX m_CallbackCtx;
349 /** The object's current reference count. */
350 ULONG m_lRefCount;
351 /** How many formats have been registered. */
352 ULONG m_cFormats;
353 LPFORMATETC m_pFormatEtc;
354 LPSTGMEDIUM m_pStgMedium;
355 /** Pointer to the associated transfer object being handled. */
356 PSHCLTRANSFER m_pTransfer;
357 /** Current stream object being used. */
358 IStream *m_pStream;
359 /** Current object index being handled by the data object.
360 * This is needed to create the next IStream object for e.g. the next upcoming file/dir/++ in the transfer. */
361 ULONG m_uObjIdx;
362 /** List of (cached) file system objects. */
363 FsObjEntryList m_lstEntries;
364 /** Critical section to serialize access. */
365 RTCRITSECT m_CritSect;
366 /** Event being triggered when reading the transfer list been completed. */
367 RTSEMEVENT m_EventListComplete;
368 /** Event being triggered when the object status has been changed. */
369 RTSEMEVENT m_EventStatusChanged;
370 /** Registered format for CFSTR_FILEDESCRIPTORA. */
371 UINT m_cfFileDescriptorA;
372 /** Registered format for CFSTR_FILEDESCRIPTORW. */
373 UINT m_cfFileDescriptorW;
374 /** Registered format for CFSTR_FILECONTENTS. */
375 UINT m_cfFileContents;
376 /** Registered format for CFSTR_PERFORMEDDROPEFFECT. */
377 UINT m_cfPerformedDropEffect;
378};
379
380/**
381 * Generic Windows class implementing IEnumFORMATETC for Shared Clipboard data transfers.
382 */
383class ShClWinEnumFormatEtc : public IEnumFORMATETC
384{
385public:
386
387 ShClWinEnumFormatEtc(void);
388 virtual ~ShClWinEnumFormatEtc(void);
389
390public:
391
392 int Init(LPFORMATETC pFormatEtc, ULONG cFormats);
393 void Destroy(void);
394
395public: /* IUnknown methods. */
396
397 STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject);
398 STDMETHOD_(ULONG, AddRef)(void);
399 STDMETHOD_(ULONG, Release)(void);
400
401public: /* IEnumFORMATETC methods. */
402
403 STDMETHOD(Next)(ULONG cFormats, LPFORMATETC pFormatEtc, ULONG *pcFetched);
404 STDMETHOD(Skip)(ULONG cFormats);
405 STDMETHOD(Reset)(void);
406 STDMETHOD(Clone)(IEnumFORMATETC **ppEnumFormatEtc);
407
408public:
409
410 static void CopyFormat(LPFORMATETC pFormatDest, LPFORMATETC pFormatSource);
411 static HRESULT CreateEnumFormatEtc(UINT cFormats, LPFORMATETC pFormatEtc, IEnumFORMATETC **ppEnumFormatEtc);
412
413private:
414
415 LONG m_lRefCount;
416 ULONG m_nIndex;
417 ULONG m_nNumFormats;
418 LPFORMATETC m_pFormatEtc;
419};
420
421/**
422 * Generic Windows class implementing IStream for Shared Clipboard data transfers.
423 */
424class ShClWinStreamImpl : public IStream
425{
426public:
427
428 ShClWinStreamImpl(ShClWinDataObject *pParent, PSHCLTRANSFER pTransfer,
429 const Utf8Str &strPath, PSHCLFSOBJINFO pObjInfo);
430 virtual ~ShClWinStreamImpl(void);
431
432public: /* IUnknown methods. */
433
434 STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject);
435 STDMETHOD_(ULONG, AddRef)(void);
436 STDMETHOD_(ULONG, Release)(void);
437
438public: /* IStream methods. */
439
440 STDMETHOD(Clone)(IStream** ppStream);
441 STDMETHOD(Commit)(DWORD dwFrags);
442 STDMETHOD(CopyTo)(IStream* pDestStream, ULARGE_INTEGER nBytesToCopy, ULARGE_INTEGER* nBytesRead, ULARGE_INTEGER* nBytesWritten);
443 STDMETHOD(LockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes,DWORD dwFlags);
444 STDMETHOD(Read)(void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead);
445 STDMETHOD(Revert)(void);
446 STDMETHOD(Seek)(LARGE_INTEGER nMove, DWORD dwOrigin, ULARGE_INTEGER* nNewPos);
447 STDMETHOD(SetSize)(ULARGE_INTEGER nNewSize);
448 STDMETHOD(Stat)(STATSTG* statstg, DWORD dwFlags);
449 STDMETHOD(UnlockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes, DWORD dwFlags);
450 STDMETHOD(Write)(const void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead);
451
452public: /* Own methods. */
453
454 static HRESULT Create(ShClWinDataObject *pParent, PSHCLTRANSFER pTransfer, const Utf8Str &strPath,
455 PSHCLFSOBJINFO pObjInfo, IStream **ppStream);
456private:
457
458 /** Pointer to the parent data object. */
459 ShClWinDataObject *m_pParent;
460 /** The stream object's current reference count. */
461 LONG m_lRefCount;
462 /** Pointer to the associated Shared Clipboard transfer. */
463 PSHCLTRANSFER m_pTransfer;
464 /** The object handle to use. */
465 SHCLOBJHANDLE m_hObj;
466 /** Object path. */
467 Utf8Str m_strPath;
468 /** (Cached) object information. */
469 SHCLFSOBJINFO m_objInfo;
470 /** Number of bytes already processed. */
471 uint64_t m_cbProcessed;
472 /** Whether this object already is in completed state or not. */
473 bool m_fIsComplete;
474};
475
476/**
477 * Class for Windows-specifics for maintaining a single Shared Clipboard transfer.
478 * Set as pvUser / cbUser for SHCLTRANSFER on Windows hosts / guests.
479 */
480class ShClWinTransferCtx
481{
482public:
483 ShClWinTransferCtx()
484 : pDataObj(NULL) { }
485
486 virtual ~ShClWinTransferCtx() { }
487
488 /** Pointer to data object to use for this transfer. Not owned.
489 * Can be NULL if not being used. */
490 ShClWinDataObject *pDataObj;
491};
492
493int ShClWinTransferGetRoots(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
494int ShClWinTransferDropFilesToStringList(DROPFILES *pDropFiles, char **papszList, uint32_t *pcbList);
495int ShClWinTransferGetRootsFromClipboard(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
496
497int ShClWinTransferCreate(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
498void ShClWinTransferDestroy(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
499
500int ShClWinTransferCreateAndSetDataObject(PSHCLWINCTX pWinCtx, PSHCLCONTEXT pCtx, ShClWinDataObject::PCALLBACKS pCallbacks);
501int ShClWinTransferInitialize(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
502int ShClWinTransferStart(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
503# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
504#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_win_h */
505
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