VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp@ 99951

Last change on this file since 99951 was 99951, checked in by vboxsync, 21 months ago

Shared Clipboard: Moved code for handling local filesystems with transfers into an own provider interface implementation. This cleans up the generic code a lot. bugref:9437

  • Property svn:eol-style set to native
  • Property svn:keyword set to Id
  • Property svn:keywords set to Author Date Id Revision
File size: 91.0 KB
Line 
1/* $Id: VBoxGuestR3LibClipboard.cpp 99951 2023-05-24 10:37:12Z vboxsync $ */
2/** @file
3 * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, Shared Clipboard.
4 */
5
6/*
7 * Copyright (C) 2007-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 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <VBox/GuestHost/SharedClipboard.h>
42#include <VBox/GuestHost/clipboard-helper.h>
43#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
44# include <VBox/GuestHost/SharedClipboard-transfers.h>
45#endif
46#include <VBox/HostServices/VBoxClipboardSvc.h>
47#include <VBox/err.h>
48#include <iprt/assert.h>
49#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
50# include <iprt/dir.h>
51# include <iprt/file.h>
52# include <iprt/path.h>
53#endif
54#include <iprt/string.h>
55#include <iprt/cpp/ministring.h>
56
57#include "VBoxGuestR3LibInternal.h"
58
59
60/*
61 * Function naming convention:
62 *
63 * FunctionNameRecv = Receives a host message (request).
64 * FunctionNameReply = Replies to a host message (request).
65 * FunctionNameSend = Sends a guest message to the host.
66 */
67
68
69/*********************************************************************************************************************************
70* Prototypes *
71*********************************************************************************************************************************/
72
73
74/**
75 * Connects to the Shared Clipboard service, legacy version, do not use anymore.
76 *
77 * @returns VBox status code
78 * @param pidClient Where to put the client id on success. The client id
79 * must be passed to all the other clipboard calls.
80 */
81VBGLR3DECL(int) VbglR3ClipboardConnect(HGCMCLIENTID *pidClient)
82{
83 int rc = VbglR3HGCMConnect("VBoxSharedClipboard", pidClient);
84 if (RT_FAILURE(rc))
85 {
86 if (rc == VERR_HGCM_SERVICE_NOT_FOUND)
87 LogRel(("Shared Clipboard: Unabled to connect, as host service was not found, skipping\n"));
88 else
89 LogRel(("Shared Clipboard: Unabled to connect to host service, rc=%Rrc\n", rc));
90 }
91 LogFlowFuncLeaveRC(rc);
92 return rc;
93}
94
95
96/**
97 * Connects to the Shared Clipboard service, extended version.
98 *
99 * @returns VBox status code.
100 * @param pCtx Command context. This will be initialized by this
101 * call.
102 * @param fGuestFeatures The guest features supported by this client,
103 * VBOX_SHCL_GF_0_XXX.
104 */
105VBGLR3DECL(int) VbglR3ClipboardConnectEx(PVBGLR3SHCLCMDCTX pCtx, uint64_t fGuestFeatures)
106{
107 /*
108 * Intialize the context structure.
109 */
110 pCtx->idClient = 0;
111 pCtx->fGuestFeatures = fGuestFeatures;
112 pCtx->fHostFeatures = 0;
113 pCtx->fUseLegacyProtocol = true;
114 pCtx->cParmsRecived = 0;
115 pCtx->idContext = 0;
116
117#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
118 /* Init callback table. */
119 RT_ZERO(pCtx->Transfers.Callbacks);
120 /* Indicate that this guest supports Shared Clipboard file transfers. */
121 pCtx->fGuestFeatures |= VBOX_SHCL_GF_0_TRANSFERS;
122# ifdef RT_OS_WINDOWS
123 /* Indicate that on Windows guest OSes we have our own IDataObject implementation which
124 * integrates nicely into the guest's Windows Explorer showing / handling the Shared Clipboard file transfers. */
125 pCtx->fGuestFeatures |= VBOX_SHCL_GF_0_TRANSFERS_FRONTEND;
126# endif
127 pCtx->Transfers.cbChunkSize = VBOX_SHCL_DEFAULT_CHUNK_SIZE; /** @todo Make this configurable. */
128 pCtx->Transfers.cbMaxChunkSize = VBOX_SHCL_MAX_CHUNK_SIZE; /** @todo Ditto. */
129#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
130
131 /*
132 * First step is connecting to the HGCM service.
133 */
134 int rc = VbglR3ClipboardConnect(&pCtx->idClient);
135 if (RT_SUCCESS(rc))
136 {
137 /*
138 * Next is reporting our features. If this fails, assume older host.
139 */
140 rc = VbglR3ClipboardReportFeatures(pCtx->idClient, pCtx->fGuestFeatures, &pCtx->fHostFeatures);
141 if (RT_SUCCESS(rc))
142 {
143 LogRel2(("Shared Clipboard: Guest features: %#RX64 - Host features: %#RX64\n",
144 pCtx->fGuestFeatures, pCtx->fHostFeatures));
145
146 if ( (pCtx->fHostFeatures & VBOX_SHCL_HF_0_CONTEXT_ID)
147 && (pCtx->fGuestFeatures & VBOX_SHCL_GF_0_CONTEXT_ID) )
148 {
149 pCtx->fUseLegacyProtocol = false;
150
151#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
152 if ( (pCtx->fHostFeatures & VBOX_SHCL_HF_0_TRANSFERS)
153 && (pCtx->fGuestFeatures & VBOX_SHCL_GF_0_TRANSFERS) )
154 {
155 VBoxShClParmNegotiateChunkSize MsgChunkSize;
156 do
157 {
158 VBGL_HGCM_HDR_INIT(&MsgChunkSize.hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_NEGOTIATE_CHUNK_SIZE,
159 VBOX_SHCL_CPARMS_NEGOTIATE_CHUNK_SIZE);
160 MsgChunkSize.cb32MaxChunkSize.SetUInt32(pCtx->Transfers.cbMaxChunkSize);
161 MsgChunkSize.cb32ChunkSize.SetUInt32(0); /* If set to 0, let the host choose. */
162 rc = VbglR3HGCMCall(&MsgChunkSize.hdr, sizeof(MsgChunkSize));
163 } while (rc == VERR_INTERRUPTED);
164 if (RT_SUCCESS(rc))
165 {
166 Assert(MsgChunkSize.cb32ChunkSize.type == VMMDevHGCMParmType_32bit);
167 pCtx->Transfers.cbChunkSize = RT_MIN(MsgChunkSize.cb32ChunkSize.u.value32, pCtx->Transfers.cbChunkSize);
168 Assert(MsgChunkSize.cb32MaxChunkSize.type == VMMDevHGCMParmType_32bit);
169 pCtx->Transfers.cbMaxChunkSize = RT_MIN(MsgChunkSize.cb32MaxChunkSize.u.value32, pCtx->Transfers.cbMaxChunkSize);
170
171 LogRel2(("Shared Clipboard: Using chunk size %RU32 (maximum is %RU32)\n",
172 pCtx->Transfers.cbChunkSize, pCtx->Transfers.cbMaxChunkSize));
173 }
174 }
175 else
176 {
177 if (!(pCtx->fHostFeatures & VBOX_SHCL_HF_0_TRANSFERS))
178 LogRel2(("Shared Clipboard: Host does not support transfers\n"));
179 }
180#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
181 }
182 else
183 {
184 if (!(pCtx->fHostFeatures & VBOX_SHCL_HF_0_CONTEXT_ID))
185 LogRel(("Shared Clipboard: Host does not support context IDs, using legacy protocol\n"));
186
187 pCtx->fUseLegacyProtocol = true;
188 }
189 }
190 else
191 {
192 AssertLogRelMsg(rc == VERR_NOT_SUPPORTED || rc == VERR_NOT_IMPLEMENTED,
193 ("Reporting features failed: %Rrc\n", rc));
194 pCtx->fUseLegacyProtocol = true;
195 }
196 }
197
198 LogFlowFuncLeaveRC(rc);
199 return rc;
200}
201
202
203/**
204 * Reports features to the host and retrieve host feature set.
205 *
206 * @returns VBox status code.
207 * @param idClient The client ID returned by VbglR3ClipboardConnect().
208 * @param fGuestFeatures Features to report, VBOX_SHCL_GF_XXX.
209 * @param pfHostFeatures Where to store the features VBOX_SHCL_HF_XXX.
210 */
211VBGLR3DECL(int) VbglR3ClipboardReportFeatures(uint32_t idClient, uint64_t fGuestFeatures, uint64_t *pfHostFeatures)
212{
213 int rc;
214 do
215 {
216 struct
217 {
218 VBGLIOCHGCMCALL Hdr;
219 HGCMFunctionParameter f64Features0;
220 HGCMFunctionParameter f64Features1;
221 } Msg;
222 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_REPORT_FEATURES, 2);
223 VbglHGCMParmUInt64Set(&Msg.f64Features0, fGuestFeatures);
224 VbglHGCMParmUInt64Set(&Msg.f64Features1, VBOX_SHCL_GF_1_MUST_BE_ONE);
225
226 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
227 if (RT_SUCCESS(rc))
228 {
229 Assert(Msg.f64Features0.type == VMMDevHGCMParmType_64bit);
230 Assert(Msg.f64Features1.type == VMMDevHGCMParmType_64bit);
231 if (Msg.f64Features1.u.value64 & VBOX_SHCL_GF_1_MUST_BE_ONE)
232 rc = VERR_NOT_SUPPORTED;
233 else if (pfHostFeatures)
234 *pfHostFeatures = Msg.f64Features0.u.value64;
235 break;
236 }
237 } while (rc == VERR_INTERRUPTED);
238 return rc;
239
240}
241
242
243/**
244 * Disconnects from the Shared Clipboard service, legacy version, do not use anymore.
245 *
246 * @returns VBox status code.
247 * @param idClient The client id returned by VbglR3ClipboardConnect().
248 */
249VBGLR3DECL(int) VbglR3ClipboardDisconnect(HGCMCLIENTID idClient)
250{
251 return VbglR3HGCMDisconnect(idClient);
252}
253
254
255/**
256 * Disconnects from the Shared Clipboard service, extended version.
257 *
258 * @returns VBox status code.
259 * @param pCtx Shared Clipboard command context to use for the connection.
260 */
261VBGLR3DECL(int) VbglR3ClipboardDisconnectEx(PVBGLR3SHCLCMDCTX pCtx)
262{
263 int rc = VbglR3ClipboardDisconnect(pCtx->idClient);
264 if (RT_SUCCESS(rc))
265 {
266 pCtx->idClient = 0;
267 }
268
269 LogFlowFuncLeaveRC(rc);
270 return rc;
271}
272
273
274/**
275 * Receives reported formats from the host.
276 *
277 * @returns VBox status code.
278 * @param pCtx Shared Clipboard command context to use for the
279 * connection.
280 * @param pfFormats Where to store the received formats from the host.
281 */
282static int vbglR3ClipboardFormatsReportRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMATS pfFormats)
283{
284 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
285 AssertPtrReturn(pfFormats, VERR_INVALID_POINTER);
286
287 *pfFormats = 0;
288
289 struct
290 {
291 VBGLIOCHGCMCALL Hdr;
292 HGCMFunctionParameter id64Context;
293 HGCMFunctionParameter f32Formats;
294 } Msg;
295
296 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_GET, 2);
297 Msg.id64Context.SetUInt32(VBOX_SHCL_HOST_MSG_FORMATS_REPORT);
298 Msg.f32Formats.SetUInt32(0);
299
300 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
301 if (RT_SUCCESS(rc))
302 {
303 rc = Msg.f32Formats.GetUInt32(pfFormats);
304 AssertRC(rc);
305 }
306
307 LogFlowFuncLeaveRC(rc);
308 return rc;
309}
310
311
312/**
313 * Fetches a VBOX_SHCL_HOST_MSG_READ_DATA_CID message.
314 *
315 * @returns VBox status code.
316 * @param pCtx Shared Clipboard command context to use for the connection.
317 * @param pfFormat Where to return the requested format.
318 */
319static int vbglR3ClipboardFetchReadDataCid(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMAT pfFormat)
320{
321 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
322 AssertPtrReturn(pfFormat, VERR_INVALID_POINTER);
323
324 struct
325 {
326 VBGLIOCHGCMCALL Hdr;
327 HGCMFunctionParameter id64Context;
328 HGCMFunctionParameter f32Format;
329 } Msg;
330
331 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_GET, 2);
332 Msg.id64Context.SetUInt64(VBOX_SHCL_HOST_MSG_READ_DATA_CID);
333 Msg.f32Format.SetUInt32(0);
334
335 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
336 if (RT_SUCCESS(rc))
337 {
338 rc = Msg.id64Context.GetUInt64(&pCtx->idContext);
339 AssertRC(rc);
340 int rc2 = Msg.f32Format.GetUInt32(pfFormat);
341 AssertRCStmt(rc2, rc = rc2);
342 }
343
344 LogFlowFuncLeaveRC(rc);
345 return rc;
346}
347
348
349/**
350 * Fetches a VBOX_SHCL_HOST_MSG_READ_DATA message.
351 *
352 * @returns VBox status code.
353 * @param pCtx Shared Clipboard command context to use for the connection.
354 * @param pfFormat Where to return the requested format.
355 */
356static int vbglR3ClipboardFetchReadData(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMAT pfFormat)
357{
358 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
359 AssertPtrReturn(pfFormat, VERR_INVALID_POINTER);
360
361 struct
362 {
363 VBGLIOCHGCMCALL Hdr;
364 HGCMFunctionParameter id32Msg;
365 HGCMFunctionParameter f32Format;
366 } Msg;
367
368 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_GET, 2);
369 Msg.id32Msg.SetUInt32(VBOX_SHCL_HOST_MSG_READ_DATA);
370 Msg.f32Format.SetUInt32(0);
371
372 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
373 if (RT_SUCCESS(rc))
374 {
375 rc = Msg.f32Format.GetUInt32(pfFormat);
376 AssertRC(rc);
377 }
378
379 LogFlowFuncLeaveRC(rc);
380 return rc;
381}
382
383
384/**
385 * Get a host message, legacy version (which does not have VBOX_SHCL_GUEST_FN_MSG_GET). Do not use anymore.
386 *
387 * Note: This is the old message which still is being used for the non-URI Shared Clipboard transfers,
388 * to not break compatibility with older additions / VBox versions.
389 *
390 * This will block until a message becomes available.
391 *
392 * @returns VBox status code.
393 * @param idClient The client id returned by VbglR3ClipboardConnect().
394 * @param pidMsg Where to store the message id.
395 * @param pfFormats Where to store the format(s) the message applies to.
396 */
397VBGLR3DECL(int) VbglR3ClipboardGetHostMsgOld(HGCMCLIENTID idClient, uint32_t *pidMsg, uint32_t *pfFormats)
398{
399 VBoxShClGetHostMsgOld Msg;
400
401 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, VBOX_SHCL_CPARMS_GET_HOST_MSG_OLD);
402 VbglHGCMParmUInt32Set(&Msg.msg, 0);
403 VbglHGCMParmUInt32Set(&Msg.formats, 0);
404
405 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
406 if (RT_SUCCESS(rc))
407 {
408 int rc2 = VbglHGCMParmUInt32Get(&Msg.msg, pidMsg);
409 if (RT_SUCCESS(rc))
410 {
411 rc2 = VbglHGCMParmUInt32Get(&Msg.formats, pfFormats);
412 if (RT_SUCCESS(rc2))
413 return rc;
414 }
415 rc = rc2;
416 }
417 *pidMsg = UINT32_MAX - 1;
418 *pfFormats = UINT32_MAX;
419 return rc;
420}
421
422
423/**
424 * Reads data from the host clipboard.
425 *
426 * Legacy function, do not use anymore.
427 *
428 * @returns VBox status code.
429 * @retval VINF_BUFFER_OVERFLOW If there is more data available than the caller provided buffer space for.
430 *
431 * @param idClient The client id returned by VbglR3ClipboardConnect().
432 * @param fFormat The format we're requesting the data in.
433 * @param pvData Where to store the data.
434 * @param cbData The size of the buffer pointed to by \a pvData.
435 * @param pcbRead The actual size of the host clipboard data. May be larger than \a cbData.
436 */
437VBGLR3DECL(int) VbglR3ClipboardReadData(HGCMCLIENTID idClient, uint32_t fFormat, void *pvData, uint32_t cbData,
438 uint32_t *pcbRead)
439{
440 LogFlowFuncEnter();
441
442 struct
443 {
444 VBGLIOCHGCMCALL Hdr;
445 VBoxShClParmDataRead Parms;
446 } Msg;
447
448 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_DATA_READ, VBOX_SHCL_CPARMS_DATA_READ);
449 VbglHGCMParmUInt32Set(&Msg.Parms.f32Format, fFormat);
450 VbglHGCMParmPtrSet( &Msg.Parms.pData, pvData, cbData);
451 VbglHGCMParmUInt32Set(&Msg.Parms.cb32Needed, 0);
452
453 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
454 if (RT_SUCCESS(rc))
455 {
456 uint32_t cbRead;
457 rc = VbglHGCMParmUInt32Get(&Msg.Parms.cb32Needed, &cbRead);
458 if (RT_SUCCESS(rc))
459 {
460 LogFlowFunc(("cbRead=%RU32\n", cbRead));
461
462 if (cbRead > cbData)
463 rc = VINF_BUFFER_OVERFLOW;
464
465 *pcbRead = cbRead;
466 }
467 }
468
469 LogFlowFuncLeaveRC(rc);
470 return rc;
471}
472
473
474/**
475 * Reads clipboard data from the host clipboard.
476 *
477 * @returns VBox status code.
478 * @retval VINF_BUFFER_OVERFLOW If there is more data available than the caller provided buffer space for.
479 *
480 * @param pCtx The command context returned by VbglR3ClipboardConnectEx().
481 * @param uFormat Clipboard format of clipboard data to be read.
482 * @param pvData Buffer where to store the read data.
483 * @param cbData Size (in bytes) of data buffer where to store the read data.
484 * @param pcbRead The actual size of the host clipboard data.
485 */
486VBGLR3DECL(int) VbglR3ClipboardReadDataEx(PVBGLR3SHCLCMDCTX pCtx,
487 SHCLFORMAT uFormat, void *pvData, uint32_t cbData, uint32_t *pcbRead)
488{
489 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
490 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
491 return VbglR3ClipboardReadData(pCtx->idClient, uFormat, pvData, cbData, pcbRead);
492}
493
494
495/**
496 * Query the host features.
497 *
498 * @returns VBox status code.
499 * @param idClient The client ID returned by VbglR3ClipboardConnect().
500 * @param pfHostFeatures Where to store the host feature, VBOX_SHCL_HF_XXX.
501 */
502VBGLR3DECL(int) VbglR3ClipboardQueryFeatures(uint32_t idClient, uint64_t *pfHostFeatures)
503{
504 int rc;
505 do
506 {
507 struct
508 {
509 VBGLIOCHGCMCALL Hdr;
510 HGCMFunctionParameter f64Features0;
511 HGCMFunctionParameter f64Features1;
512 } Msg;
513 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_QUERY_FEATURES, 2);
514 VbglHGCMParmUInt64Set(&Msg.f64Features0, 0);
515 VbglHGCMParmUInt64Set(&Msg.f64Features1, RT_BIT_64(63));
516
517 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
518 if (RT_SUCCESS(rc))
519 {
520 Assert(Msg.f64Features0.type == VMMDevHGCMParmType_64bit);
521 Assert(Msg.f64Features1.type == VMMDevHGCMParmType_64bit);
522 if (Msg.f64Features1.u.value64 & RT_BIT_64(63))
523 rc = VERR_NOT_SUPPORTED;
524 else if (pfHostFeatures)
525 *pfHostFeatures = Msg.f64Features0.u.value64;
526 break;
527 }
528 } while (rc == VERR_INTERRUPTED);
529 return rc;
530
531}
532
533/**
534 * Peeks at the next host message, waiting for one to turn up.
535 *
536 * This glosses over the difference between new (6.1) and old (1.3.2) host
537 * service versions, however it does so by abusing @a pcParameters, so don't use
538 * it directly when in legacy mode, always pass it on to
539 * VbglR3ClipboardEventGetNext() or VbglR3ClipboardEventGetNextEx().
540 *
541 * @returns VBox status code.
542 * @retval VERR_INTERRUPTED if interrupted. Does the necessary cleanup, so
543 * caller just have to repeat this call.
544 * @retval VERR_VM_RESTORED if the VM has been restored (idRestoreCheck).
545 *
546 * @param pCtx Shared Clipboard command context to use for the connection.
547 * @param pidMsg Where to store the message id.
548 * @param pcParameters Where to store the number of parameters which will
549 * be received in a second call to the host.
550 * @param pidRestoreCheck Pointer to the VbglR3GetSessionId() variable to use
551 * for the VM restore check. Optional.
552 *
553 * @note Restore check is only performed optimally with a 6.0 host.
554 */
555VBGLR3DECL(int) VbglR3ClipboardMsgPeekWait(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pidMsg,
556 uint32_t *pcParameters, uint64_t *pidRestoreCheck)
557{
558 AssertPtrReturn(pidMsg, VERR_INVALID_POINTER);
559 AssertPtrReturn(pcParameters, VERR_INVALID_POINTER);
560
561 struct
562 {
563 VBGLIOCHGCMCALL Hdr;
564 HGCMFunctionParameter idMsg; /* Doubles as restore check on input. */
565 HGCMFunctionParameter cParameters;
566 } Msg;
567 int rc;
568 if (!pCtx->fUseLegacyProtocol)
569 {
570 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT, 2);
571 VbglHGCMParmUInt64Set(&Msg.idMsg, pidRestoreCheck ? *pidRestoreCheck : 0);
572 VbglHGCMParmUInt32Set(&Msg.cParameters, 0);
573 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
574 LogFlowFunc(("VbglR3HGCMCall -> %Rrc\n", rc));
575 if (RT_SUCCESS(rc))
576 {
577 AssertMsgReturn( Msg.idMsg.type == VMMDevHGCMParmType_64bit
578 && Msg.cParameters.type == VMMDevHGCMParmType_32bit,
579 ("msg.type=%d num_parms.type=%d\n", Msg.idMsg.type, Msg.cParameters.type),
580 VERR_INTERNAL_ERROR_3);
581
582 *pidMsg = (uint32_t)Msg.idMsg.u.value64;
583 *pcParameters = Msg.cParameters.u.value32;
584 return rc;
585 }
586
587 /*
588 * If restored, update pidRestoreCheck.
589 */
590 if (rc == VERR_VM_RESTORED && pidRestoreCheck)
591 *pidRestoreCheck = Msg.idMsg.u.value64;
592 }
593 else
594 {
595 /*
596 * We do some crude stuff here by putting the 2nd parameter (foramts) in the parameter count,
597 * however it's supposed to be passed directly to VbglR3ClipboardEventGetNext or
598 * VbglR3ClipboardEventGetNextEx, so that's fine...
599 */
600 rc = VbglR3ClipboardGetHostMsgOld(pCtx->idClient, pidMsg, pcParameters);
601 if (RT_SUCCESS(rc))
602 return rc;
603 }
604
605 /*
606 * If interrupted we must cancel the call so it doesn't prevent us from making another one.
607 */
608 if (rc == VERR_INTERRUPTED)
609 {
610 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_CANCEL, 0);
611 int rc2 = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg.Hdr));
612 AssertRC(rc2);
613 }
614
615 *pidMsg = UINT32_MAX - 1;
616 *pcParameters = UINT32_MAX - 2;
617 return rc;
618}
619
620#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
621
622/**
623 * Reads a root list header from the host.
624 *
625 * @returns VBox status code.
626 * @param pCtx Shared Clipboard command context to use for the connection.
627 * @param pRootListHdr Where to store the received root list header.
628 */
629static int vbglR3ClipboardRootListHdrRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLISTHDR pRootListHdr)
630{
631 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
632 AssertPtrReturn(pRootListHdr, VERR_INVALID_POINTER);
633
634 VBoxShClRootListHdrMsg Msg;
635
636 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
637 VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ);
638
639 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
640 Msg.ReqParms.fRoots.SetUInt32(0);
641
642 Msg.cRoots.SetUInt32(0);
643
644 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
645 if (RT_SUCCESS(rc))
646 {
647 rc = Msg.ReqParms.fRoots.GetUInt32(&pRootListHdr->fRoots); AssertRC(rc);
648 if (RT_SUCCESS(rc))
649 {
650 rc = Msg.cRoots.GetUInt32(&pRootListHdr->cRoots);
651 AssertRC(rc);
652 }
653 }
654
655 LogFlowFuncLeaveRC(rc);
656 return rc;
657}
658
659/**
660 * Reads a root list entry from the host.
661 *
662 * @returns VBox status code.
663 * @param pCtx Shared Clipboard command context to use for the connection.
664 * @param uIndex Index of root list entry to read.
665 * @param pRootListEntry Where to store the root list entry read from the host.
666 */
667static int vbglR3ClipboardRootListEntryRead(PVBGLR3SHCLCMDCTX pCtx, uint32_t uIndex, PSHCLROOTLISTENTRY pRootListEntry)
668{
669 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
670 AssertPtrReturn(pRootListEntry, VERR_INVALID_POINTER);
671
672 VBoxShClRootListEntryMsg Msg;
673
674 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
675 VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ);
676
677 Msg.Parms.uContext.SetUInt64(pCtx->idContext);
678 Msg.Parms.fInfo.SetUInt32(pRootListEntry->fInfo);
679 Msg.Parms.uIndex.SetUInt32(uIndex);
680
681 Msg.szName.SetPtr(pRootListEntry->pszName, pRootListEntry->cbName);
682 Msg.cbInfo.SetUInt32(pRootListEntry->cbInfo);
683 Msg.pvInfo.SetPtr(pRootListEntry->pvInfo, pRootListEntry->cbInfo);
684
685 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
686 if (RT_SUCCESS(rc))
687 {
688 rc = Msg.Parms.fInfo.GetUInt32(&pRootListEntry->fInfo); AssertRC(rc);
689 if (RT_SUCCESS(rc))
690 {
691 uint32_t cbInfo = 0;
692 rc = Msg.cbInfo.GetUInt32(&cbInfo); AssertRC(rc);
693 if (pRootListEntry->cbInfo != cbInfo)
694 rc = VERR_INVALID_PARAMETER;
695 }
696 }
697
698 LogFlowFuncLeaveRC(rc);
699 return rc;
700}
701
702/**
703 * Reads the root list from the host.
704 *
705 * @returns VBox status code.
706 * @param pCtx Shared Clipboard command context to use for the connection.
707 * @param ppRootList Where to store the (allocated) root list. Must be free'd by the caller with
708 * SharedClipboardTransferRootListFree().
709 */
710VBGLR3DECL(int) VbglR3ClipboardRootListRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLIST *ppRootList)
711{
712 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
713 AssertPtrReturn(ppRootList, VERR_INVALID_POINTER);
714
715 int rc;
716
717 PSHCLROOTLIST pRootList = ShClTransferRootListAlloc();
718 if (pRootList)
719 {
720 rc = vbglR3ClipboardRootListHdrRead(pCtx, &pRootList->Hdr);
721 if (RT_SUCCESS(rc))
722 {
723 if (pRootList->Hdr.cRoots)
724 {
725 pRootList->paEntries =
726 (PSHCLROOTLISTENTRY)RTMemAllocZ(pRootList->Hdr.cRoots * sizeof(SHCLROOTLISTENTRY));
727 if (pRootList->paEntries)
728 {
729 for (uint32_t i = 0; i < pRootList->Hdr.cRoots; i++)
730 {
731 SHCLROOTLISTENTRY *pEntry = &pRootList->paEntries[i];
732 AssertPtr(pEntry);
733
734 rc = ShClTransferRootListEntryInit(pEntry);
735 if (RT_SUCCESS(rc))
736 rc = vbglR3ClipboardRootListEntryRead(pCtx, i, pEntry);
737
738 if (RT_FAILURE(rc))
739 break;
740 }
741 }
742 else
743 rc = VERR_NO_MEMORY;
744 }
745 }
746
747 if (RT_SUCCESS(rc))
748 {
749 *ppRootList = pRootList;
750 }
751 else
752 ShClTransferRootListFree(pRootList);
753 }
754 else
755 rc = VERR_NO_MEMORY;
756
757 LogFlowFuncLeaveRC(rc);
758 return rc;
759}
760
761/**
762 * Receives a transfer status from the host.
763 *
764 * @returns VBox status code.
765 * @param pCtx Shared Clipboard command context to use for the connection.
766 * @param pEnmDir Where to store the transfer direction for the reported transfer.
767 * @param pReport Where to store the transfer (status) report.
768 */
769VBGLR3DECL(int) VbglR3ClipboarTransferStatusRecv(PVBGLR3SHCLCMDCTX pCtx,
770 PSHCLTRANSFERDIR pEnmDir, PSHCLTRANSFERREPORT pReport)
771{
772 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
773 AssertPtrReturn(pReport, VERR_INVALID_POINTER);
774 AssertPtrReturn(pEnmDir, VERR_INVALID_POINTER);
775
776 VBoxShClTransferStatusMsg Msg;
777 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
778 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_TRANSFER_STATUS);
779
780 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_STATUS);
781 Msg.enmDir.SetUInt32(0);
782 Msg.enmStatus.SetUInt32(0);
783 Msg.rc.SetUInt32(0);
784 Msg.fFlags.SetUInt32(0);
785
786 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
787 if (RT_SUCCESS(rc))
788 {
789 rc = Msg.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
790 if (RT_SUCCESS(rc))
791 {
792 rc = Msg.enmDir.GetUInt32((uint32_t *)pEnmDir);
793 AssertRC(rc);
794 }
795 if (RT_SUCCESS(rc))
796 {
797 rc = Msg.enmStatus.GetUInt32(&pReport->uStatus);
798 AssertRC(rc);
799 }
800 if (RT_SUCCESS(rc))
801 {
802 rc = Msg.rc.GetUInt32((uint32_t *)&pReport->rc);
803 AssertRC(rc);
804 }
805 if (RT_SUCCESS(rc))
806 {
807 rc = Msg.fFlags.GetUInt32(&pReport->fFlags);
808 AssertRC(rc);
809 }
810 }
811
812 LogFlowFuncLeaveRC(rc);
813 return rc;
814}
815
816/**
817 * Replies to a transfer report from the host.
818 *
819 * @returns VBox status code.
820 * @param pCtx Shared Clipboard command context to use for the connection.
821 * @param pTransfer Transfer of report to reply to.
822 * @param uStatus Tranfer status to reply.
823 * @param rcTransfer Result code (rc) to reply.
824 */
825VBGLR3DECL(int) VbglR3ClipboardTransferStatusReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFER pTransfer,
826 SHCLTRANSFERSTATUS uStatus, int rcTransfer)
827{
828 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
829 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
830
831 RT_NOREF(pTransfer);
832
833 VBoxShClReplyMsg Msg;
834 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
835 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
836
837 Msg.uContext.SetUInt64(pCtx->idContext);
838 Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS);
839 Msg.rc.SetUInt32((uint32_t )rcTransfer); /* int vs. uint32_t */
840 Msg.pvPayload.SetPtr(NULL, 0);
841
842 Msg.u.TransferStatus.enmStatus.SetUInt32((uint32_t)uStatus);
843
844 LogFlowFunc(("%s\n", ShClTransferStatusToStr(uStatus)));
845
846 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
847
848 LogFlowFuncLeaveRC(rc);
849 return rc;
850}
851
852/**
853 * Receives a host request to read a root list header from the guest.
854 *
855 * @returns VBox status code.
856 * @param pCtx Shared Clipboard command context to use for the connection.
857 * @param pfRoots Where to store the root list header flags to use, requested by the host.
858 */
859VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReq(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pfRoots)
860{
861 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
862 AssertPtrReturn(pfRoots, VERR_INVALID_POINTER);
863
864 VBoxShClRootListReadReqMsg Msg;
865 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
866 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ_REQ);
867
868 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ);
869 Msg.ReqParms.fRoots.SetUInt32(0);
870
871 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
872 if (RT_SUCCESS(rc))
873 {
874 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
875 if (RT_SUCCESS(rc))
876 {
877 rc = Msg.ReqParms.fRoots.GetUInt32(pfRoots);
878 AssertRC(rc);
879 }
880 }
881
882 LogFlowFuncLeaveRC(rc);
883 return rc;
884}
885
886/**
887 * Replies to a root list header request.
888 *
889 * @returns VBox status code.
890 * @param pCtx Shared Clipboard command context to use for the connection.
891 * @param pRootListHdr Root lsit header to reply to the host.
892 */
893VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLISTHDR pRootListHdr)
894{
895 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
896 AssertPtrReturn(pRootListHdr, VERR_INVALID_POINTER);
897
898 VBoxShClRootListHdrMsg Msg;
899 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
900 VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_WRITE);
901
902 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
903 Msg.ReqParms.fRoots.SetUInt32(pRootListHdr->fRoots);
904
905 Msg.cRoots.SetUInt32(pRootListHdr->cRoots);
906
907 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
908
909 LogFlowFuncLeaveRC(rc);
910 return rc;
911}
912
913/**
914 * Receives a host request to read a root list entry from the guest.
915 *
916 * @returns VBox status code.
917 * @param pCtx Shared Clipboard command context to use for the connection.
918 * @param puIndex Where to return the index of the root list entry the host wants to read.
919 * @param pfInfo Where to return the read flags the host wants to use.
920 */
921VBGLR3DECL(int) VbglR3ClipboardRootListEntryReadReq(PVBGLR3SHCLCMDCTX pCtx, uint32_t *puIndex, uint32_t *pfInfo)
922{
923 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
924 AssertPtrReturn(puIndex, VERR_INVALID_POINTER);
925 AssertPtrReturn(pfInfo, VERR_INVALID_POINTER);
926
927 VBoxShClRootListEntryReadReqMsg Msg;
928 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
929 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ);
930
931 Msg.Parms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ);
932 Msg.Parms.fInfo.SetUInt32(0);
933 Msg.Parms.uIndex.SetUInt32(0);
934
935 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
936 if (RT_SUCCESS(rc))
937 {
938 rc = Msg.Parms.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
939 if (RT_SUCCESS(rc))
940 {
941 rc = Msg.Parms.fInfo.GetUInt32(pfInfo);
942 AssertRC(rc);
943 }
944 if (RT_SUCCESS(rc))
945 {
946 rc = Msg.Parms.uIndex.GetUInt32(puIndex);
947 AssertRC(rc);
948 }
949 }
950
951 LogFlowFuncLeaveRC(rc);
952 return rc;
953}
954
955/**
956 * Replies to a root list entry read request from the host.
957 *
958 * @returns VBox status code.
959 * @param pCtx Shared Clipboard command context to use for the connection.
960 * @param uIndex Index of root list entry to reply.
961 * @param pEntry Actual root list entry to reply.
962 */
963VBGLR3DECL(int) VbglR3ClipboardRootListEntryReadReply(PVBGLR3SHCLCMDCTX pCtx, uint32_t uIndex, PSHCLROOTLISTENTRY pEntry)
964{
965 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
966 AssertPtrReturn(pEntry, VERR_INVALID_POINTER);
967
968 VBoxShClRootListEntryMsg Msg;
969 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
970 VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_WRITE);
971
972 Msg.Parms.uContext.SetUInt64(pCtx->idContext);
973 Msg.Parms.fInfo.SetUInt32(0);
974 Msg.Parms.uIndex.SetUInt32(uIndex);
975
976 Msg.szName.SetPtr(pEntry->pszName, pEntry->cbName);
977 Msg.cbInfo.SetUInt32(pEntry->cbInfo);
978 Msg.pvInfo.SetPtr(pEntry->pvInfo, pEntry->cbInfo);
979
980 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
981
982 LogFlowFuncLeaveRC(rc);
983 return rc;
984}
985
986/**
987 * Sends a request to open a list handle to the host.
988 *
989 * @returns VBox status code.
990 * @param pCtx Shared Clipboard command context to use for the connection.
991 * @param pOpenParms List open parameters to use for the open request.
992 * @param phList Where to return the list handle received from the host.
993 */
994VBGLR3DECL(int) VbglR3ClipboardListOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
995 PSHCLLISTHANDLE phList)
996{
997 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
998 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
999 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1000
1001 VBoxShClListOpenMsg Msg;
1002 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1003 VBOX_SHCL_GUEST_FN_LIST_OPEN, VBOX_SHCL_CPARMS_LIST_OPEN);
1004
1005 Msg.uContext.SetUInt64(pCtx->idContext);
1006 Msg.fList.SetUInt32(0);
1007 Msg.pvFilter.SetPtr(pOpenParms->pszFilter, pOpenParms->cbFilter);
1008 Msg.pvPath.SetPtr(pOpenParms->pszPath, pOpenParms->cbPath);
1009 Msg.uHandle.SetUInt64(0);
1010
1011 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1012 if (RT_SUCCESS(rc))
1013 {
1014 rc = Msg.uHandle.GetUInt64(phList); AssertRC(rc);
1015 }
1016
1017 LogFlowFuncLeaveRC(rc);
1018 return rc;
1019}
1020
1021/**
1022 * Receives a host request to open a list handle on the guest.
1023 *
1024 * @returns VBox status code.
1025 * @param pCtx Shared Clipboard command context to use for the connection.
1026 * @param pOpenParms Where to store the open parameters the host wants to use for opening the list handle.
1027 */
1028VBGLR3DECL(int) VbglR3ClipboardListOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms)
1029{
1030 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1031 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
1032
1033 VBoxShClListOpenMsg Msg;
1034 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1035 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_OPEN);
1036
1037 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN);
1038 Msg.fList.SetUInt32(0);
1039 Msg.pvPath.SetPtr(pOpenParms->pszPath, pOpenParms->cbPath);
1040 Msg.pvFilter.SetPtr(pOpenParms->pszFilter, pOpenParms->cbFilter);
1041 Msg.uHandle.SetUInt64(0);
1042
1043 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1044 if (RT_SUCCESS(rc))
1045 {
1046 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1047 if (RT_SUCCESS(rc))
1048 rc = Msg.fList.GetUInt32(&pOpenParms->fList);
1049 }
1050
1051 LogFlowFuncLeaveRC(rc);
1052 return rc;
1053}
1054
1055/**
1056 * Replies to a list open request from the host.
1057 *
1058 * @returns VBox status code.
1059 * @param pCtx Shared Clipboard command context to use for the connection.
1060 * @param rcReply Return code to reply to the host.
1061 * @param hList List handle of (guest) list to reply to the host.
1062 */
1063VBGLR3DECL(int) VbglR3ClipboardListOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList)
1064{
1065 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1066
1067 VBoxShClReplyMsg Msg;
1068 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1069 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1070
1071 Msg.uContext.SetUInt64(pCtx->idContext);
1072 Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN);
1073 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1074 Msg.pvPayload.SetPtr(NULL, 0);
1075
1076 Msg.u.ListOpen.uHandle.SetUInt64(hList);
1077
1078 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1079
1080 LogFlowFuncLeaveRC(rc);
1081 return rc;
1082}
1083
1084/**
1085 * Receives a host request to close a list handle on the guest.
1086 *
1087 * @returns VBox status code.
1088 * @param pCtx Shared Clipboard command context to use for the connection.
1089 * @param phList Where to store the list handle to close, received from the host.
1090 */
1091VBGLR3DECL(int) VbglR3ClipboardListCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList)
1092{
1093 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1094 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1095
1096 VBoxShClListCloseMsg Msg;
1097 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1098 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_CLOSE);
1099
1100 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE);
1101 Msg.uHandle.SetUInt64(0);
1102
1103 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1104 if (RT_SUCCESS(rc))
1105 {
1106 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1107 if (RT_SUCCESS(rc))
1108 {
1109 rc = Msg.uHandle.GetUInt64(phList);
1110 AssertRC(rc);
1111 }
1112 }
1113
1114 LogFlowFuncLeaveRC(rc);
1115 return rc;
1116}
1117
1118/**
1119 * Replies to a list handle close request from the host.
1120 *
1121 * @returns VBox status code.
1122 * @param pCtx Shared Clipboard command context to use for the connection.
1123 * @param rcReply Return code to reply to the host.
1124 * @param hList List handle the send the close reply for.
1125 */
1126VBGLR3DECL(int) VbglR3ClipboardListCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList)
1127{
1128 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1129
1130 VBoxShClReplyMsg Msg;
1131 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1132 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1133
1134 Msg.uContext.SetUInt64(pCtx->idContext);
1135 Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_LIST_CLOSE);
1136 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1137 Msg.pvPayload.SetPtr(NULL, 0);
1138
1139 Msg.u.ListOpen.uHandle.SetUInt64(hList);
1140
1141 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1142
1143 LogFlowFuncLeaveRC(rc);
1144 return rc;
1145}
1146
1147/**
1148 * Sends a request to close a list handle to the host.
1149 *
1150 * @returns VBox status code.
1151 * @param pCtx Shared Clipboard command context to use for the connection.
1152 * @param hList List handle to request for closing on the host.
1153 */
1154VBGLR3DECL(int) VbglR3ClipboardListCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList)
1155{
1156 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1157
1158 VBoxShClListCloseMsg Msg;
1159 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1160 VBOX_SHCL_GUEST_FN_LIST_CLOSE, VBOX_SHCL_CPARMS_LIST_CLOSE);
1161
1162 Msg.uContext.SetUInt64(pCtx->idContext);
1163 Msg.uHandle.SetUInt64(hList);
1164
1165 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1166
1167 LogFlowFuncLeaveRC(rc);
1168 return rc;
1169}
1170
1171/**
1172 * Sends a request to read a list header to the host.
1173 *
1174 * @returns VBox status code.
1175 * @param pCtx Shared Clipboard command context to use for the connection.
1176 * @param hList List handle to read list header for.
1177 * @param fFlags List header read flags to use.
1178 * @param pListHdr Where to return the list header received from the host.
1179 */
1180VBGLR3DECL(int) VbglR3ClipboardListHdrRead(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList, uint32_t fFlags,
1181 PSHCLLISTHDR pListHdr)
1182{
1183 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1184 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
1185
1186 VBoxShClListHdrMsg Msg;
1187 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1188 VBOX_SHCL_GUEST_FN_LIST_HDR_READ, VBOX_SHCL_CPARMS_LIST_HDR);
1189
1190 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1191 Msg.ReqParms.uHandle.SetUInt64(hList);
1192 Msg.ReqParms.fFlags.SetUInt32(fFlags);
1193
1194 Msg.fFeatures.SetUInt32(0);
1195 Msg.cbTotalSize.SetUInt32(0);
1196 Msg.cTotalObjects.SetUInt64(0);
1197 Msg.cbTotalSize.SetUInt64(0);
1198
1199 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1200 if (RT_SUCCESS(rc))
1201 {
1202 rc = Msg.fFeatures.GetUInt32(&pListHdr->fFeatures);
1203 if (RT_SUCCESS(rc))
1204 rc = Msg.cTotalObjects.GetUInt64(&pListHdr->cTotalObjects);
1205 if (RT_SUCCESS(rc))
1206 rc = Msg.cbTotalSize.GetUInt64(&pListHdr->cbTotalSize);
1207 }
1208
1209 LogFlowFuncLeaveRC(rc);
1210 return rc;
1211}
1212
1213/**
1214 * Receives a host request to read a list header on the guest.
1215 *
1216 * @returns VBox status code.
1217 * @param pCtx Shared Clipboard command context to use for the connection.
1218 * @param phList Where to return the list handle to read list header for.
1219 * @param pfFlags Where to return the List header read flags to use.
1220 */
1221VBGLR3DECL(int) VbglR3ClipboardListHdrReadRecvReq(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList, uint32_t *pfFlags)
1222{
1223 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1224 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1225 AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
1226
1227 VBoxShClListHdrReadReqMsg Msg;
1228 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1229 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_HDR_READ_REQ);
1230
1231 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ);
1232 Msg.ReqParms.uHandle.SetUInt64(0);
1233 Msg.ReqParms.fFlags.SetUInt32(0);
1234
1235 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1236 if (RT_SUCCESS(rc))
1237 {
1238 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1239 if (RT_SUCCESS(rc))
1240 rc = Msg.ReqParms.uHandle.GetUInt64(phList);
1241 if (RT_SUCCESS(rc))
1242 rc = Msg.ReqParms.fFlags.GetUInt32(pfFlags);
1243 }
1244
1245 LogFlowFuncLeaveRC(rc);
1246 return rc;
1247}
1248
1249/**
1250 * Sends (writes) a list header to the host.
1251 *
1252 * @returns VBox status code.
1253 * @param pCtx Shared Clipboard command context to use for the connection.
1254 * @param hList List handle to write list header for.
1255 * @param pListHdr List header to write.
1256 */
1257VBGLR3DECL(int) VbglR3ClipboardListHdrWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1258 PSHCLLISTHDR pListHdr)
1259{
1260 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1261 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
1262
1263 VBoxShClListHdrMsg Msg;
1264 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1265 VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE, VBOX_SHCL_CPARMS_LIST_HDR);
1266
1267 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1268 Msg.ReqParms.uHandle.SetUInt64(hList);
1269 Msg.ReqParms.fFlags.SetUInt32(0);
1270
1271 Msg.fFeatures.SetUInt32(0);
1272 Msg.cbTotalSize.SetUInt32(pListHdr->fFeatures);
1273 Msg.cTotalObjects.SetUInt64(pListHdr->cTotalObjects);
1274 Msg.cbTotalSize.SetUInt64(pListHdr->cbTotalSize);
1275
1276 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1277
1278 LogFlowFuncLeaveRC(rc);
1279 return rc;
1280}
1281
1282/**
1283 * Sends a request to read a list entry from the host.
1284 *
1285 * @returns VBox status code.
1286 * @param pCtx Shared Clipboard command context to use for the connection.
1287 * @param hList List handle to request to read a list entry for.
1288 * @param pListEntry Where to return the list entry read from the host.
1289 */
1290VBGLR3DECL(int) VbglR3ClipboardListEntryRead(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1291 PSHCLLISTENTRY pListEntry)
1292{
1293 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1294 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
1295
1296 VBoxShClListEntryMsg Msg;
1297 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1298 VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ, VBOX_SHCL_CPARMS_LIST_ENTRY);
1299
1300 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1301 Msg.ReqParms.uHandle.SetUInt64(hList);
1302 Msg.ReqParms.fInfo.SetUInt32(0);
1303
1304 Msg.szName.SetPtr(pListEntry->pszName, pListEntry->cbName);
1305 Msg.cbInfo.SetUInt32(pListEntry->cbInfo);
1306 Msg.pvInfo.SetPtr(pListEntry->pvInfo, pListEntry->cbInfo);
1307
1308 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1309 if (RT_SUCCESS(rc))
1310 {
1311 rc = Msg.cbInfo.GetUInt32(&pListEntry->cbInfo); AssertRC(rc);
1312 }
1313
1314 LogFlowFuncLeaveRC(rc);
1315 return rc;
1316}
1317
1318/**
1319 * Receives a host request to read a list entry from the guest.
1320 *
1321 * @returns VBox status code.
1322 * @param pCtx Shared Clipboard command context to use for the connection.
1323 * @param phList Where to return the list handle to read a list entry for.
1324 * @param pfInfo Where to return the list read flags.
1325 */
1326VBGLR3DECL(int) VbglR3ClipboardListEntryReadRecvReq(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList, uint32_t *pfInfo)
1327{
1328 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1329 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1330 AssertPtrReturn(pfInfo, VERR_INVALID_POINTER);
1331
1332 VBoxShClListEntryReadReqMsg Msg;
1333 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1334 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_ENTRY_READ);
1335
1336 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ);
1337 Msg.ReqParms.uHandle.SetUInt64(0);
1338 Msg.ReqParms.fInfo.SetUInt32(0);
1339
1340 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1341 if (RT_SUCCESS(rc))
1342 {
1343 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1344 if (RT_SUCCESS(rc))
1345 {
1346 rc = Msg.ReqParms.uHandle.GetUInt64(phList);
1347 AssertRC(rc);
1348 }
1349 if (RT_SUCCESS(rc))
1350 {
1351 rc = Msg.ReqParms.fInfo.GetUInt32(pfInfo);
1352 AssertRC(rc);
1353 }
1354 }
1355
1356 LogFlowFuncLeaveRC(rc);
1357 return rc;
1358}
1359
1360/**
1361 * Sends (writes) a list entry to the host.
1362 *
1363 * @returns VBox status code.
1364 * @param pCtx Shared Clipboard command context to use for the connection.
1365 * @param hList List handle to write a list etnry for.
1366 * @param pListEntry List entry to write.
1367 */
1368VBGLR3DECL(int) VbglR3ClipboardListEntryWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1369 PSHCLLISTENTRY pListEntry)
1370{
1371 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1372 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
1373
1374 VBoxShClListEntryMsg Msg;
1375 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1376 VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE, VBOX_SHCL_CPARMS_LIST_ENTRY);
1377
1378 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1379 Msg.ReqParms.uHandle.SetUInt64(hList);
1380 Msg.ReqParms.fInfo.SetUInt32(pListEntry->fInfo);
1381
1382 Msg.szName.SetPtr(pListEntry->pszName, pListEntry->cbName);
1383 Msg.cbInfo.SetUInt32(pListEntry->cbInfo);
1384 Msg.pvInfo.SetPtr(pListEntry->pvInfo, pListEntry->cbInfo);
1385
1386 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1387
1388 LogFlowFuncLeaveRC(rc);
1389 return rc;
1390}
1391
1392/**
1393 * Receives a host request to open an object on the guest.
1394 *
1395 * @returns VBox status code.
1396 * @param pCtx Shared Clipboard command context to use for the connection.
1397 * @param pCreateParms Where to store the object open/create parameters received from the host.
1398 */
1399VBGLR3DECL(int) VbglR3ClipboardObjOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms)
1400{
1401 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1402 AssertPtrReturn(pCreateParms, VERR_INVALID_POINTER);
1403
1404 VBoxShClObjOpenMsg Msg;
1405 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1406 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_OPEN);
1407
1408 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN);
1409 Msg.uHandle.SetUInt64(0);
1410 Msg.szPath.SetPtr(pCreateParms->pszPath, pCreateParms->cbPath);
1411 Msg.fCreate.SetUInt32(0);
1412
1413 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1414 if (RT_SUCCESS(rc))
1415 {
1416 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1417 if (RT_SUCCESS(rc))
1418 rc = Msg.fCreate.GetUInt32(&pCreateParms->fCreate);
1419 }
1420
1421 LogFlowFuncLeaveRC(rc);
1422 return rc;
1423}
1424
1425/**
1426 * Replies a host request to open an object.
1427 *
1428 * @returns VBox status code.
1429 * @param pCtx Shared Clipboard command context to use for the connection.
1430 * @param rcReply Return code to reply to the host.
1431 * @param hObj Object handle of opened object to reply to the host.
1432 */
1433VBGLR3DECL(int) VbglR3ClipboardObjOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj)
1434{
1435 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1436
1437 VBoxShClReplyMsg Msg;
1438 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1439 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1440
1441 Msg.uContext.SetUInt64(pCtx->idContext);
1442 Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN);
1443 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1444 Msg.pvPayload.SetPtr(NULL, 0);
1445
1446 Msg.u.ObjOpen.uHandle.SetUInt64(hObj);
1447
1448 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1449
1450 LogFlowFuncLeaveRC(rc);
1451 return rc;
1452}
1453
1454/**
1455 * Sends an object open request to the host.
1456 *
1457 * @returns VBox status code.
1458 * @param pCtx Shared Clipboard command context to use for the connection.
1459 * @param pCreateParms Object open/create parameters to use for opening the object on the host.
1460 * @param phObj Where to return the object handle from the host.
1461 */
1462VBGLR3DECL(int) VbglR3ClipboardObjOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms,
1463 PSHCLOBJHANDLE phObj)
1464{
1465 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1466 AssertPtrReturn(pCreateParms, VERR_INVALID_POINTER);
1467 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1468
1469 VBoxShClObjOpenMsg Msg;
1470 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1471 VBOX_SHCL_GUEST_FN_OBJ_OPEN, VBOX_SHCL_CPARMS_OBJ_OPEN);
1472
1473 Msg.uContext.SetUInt64(pCtx->idContext);
1474 Msg.uHandle.SetUInt64(0);
1475 Msg.szPath.SetPtr((void *)pCreateParms->pszPath, pCreateParms->cbPath);
1476 Msg.fCreate.SetUInt32(pCreateParms->fCreate);
1477
1478 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1479 if (RT_SUCCESS(rc))
1480 {
1481 Msg.uHandle.GetUInt64(phObj);
1482 }
1483
1484 LogFlowFuncLeaveRC(rc);
1485 return rc;
1486}
1487
1488/**
1489 * Receives a host request to close an object on the guest.
1490 *
1491 * @returns VBox status code.
1492 * @param pCtx Shared Clipboard command context to use for the connection.
1493 * @param phObj Where to return the object handle to close from the host.
1494 */
1495VBGLR3DECL(int) VbglR3ClipboardObjCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj)
1496{
1497 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1498 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1499
1500 VBoxShClObjCloseMsg Msg;
1501 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1502 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_CLOSE);
1503
1504 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE);
1505 Msg.uHandle.SetUInt64(0);
1506
1507 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1508 if (RT_SUCCESS(rc))
1509 {
1510 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1511 if (RT_SUCCESS(rc))
1512 rc = Msg.uHandle.GetUInt64(phObj);
1513 }
1514
1515 LogFlowFuncLeaveRC(rc);
1516 return rc;
1517}
1518
1519/**
1520 * Replies to an object open request from the host.
1521 *
1522 * @returns VBox status code.
1523 * @param pCtx Shared Clipboard command context to use for the connection.
1524 * @param rcReply Return code to reply to the host.
1525 * @param hObj Object handle to reply to the host.
1526 */
1527VBGLR3DECL(int) VbglR3ClipboardObjCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj)
1528{
1529 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1530
1531 VBoxShClReplyMsg Msg;
1532 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1533 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1534
1535 Msg.uContext.SetUInt64(pCtx->idContext);
1536 Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE);
1537 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1538 Msg.pvPayload.SetPtr(NULL, 0);
1539
1540 Msg.u.ObjClose.uHandle.SetUInt64(hObj);
1541
1542 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1543
1544 LogFlowFuncLeaveRC(rc);
1545 return rc;
1546}
1547
1548/**
1549 * Sends a request to close an object to the host.
1550 *
1551 * @returns VBox status code.
1552 * @param pCtx Shared Clipboard command context to use for the connection.
1553 * @param hObj Object handle to close on the host.
1554 */
1555VBGLR3DECL(int) VbglR3ClipboardObjCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj)
1556{
1557 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1558
1559 VBoxShClObjCloseMsg Msg;
1560 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1561 VBOX_SHCL_GUEST_FN_OBJ_CLOSE, VBOX_SHCL_CPARMS_OBJ_CLOSE);
1562
1563 Msg.uContext.SetUInt64(pCtx->idContext);
1564 Msg.uHandle.SetUInt64(hObj);
1565
1566 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1567
1568 LogFlowFuncLeaveRC(rc);
1569 return rc;
1570}
1571
1572/**
1573 * Receives a host request to read from an object on the guest.
1574 *
1575 * @returns VBox status code.
1576 * @param pCtx Shared Clipboard command context to use for the connection.
1577 * @param phObj Where to return the object handle to read from.
1578 * @param pcbToRead Where to return the amount (in bytes) to read.
1579 * @param pfFlags Where to return the read flags.
1580 */
1581VBGLR3DECL(int) VbglR3ClipboardObjReadRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj, uint32_t *pcbToRead,
1582 uint32_t *pfFlags)
1583{
1584 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1585 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1586 AssertPtrReturn(pcbToRead, VERR_INVALID_POINTER);
1587 AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
1588
1589 VBoxShClObjReadReqMsg Msg;
1590 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1591 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_READ_REQ);
1592
1593 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ);
1594 Msg.ReqParms.uHandle.SetUInt64(0);
1595 Msg.ReqParms.cbToRead.SetUInt32(0);
1596 Msg.ReqParms.fRead.SetUInt32(0);
1597
1598 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1599 if (RT_SUCCESS(rc))
1600 {
1601 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1602 if (RT_SUCCESS(rc))
1603 rc = Msg.ReqParms.uHandle.GetUInt64(phObj);
1604 if (RT_SUCCESS(rc))
1605 rc = Msg.ReqParms.cbToRead.GetUInt32(pcbToRead);
1606 if (RT_SUCCESS(rc))
1607 rc = Msg.ReqParms.fRead.GetUInt32(pfFlags);
1608 }
1609
1610 LogFlowFuncLeaveRC(rc);
1611 return rc;
1612}
1613
1614/**
1615 * Sends a request to read from an object to the host.
1616 *
1617 * @returns VBox status code.
1618 * @param pCtx Shared Clipboard command context to use for the connection.
1619 * @param hObj Object handle of object to read from.
1620 * @param pvData Buffer where to store the read object data.
1621 * @param cbData Size (in bytes) of buffer.
1622 * @param pcbRead Where to store the amount (in bytes) read from the object.
1623 */
1624VBGLR3DECL(int) VbglR3ClipboardObjReadSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj,
1625 void *pvData, uint32_t cbData, uint32_t *pcbRead)
1626{
1627 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1628 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1629 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1630 /* pcbRead is optional. */
1631
1632 VBoxShClObjReadWriteMsg Msg;
1633 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1634 VBOX_SHCL_GUEST_FN_OBJ_READ, VBOX_SHCL_CPARMS_OBJ_READ);
1635
1636 Msg.uContext.SetUInt64(pCtx->idContext);
1637 Msg.uHandle.SetUInt64(hObj);
1638 Msg.cbData.SetUInt32(cbData);
1639 Msg.pvData.SetPtr(pvData, cbData);
1640 Msg.cbChecksum.SetUInt32(0);
1641 Msg.pvChecksum.SetPtr(NULL, 0);
1642
1643 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1644 if (RT_SUCCESS(rc))
1645 {
1646 /** @todo Add checksum support. */
1647
1648 if (pcbRead)
1649 {
1650 rc = Msg.cbData.GetUInt32(pcbRead); AssertRC(rc);
1651 AssertReturn(cbData >= *pcbRead, VERR_TOO_MUCH_DATA);
1652 }
1653 }
1654
1655 LogFlowFuncLeaveRC(rc);
1656 return rc;
1657}
1658
1659/**
1660 * Sends a request to write to an object to the host.
1661 *
1662 * @returns VBox status code.
1663 * @param pCtx Shared Clipboard command context to use for the connection.
1664 * @param hObj Object handle of object to write to.
1665 * @param pvData Buffer of data to write to object.
1666 * @param cbData Size (in bytes) of buffer.
1667 * @param pcbWritten Where to store the amount (in bytes) written to the object.
1668 */
1669VBGLR3DECL(int) VbglR3ClipboardObjWriteSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj,
1670 void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1671{
1672 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1673 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1674 /* cbData can be 0. */
1675 /* pcbWritten is optional. */
1676
1677 VBoxShClObjReadWriteMsg Msg;
1678 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1679 VBOX_SHCL_GUEST_FN_OBJ_WRITE, VBOX_SHCL_CPARMS_OBJ_WRITE);
1680
1681 Msg.uContext.SetUInt64(pCtx->idContext);
1682 Msg.uHandle.SetUInt64(hObj);
1683 Msg.pvData.SetPtr(pvData, cbData);
1684 Msg.pvChecksum.SetPtr(NULL, 0);
1685
1686 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1687 if (RT_SUCCESS(rc))
1688 {
1689 /** @todo Add checksum support. */
1690
1691 if (pcbWritten)
1692 *pcbWritten = cbData; /** @todo For now return all as being written. */
1693 }
1694
1695 LogFlowFuncLeaveRC(rc);
1696 return rc;
1697}
1698
1699
1700/*********************************************************************************************************************************
1701* Transfer interface implementations *
1702*********************************************************************************************************************************/
1703
1704static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceGetRoots(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList)
1705{
1706 LogFlowFuncEnter();
1707
1708 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1709 AssertPtr(pCmdCtx);
1710
1711 int rc = VbglR3ClipboardRootListRead(pCmdCtx, ppRootList);
1712
1713 LogFlowFuncLeaveRC(rc);
1714 return rc;
1715}
1716
1717static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
1718 PSHCLLISTHANDLE phList)
1719{
1720 LogFlowFuncEnter();
1721
1722 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1723 AssertPtr(pCmdCtx);
1724
1725 int rc = VbglR3ClipboardListOpenSend(pCmdCtx, pOpenParms, phList);
1726
1727 LogFlowFuncLeaveRC(rc);
1728 return rc;
1729}
1730
1731static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
1732{
1733 LogFlowFuncEnter();
1734
1735 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1736 AssertPtr(pCmdCtx);
1737
1738 int rc = VbglR3ClipboardListCloseSend(pCmdCtx, hList);
1739
1740 LogFlowFuncLeaveRC(rc);
1741 return rc;
1742}
1743
1744static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListHdrRead(PSHCLTXPROVIDERCTX pCtx,
1745 SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
1746{
1747 LogFlowFuncEnter();
1748
1749 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1750 AssertPtr(pCmdCtx);
1751
1752 int rc = ShClTransferListHdrInit(pListHdr);
1753 if (RT_SUCCESS(rc))
1754 {
1755 if (RT_SUCCESS(rc))
1756 {
1757 rc = VbglR3ClipboardListHdrRead(pCmdCtx, hList, 0 /* fFlags */, pListHdr);
1758 }
1759 else
1760 ShClTransferListHdrDestroy(pListHdr);
1761 }
1762
1763 LogFlowFuncLeaveRC(rc);
1764 return rc;
1765}
1766
1767static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListEntryRead(PSHCLTXPROVIDERCTX pCtx,
1768 SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry)
1769{
1770 LogFlowFuncEnter();
1771
1772 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1773 AssertPtr(pCmdCtx);
1774
1775 int rc = VbglR3ClipboardListEntryRead(pCmdCtx, hList, pEntry);
1776
1777 LogFlowFuncLeaveRC(rc);
1778 return rc;
1779}
1780
1781static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceObjOpen(PSHCLTXPROVIDERCTX pCtx,
1782 PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)
1783{
1784 LogFlowFuncEnter();
1785
1786 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1787 AssertPtr(pCmdCtx);
1788
1789 int rc = VbglR3ClipboardObjOpenSend(pCmdCtx, pCreateParms, phObj);
1790
1791 LogFlowFuncLeaveRC(rc);
1792 return rc;
1793}
1794
1795static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
1796{
1797 LogFlowFuncEnter();
1798
1799 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1800 AssertPtr(pCmdCtx);
1801
1802 int rc = VbglR3ClipboardObjCloseSend(pCmdCtx, hObj);
1803
1804 LogFlowFuncLeaveRC(rc);
1805 return rc;
1806}
1807
1808static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceObjRead(PSHCLTXPROVIDERCTX pCtx,
1809 SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData,
1810 uint32_t fFlags, uint32_t *pcbRead)
1811{
1812 LogFlowFuncEnter();
1813
1814 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1815 AssertPtr(pCmdCtx);
1816
1817 RT_NOREF(fFlags); /* Not used yet. */
1818
1819 int rc = VbglR3ClipboardObjReadSend(pCmdCtx, hObj, pvData, cbData, pcbRead);
1820
1821 LogFlowFuncLeaveRC(rc);
1822 return rc;
1823}
1824
1825/**
1826 * Starts a transfer on the guest side.
1827 *
1828 * @returns VBox status code.
1829 * @param pCmdCtx Command context to use.
1830 * @param pTransferCtx Transfer context to create transfer for.
1831 * @param uTransferID ID to use for transfer to start.
1832 * @param enmDir Direction of transfer to start.
1833 * @param enmSource Source of transfer to start.
1834 * @param ppTransfer Where to return the transfer object on success. Optional.
1835 */
1836static int vbglR3ClipboardTransferStart(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
1837 SHCLTRANSFERID uTransferID, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource,
1838 PSHCLTRANSFER *ppTransfer)
1839{
1840 PSHCLTRANSFER pTransfer;
1841 int rc = ShClTransferCreate(&pTransfer);
1842 if (RT_SUCCESS(rc))
1843 {
1844 ShClTransferSetCallbacks(pTransfer, &pCmdCtx->Transfers.Callbacks);
1845
1846 rc = ShClTransferInit(pTransfer, enmDir, enmSource);
1847 if (RT_SUCCESS(rc))
1848 {
1849 rc = ShClTransferCtxTransferRegisterById(pTransferCtx, pTransfer, uTransferID);
1850 if (RT_SUCCESS(rc))
1851 {
1852 SHCLTXPROVIDERCREATIONCTX creationCtx;
1853 RT_ZERO(creationCtx);
1854
1855 /* Assign local provider first and overwrite interface methods below if needed. */
1856 VBClTransferQueryIfaceLocal(&creationCtx.Interface);
1857
1858 /* If this is a read transfer (reading data from host), set the interface to use
1859 * our VbglR3 routines here. */
1860 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE)
1861 {
1862 creationCtx.Interface.pfnRootsGet = vbglR3ClipboardTransferIfaceGetRoots;
1863
1864 creationCtx.Interface.pfnListOpen = vbglR3ClipboardTransferIfaceListOpen;
1865 creationCtx.Interface.pfnListClose = vbglR3ClipboardTransferIfaceListClose;
1866 creationCtx.Interface.pfnListHdrRead = vbglR3ClipboardTransferIfaceListHdrRead;
1867 creationCtx.Interface.pfnListEntryRead = vbglR3ClipboardTransferIfaceListEntryRead;
1868
1869 creationCtx.Interface.pfnObjOpen = vbglR3ClipboardTransferIfaceObjOpen;
1870 creationCtx.Interface.pfnObjClose = vbglR3ClipboardTransferIfaceObjClose;
1871 creationCtx.Interface.pfnObjRead = vbglR3ClipboardTransferIfaceObjRead;
1872
1873 creationCtx.pvUser = pCmdCtx;
1874
1875 rc = ShClTransferSetProviderIface(pTransfer, &creationCtx);
1876 }
1877
1878 if (RT_SUCCESS(rc))
1879 rc = ShClTransferStart(pTransfer);
1880 }
1881
1882 if (RT_FAILURE(rc))
1883 ShClTransferCtxTransferUnregister(pTransferCtx, uTransferID);
1884 }
1885 }
1886
1887 if (RT_SUCCESS(rc))
1888 {
1889 if (ppTransfer)
1890 *ppTransfer = pTransfer;
1891
1892 LogRel2(("Shared Clipboard: Transfer ID=%RU32 (%s %s) successfully started\n",
1893 uTransferID,
1894 enmDir == SHCLTRANSFERDIR_FROM_REMOTE ? "reading from" : "writing to",
1895 enmSource == SHCLSOURCE_LOCAL ? "local" : "remote"));
1896 }
1897 else
1898 LogRel(("Shared Clipboard: Unable to start transfer ID=%RU32, rc=%Rrc\n", uTransferID, rc));
1899
1900 /* Send a reply in any case. */
1901 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
1902 RT_SUCCESS(rc)
1903 ? SHCLTRANSFERSTATUS_STARTED : SHCLTRANSFERSTATUS_ERROR, rc);
1904 if (RT_SUCCESS(rc))
1905 rc = rc2;
1906
1907 if (RT_FAILURE(rc))
1908 {
1909 ShClTransferDestroy(pTransfer);
1910 pTransfer = NULL;
1911 }
1912
1913 LogFlowFuncLeaveRC(rc);
1914 return rc;
1915}
1916
1917/**
1918 * Stops a transfer on the guest side.
1919 *
1920 * @returns VBox status code, or VERR_NOT_FOUND if transfer has not been found.
1921 * @param pCmdCtx Command context to use.
1922 * @param pTransferCtx Transfer context to stop transfer for.
1923 * @param uTransferID ID of transfer to stop.
1924 */
1925static int vbglR3ClipboardTransferStop(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
1926 SHCLTRANSFERID uTransferID)
1927{
1928 int rc;
1929
1930 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, uTransferID);
1931 if (pTransfer)
1932 {
1933 rc = ShClTransferCtxTransferUnregister(pTransferCtx, uTransferID);
1934 if (RT_SUCCESS(rc))
1935 {
1936 LogRel2(("Shared Clipboard: Transfer ID=%RU32 successfully stopped\n", uTransferID));
1937 }
1938 else
1939 LogRel(("Shared Clipboard: Unable to stop transfer ID=%RU32, rc=%Rrc\n", uTransferID, rc));
1940
1941 /* Send a reply in any case. */
1942 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
1943 RT_SUCCESS(rc)
1944 ? SHCLTRANSFERSTATUS_STOPPED : SHCLTRANSFERSTATUS_ERROR, rc);
1945 AssertRC(rc2);
1946 }
1947 else
1948 rc = VERR_NOT_FOUND;
1949
1950 LogFlowFuncLeaveRC(rc);
1951 return rc;
1952}
1953
1954/**
1955 * Sets transfer callbacks of a Shared Clipboard command context.
1956 *
1957 * @param pCmdCtx Command context to set callbacks for.
1958 * @param pCallbacks Pointer to callback table to set.
1959 */
1960VBGLR3DECL(void) VbglR3ClipboardTransferSetCallbacks(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCALLBACKTABLE pCallbacks)
1961{
1962 AssertPtrReturnVoid(pCmdCtx);
1963 AssertPtrReturnVoid(pCallbacks);
1964
1965 ShClTransferCopyCallbacks(&pCmdCtx->Transfers.Callbacks, pCallbacks);
1966}
1967
1968VBGLR3DECL(int) VbglR3ClipboardEventGetNextEx(uint32_t idMsg, uint32_t cParms,
1969 PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
1970 PVBGLR3CLIPBOARDEVENT pEvent)
1971{
1972 AssertPtrReturn(pCmdCtx, VERR_INVALID_POINTER);
1973 AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER);
1974 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1975
1976 LogFunc(("Handling idMsg=%RU32 (%s), cParms=%RU32\n", idMsg, ShClHostMsgToStr(idMsg), cParms));
1977
1978 int rc;
1979 if (!pCmdCtx->fUseLegacyProtocol)
1980 {
1981 bool fErrorSent = false; /* Whether an error has been reported back to the host already. */
1982
1983 switch (idMsg)
1984 {
1985 case VBOX_SHCL_HOST_MSG_TRANSFER_STATUS:
1986 {
1987 SHCLTRANSFERDIR enmDir;
1988 SHCLTRANSFERREPORT transferReport;
1989 rc = VbglR3ClipboarTransferStatusRecv(pCmdCtx, &enmDir, &transferReport);
1990 if (RT_SUCCESS(rc))
1991 {
1992 const SHCLTRANSFERID uTransferID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
1993
1994 LogFlowFunc(("[Transfer %RU32] enmDir=%RU32, status=%s\n",
1995 uTransferID, enmDir, ShClTransferStatusToStr(transferReport.uStatus)));
1996
1997 switch (transferReport.uStatus)
1998 {
1999 case SHCLTRANSFERSTATUS_INITIALIZED:
2000 RT_FALL_THROUGH();
2001 case SHCLTRANSFERSTATUS_STARTED:
2002 {
2003 SHCLSOURCE enmSource = SHCLSOURCE_INVALID;
2004
2005 /* The host announces the transfer direction from its point of view, so inverse the direction here. */
2006 if (enmDir == SHCLTRANSFERDIR_TO_REMOTE)
2007 {
2008 enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
2009 enmSource = SHCLSOURCE_REMOTE;
2010 }
2011 else if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE)
2012 {
2013 enmDir = SHCLTRANSFERDIR_TO_REMOTE;
2014 enmSource = SHCLSOURCE_LOCAL;
2015 }
2016 else
2017 AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
2018
2019 rc = vbglR3ClipboardTransferStart(pCmdCtx, pTransferCtx, uTransferID,
2020 enmDir, enmSource, NULL /* ppTransfer */);
2021 break;
2022 }
2023
2024 case SHCLTRANSFERSTATUS_STOPPED:
2025 RT_FALL_THROUGH();
2026 case SHCLTRANSFERSTATUS_CANCELED:
2027 RT_FALL_THROUGH();
2028 case SHCLTRANSFERSTATUS_KILLED:
2029 RT_FALL_THROUGH();
2030 case SHCLTRANSFERSTATUS_ERROR:
2031 {
2032 rc = vbglR3ClipboardTransferStop(pCmdCtx, pTransferCtx,
2033 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2034 break;
2035 }
2036
2037 default:
2038 rc = VERR_NOT_SUPPORTED;
2039 break;
2040 }
2041
2042 if (RT_SUCCESS(rc))
2043 {
2044 pEvent->u.TransferStatus.enmDir = enmDir;
2045 pEvent->u.TransferStatus.Report = transferReport;
2046 pEvent->u.TransferStatus.uID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
2047
2048 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS;
2049
2050 LogRel2(("Shared Clipboard: Received status %s (rc=%Rrc) for transfer ID=%RU32\n",
2051 ShClTransferStatusToStr(pEvent->u.TransferStatus.Report.uStatus), pEvent->u.TransferStatus.Report.rc,
2052 pEvent->u.TransferStatus.uID));
2053 }
2054 }
2055 break;
2056 }
2057
2058 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ:
2059 {
2060 uint32_t fRoots;
2061 rc = VbglR3ClipboardRootListHdrReadReq(pCmdCtx, &fRoots);
2062
2063 /** @todo Validate / handle fRoots. */
2064
2065 if (RT_SUCCESS(rc))
2066 {
2067 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2068 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2069 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2070
2071 SHCLROOTLISTHDR rootListHdr;
2072 RT_ZERO(rootListHdr);
2073
2074 rootListHdr.cRoots = ShClTransferRootsCount(pTransfer);
2075
2076 LogFlowFunc(("cRoots=%RU32\n", rootListHdr.cRoots));
2077
2078 rc = VbglR3ClipboardRootListHdrReadReply(pCmdCtx, &rootListHdr);
2079 }
2080 break;
2081 }
2082
2083 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ:
2084 {
2085 uint32_t uIndex;
2086 uint32_t fInfo;
2087 rc = VbglR3ClipboardRootListEntryReadReq(pCmdCtx, &uIndex, &fInfo);
2088 if (RT_SUCCESS(rc))
2089 {
2090 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2091 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2092 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2093
2094 SHCLROOTLISTENTRY rootListEntry;
2095 rc = ShClTransferRootsEntry(pTransfer, uIndex, &rootListEntry);
2096 if (RT_SUCCESS(rc))
2097 rc = VbglR3ClipboardRootListEntryReadReply(pCmdCtx, uIndex, &rootListEntry);
2098 }
2099 break;
2100 }
2101
2102 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN:
2103 {
2104 SHCLLISTOPENPARMS openParmsList;
2105 rc = ShClTransferListOpenParmsInit(&openParmsList);
2106 if (RT_SUCCESS(rc))
2107 {
2108 rc = VbglR3ClipboardListOpenRecv(pCmdCtx, &openParmsList);
2109 if (RT_SUCCESS(rc))
2110 {
2111 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2112 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2113 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2114
2115 LogFlowFunc(("pszPath=%s\n", openParmsList.pszPath));
2116
2117 SHCLLISTHANDLE hList = NIL_SHCLLISTHANDLE;
2118 rc = ShClTransferListOpen(pTransfer, &openParmsList, &hList);
2119
2120 /* Reply in any case. */
2121 int rc2 = VbglR3ClipboardListOpenReply(pCmdCtx, rc, hList);
2122 AssertRC(rc2);
2123 }
2124
2125 ShClTransferListOpenParmsDestroy(&openParmsList);
2126 }
2127
2128 break;
2129 }
2130
2131 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE:
2132 {
2133 SHCLLISTHANDLE hList;
2134 rc = VbglR3ClipboardListCloseRecv(pCmdCtx, &hList);
2135 if (RT_SUCCESS(rc))
2136 {
2137 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2138 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2139 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2140
2141 rc = ShClTransferListClose(pTransfer, hList);
2142
2143 /* Reply in any case. */
2144 int rc2 = VbglR3ClipboardListCloseReply(pCmdCtx, rc, hList);
2145 AssertRC(rc2);
2146 }
2147
2148 break;
2149 }
2150
2151 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ:
2152 {
2153 /** @todo Handle filter + list features. */
2154
2155 SHCLLISTHANDLE hList = NIL_SHCLLISTHANDLE;
2156 uint32_t fFlags = 0;
2157 rc = VbglR3ClipboardListHdrReadRecvReq(pCmdCtx, &hList, &fFlags);
2158 if (RT_SUCCESS(rc))
2159 {
2160 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2161 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2162 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2163
2164 SHCLLISTHDR hdrList;
2165 rc = ShClTransferListGetHeader(pTransfer, hList, &hdrList);
2166 if (RT_SUCCESS(rc))
2167 {
2168 rc = VbglR3ClipboardListHdrWrite(pCmdCtx, hList, &hdrList);
2169
2170 ShClTransferListHdrDestroy(&hdrList);
2171 }
2172 }
2173
2174 break;
2175 }
2176
2177 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ:
2178 {
2179 LogFlowFunc(("VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ\n"));
2180
2181 SHCLLISTENTRY entryList;
2182 rc = ShClTransferListEntryInit(&entryList);
2183 if (RT_SUCCESS(rc))
2184 {
2185 SHCLLISTHANDLE hList;
2186 uint32_t fInfo;
2187 rc = VbglR3ClipboardListEntryReadRecvReq(pCmdCtx, &hList, &fInfo);
2188 if (RT_SUCCESS(rc))
2189 {
2190 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2191 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2192 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2193
2194 rc = ShClTransferListRead(pTransfer, hList, &entryList);
2195 if (RT_SUCCESS(rc))
2196 {
2197 PSHCLFSOBJINFO pObjInfo = (PSHCLFSOBJINFO)entryList.pvInfo;
2198 Assert(entryList.cbInfo == sizeof(SHCLFSOBJINFO));
2199
2200 RT_NOREF(pObjInfo);
2201
2202 LogFlowFunc(("\t%s (%RU64 bytes)\n", entryList.pszName, pObjInfo->cbObject));
2203
2204 rc = VbglR3ClipboardListEntryWrite(pCmdCtx, hList, &entryList);
2205 }
2206 }
2207
2208 ShClTransferListEntryDestroy(&entryList);
2209 }
2210
2211 break;
2212 }
2213
2214 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN:
2215 {
2216 SHCLOBJOPENCREATEPARMS openParms;
2217 rc = ShClTransferObjOpenParmsInit(&openParms);
2218 if (RT_SUCCESS(rc))
2219 {
2220 rc = VbglR3ClipboardObjOpenRecv(pCmdCtx, &openParms);
2221 if (RT_SUCCESS(rc))
2222 {
2223 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2224 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2225 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2226
2227 SHCLOBJHANDLE hObj;
2228 rc = ShClTransferObjOpen(pTransfer, &openParms, &hObj);
2229
2230 /* Reply in any case. */
2231 int rc2 = VbglR3ClipboardObjOpenReply(pCmdCtx, rc, hObj);
2232 AssertRC(rc2);
2233 }
2234
2235 ShClTransferObjOpenParmsDestroy(&openParms);
2236 }
2237
2238 break;
2239 }
2240
2241 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE:
2242 {
2243 SHCLOBJHANDLE hObj;
2244 rc = VbglR3ClipboardObjCloseRecv(pCmdCtx, &hObj);
2245 if (RT_SUCCESS(rc))
2246 {
2247 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2248 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2249 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2250
2251 rc = ShClTransferObjClose(pTransfer, hObj);
2252
2253 /* Reply in any case. */
2254 int rc2 = VbglR3ClipboardObjCloseReply(pCmdCtx, rc, hObj);
2255 AssertRC(rc2);
2256 }
2257
2258 break;
2259 }
2260
2261 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ:
2262 {
2263 SHCLOBJHANDLE hObj;
2264 uint32_t cbBuf;
2265 uint32_t fFlags;
2266 rc = VbglR3ClipboardObjReadRecv(pCmdCtx, &hObj, &cbBuf, &fFlags);
2267 if (RT_SUCCESS(rc))
2268 {
2269 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2270 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2271 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2272
2273 AssertBreakStmt(pCmdCtx->Transfers.cbChunkSize, rc = VERR_INVALID_PARAMETER);
2274
2275 const uint32_t cbToRead = RT_MIN(cbBuf, pCmdCtx->Transfers.cbChunkSize);
2276
2277 LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, fFlags=0x%x -> cbChunkSize=%RU32, cbToRead=%RU32\n",
2278 hObj, cbBuf, fFlags, pCmdCtx->Transfers.cbChunkSize, cbToRead));
2279
2280 void *pvBuf = RTMemAlloc(cbToRead);
2281 if (pvBuf)
2282 {
2283 uint32_t cbRead;
2284 rc = ShClTransferObjRead(pTransfer, hObj, pvBuf, cbToRead, fFlags, &cbRead);
2285 if (RT_SUCCESS(rc))
2286 rc = VbglR3ClipboardObjWriteSend(pCmdCtx, hObj, pvBuf, cbRead, NULL /* pcbWritten */);
2287
2288 RTMemFree(pvBuf);
2289 }
2290 else
2291 rc = VERR_NO_MEMORY;
2292 }
2293
2294 break;
2295 }
2296
2297 default:
2298 {
2299 rc = VbglR3ClipboardEventGetNext(idMsg, cParms, pCmdCtx, pEvent);
2300 if (RT_FAILURE(rc))
2301 fErrorSent = true;
2302 break;
2303 }
2304 }
2305
2306 if ( !fErrorSent
2307 && RT_FAILURE(rc))
2308 {
2309 /* Report error back to the host. */
2310 int rc2 = VbglR3ClipboardWriteError(pCmdCtx->idClient, rc);
2311 AssertRC(rc2);
2312 }
2313 }
2314 else
2315 {
2316 /*
2317 * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
2318 * !HACK ALERT! cParms is the format flag or flags.
2319 */
2320 rc = VINF_SUCCESS;
2321 switch (idMsg)
2322 {
2323 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2324 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2325 pEvent->u.fReportedFormats = cParms;
2326 break;
2327
2328 case VBOX_SHCL_HOST_MSG_READ_DATA:
2329 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2330 pEvent->u.fReadData = cParms;
2331 break;
2332
2333 case VBOX_SHCL_HOST_MSG_QUIT:
2334 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2335 break;
2336
2337 default:
2338 AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
2339 rc = VERR_NOT_SUPPORTED;
2340 break;
2341 }
2342 }
2343
2344 LogFlowFuncLeaveRC(rc);
2345 return rc;
2346}
2347
2348#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
2349
2350VBGLR3DECL(int) VbglR3ClipboardEventGetNext(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PVBGLR3CLIPBOARDEVENT pEvent)
2351{
2352 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2353 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2354
2355 RT_NOREF(cParms);
2356
2357 int rc;
2358 if (!pCtx->fUseLegacyProtocol)
2359 {
2360 LogFunc(("Handling idMsg=%RU32 (%s)\n", idMsg, ShClHostMsgToStr(idMsg)));
2361 switch (idMsg)
2362 {
2363 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2364 {
2365 rc = vbglR3ClipboardFormatsReportRecv(pCtx, &pEvent->u.fReportedFormats);
2366 if (RT_SUCCESS(rc))
2367 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2368 break;
2369 }
2370
2371 case VBOX_SHCL_HOST_MSG_READ_DATA_CID:
2372 {
2373 rc = vbglR3ClipboardFetchReadDataCid(pCtx, &pEvent->u.fReadData);
2374 if (RT_SUCCESS(rc))
2375 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2376 break;
2377 }
2378
2379 case VBOX_SHCL_HOST_MSG_READ_DATA:
2380 {
2381 rc = vbglR3ClipboardFetchReadData(pCtx, &pEvent->u.fReadData);
2382 if (RT_SUCCESS(rc))
2383 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2384 break;
2385 }
2386
2387 case VBOX_SHCL_HOST_MSG_QUIT:
2388 {
2389 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2390 rc = VINF_SUCCESS;
2391 break;
2392 }
2393
2394 default:
2395 {
2396 /** @todo r=bird: BUGBUG - need a skip command here! */
2397 rc = VERR_NOT_SUPPORTED;
2398 break;
2399 }
2400 }
2401
2402 if (RT_SUCCESS(rc))
2403 {
2404 /* Copy over our command context to the event. */
2405 pEvent->cmdCtx = *pCtx;
2406 }
2407 else
2408 {
2409 /* Report error back to the host. */
2410 int rc2 = VbglR3ClipboardWriteError(pCtx->idClient, rc);
2411 AssertRC(rc2);
2412 }
2413 }
2414 else
2415 {
2416 /*
2417 * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
2418 * !HACK ALERT! cParms is the format flag or flags.
2419 */
2420 rc = VINF_SUCCESS;
2421 switch (idMsg)
2422 {
2423 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2424 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2425 pEvent->u.fReportedFormats = cParms;
2426 break;
2427
2428 case VBOX_SHCL_HOST_MSG_READ_DATA:
2429 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2430 pEvent->u.fReadData = cParms;
2431 break;
2432
2433 case VBOX_SHCL_HOST_MSG_QUIT:
2434 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2435 break;
2436
2437 default:
2438 AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
2439 rc = VERR_NOT_SUPPORTED;
2440 break;
2441 }
2442 pEvent->cmdCtx = *pCtx;
2443 }
2444
2445 LogFlowFuncLeaveRC(rc);
2446 return rc;
2447}
2448
2449/**
2450 * Frees (destroys) a formerly allocated Shared Clipboard event.
2451 *
2452 * @returns IPRT status code.
2453 * @param pEvent Event to free (destroy).
2454 */
2455VBGLR3DECL(void) VbglR3ClipboardEventFree(PVBGLR3CLIPBOARDEVENT pEvent)
2456{
2457 if (!pEvent)
2458 return;
2459
2460 /* Some messages require additional cleanup. */
2461 switch (pEvent->enmType)
2462 {
2463 default:
2464 break;
2465 }
2466
2467 RTMemFree(pEvent);
2468 pEvent = NULL;
2469}
2470
2471/**
2472 * Reports (advertises) guest clipboard formats to the host.
2473 *
2474 * Legacy function, do not use anymore.
2475 *
2476 * @returns VBox status code.
2477 * @param idClient The client id returned by VbglR3ClipboardConnect().
2478 * @param fFormats The formats to report.
2479 */
2480VBGLR3DECL(int) VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats)
2481{
2482 struct
2483 {
2484 VBGLIOCHGCMCALL Hdr;
2485 VBoxShClParmReportFormats Parms;
2486 } Msg;
2487
2488 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_REPORT_FORMATS, VBOX_SHCL_CPARMS_REPORT_FORMATS);
2489 VbglHGCMParmUInt32Set(&Msg.Parms.f32Formats, fFormats);
2490
2491 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2492
2493 LogFlowFuncLeaveRC(rc);
2494 return rc;
2495}
2496
2497/**
2498 * Sends guest clipboard data to the host.
2499 *
2500 * Legacy function kept for compatibility, do not use anymore.
2501 *
2502 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
2503 * from the host.
2504 *
2505 * @returns VBox status code.
2506 * @param idClient The client id returned by VbglR3ClipboardConnect().
2507 * @param fFormat The format of the data.
2508 * @param pvData Pointer to the data to send. Can be NULL if @a cbData
2509 * is zero.
2510 * @param cbData Number of bytes of data to send. Zero is valid.
2511 */
2512VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
2513{
2514 LogFlowFuncEnter();
2515
2516 struct
2517 {
2518 VBGLIOCHGCMCALL Hdr;
2519 VBoxShClParmDataWriteOld Parms;
2520 } Msg;
2521
2522 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE_OLD);
2523 VbglHGCMParmUInt32Set(&Msg.Parms.f32Format, fFormat);
2524 VbglHGCMParmPtrSet(&Msg.Parms.pData, pv, cb);
2525
2526 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2527
2528 LogFlowFuncLeaveRC(rc);
2529 return rc;
2530}
2531
2532/**
2533 * Sends guest clipboard data to the host.
2534 *
2535 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
2536 * from the host.
2537 *
2538 * @returns VBox status code.
2539 * @param pCtx The command context returned by VbglR3ClipboardConnectEx().
2540 * @param fFormat Clipboard format to send.
2541 * @param pvData Pointer to the data to send. Can be NULL if @a cbData
2542 * is zero.
2543 * @param cbData Number of bytes of data to send. Zero is valid.
2544 */
2545VBGLR3DECL(int) VbglR3ClipboardWriteDataEx(PVBGLR3SHCLCMDCTX pCtx, SHCLFORMAT fFormat, void *pvData, uint32_t cbData)
2546{
2547 LogFlowFunc(("ENTER: fFormat=%#x pvData=%p cbData=%#x\n", fFormat, pvData, cbData));
2548 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2549 if (cbData > 0)
2550 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
2551
2552 int rc;
2553 if (pCtx->fUseLegacyProtocol)
2554 rc = VbglR3ClipboardWriteData(pCtx->idClient, fFormat, pvData, cbData);
2555 else
2556 {
2557 struct
2558 {
2559 VBGLIOCHGCMCALL Hdr;
2560 VBoxShClParmDataWrite Parms;
2561 } Msg;
2562
2563 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE);
2564 Msg.Parms.id64Context.SetUInt64(pCtx->idContext);
2565 Msg.Parms.f32Format.SetUInt32(fFormat);
2566 Msg.Parms.pData.SetPtr(pvData, cbData);
2567
2568 LogFlowFunc(("CID=%RU32\n", pCtx->idContext));
2569
2570 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2571 }
2572
2573 LogFlowFuncLeaveRC(rc);
2574 return rc;
2575}
2576
2577/**
2578 * Writes an error to the host.
2579 *
2580 * @returns IPRT status code.
2581 * @param idClient The client id returned by VbglR3ClipboardConnect().
2582 * @param rcErr Error (IPRT-style) to send.
2583 */
2584VBGLR3DECL(int) VbglR3ClipboardWriteError(HGCMCLIENTID idClient, int rcErr)
2585{
2586 AssertReturn(idClient, VERR_INVALID_PARAMETER);
2587
2588 VBoxShClWriteErrorMsg Msg;
2589 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_ERROR, VBOX_SHCL_CPARMS_ERROR);
2590
2591 /** @todo Context ID not used yet. */
2592 Msg.uContext.SetUInt64(0);
2593 Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
2594
2595 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
2596
2597 if (RT_FAILURE(rc))
2598 LogFlowFunc(("Sending error %Rrc failed with rc=%Rrc\n", rcErr, rc));
2599 if (rc == VERR_NOT_SUPPORTED)
2600 rc = VINF_SUCCESS;
2601
2602 if (RT_FAILURE(rc))
2603 LogRel(("Shared Clipboard: Reporting error %Rrc to the host failed with %Rrc\n", rcErr, rc));
2604
2605 LogFlowFuncLeaveRC(rc);
2606 return rc;
2607}
2608
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