VirtualBox

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

Last change on this file since 99937 was 99937, checked in by vboxsync, 2 years ago

Shared Clipboard: Added new testcase for the HTTP server in combination with the Shared Clipboard API, various updates and general improvements. 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: 90.9 KB
Line 
1/* $Id: VBoxGuestR3LibClipboard.cpp 99937 2023-05-23 15:38:52Z 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.215389.xyz.
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 /* If this is a read transfer (reading data from host), set the interface to use
1853 * our VbglR3 routines here. */
1854 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE)
1855 {
1856 SHCLTXPROVIDERCREATIONCTX creationCtx;
1857 RT_ZERO(creationCtx);
1858
1859 creationCtx.Interface.pfnRootsGet = vbglR3ClipboardTransferIfaceGetRoots;
1860
1861 creationCtx.Interface.pfnListOpen = vbglR3ClipboardTransferIfaceListOpen;
1862 creationCtx.Interface.pfnListClose = vbglR3ClipboardTransferIfaceListClose;
1863 creationCtx.Interface.pfnListHdrRead = vbglR3ClipboardTransferIfaceListHdrRead;
1864 creationCtx.Interface.pfnListEntryRead = vbglR3ClipboardTransferIfaceListEntryRead;
1865
1866 creationCtx.Interface.pfnObjOpen = vbglR3ClipboardTransferIfaceObjOpen;
1867 creationCtx.Interface.pfnObjClose = vbglR3ClipboardTransferIfaceObjClose;
1868 creationCtx.Interface.pfnObjRead = vbglR3ClipboardTransferIfaceObjRead;
1869
1870 creationCtx.pvUser = pCmdCtx;
1871
1872 rc = ShClTransferSetProviderIface(pTransfer, &creationCtx);
1873 }
1874
1875 if (RT_SUCCESS(rc))
1876 rc = ShClTransferStart(pTransfer);
1877 }
1878
1879 if (RT_FAILURE(rc))
1880 ShClTransferCtxTransferUnregister(pTransferCtx, uTransferID);
1881 }
1882 }
1883
1884 if (RT_SUCCESS(rc))
1885 {
1886 if (ppTransfer)
1887 *ppTransfer = pTransfer;
1888
1889 LogRel2(("Shared Clipboard: Transfer ID=%RU32 (%s %s) successfully started\n",
1890 uTransferID,
1891 enmDir == SHCLTRANSFERDIR_FROM_REMOTE ? "reading from" : "writing to",
1892 enmSource == SHCLSOURCE_LOCAL ? "local" : "remote"));
1893 }
1894 else
1895 LogRel(("Shared Clipboard: Unable to start transfer ID=%RU32, rc=%Rrc\n", uTransferID, rc));
1896
1897 /* Send a reply in any case. */
1898 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
1899 RT_SUCCESS(rc)
1900 ? SHCLTRANSFERSTATUS_STARTED : SHCLTRANSFERSTATUS_ERROR, rc);
1901 if (RT_SUCCESS(rc))
1902 rc = rc2;
1903
1904 if (RT_FAILURE(rc))
1905 {
1906 ShClTransferDestroy(pTransfer);
1907 pTransfer = NULL;
1908 }
1909
1910 LogFlowFuncLeaveRC(rc);
1911 return rc;
1912}
1913
1914/**
1915 * Stops a transfer on the guest side.
1916 *
1917 * @returns VBox status code, or VERR_NOT_FOUND if transfer has not been found.
1918 * @param pCmdCtx Command context to use.
1919 * @param pTransferCtx Transfer context to stop transfer for.
1920 * @param uTransferID ID of transfer to stop.
1921 */
1922static int vbglR3ClipboardTransferStop(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
1923 SHCLTRANSFERID uTransferID)
1924{
1925 int rc;
1926
1927 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, uTransferID);
1928 if (pTransfer)
1929 {
1930 rc = ShClTransferCtxTransferUnregister(pTransferCtx, uTransferID);
1931 if (RT_SUCCESS(rc))
1932 {
1933 LogRel2(("Shared Clipboard: Transfer ID=%RU32 successfully stopped\n", uTransferID));
1934 }
1935 else
1936 LogRel(("Shared Clipboard: Unable to stop transfer ID=%RU32, rc=%Rrc\n", uTransferID, rc));
1937
1938 /* Send a reply in any case. */
1939 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
1940 RT_SUCCESS(rc)
1941 ? SHCLTRANSFERSTATUS_STOPPED : SHCLTRANSFERSTATUS_ERROR, rc);
1942 AssertRC(rc2);
1943 }
1944 else
1945 rc = VERR_NOT_FOUND;
1946
1947 LogFlowFuncLeaveRC(rc);
1948 return rc;
1949}
1950
1951/**
1952 * Sets transfer callbacks of a Shared Clipboard command context.
1953 *
1954 * @param pCmdCtx Command context to set callbacks for.
1955 * @param pCallbacks Pointer to callback table to set.
1956 */
1957VBGLR3DECL(void) VbglR3ClipboardTransferSetCallbacks(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCALLBACKTABLE pCallbacks)
1958{
1959 AssertPtrReturnVoid(pCmdCtx);
1960 AssertPtrReturnVoid(pCallbacks);
1961
1962 ShClTransferCopyCallbacks(&pCmdCtx->Transfers.Callbacks, pCallbacks);
1963}
1964
1965VBGLR3DECL(int) VbglR3ClipboardEventGetNextEx(uint32_t idMsg, uint32_t cParms,
1966 PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
1967 PVBGLR3CLIPBOARDEVENT pEvent)
1968{
1969 AssertPtrReturn(pCmdCtx, VERR_INVALID_POINTER);
1970 AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER);
1971 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1972
1973 LogFunc(("Handling idMsg=%RU32 (%s), cParms=%RU32\n", idMsg, ShClHostMsgToStr(idMsg), cParms));
1974
1975 int rc;
1976 if (!pCmdCtx->fUseLegacyProtocol)
1977 {
1978 bool fErrorSent = false; /* Whether an error has been reported back to the host already. */
1979
1980 switch (idMsg)
1981 {
1982 case VBOX_SHCL_HOST_MSG_TRANSFER_STATUS:
1983 {
1984 SHCLTRANSFERDIR enmDir;
1985 SHCLTRANSFERREPORT transferReport;
1986 rc = VbglR3ClipboarTransferStatusRecv(pCmdCtx, &enmDir, &transferReport);
1987 if (RT_SUCCESS(rc))
1988 {
1989 const SHCLTRANSFERID uTransferID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
1990
1991 LogFlowFunc(("[Transfer %RU32] enmDir=%RU32, status=%s\n",
1992 uTransferID, enmDir, ShClTransferStatusToStr(transferReport.uStatus)));
1993
1994 switch (transferReport.uStatus)
1995 {
1996 case SHCLTRANSFERSTATUS_INITIALIZED:
1997 RT_FALL_THROUGH();
1998 case SHCLTRANSFERSTATUS_STARTED:
1999 {
2000 SHCLSOURCE enmSource = SHCLSOURCE_INVALID;
2001
2002 /* The host announces the transfer direction from its point of view, so inverse the direction here. */
2003 if (enmDir == SHCLTRANSFERDIR_TO_REMOTE)
2004 {
2005 enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
2006 enmSource = SHCLSOURCE_REMOTE;
2007 }
2008 else if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE)
2009 {
2010 enmDir = SHCLTRANSFERDIR_TO_REMOTE;
2011 enmSource = SHCLSOURCE_LOCAL;
2012 }
2013 else
2014 AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
2015
2016 rc = vbglR3ClipboardTransferStart(pCmdCtx, pTransferCtx, uTransferID,
2017 enmDir, enmSource, NULL /* ppTransfer */);
2018 break;
2019 }
2020
2021 case SHCLTRANSFERSTATUS_STOPPED:
2022 RT_FALL_THROUGH();
2023 case SHCLTRANSFERSTATUS_CANCELED:
2024 RT_FALL_THROUGH();
2025 case SHCLTRANSFERSTATUS_KILLED:
2026 RT_FALL_THROUGH();
2027 case SHCLTRANSFERSTATUS_ERROR:
2028 {
2029 rc = vbglR3ClipboardTransferStop(pCmdCtx, pTransferCtx,
2030 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2031 break;
2032 }
2033
2034 default:
2035 rc = VERR_NOT_SUPPORTED;
2036 break;
2037 }
2038
2039 if (RT_SUCCESS(rc))
2040 {
2041 pEvent->u.TransferStatus.enmDir = enmDir;
2042 pEvent->u.TransferStatus.Report = transferReport;
2043 pEvent->u.TransferStatus.uID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
2044
2045 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS;
2046
2047 LogRel2(("Shared Clipboard: Received status %s (rc=%Rrc) for transfer ID=%RU32\n",
2048 ShClTransferStatusToStr(pEvent->u.TransferStatus.Report.uStatus), pEvent->u.TransferStatus.Report.rc,
2049 pEvent->u.TransferStatus.uID));
2050 }
2051 }
2052 break;
2053 }
2054
2055 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ:
2056 {
2057 uint32_t fRoots;
2058 rc = VbglR3ClipboardRootListHdrReadReq(pCmdCtx, &fRoots);
2059
2060 /** @todo Validate / handle fRoots. */
2061
2062 if (RT_SUCCESS(rc))
2063 {
2064 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2065 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2066 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2067
2068 SHCLROOTLISTHDR rootListHdr;
2069 RT_ZERO(rootListHdr);
2070
2071 rootListHdr.cRoots = ShClTransferRootsCount(pTransfer);
2072
2073 LogFlowFunc(("cRoots=%RU32\n", rootListHdr.cRoots));
2074
2075 rc = VbglR3ClipboardRootListHdrReadReply(pCmdCtx, &rootListHdr);
2076 }
2077 break;
2078 }
2079
2080 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ:
2081 {
2082 uint32_t uIndex;
2083 uint32_t fInfo;
2084 rc = VbglR3ClipboardRootListEntryReadReq(pCmdCtx, &uIndex, &fInfo);
2085 if (RT_SUCCESS(rc))
2086 {
2087 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2088 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2089 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2090
2091 SHCLROOTLISTENTRY rootListEntry;
2092 rc = ShClTransferRootsEntry(pTransfer, uIndex, &rootListEntry);
2093 if (RT_SUCCESS(rc))
2094 rc = VbglR3ClipboardRootListEntryReadReply(pCmdCtx, uIndex, &rootListEntry);
2095 }
2096 break;
2097 }
2098
2099 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN:
2100 {
2101 SHCLLISTOPENPARMS openParmsList;
2102 rc = ShClTransferListOpenParmsInit(&openParmsList);
2103 if (RT_SUCCESS(rc))
2104 {
2105 rc = VbglR3ClipboardListOpenRecv(pCmdCtx, &openParmsList);
2106 if (RT_SUCCESS(rc))
2107 {
2108 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2109 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2110 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2111
2112 LogFlowFunc(("pszPath=%s\n", openParmsList.pszPath));
2113
2114 SHCLLISTHANDLE hList = NIL_SHCLLISTHANDLE;
2115 rc = ShClTransferListOpen(pTransfer, &openParmsList, &hList);
2116
2117 /* Reply in any case. */
2118 int rc2 = VbglR3ClipboardListOpenReply(pCmdCtx, rc, hList);
2119 AssertRC(rc2);
2120 }
2121
2122 ShClTransferListOpenParmsDestroy(&openParmsList);
2123 }
2124
2125 break;
2126 }
2127
2128 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE:
2129 {
2130 SHCLLISTHANDLE hList;
2131 rc = VbglR3ClipboardListCloseRecv(pCmdCtx, &hList);
2132 if (RT_SUCCESS(rc))
2133 {
2134 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2135 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2136 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2137
2138 rc = ShClTransferListClose(pTransfer, hList);
2139
2140 /* Reply in any case. */
2141 int rc2 = VbglR3ClipboardListCloseReply(pCmdCtx, rc, hList);
2142 AssertRC(rc2);
2143 }
2144
2145 break;
2146 }
2147
2148 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ:
2149 {
2150 /** @todo Handle filter + list features. */
2151
2152 SHCLLISTHANDLE hList = NIL_SHCLLISTHANDLE;
2153 uint32_t fFlags = 0;
2154 rc = VbglR3ClipboardListHdrReadRecvReq(pCmdCtx, &hList, &fFlags);
2155 if (RT_SUCCESS(rc))
2156 {
2157 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2158 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2159 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2160
2161 SHCLLISTHDR hdrList;
2162 rc = ShClTransferListGetHeader(pTransfer, hList, &hdrList);
2163 if (RT_SUCCESS(rc))
2164 {
2165 rc = VbglR3ClipboardListHdrWrite(pCmdCtx, hList, &hdrList);
2166
2167 ShClTransferListHdrDestroy(&hdrList);
2168 }
2169 }
2170
2171 break;
2172 }
2173
2174 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ:
2175 {
2176 LogFlowFunc(("VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ\n"));
2177
2178 SHCLLISTENTRY entryList;
2179 rc = ShClTransferListEntryInit(&entryList);
2180 if (RT_SUCCESS(rc))
2181 {
2182 SHCLLISTHANDLE hList;
2183 uint32_t fInfo;
2184 rc = VbglR3ClipboardListEntryReadRecvReq(pCmdCtx, &hList, &fInfo);
2185 if (RT_SUCCESS(rc))
2186 {
2187 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2188 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2189 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2190
2191 rc = ShClTransferListRead(pTransfer, hList, &entryList);
2192 if (RT_SUCCESS(rc))
2193 {
2194 PSHCLFSOBJINFO pObjInfo = (PSHCLFSOBJINFO)entryList.pvInfo;
2195 Assert(entryList.cbInfo == sizeof(SHCLFSOBJINFO));
2196
2197 RT_NOREF(pObjInfo);
2198
2199 LogFlowFunc(("\t%s (%RU64 bytes)\n", entryList.pszName, pObjInfo->cbObject));
2200
2201 rc = VbglR3ClipboardListEntryWrite(pCmdCtx, hList, &entryList);
2202 }
2203 }
2204
2205 ShClTransferListEntryDestroy(&entryList);
2206 }
2207
2208 break;
2209 }
2210
2211 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN:
2212 {
2213 SHCLOBJOPENCREATEPARMS openParms;
2214 rc = ShClTransferObjOpenParmsInit(&openParms);
2215 if (RT_SUCCESS(rc))
2216 {
2217 rc = VbglR3ClipboardObjOpenRecv(pCmdCtx, &openParms);
2218 if (RT_SUCCESS(rc))
2219 {
2220 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2221 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2222 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2223
2224 SHCLOBJHANDLE hObj;
2225 rc = ShClTransferObjOpen(pTransfer, &openParms, &hObj);
2226
2227 /* Reply in any case. */
2228 int rc2 = VbglR3ClipboardObjOpenReply(pCmdCtx, rc, hObj);
2229 AssertRC(rc2);
2230 }
2231
2232 ShClTransferObjOpenParmsDestroy(&openParms);
2233 }
2234
2235 break;
2236 }
2237
2238 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE:
2239 {
2240 SHCLOBJHANDLE hObj;
2241 rc = VbglR3ClipboardObjCloseRecv(pCmdCtx, &hObj);
2242 if (RT_SUCCESS(rc))
2243 {
2244 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2245 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2246 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2247
2248 rc = ShClTransferObjClose(pTransfer, hObj);
2249
2250 /* Reply in any case. */
2251 int rc2 = VbglR3ClipboardObjCloseReply(pCmdCtx, rc, hObj);
2252 AssertRC(rc2);
2253 }
2254
2255 break;
2256 }
2257
2258 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ:
2259 {
2260 SHCLOBJHANDLE hObj;
2261 uint32_t cbBuf;
2262 uint32_t fFlags;
2263 rc = VbglR3ClipboardObjReadRecv(pCmdCtx, &hObj, &cbBuf, &fFlags);
2264 if (RT_SUCCESS(rc))
2265 {
2266 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2267 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2268 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2269
2270 AssertBreakStmt(pCmdCtx->Transfers.cbChunkSize, rc = VERR_INVALID_PARAMETER);
2271
2272 const uint32_t cbToRead = RT_MIN(cbBuf, pCmdCtx->Transfers.cbChunkSize);
2273
2274 LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, fFlags=0x%x -> cbChunkSize=%RU32, cbToRead=%RU32\n",
2275 hObj, cbBuf, fFlags, pCmdCtx->Transfers.cbChunkSize, cbToRead));
2276
2277 void *pvBuf = RTMemAlloc(cbToRead);
2278 if (pvBuf)
2279 {
2280 uint32_t cbRead;
2281 rc = ShClTransferObjRead(pTransfer, hObj, pvBuf, cbToRead, fFlags, &cbRead);
2282 if (RT_SUCCESS(rc))
2283 rc = VbglR3ClipboardObjWriteSend(pCmdCtx, hObj, pvBuf, cbRead, NULL /* pcbWritten */);
2284
2285 RTMemFree(pvBuf);
2286 }
2287 else
2288 rc = VERR_NO_MEMORY;
2289 }
2290
2291 break;
2292 }
2293
2294 default:
2295 {
2296 rc = VbglR3ClipboardEventGetNext(idMsg, cParms, pCmdCtx, pEvent);
2297 if (RT_FAILURE(rc))
2298 fErrorSent = true;
2299 break;
2300 }
2301 }
2302
2303 if ( !fErrorSent
2304 && RT_FAILURE(rc))
2305 {
2306 /* Report error back to the host. */
2307 int rc2 = VbglR3ClipboardWriteError(pCmdCtx->idClient, rc);
2308 AssertRC(rc2);
2309 }
2310 }
2311 else
2312 {
2313 /*
2314 * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
2315 * !HACK ALERT! cParms is the format flag or flags.
2316 */
2317 rc = VINF_SUCCESS;
2318 switch (idMsg)
2319 {
2320 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2321 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2322 pEvent->u.fReportedFormats = cParms;
2323 break;
2324
2325 case VBOX_SHCL_HOST_MSG_READ_DATA:
2326 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2327 pEvent->u.fReadData = cParms;
2328 break;
2329
2330 case VBOX_SHCL_HOST_MSG_QUIT:
2331 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2332 break;
2333
2334 default:
2335 AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
2336 rc = VERR_NOT_SUPPORTED;
2337 break;
2338 }
2339 }
2340
2341 LogFlowFuncLeaveRC(rc);
2342 return rc;
2343}
2344
2345#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
2346
2347VBGLR3DECL(int) VbglR3ClipboardEventGetNext(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PVBGLR3CLIPBOARDEVENT pEvent)
2348{
2349 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2350 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2351
2352 RT_NOREF(cParms);
2353
2354 int rc;
2355 if (!pCtx->fUseLegacyProtocol)
2356 {
2357 LogFunc(("Handling idMsg=%RU32 (%s)\n", idMsg, ShClHostMsgToStr(idMsg)));
2358 switch (idMsg)
2359 {
2360 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2361 {
2362 rc = vbglR3ClipboardFormatsReportRecv(pCtx, &pEvent->u.fReportedFormats);
2363 if (RT_SUCCESS(rc))
2364 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2365 break;
2366 }
2367
2368 case VBOX_SHCL_HOST_MSG_READ_DATA_CID:
2369 {
2370 rc = vbglR3ClipboardFetchReadDataCid(pCtx, &pEvent->u.fReadData);
2371 if (RT_SUCCESS(rc))
2372 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2373 break;
2374 }
2375
2376 case VBOX_SHCL_HOST_MSG_READ_DATA:
2377 {
2378 rc = vbglR3ClipboardFetchReadData(pCtx, &pEvent->u.fReadData);
2379 if (RT_SUCCESS(rc))
2380 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2381 break;
2382 }
2383
2384 case VBOX_SHCL_HOST_MSG_QUIT:
2385 {
2386 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2387 rc = VINF_SUCCESS;
2388 break;
2389 }
2390
2391 default:
2392 {
2393 /** @todo r=bird: BUGBUG - need a skip command here! */
2394 rc = VERR_NOT_SUPPORTED;
2395 break;
2396 }
2397 }
2398
2399 if (RT_SUCCESS(rc))
2400 {
2401 /* Copy over our command context to the event. */
2402 pEvent->cmdCtx = *pCtx;
2403 }
2404 else
2405 {
2406 /* Report error back to the host. */
2407 int rc2 = VbglR3ClipboardWriteError(pCtx->idClient, rc);
2408 AssertRC(rc2);
2409 }
2410 }
2411 else
2412 {
2413 /*
2414 * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
2415 * !HACK ALERT! cParms is the format flag or flags.
2416 */
2417 rc = VINF_SUCCESS;
2418 switch (idMsg)
2419 {
2420 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2421 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2422 pEvent->u.fReportedFormats = cParms;
2423 break;
2424
2425 case VBOX_SHCL_HOST_MSG_READ_DATA:
2426 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2427 pEvent->u.fReadData = cParms;
2428 break;
2429
2430 case VBOX_SHCL_HOST_MSG_QUIT:
2431 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2432 break;
2433
2434 default:
2435 AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
2436 rc = VERR_NOT_SUPPORTED;
2437 break;
2438 }
2439 pEvent->cmdCtx = *pCtx;
2440 }
2441
2442 LogFlowFuncLeaveRC(rc);
2443 return rc;
2444}
2445
2446/**
2447 * Frees (destroys) a formerly allocated Shared Clipboard event.
2448 *
2449 * @returns IPRT status code.
2450 * @param pEvent Event to free (destroy).
2451 */
2452VBGLR3DECL(void) VbglR3ClipboardEventFree(PVBGLR3CLIPBOARDEVENT pEvent)
2453{
2454 if (!pEvent)
2455 return;
2456
2457 /* Some messages require additional cleanup. */
2458 switch (pEvent->enmType)
2459 {
2460 default:
2461 break;
2462 }
2463
2464 RTMemFree(pEvent);
2465 pEvent = NULL;
2466}
2467
2468/**
2469 * Reports (advertises) guest clipboard formats to the host.
2470 *
2471 * Legacy function, do not use anymore.
2472 *
2473 * @returns VBox status code.
2474 * @param idClient The client id returned by VbglR3ClipboardConnect().
2475 * @param fFormats The formats to report.
2476 */
2477VBGLR3DECL(int) VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats)
2478{
2479 struct
2480 {
2481 VBGLIOCHGCMCALL Hdr;
2482 VBoxShClParmReportFormats Parms;
2483 } Msg;
2484
2485 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_REPORT_FORMATS, VBOX_SHCL_CPARMS_REPORT_FORMATS);
2486 VbglHGCMParmUInt32Set(&Msg.Parms.f32Formats, fFormats);
2487
2488 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2489
2490 LogFlowFuncLeaveRC(rc);
2491 return rc;
2492}
2493
2494/**
2495 * Sends guest clipboard data to the host.
2496 *
2497 * Legacy function kept for compatibility, do not use anymore.
2498 *
2499 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
2500 * from the host.
2501 *
2502 * @returns VBox status code.
2503 * @param idClient The client id returned by VbglR3ClipboardConnect().
2504 * @param fFormat The format of the data.
2505 * @param pvData Pointer to the data to send. Can be NULL if @a cbData
2506 * is zero.
2507 * @param cbData Number of bytes of data to send. Zero is valid.
2508 */
2509VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
2510{
2511 LogFlowFuncEnter();
2512
2513 struct
2514 {
2515 VBGLIOCHGCMCALL Hdr;
2516 VBoxShClParmDataWriteOld Parms;
2517 } Msg;
2518
2519 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE_OLD);
2520 VbglHGCMParmUInt32Set(&Msg.Parms.f32Format, fFormat);
2521 VbglHGCMParmPtrSet(&Msg.Parms.pData, pv, cb);
2522
2523 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2524
2525 LogFlowFuncLeaveRC(rc);
2526 return rc;
2527}
2528
2529/**
2530 * Sends guest clipboard data to the host.
2531 *
2532 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
2533 * from the host.
2534 *
2535 * @returns VBox status code.
2536 * @param pCtx The command context returned by VbglR3ClipboardConnectEx().
2537 * @param fFormat Clipboard format to send.
2538 * @param pvData Pointer to the data to send. Can be NULL if @a cbData
2539 * is zero.
2540 * @param cbData Number of bytes of data to send. Zero is valid.
2541 */
2542VBGLR3DECL(int) VbglR3ClipboardWriteDataEx(PVBGLR3SHCLCMDCTX pCtx, SHCLFORMAT fFormat, void *pvData, uint32_t cbData)
2543{
2544 LogFlowFunc(("ENTER: fFormat=%#x pvData=%p cbData=%#x\n", fFormat, pvData, cbData));
2545 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2546 if (cbData > 0)
2547 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
2548
2549 int rc;
2550 if (pCtx->fUseLegacyProtocol)
2551 rc = VbglR3ClipboardWriteData(pCtx->idClient, fFormat, pvData, cbData);
2552 else
2553 {
2554 struct
2555 {
2556 VBGLIOCHGCMCALL Hdr;
2557 VBoxShClParmDataWrite Parms;
2558 } Msg;
2559
2560 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE);
2561 Msg.Parms.id64Context.SetUInt64(pCtx->idContext);
2562 Msg.Parms.f32Format.SetUInt32(fFormat);
2563 Msg.Parms.pData.SetPtr(pvData, cbData);
2564
2565 LogFlowFunc(("CID=%RU32\n", pCtx->idContext));
2566
2567 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2568 }
2569
2570 LogFlowFuncLeaveRC(rc);
2571 return rc;
2572}
2573
2574/**
2575 * Writes an error to the host.
2576 *
2577 * @returns IPRT status code.
2578 * @param idClient The client id returned by VbglR3ClipboardConnect().
2579 * @param rcErr Error (IPRT-style) to send.
2580 */
2581VBGLR3DECL(int) VbglR3ClipboardWriteError(HGCMCLIENTID idClient, int rcErr)
2582{
2583 AssertReturn(idClient, VERR_INVALID_PARAMETER);
2584
2585 VBoxShClWriteErrorMsg Msg;
2586 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_ERROR, VBOX_SHCL_CPARMS_ERROR);
2587
2588 /** @todo Context ID not used yet. */
2589 Msg.uContext.SetUInt64(0);
2590 Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
2591
2592 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
2593
2594 if (RT_FAILURE(rc))
2595 LogFlowFunc(("Sending error %Rrc failed with rc=%Rrc\n", rcErr, rc));
2596 if (rc == VERR_NOT_SUPPORTED)
2597 rc = VINF_SUCCESS;
2598
2599 if (RT_FAILURE(rc))
2600 LogRel(("Shared Clipboard: Reporting error %Rrc to the host failed with %Rrc\n", rcErr, rc));
2601
2602 LogFlowFuncLeaveRC(rc);
2603 return rc;
2604}
2605
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette