VirtualBox

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

Last change on this file since 102797 was 100665, checked in by vboxsync, 17 months ago

Shared Clipboard: More Windows data object refcount bugfixes. Added VBOX_SHARED_CLIPBOARD_DEBUG_OBJECT_COUNTS for helping tracking down those issues. bugref:9437

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