VirtualBox

source: vbox/trunk/src/VBox/GuestHost/SharedClipboard/ClipboardStreamImpl-win.cpp

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.6 KB
Line 
1/* $Id: ClipboardStreamImpl-win.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * ClipboardStreamImpl-win.cpp - Shared Clipboard IStream object implementation (guest and host side).
4 */
5
6/*
7 * Copyright (C) 2019-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
33#include <VBox/GuestHost/SharedClipboard-win.h>
34
35#include <iprt/asm.h>
36#include <iprt/ldr.h>
37#include <iprt/thread.h>
38
39#include <VBox/GuestHost/SharedClipboard.h>
40#include <VBox/GuestHost/SharedClipboard-transfers.h>
41#include <VBox/GuestHost/SharedClipboard-win.h>
42
43#include <VBox/log.h>
44
45
46/*********************************************************************************************************************************
47* Structures and Typedefs *
48*********************************************************************************************************************************/
49
50
51
52/*********************************************************************************************************************************
53* Static variables *
54*********************************************************************************************************************************/
55#ifdef VBOX_SHARED_CLIPBOARD_DEBUG_OBJECT_COUNTS
56 extern int g_cDbgDataObj;
57 extern int g_cDbgStreamObj;
58 extern int g_cDbgEnumFmtObj;
59#endif
60
61
62ShClWinStreamImpl::ShClWinStreamImpl(ShClWinDataObject *pParent, PSHCLTRANSFER pTransfer,
63 const Utf8Str &strPath, PSHCLFSOBJINFO pObjInfo)
64 : m_pParent(pParent)
65 , m_lRefCount(1) /* Our IDataObjct *always* holds the last reference to this object; needed for the callbacks. */
66 , m_pTransfer(pTransfer)
67 , m_hObj(NIL_SHCLOBJHANDLE)
68 , m_strPath(strPath)
69 , m_objInfo(*pObjInfo)
70 , m_cbProcessed(0)
71 , m_fIsComplete(false)
72{
73 AssertPtr(m_pTransfer);
74
75 LogFunc(("m_strPath=%s\n", m_strPath.c_str()));
76
77#ifdef VBOX_SHARED_CLIPBOARD_DEBUG_OBJECT_COUNTS
78 g_cDbgStreamObj++;
79 LogFlowFunc(("g_cDataObj=%d, g_cStreamObj=%d, g_cEnumFmtObj=%d\n", g_cDbgDataObj, g_cDbgStreamObj, g_cDbgEnumFmtObj));
80#endif
81}
82
83ShClWinStreamImpl::~ShClWinStreamImpl(void)
84{
85 LogFlowThisFuncEnter();
86
87#ifdef VBOX_SHARED_CLIPBOARD_DEBUG_OBJECT_COUNTS
88 g_cDbgStreamObj--;
89 LogFlowFunc(("g_cDataObj=%d, g_cStreamObj=%d, g_cEnumFmtObj=%d\n", g_cDbgDataObj, g_cDbgStreamObj, g_cDbgEnumFmtObj));
90#endif
91}
92
93/*
94 * IUnknown methods.
95 */
96
97STDMETHODIMP ShClWinStreamImpl::QueryInterface(REFIID iid, void **ppvObject)
98{
99 AssertPtrReturn(ppvObject, E_INVALIDARG);
100
101 if (iid == IID_IUnknown)
102 {
103 LogFlowFunc(("IID_IUnknown\n"));
104 *ppvObject = (IUnknown *)(ISequentialStream *)this;
105 }
106 else if (iid == IID_ISequentialStream)
107 {
108 LogFlowFunc(("IID_ISequentialStream\n"));
109 *ppvObject = (ISequentialStream *)this;
110 }
111 else if (iid == IID_IStream)
112 {
113 LogFlowFunc(("IID_IStream\n"));
114 *ppvObject = (IStream *)this;
115 }
116 else
117 {
118 *ppvObject = NULL;
119 return E_NOINTERFACE;
120 }
121
122 AddRef();
123 return S_OK;
124}
125
126STDMETHODIMP_(ULONG) ShClWinStreamImpl::AddRef(void)
127{
128 LONG lCount = InterlockedIncrement(&m_lRefCount);
129 LogFlowFunc(("lCount=%RI32\n", lCount));
130 return lCount;
131}
132
133STDMETHODIMP_(ULONG) ShClWinStreamImpl::Release(void)
134{
135 LONG lCount = InterlockedDecrement(&m_lRefCount);
136 LogFlowFunc(("lCount=%RI32\n", m_lRefCount));
137 if (lCount == 0)
138 {
139 delete this;
140 return 0;
141 }
142
143 return lCount;
144}
145
146/*
147 * IStream methods.
148 */
149
150STDMETHODIMP ShClWinStreamImpl::Clone(IStream** ppStream)
151{
152 RT_NOREF(ppStream);
153
154 LogFlowFuncEnter();
155 return E_NOTIMPL;
156}
157
158STDMETHODIMP ShClWinStreamImpl::Commit(DWORD dwFrags)
159{
160 RT_NOREF(dwFrags);
161
162 LogFlowThisFuncEnter();
163 return E_NOTIMPL;
164}
165
166STDMETHODIMP ShClWinStreamImpl::CopyTo(IStream *pDestStream, ULARGE_INTEGER nBytesToCopy, ULARGE_INTEGER *nBytesRead,
167 ULARGE_INTEGER *nBytesWritten)
168{
169 RT_NOREF(pDestStream, nBytesToCopy, nBytesRead, nBytesWritten);
170
171 LogFlowThisFuncEnter();
172 return E_NOTIMPL;
173}
174
175STDMETHODIMP ShClWinStreamImpl::LockRegion(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes,DWORD dwFlags)
176{
177 RT_NOREF(nStart, nBytes, dwFlags);
178
179 LogFlowThisFuncEnter();
180 return STG_E_INVALIDFUNCTION;
181}
182
183/* Note: Windows seems to assume EOF if nBytesRead < nBytesToRead. */
184STDMETHODIMP ShClWinStreamImpl::Read(void *pvBuffer, ULONG nBytesToRead, ULONG *nBytesRead)
185{
186 LogFlowThisFunc(("Enter: m_cbProcessed=%RU64\n", m_cbProcessed));
187
188 /** @todo Is there any locking required so that parallel reads aren't possible? */
189
190 if (!pvBuffer)
191 return STG_E_INVALIDPOINTER;
192
193 if ( nBytesToRead == 0
194 || m_fIsComplete)
195 {
196 if (nBytesRead)
197 *nBytesRead = 0;
198 return S_OK;
199 }
200
201 int rc;
202
203 if (m_hObj == NIL_SHCLOBJHANDLE)
204 {
205 SHCLOBJOPENCREATEPARMS openParms;
206 rc = ShClTransferObjOpenParmsInit(&openParms);
207 if (RT_SUCCESS(rc))
208 {
209 openParms.fCreate = SHCL_OBJ_CF_ACCESS_READ
210 | SHCL_OBJ_CF_ACCESS_DENYWRITE;
211
212 rc = RTStrCopy(openParms.pszPath, openParms.cbPath, m_strPath.c_str());
213 if (RT_SUCCESS(rc))
214 {
215 rc = ShClTransferTransformPath(openParms.pszPath, openParms.cbPath);
216 if (RT_SUCCESS(rc))
217 rc = ShClTransferObjOpen(m_pTransfer, &openParms, &m_hObj);
218 }
219
220 ShClTransferObjOpenParmsDestroy(&openParms);
221 }
222 }
223 else
224 rc = VINF_SUCCESS;
225
226 uint32_t cbRead = 0;
227
228 const uint64_t cbSize = (uint64_t)m_objInfo.cbObject;
229 const uint32_t cbToRead = RT_MIN(cbSize - m_cbProcessed, nBytesToRead);
230
231 if (RT_SUCCESS(rc))
232 {
233 if (cbToRead)
234 {
235 rc = ShClTransferObjRead(m_pTransfer, m_hObj, pvBuffer, cbToRead, 0 /* fFlags */, &cbRead);
236 if (RT_SUCCESS(rc))
237 {
238 m_cbProcessed += cbRead;
239 Assert(m_cbProcessed <= cbSize);
240 }
241 }
242
243 /* Transfer complete? Make sure to close the object again. */
244 m_fIsComplete = m_cbProcessed == cbSize;
245
246 if (m_fIsComplete)
247 {
248 rc = ShClTransferObjClose(m_pTransfer, m_hObj);
249
250 if (m_pParent)
251 m_pParent->SetStatus(ShClWinDataObject::Completed);
252 }
253 }
254
255 if (RT_FAILURE(rc))
256 {
257 if (m_pParent)
258 m_pParent->SetStatus(ShClWinDataObject::Error, rc /* Propagate rc */);
259 }
260
261 LogFlowThisFunc(("LEAVE: rc=%Rrc, cbSize=%RU64, cbProcessed=%RU64 -> nBytesToRead=%RU32, cbToRead=%RU32, cbRead=%RU32\n",
262 rc, cbSize, m_cbProcessed, nBytesToRead, cbToRead, cbRead));
263
264 if (nBytesRead)
265 *nBytesRead = (ULONG)cbRead;
266
267 if (nBytesToRead != cbRead)
268 return S_FALSE;
269
270 return S_OK;
271}
272
273STDMETHODIMP ShClWinStreamImpl::Revert(void)
274{
275 LogFlowThisFuncEnter();
276 return E_NOTIMPL;
277}
278
279STDMETHODIMP ShClWinStreamImpl::Seek(LARGE_INTEGER nMove, DWORD dwOrigin, ULARGE_INTEGER* nNewPos)
280{
281 RT_NOREF(nMove, dwOrigin, nNewPos);
282
283 LogFlowThisFunc(("nMove=%RI64, dwOrigin=%RI32\n", nMove, dwOrigin));
284
285 return E_NOTIMPL;
286}
287
288STDMETHODIMP ShClWinStreamImpl::SetSize(ULARGE_INTEGER nNewSize)
289{
290 RT_NOREF(nNewSize);
291
292 LogFlowThisFuncEnter();
293 return E_NOTIMPL;
294}
295
296STDMETHODIMP ShClWinStreamImpl::Stat(STATSTG *pStatStg, DWORD dwFlags)
297{
298 HRESULT hr = S_OK;
299
300 if (pStatStg)
301 {
302 RT_ZERO(*pStatStg);
303
304 switch (dwFlags)
305 {
306 case STATFLAG_NONAME:
307 pStatStg->pwcsName = NULL;
308 break;
309
310 case STATFLAG_DEFAULT:
311 {
312 size_t const cchLen = m_strPath.length() + 1 /* Include terminator */;
313 pStatStg->pwcsName = (LPOLESTR)CoTaskMemAlloc(cchLen * sizeof(RTUTF16));
314 if (pStatStg->pwcsName)
315 {
316 PRTUTF16 pwszStr;
317 int rc2 = RTStrToUtf16(m_strPath.c_str(), &pwszStr);
318 if (RT_SUCCESS(rc2))
319 {
320 memcpy(pStatStg->pwcsName, pwszStr, cchLen * sizeof(RTUTF16));
321 RTUtf16Free(pwszStr);
322 pwszStr = NULL;
323 }
324
325 if (RT_FAILURE(rc2))
326 {
327 CoTaskMemFree(pStatStg->pwcsName);
328 pStatStg->pwcsName = NULL;
329 hr = E_UNEXPECTED;
330 }
331 }
332 else
333 hr = E_OUTOFMEMORY;
334 break;
335 }
336
337 default:
338 hr = STG_E_INVALIDFLAG;
339 break;
340 }
341
342 if (SUCCEEDED(hr))
343 {
344 pStatStg->type = STGTY_STREAM;
345 pStatStg->grfMode = STGM_READ;
346 pStatStg->grfLocksSupported = 0;
347 pStatStg->cbSize.QuadPart = (uint64_t)m_objInfo.cbObject;
348 }
349 }
350 else
351 hr = STG_E_INVALIDPOINTER;
352
353 LogFlowThisFunc(("hr=%Rhrc\n", hr));
354 return hr;
355}
356
357STDMETHODIMP ShClWinStreamImpl::UnlockRegion(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes, DWORD dwFlags)
358{
359 RT_NOREF(nStart, nBytes, dwFlags);
360
361 LogFlowThisFuncEnter();
362 return E_NOTIMPL;
363}
364
365STDMETHODIMP ShClWinStreamImpl::Write(const void *pvBuffer, ULONG nBytesToRead, ULONG *nBytesRead)
366{
367 RT_NOREF(pvBuffer, nBytesToRead, nBytesRead);
368
369 LogFlowThisFuncEnter();
370 return E_NOTIMPL;
371}
372
373/*
374 * Own stuff.
375 */
376
377/**
378 * Factory to create our own IStream implementation.
379 *
380 * @returns HRESULT
381 * @param pParent Pointer to the parent data object.
382 * @param pTransfer Pointer to Shared Clipboard transfer object to use.
383 * @param strPath Path of object to handle for the stream.
384 * @param pObjInfo Pointer to object information.
385 * @param ppStream Where to return the created stream object on success.
386 */
387/* static */
388HRESULT ShClWinStreamImpl::Create(ShClWinDataObject *pParent, PSHCLTRANSFER pTransfer,
389 const Utf8Str &strPath, PSHCLFSOBJINFO pObjInfo,
390 IStream **ppStream)
391{
392 AssertPtrReturn(pTransfer, E_POINTER);
393
394 ShClWinStreamImpl *pStream = new ShClWinStreamImpl(pParent, pTransfer, strPath, pObjInfo);
395 if (pStream)
396 {
397 *ppStream = pStream;
398 return S_OK;
399 }
400
401 return E_FAIL;
402}
403
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