VirtualBox

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

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

scm copyright and license note update

  • 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 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, Shared Clipboard.
4 */
5
6/*
7 * Copyright (C) 2007-2022 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 SHCLROOTLISTHDR srcRootListHdr;
721 rc = vbglR3ClipboardRootListHdrRead(pCtx, &srcRootListHdr);
722 if (RT_SUCCESS(rc))
723 {
724 pRootList->Hdr.cRoots = srcRootListHdr.cRoots;
725 pRootList->Hdr.fRoots = 0; /** @todo Implement this. */
726
727 if (srcRootListHdr.cRoots)
728 {
729 pRootList->paEntries =
730 (PSHCLROOTLISTENTRY)RTMemAllocZ(srcRootListHdr.cRoots * sizeof(SHCLROOTLISTENTRY));
731 if (pRootList->paEntries)
732 {
733 for (uint32_t i = 0; i < srcRootListHdr.cRoots; i++)
734 {
735 SHCLROOTLISTENTRY *pEntry = &pRootList->paEntries[i];
736 AssertPtr(pEntry);
737
738 rc = ShClTransferRootListEntryInit(pEntry);
739 if (RT_SUCCESS(rc))
740 rc = vbglR3ClipboardRootListEntryRead(pCtx, i, pEntry);
741
742 if (RT_FAILURE(rc))
743 break;
744 }
745 }
746 else
747 rc = VERR_NO_MEMORY;
748 }
749 }
750
751 if (RT_SUCCESS(rc))
752 {
753 *ppRootList = pRootList;
754 }
755 else
756 ShClTransferRootListFree(pRootList);
757 }
758 else
759 rc = VERR_NO_MEMORY;
760
761 LogFlowFuncLeaveRC(rc);
762 return rc;
763}
764
765/**
766 * Receives a transfer status from the host.
767 *
768 * @returns VBox status code.
769 * @param pCtx Shared Clipboard command context to use for the connection.
770 * @param pEnmDir Where to store the transfer direction for the reported transfer.
771 * @param pReport Where to store the transfer (status) report.
772 */
773VBGLR3DECL(int) VbglR3ClipboarTransferStatusRecv(PVBGLR3SHCLCMDCTX pCtx,
774 PSHCLTRANSFERDIR pEnmDir, PSHCLTRANSFERREPORT pReport)
775{
776 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
777 AssertPtrReturn(pReport, VERR_INVALID_POINTER);
778 AssertPtrReturn(pEnmDir, VERR_INVALID_POINTER);
779
780 VBoxShClTransferStatusMsg Msg;
781 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
782 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_TRANSFER_STATUS);
783
784 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_STATUS);
785 Msg.enmDir.SetUInt32(0);
786 Msg.enmStatus.SetUInt32(0);
787 Msg.rc.SetUInt32(0);
788 Msg.fFlags.SetUInt32(0);
789
790 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
791 if (RT_SUCCESS(rc))
792 {
793 rc = Msg.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
794 if (RT_SUCCESS(rc))
795 {
796 rc = Msg.enmDir.GetUInt32((uint32_t *)pEnmDir);
797 AssertRC(rc);
798 }
799 if (RT_SUCCESS(rc))
800 {
801 rc = Msg.enmStatus.GetUInt32(&pReport->uStatus);
802 AssertRC(rc);
803 }
804 if (RT_SUCCESS(rc))
805 {
806 rc = Msg.rc.GetUInt32((uint32_t *)&pReport->rc);
807 AssertRC(rc);
808 }
809 if (RT_SUCCESS(rc))
810 {
811 rc = Msg.fFlags.GetUInt32(&pReport->fFlags);
812 AssertRC(rc);
813 }
814 }
815
816 LogFlowFuncLeaveRC(rc);
817 return rc;
818}
819
820/**
821 * Replies to a transfer report from the host.
822 *
823 * @returns VBox status code.
824 * @param pCtx Shared Clipboard command context to use for the connection.
825 * @param pTransfer Transfer of report to reply to.
826 * @param uStatus Tranfer status to reply.
827 * @param rcTransfer Result code (rc) to reply.
828 */
829VBGLR3DECL(int) VbglR3ClipboardTransferStatusReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFER pTransfer,
830 SHCLTRANSFERSTATUS uStatus, int rcTransfer)
831{
832 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
833 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
834
835 RT_NOREF(pTransfer);
836
837 VBoxShClReplyMsg Msg;
838 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
839 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
840
841 Msg.uContext.SetUInt64(pCtx->idContext);
842 Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS);
843 Msg.rc.SetUInt32((uint32_t )rcTransfer); /* int vs. uint32_t */
844 Msg.pvPayload.SetPtr(NULL, 0);
845
846 Msg.u.TransferStatus.enmStatus.SetUInt32((uint32_t)uStatus);
847
848 LogFlowFunc(("%s\n", ShClTransferStatusToStr(uStatus)));
849
850 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
851
852 LogFlowFuncLeaveRC(rc);
853 return rc;
854}
855
856/**
857 * Receives a host request to read a root list header from the guest.
858 *
859 * @returns VBox status code.
860 * @param pCtx Shared Clipboard command context to use for the connection.
861 * @param pfRoots Where to store the root list header flags to use, requested by the host.
862 */
863VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReq(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pfRoots)
864{
865 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
866 AssertPtrReturn(pfRoots, VERR_INVALID_POINTER);
867
868 VBoxShClRootListReadReqMsg Msg;
869 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
870 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ_REQ);
871
872 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ);
873 Msg.ReqParms.fRoots.SetUInt32(0);
874
875 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
876 if (RT_SUCCESS(rc))
877 {
878 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
879 if (RT_SUCCESS(rc))
880 {
881 rc = Msg.ReqParms.fRoots.GetUInt32(pfRoots);
882 AssertRC(rc);
883 }
884 }
885
886 LogFlowFuncLeaveRC(rc);
887 return rc;
888}
889
890/**
891 * Replies to a root list header request.
892 *
893 * @returns VBox status code.
894 * @param pCtx Shared Clipboard command context to use for the connection.
895 * @param pRootListHdr Root lsit header to reply to the host.
896 */
897VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLISTHDR pRootListHdr)
898{
899 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
900 AssertPtrReturn(pRootListHdr, VERR_INVALID_POINTER);
901
902 VBoxShClRootListHdrMsg Msg;
903 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
904 VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_WRITE);
905
906 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
907 Msg.ReqParms.fRoots.SetUInt32(pRootListHdr->fRoots);
908
909 Msg.cRoots.SetUInt32(pRootListHdr->cRoots);
910
911 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
912
913 LogFlowFuncLeaveRC(rc);
914 return rc;
915}
916
917/**
918 * Receives a host request to read a root list entry from the guest.
919 *
920 * @returns VBox status code.
921 * @param pCtx Shared Clipboard command context to use for the connection.
922 * @param puIndex Where to return the index of the root list entry the host wants to read.
923 * @param pfInfo Where to return the read flags the host wants to use.
924 */
925VBGLR3DECL(int) VbglR3ClipboardRootListEntryReadReq(PVBGLR3SHCLCMDCTX pCtx, uint32_t *puIndex, uint32_t *pfInfo)
926{
927 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
928 AssertPtrReturn(puIndex, VERR_INVALID_POINTER);
929 AssertPtrReturn(pfInfo, VERR_INVALID_POINTER);
930
931 VBoxShClRootListEntryReadReqMsg Msg;
932 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
933 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ);
934
935 Msg.Parms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ);
936 Msg.Parms.fInfo.SetUInt32(0);
937 Msg.Parms.uIndex.SetUInt32(0);
938
939 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
940 if (RT_SUCCESS(rc))
941 {
942 rc = Msg.Parms.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
943 if (RT_SUCCESS(rc))
944 {
945 rc = Msg.Parms.fInfo.GetUInt32(pfInfo);
946 AssertRC(rc);
947 }
948 if (RT_SUCCESS(rc))
949 {
950 rc = Msg.Parms.uIndex.GetUInt32(puIndex);
951 AssertRC(rc);
952 }
953 }
954
955 LogFlowFuncLeaveRC(rc);
956 return rc;
957}
958
959/**
960 * Replies to a root list entry read request from the host.
961 *
962 * @returns VBox status code.
963 * @param pCtx Shared Clipboard command context to use for the connection.
964 * @param uIndex Index of root list entry to reply.
965 * @param pEntry Actual root list entry to reply.
966 */
967VBGLR3DECL(int) VbglR3ClipboardRootListEntryReadReply(PVBGLR3SHCLCMDCTX pCtx, uint32_t uIndex, PSHCLROOTLISTENTRY pEntry)
968{
969 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
970 AssertPtrReturn(pEntry, VERR_INVALID_POINTER);
971
972 VBoxShClRootListEntryMsg Msg;
973 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
974 VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_WRITE);
975
976 Msg.Parms.uContext.SetUInt64(pCtx->idContext);
977 Msg.Parms.fInfo.SetUInt32(0);
978 Msg.Parms.uIndex.SetUInt32(uIndex);
979
980 Msg.szName.SetPtr(pEntry->pszName, pEntry->cbName);
981 Msg.cbInfo.SetUInt32(pEntry->cbInfo);
982 Msg.pvInfo.SetPtr(pEntry->pvInfo, pEntry->cbInfo);
983
984 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
985
986 LogFlowFuncLeaveRC(rc);
987 return rc;
988}
989
990/**
991 * Sends a request to open a list handle to the host.
992 *
993 * @returns VBox status code.
994 * @param pCtx Shared Clipboard command context to use for the connection.
995 * @param pOpenParms List open parameters to use for the open request.
996 * @param phList Where to return the list handle received from the host.
997 */
998VBGLR3DECL(int) VbglR3ClipboardListOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
999 PSHCLLISTHANDLE phList)
1000{
1001 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1002 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
1003 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1004
1005 VBoxShClListOpenMsg Msg;
1006 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1007 VBOX_SHCL_GUEST_FN_LIST_OPEN, VBOX_SHCL_CPARMS_LIST_OPEN);
1008
1009 Msg.uContext.SetUInt64(pCtx->idContext);
1010 Msg.fList.SetUInt32(0);
1011 Msg.pvFilter.SetPtr(pOpenParms->pszFilter, pOpenParms->cbFilter);
1012 Msg.pvPath.SetPtr(pOpenParms->pszPath, pOpenParms->cbPath);
1013 Msg.uHandle.SetUInt64(0);
1014
1015 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1016 if (RT_SUCCESS(rc))
1017 {
1018 rc = Msg.uHandle.GetUInt64(phList); AssertRC(rc);
1019 }
1020
1021 LogFlowFuncLeaveRC(rc);
1022 return rc;
1023}
1024
1025/**
1026 * Receives a host request to open a list handle on the guest.
1027 *
1028 * @returns VBox status code.
1029 * @param pCtx Shared Clipboard command context to use for the connection.
1030 * @param pOpenParms Where to store the open parameters the host wants to use for opening the list handle.
1031 */
1032VBGLR3DECL(int) VbglR3ClipboardListOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms)
1033{
1034 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1035 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
1036
1037 VBoxShClListOpenMsg Msg;
1038 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1039 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_OPEN);
1040
1041 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN);
1042 Msg.fList.SetUInt32(0);
1043 Msg.pvPath.SetPtr(pOpenParms->pszPath, pOpenParms->cbPath);
1044 Msg.pvFilter.SetPtr(pOpenParms->pszFilter, pOpenParms->cbFilter);
1045 Msg.uHandle.SetUInt64(0);
1046
1047 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1048 if (RT_SUCCESS(rc))
1049 {
1050 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1051 if (RT_SUCCESS(rc))
1052 rc = Msg.fList.GetUInt32(&pOpenParms->fList);
1053 }
1054
1055 LogFlowFuncLeaveRC(rc);
1056 return rc;
1057}
1058
1059/**
1060 * Replies to a list open request from the host.
1061 *
1062 * @returns VBox status code.
1063 * @param pCtx Shared Clipboard command context to use for the connection.
1064 * @param rcReply Return code to reply to the host.
1065 * @param hList List handle of (guest) list to reply to the host.
1066 */
1067VBGLR3DECL(int) VbglR3ClipboardListOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList)
1068{
1069 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1070
1071 VBoxShClReplyMsg Msg;
1072 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1073 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1074
1075 Msg.uContext.SetUInt64(pCtx->idContext);
1076 Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN);
1077 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1078 Msg.pvPayload.SetPtr(NULL, 0);
1079
1080 Msg.u.ListOpen.uHandle.SetUInt64(hList);
1081
1082 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1083
1084 LogFlowFuncLeaveRC(rc);
1085 return rc;
1086}
1087
1088/**
1089 * Receives a host request to close a list handle on the guest.
1090 *
1091 * @returns VBox status code.
1092 * @param pCtx Shared Clipboard command context to use for the connection.
1093 * @param phList Where to store the list handle to close, received from the host.
1094 */
1095VBGLR3DECL(int) VbglR3ClipboardListCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList)
1096{
1097 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1098 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1099
1100 VBoxShClListCloseMsg Msg;
1101 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1102 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_CLOSE);
1103
1104 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE);
1105 Msg.uHandle.SetUInt64(0);
1106
1107 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1108 if (RT_SUCCESS(rc))
1109 {
1110 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1111 if (RT_SUCCESS(rc))
1112 {
1113 rc = Msg.uHandle.GetUInt64(phList);
1114 AssertRC(rc);
1115 }
1116 }
1117
1118 LogFlowFuncLeaveRC(rc);
1119 return rc;
1120}
1121
1122/**
1123 * Replies to a list handle close request from the host.
1124 *
1125 * @returns VBox status code.
1126 * @param pCtx Shared Clipboard command context to use for the connection.
1127 * @param rcReply Return code to reply to the host.
1128 * @param hList List handle the send the close reply for.
1129 */
1130VBGLR3DECL(int) VbglR3ClipboardListCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList)
1131{
1132 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1133
1134 VBoxShClReplyMsg Msg;
1135 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1136 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1137
1138 Msg.uContext.SetUInt64(pCtx->idContext);
1139 Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_LIST_CLOSE);
1140 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1141 Msg.pvPayload.SetPtr(NULL, 0);
1142
1143 Msg.u.ListOpen.uHandle.SetUInt64(hList);
1144
1145 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1146
1147 LogFlowFuncLeaveRC(rc);
1148 return rc;
1149}
1150
1151/**
1152 * Sends a request to close a list handle to the host.
1153 *
1154 * @returns VBox status code.
1155 * @param pCtx Shared Clipboard command context to use for the connection.
1156 * @param hList List handle to request for closing on the host.
1157 */
1158VBGLR3DECL(int) VbglR3ClipboardListCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList)
1159{
1160 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1161
1162 VBoxShClListCloseMsg Msg;
1163 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1164 VBOX_SHCL_GUEST_FN_LIST_CLOSE, VBOX_SHCL_CPARMS_LIST_CLOSE);
1165
1166 Msg.uContext.SetUInt64(pCtx->idContext);
1167 Msg.uHandle.SetUInt64(hList);
1168
1169 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1170
1171 LogFlowFuncLeaveRC(rc);
1172 return rc;
1173}
1174
1175/**
1176 * Sends a request to read a list header to the host.
1177 *
1178 * @returns VBox status code.
1179 * @param pCtx Shared Clipboard command context to use for the connection.
1180 * @param hList List handle to read list header for.
1181 * @param fFlags List header read flags to use.
1182 * @param pListHdr Where to return the list header received from the host.
1183 */
1184VBGLR3DECL(int) VbglR3ClipboardListHdrRead(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList, uint32_t fFlags,
1185 PSHCLLISTHDR pListHdr)
1186{
1187 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1188 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
1189
1190 VBoxShClListHdrMsg Msg;
1191 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1192 VBOX_SHCL_GUEST_FN_LIST_HDR_READ, VBOX_SHCL_CPARMS_LIST_HDR);
1193
1194 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1195 Msg.ReqParms.uHandle.SetUInt64(hList);
1196 Msg.ReqParms.fFlags.SetUInt32(fFlags);
1197
1198 Msg.fFeatures.SetUInt32(0);
1199 Msg.cbTotalSize.SetUInt32(0);
1200 Msg.cTotalObjects.SetUInt64(0);
1201 Msg.cbTotalSize.SetUInt64(0);
1202
1203 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1204 if (RT_SUCCESS(rc))
1205 {
1206 rc = Msg.fFeatures.GetUInt32(&pListHdr->fFeatures);
1207 if (RT_SUCCESS(rc))
1208 rc = Msg.cTotalObjects.GetUInt64(&pListHdr->cTotalObjects);
1209 if (RT_SUCCESS(rc))
1210 rc = Msg.cbTotalSize.GetUInt64(&pListHdr->cbTotalSize);
1211 }
1212
1213 LogFlowFuncLeaveRC(rc);
1214 return rc;
1215}
1216
1217/**
1218 * Receives a host request to read a list header on the guest.
1219 *
1220 * @returns VBox status code.
1221 * @param pCtx Shared Clipboard command context to use for the connection.
1222 * @param phList Where to return the list handle to read list header for.
1223 * @param pfFlags Where to return the List header read flags to use.
1224 */
1225VBGLR3DECL(int) VbglR3ClipboardListHdrReadRecvReq(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList, uint32_t *pfFlags)
1226{
1227 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1228 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1229 AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
1230
1231 VBoxShClListHdrReadReqMsg Msg;
1232 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1233 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_HDR_READ_REQ);
1234
1235 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ);
1236 Msg.ReqParms.uHandle.SetUInt64(0);
1237 Msg.ReqParms.fFlags.SetUInt32(0);
1238
1239 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1240 if (RT_SUCCESS(rc))
1241 {
1242 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1243 if (RT_SUCCESS(rc))
1244 rc = Msg.ReqParms.uHandle.GetUInt64(phList);
1245 if (RT_SUCCESS(rc))
1246 rc = Msg.ReqParms.fFlags.GetUInt32(pfFlags);
1247 }
1248
1249 LogFlowFuncLeaveRC(rc);
1250 return rc;
1251}
1252
1253/**
1254 * Sends (writes) a list header to the host.
1255 *
1256 * @returns VBox status code.
1257 * @param pCtx Shared Clipboard command context to use for the connection.
1258 * @param hList List handle to write list header for.
1259 * @param pListHdr List header to write.
1260 */
1261VBGLR3DECL(int) VbglR3ClipboardListHdrWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1262 PSHCLLISTHDR pListHdr)
1263{
1264 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1265 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
1266
1267 VBoxShClListHdrMsg Msg;
1268 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1269 VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE, VBOX_SHCL_CPARMS_LIST_HDR);
1270
1271 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1272 Msg.ReqParms.uHandle.SetUInt64(hList);
1273 Msg.ReqParms.fFlags.SetUInt32(0);
1274
1275 Msg.fFeatures.SetUInt32(0);
1276 Msg.cbTotalSize.SetUInt32(pListHdr->fFeatures);
1277 Msg.cTotalObjects.SetUInt64(pListHdr->cTotalObjects);
1278 Msg.cbTotalSize.SetUInt64(pListHdr->cbTotalSize);
1279
1280 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1281
1282 LogFlowFuncLeaveRC(rc);
1283 return rc;
1284}
1285
1286/**
1287 * Sends a request to read a list entry from the host.
1288 *
1289 * @returns VBox status code.
1290 * @param pCtx Shared Clipboard command context to use for the connection.
1291 * @param hList List handle to request to read a list entry for.
1292 * @param pListEntry Where to return the list entry read from the host.
1293 */
1294VBGLR3DECL(int) VbglR3ClipboardListEntryRead(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1295 PSHCLLISTENTRY pListEntry)
1296{
1297 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1298 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
1299
1300 VBoxShClListEntryMsg Msg;
1301 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1302 VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ, VBOX_SHCL_CPARMS_LIST_ENTRY);
1303
1304 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1305 Msg.ReqParms.uHandle.SetUInt64(hList);
1306 Msg.ReqParms.fInfo.SetUInt32(0);
1307
1308 Msg.szName.SetPtr(pListEntry->pszName, pListEntry->cbName);
1309 Msg.cbInfo.SetUInt32(pListEntry->cbInfo);
1310 Msg.pvInfo.SetPtr(pListEntry->pvInfo, pListEntry->cbInfo);
1311
1312 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1313 if (RT_SUCCESS(rc))
1314 {
1315 rc = Msg.cbInfo.GetUInt32(&pListEntry->cbInfo); AssertRC(rc);
1316 }
1317
1318 LogFlowFuncLeaveRC(rc);
1319 return rc;
1320}
1321
1322/**
1323 * Receives a host request to read a list entry from the guest.
1324 *
1325 * @returns VBox status code.
1326 * @param pCtx Shared Clipboard command context to use for the connection.
1327 * @param phList Where to return the list handle to read a list entry for.
1328 * @param pfInfo Where to return the list read flags.
1329 */
1330VBGLR3DECL(int) VbglR3ClipboardListEntryReadRecvReq(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList, uint32_t *pfInfo)
1331{
1332 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1333 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1334 AssertPtrReturn(pfInfo, VERR_INVALID_POINTER);
1335
1336 VBoxShClListEntryReadReqMsg Msg;
1337 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1338 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_ENTRY_READ);
1339
1340 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ);
1341 Msg.ReqParms.uHandle.SetUInt64(0);
1342 Msg.ReqParms.fInfo.SetUInt32(0);
1343
1344 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1345 if (RT_SUCCESS(rc))
1346 {
1347 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1348 if (RT_SUCCESS(rc))
1349 {
1350 rc = Msg.ReqParms.uHandle.GetUInt64(phList);
1351 AssertRC(rc);
1352 }
1353 if (RT_SUCCESS(rc))
1354 {
1355 rc = Msg.ReqParms.fInfo.GetUInt32(pfInfo);
1356 AssertRC(rc);
1357 }
1358 }
1359
1360 LogFlowFuncLeaveRC(rc);
1361 return rc;
1362}
1363
1364/**
1365 * Sends (writes) a list entry to the host.
1366 *
1367 * @returns VBox status code.
1368 * @param pCtx Shared Clipboard command context to use for the connection.
1369 * @param hList List handle to write a list etnry for.
1370 * @param pListEntry List entry to write.
1371 */
1372VBGLR3DECL(int) VbglR3ClipboardListEntryWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1373 PSHCLLISTENTRY pListEntry)
1374{
1375 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1376 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
1377
1378 VBoxShClListEntryMsg Msg;
1379 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1380 VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE, VBOX_SHCL_CPARMS_LIST_ENTRY);
1381
1382 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1383 Msg.ReqParms.uHandle.SetUInt64(hList);
1384 Msg.ReqParms.fInfo.SetUInt32(pListEntry->fInfo);
1385
1386 Msg.szName.SetPtr(pListEntry->pszName, pListEntry->cbName);
1387 Msg.cbInfo.SetUInt32(pListEntry->cbInfo);
1388 Msg.pvInfo.SetPtr(pListEntry->pvInfo, pListEntry->cbInfo);
1389
1390 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1391
1392 LogFlowFuncLeaveRC(rc);
1393 return rc;
1394}
1395
1396/**
1397 * Receives a host request to open an object on the guest.
1398 *
1399 * @returns VBox status code.
1400 * @param pCtx Shared Clipboard command context to use for the connection.
1401 * @param pCreateParms Where to store the object open/create parameters received from the host.
1402 */
1403VBGLR3DECL(int) VbglR3ClipboardObjOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms)
1404{
1405 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1406 AssertPtrReturn(pCreateParms, VERR_INVALID_POINTER);
1407
1408 VBoxShClObjOpenMsg Msg;
1409 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1410 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_OPEN);
1411
1412 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN);
1413 Msg.uHandle.SetUInt64(0);
1414 Msg.szPath.SetPtr(pCreateParms->pszPath, pCreateParms->cbPath);
1415 Msg.fCreate.SetUInt32(0);
1416
1417 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1418 if (RT_SUCCESS(rc))
1419 {
1420 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1421 if (RT_SUCCESS(rc))
1422 rc = Msg.fCreate.GetUInt32(&pCreateParms->fCreate);
1423 }
1424
1425 LogFlowFuncLeaveRC(rc);
1426 return rc;
1427}
1428
1429/**
1430 * Replies a host request to open an object.
1431 *
1432 * @returns VBox status code.
1433 * @param pCtx Shared Clipboard command context to use for the connection.
1434 * @param rcReply Return code to reply to the host.
1435 * @param hObj Object handle of opened object to reply to the host.
1436 */
1437VBGLR3DECL(int) VbglR3ClipboardObjOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj)
1438{
1439 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1440
1441 VBoxShClReplyMsg Msg;
1442 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1443 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1444
1445 Msg.uContext.SetUInt64(pCtx->idContext);
1446 Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN);
1447 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1448 Msg.pvPayload.SetPtr(NULL, 0);
1449
1450 Msg.u.ObjOpen.uHandle.SetUInt64(hObj);
1451
1452 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1453
1454 LogFlowFuncLeaveRC(rc);
1455 return rc;
1456}
1457
1458/**
1459 * Sends an object open request to the host.
1460 *
1461 * @returns VBox status code.
1462 * @param pCtx Shared Clipboard command context to use for the connection.
1463 * @param pCreateParms Object open/create parameters to use for opening the object on the host.
1464 * @param phObj Where to return the object handle from the host.
1465 */
1466VBGLR3DECL(int) VbglR3ClipboardObjOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms,
1467 PSHCLOBJHANDLE phObj)
1468{
1469 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1470 AssertPtrReturn(pCreateParms, VERR_INVALID_POINTER);
1471 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1472
1473 VBoxShClObjOpenMsg Msg;
1474 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1475 VBOX_SHCL_GUEST_FN_OBJ_OPEN, VBOX_SHCL_CPARMS_OBJ_OPEN);
1476
1477 Msg.uContext.SetUInt64(pCtx->idContext);
1478 Msg.uHandle.SetUInt64(0);
1479 Msg.szPath.SetPtr((void *)pCreateParms->pszPath, pCreateParms->cbPath);
1480 Msg.fCreate.SetUInt32(pCreateParms->fCreate);
1481
1482 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1483 if (RT_SUCCESS(rc))
1484 {
1485 Msg.uHandle.GetUInt64(phObj);
1486 }
1487
1488 LogFlowFuncLeaveRC(rc);
1489 return rc;
1490}
1491
1492/**
1493 * Receives a host request to close an object on the guest.
1494 *
1495 * @returns VBox status code.
1496 * @param pCtx Shared Clipboard command context to use for the connection.
1497 * @param phObj Where to return the object handle to close from the host.
1498 */
1499VBGLR3DECL(int) VbglR3ClipboardObjCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj)
1500{
1501 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1502 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1503
1504 VBoxShClObjCloseMsg Msg;
1505 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1506 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_CLOSE);
1507
1508 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE);
1509 Msg.uHandle.SetUInt64(0);
1510
1511 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1512 if (RT_SUCCESS(rc))
1513 {
1514 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1515 if (RT_SUCCESS(rc))
1516 rc = Msg.uHandle.GetUInt64(phObj);
1517 }
1518
1519 LogFlowFuncLeaveRC(rc);
1520 return rc;
1521}
1522
1523/**
1524 * Replies to an object open request from the host.
1525 *
1526 * @returns VBox status code.
1527 * @param pCtx Shared Clipboard command context to use for the connection.
1528 * @param rcReply Return code to reply to the host.
1529 * @param hObj Object handle to reply to the host.
1530 */
1531VBGLR3DECL(int) VbglR3ClipboardObjCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj)
1532{
1533 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1534
1535 VBoxShClReplyMsg Msg;
1536 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1537 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1538
1539 Msg.uContext.SetUInt64(pCtx->idContext);
1540 Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE);
1541 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1542 Msg.pvPayload.SetPtr(NULL, 0);
1543
1544 Msg.u.ObjClose.uHandle.SetUInt64(hObj);
1545
1546 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1547
1548 LogFlowFuncLeaveRC(rc);
1549 return rc;
1550}
1551
1552/**
1553 * Sends a request to close an object to the host.
1554 *
1555 * @returns VBox status code.
1556 * @param pCtx Shared Clipboard command context to use for the connection.
1557 * @param hObj Object handle to close on the host.
1558 */
1559VBGLR3DECL(int) VbglR3ClipboardObjCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj)
1560{
1561 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1562
1563 VBoxShClObjCloseMsg Msg;
1564 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1565 VBOX_SHCL_GUEST_FN_OBJ_CLOSE, VBOX_SHCL_CPARMS_OBJ_CLOSE);
1566
1567 Msg.uContext.SetUInt64(pCtx->idContext);
1568 Msg.uHandle.SetUInt64(hObj);
1569
1570 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1571
1572 LogFlowFuncLeaveRC(rc);
1573 return rc;
1574}
1575
1576/**
1577 * Receives a host request to read from an object on the guest.
1578 *
1579 * @returns VBox status code.
1580 * @param pCtx Shared Clipboard command context to use for the connection.
1581 * @param phObj Where to return the object handle to read from.
1582 * @param pcbToRead Where to return the amount (in bytes) to read.
1583 * @param pfFlags Where to return the read flags.
1584 */
1585VBGLR3DECL(int) VbglR3ClipboardObjReadRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj, uint32_t *pcbToRead,
1586 uint32_t *pfFlags)
1587{
1588 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1589 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1590 AssertPtrReturn(pcbToRead, VERR_INVALID_POINTER);
1591 AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
1592
1593 VBoxShClObjReadReqMsg Msg;
1594 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1595 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_READ_REQ);
1596
1597 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ);
1598 Msg.ReqParms.uHandle.SetUInt64(0);
1599 Msg.ReqParms.cbToRead.SetUInt32(0);
1600 Msg.ReqParms.fRead.SetUInt32(0);
1601
1602 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1603 if (RT_SUCCESS(rc))
1604 {
1605 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1606 if (RT_SUCCESS(rc))
1607 rc = Msg.ReqParms.uHandle.GetUInt64(phObj);
1608 if (RT_SUCCESS(rc))
1609 rc = Msg.ReqParms.cbToRead.GetUInt32(pcbToRead);
1610 if (RT_SUCCESS(rc))
1611 rc = Msg.ReqParms.fRead.GetUInt32(pfFlags);
1612 }
1613
1614 LogFlowFuncLeaveRC(rc);
1615 return rc;
1616}
1617
1618/**
1619 * Sends a request to read from an object to the host.
1620 *
1621 * @returns VBox status code.
1622 * @param pCtx Shared Clipboard command context to use for the connection.
1623 * @param hObj Object handle of object to read from.
1624 * @param pvData Buffer where to store the read object data.
1625 * @param cbData Size (in bytes) of buffer.
1626 * @param pcbRead Where to store the amount (in bytes) read from the object.
1627 */
1628VBGLR3DECL(int) VbglR3ClipboardObjReadSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj,
1629 void *pvData, uint32_t cbData, uint32_t *pcbRead)
1630{
1631 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1632 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1633 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1634 /* pcbRead is optional. */
1635
1636 VBoxShClObjReadWriteMsg Msg;
1637 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1638 VBOX_SHCL_GUEST_FN_OBJ_READ, VBOX_SHCL_CPARMS_OBJ_READ);
1639
1640 Msg.uContext.SetUInt64(pCtx->idContext);
1641 Msg.uHandle.SetUInt64(hObj);
1642 Msg.cbData.SetUInt32(cbData);
1643 Msg.pvData.SetPtr(pvData, cbData);
1644 Msg.cbChecksum.SetUInt32(0);
1645 Msg.pvChecksum.SetPtr(NULL, 0);
1646
1647 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1648 if (RT_SUCCESS(rc))
1649 {
1650 /** @todo Add checksum support. */
1651
1652 if (pcbRead)
1653 {
1654 rc = Msg.cbData.GetUInt32(pcbRead); AssertRC(rc);
1655 AssertReturn(cbData >= *pcbRead, VERR_TOO_MUCH_DATA);
1656 }
1657 }
1658
1659 LogFlowFuncLeaveRC(rc);
1660 return rc;
1661}
1662
1663/**
1664 * Sends a request to write to an object to the host.
1665 *
1666 * @returns VBox status code.
1667 * @param pCtx Shared Clipboard command context to use for the connection.
1668 * @param hObj Object handle of object to write to.
1669 * @param pvData Buffer of data to write to object.
1670 * @param cbData Size (in bytes) of buffer.
1671 * @param pcbWritten Where to store the amount (in bytes) written to the object.
1672 */
1673VBGLR3DECL(int) VbglR3ClipboardObjWriteSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj,
1674 void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1675{
1676 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1677 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1678 /* cbData can be 0. */
1679 /* pcbWritten is optional. */
1680
1681 VBoxShClObjReadWriteMsg Msg;
1682 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1683 VBOX_SHCL_GUEST_FN_OBJ_WRITE, VBOX_SHCL_CPARMS_OBJ_WRITE);
1684
1685 Msg.uContext.SetUInt64(pCtx->idContext);
1686 Msg.uHandle.SetUInt64(hObj);
1687 Msg.pvData.SetPtr(pvData, cbData);
1688 Msg.pvChecksum.SetPtr(NULL, 0);
1689
1690 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1691 if (RT_SUCCESS(rc))
1692 {
1693 /** @todo Add checksum support. */
1694
1695 if (pcbWritten)
1696 *pcbWritten = cbData; /** @todo For now return all as being written. */
1697 }
1698
1699 LogFlowFuncLeaveRC(rc);
1700 return rc;
1701}
1702
1703
1704/*********************************************************************************************************************************
1705* Transfer interface implementations *
1706*********************************************************************************************************************************/
1707
1708static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceGetRoots(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList)
1709{
1710 LogFlowFuncEnter();
1711
1712 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1713 AssertPtr(pCmdCtx);
1714
1715 int rc = VbglR3ClipboardRootListRead(pCmdCtx, ppRootList);
1716
1717 LogFlowFuncLeaveRC(rc);
1718 return rc;
1719}
1720
1721static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
1722 PSHCLLISTHANDLE phList)
1723{
1724 LogFlowFuncEnter();
1725
1726 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1727 AssertPtr(pCmdCtx);
1728
1729 int rc = VbglR3ClipboardListOpenSend(pCmdCtx, pOpenParms, phList);
1730
1731 LogFlowFuncLeaveRC(rc);
1732 return rc;
1733}
1734
1735static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
1736{
1737 LogFlowFuncEnter();
1738
1739 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1740 AssertPtr(pCmdCtx);
1741
1742 int rc = VbglR3ClipboardListCloseSend(pCmdCtx, hList);
1743
1744 LogFlowFuncLeaveRC(rc);
1745 return rc;
1746}
1747
1748static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListHdrRead(PSHCLTXPROVIDERCTX pCtx,
1749 SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
1750{
1751 LogFlowFuncEnter();
1752
1753 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1754 AssertPtr(pCmdCtx);
1755
1756 int rc = ShClTransferListHdrInit(pListHdr);
1757 if (RT_SUCCESS(rc))
1758 {
1759 if (RT_SUCCESS(rc))
1760 {
1761 rc = VbglR3ClipboardListHdrRead(pCmdCtx, hList, 0 /* fFlags */, pListHdr);
1762 }
1763 else
1764 ShClTransferListHdrDestroy(pListHdr);
1765 }
1766
1767 LogFlowFuncLeaveRC(rc);
1768 return rc;
1769}
1770
1771static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListEntryRead(PSHCLTXPROVIDERCTX pCtx,
1772 SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry)
1773{
1774 LogFlowFuncEnter();
1775
1776 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1777 AssertPtr(pCmdCtx);
1778
1779 int rc = VbglR3ClipboardListEntryRead(pCmdCtx, hList, pEntry);
1780
1781 LogFlowFuncLeaveRC(rc);
1782 return rc;
1783}
1784
1785static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceObjOpen(PSHCLTXPROVIDERCTX pCtx,
1786 PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)
1787{
1788 LogFlowFuncEnter();
1789
1790 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1791 AssertPtr(pCmdCtx);
1792
1793 int rc = VbglR3ClipboardObjOpenSend(pCmdCtx, pCreateParms, phObj);
1794
1795 LogFlowFuncLeaveRC(rc);
1796 return rc;
1797}
1798
1799static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
1800{
1801 LogFlowFuncEnter();
1802
1803 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1804 AssertPtr(pCmdCtx);
1805
1806 int rc = VbglR3ClipboardObjCloseSend(pCmdCtx, hObj);
1807
1808 LogFlowFuncLeaveRC(rc);
1809 return rc;
1810}
1811
1812static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceObjRead(PSHCLTXPROVIDERCTX pCtx,
1813 SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData,
1814 uint32_t fFlags, uint32_t *pcbRead)
1815{
1816 LogFlowFuncEnter();
1817
1818 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1819 AssertPtr(pCmdCtx);
1820
1821 RT_NOREF(fFlags); /* Not used yet. */
1822
1823 int rc = VbglR3ClipboardObjReadSend(pCmdCtx, hObj, pvData, cbData, pcbRead);
1824
1825 LogFlowFuncLeaveRC(rc);
1826 return rc;
1827}
1828
1829/**
1830 * Starts a transfer on the guest side.
1831 *
1832 * @returns VBox status code.
1833 * @param pCmdCtx Command context to use.
1834 * @param pTransferCtx Transfer context to create transfer for.
1835 * @param uTransferID ID to use for transfer to start.
1836 * @param enmDir Direction of transfer to start.
1837 * @param enmSource Source of transfer to start.
1838 * @param ppTransfer Where to return the transfer object on success. Optional.
1839 */
1840static int vbglR3ClipboardTransferStart(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
1841 SHCLTRANSFERID uTransferID, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource,
1842 PSHCLTRANSFER *ppTransfer)
1843{
1844 PSHCLTRANSFER pTransfer;
1845 int rc = ShClTransferCreate(&pTransfer);
1846 if (RT_SUCCESS(rc))
1847 {
1848 ShClTransferSetCallbacks(pTransfer, &pCmdCtx->Transfers.Callbacks);
1849
1850 rc = ShClTransferInit(pTransfer, enmDir, enmSource);
1851 if (RT_SUCCESS(rc))
1852 {
1853 rc = ShClTransferCtxTransferRegisterById(pTransferCtx, pTransfer, uTransferID);
1854 if (RT_SUCCESS(rc))
1855 {
1856 /* If this is a read transfer (reading data from host), set the interface to use
1857 * our VbglR3 routines here. */
1858 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE)
1859 {
1860 SHCLTXPROVIDERCREATIONCTX creationCtx;
1861 RT_ZERO(creationCtx);
1862
1863 creationCtx.Interface.pfnRootsGet = vbglR3ClipboardTransferIfaceGetRoots;
1864
1865 creationCtx.Interface.pfnListOpen = vbglR3ClipboardTransferIfaceListOpen;
1866 creationCtx.Interface.pfnListClose = vbglR3ClipboardTransferIfaceListClose;
1867 creationCtx.Interface.pfnListHdrRead = vbglR3ClipboardTransferIfaceListHdrRead;
1868 creationCtx.Interface.pfnListEntryRead = vbglR3ClipboardTransferIfaceListEntryRead;
1869
1870 creationCtx.Interface.pfnObjOpen = vbglR3ClipboardTransferIfaceObjOpen;
1871 creationCtx.Interface.pfnObjClose = vbglR3ClipboardTransferIfaceObjClose;
1872 creationCtx.Interface.pfnObjRead = vbglR3ClipboardTransferIfaceObjRead;
1873
1874 creationCtx.pvUser = pCmdCtx;
1875
1876 rc = ShClTransferSetProviderIface(pTransfer, &creationCtx);
1877 }
1878
1879 if (RT_SUCCESS(rc))
1880 rc = ShClTransferStart(pTransfer);
1881 }
1882
1883 if (RT_FAILURE(rc))
1884 ShClTransferCtxTransferUnregister(pTransferCtx, uTransferID);
1885 }
1886 }
1887
1888 if (RT_SUCCESS(rc))
1889 {
1890 if (ppTransfer)
1891 *ppTransfer = pTransfer;
1892
1893 LogRel2(("Shared Clipboard: Transfer ID=%RU32 (%s %s) successfully started\n",
1894 uTransferID,
1895 enmDir == SHCLTRANSFERDIR_FROM_REMOTE ? "reading from" : "writing to",
1896 enmSource == SHCLSOURCE_LOCAL ? "local" : "remote"));
1897 }
1898 else
1899 LogRel(("Shared Clipboard: Unable to start transfer ID=%RU32, rc=%Rrc\n", uTransferID, rc));
1900
1901 /* Send a reply in any case. */
1902 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
1903 RT_SUCCESS(rc)
1904 ? SHCLTRANSFERSTATUS_STARTED : SHCLTRANSFERSTATUS_ERROR, rc);
1905 if (RT_SUCCESS(rc))
1906 rc = rc2;
1907
1908 if (RT_FAILURE(rc))
1909 {
1910 ShClTransferDestroy(pTransfer);
1911 pTransfer = NULL;
1912 }
1913
1914 LogFlowFuncLeaveRC(rc);
1915 return rc;
1916}
1917
1918/**
1919 * Stops a transfer on the guest side.
1920 *
1921 * @returns VBox status code, or VERR_NOT_FOUND if transfer has not been found.
1922 * @param pCmdCtx Command context to use.
1923 * @param pTransferCtx Transfer context to stop transfer for.
1924 * @param uTransferID ID of transfer to stop.
1925 */
1926static int vbglR3ClipboardTransferStop(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
1927 SHCLTRANSFERID uTransferID)
1928{
1929 int rc;
1930
1931 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, uTransferID);
1932 if (pTransfer)
1933 {
1934 rc = ShClTransferCtxTransferUnregister(pTransferCtx, uTransferID);
1935 if (RT_SUCCESS(rc))
1936 {
1937 LogRel2(("Shared Clipboard: Transfer ID=%RU32 successfully stopped\n", uTransferID));
1938 }
1939 else
1940 LogRel(("Shared Clipboard: Unable to stop transfer ID=%RU32, rc=%Rrc\n", uTransferID, rc));
1941
1942 /* Send a reply in any case. */
1943 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
1944 RT_SUCCESS(rc)
1945 ? SHCLTRANSFERSTATUS_STOPPED : SHCLTRANSFERSTATUS_ERROR, rc);
1946 AssertRC(rc2);
1947 }
1948 else
1949 rc = VERR_NOT_FOUND;
1950
1951 LogFlowFuncLeaveRC(rc);
1952 return rc;
1953}
1954
1955/**
1956 * Sets transfer callbacks of a Shared Clipboard command context.
1957 *
1958 * @param pCmdCtx Command context to set callbacks for.
1959 * @param pCallbacks Pointer to callback table to set.
1960 */
1961VBGLR3DECL(void) VbglR3ClipboardTransferSetCallbacks(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCALLBACKTABLE pCallbacks)
1962{
1963 AssertPtrReturnVoid(pCmdCtx);
1964 AssertPtrReturnVoid(pCallbacks);
1965
1966 ShClTransferCopyCallbacks(&pCmdCtx->Transfers.Callbacks, pCallbacks);
1967}
1968
1969VBGLR3DECL(int) VbglR3ClipboardEventGetNextEx(uint32_t idMsg, uint32_t cParms,
1970 PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
1971 PVBGLR3CLIPBOARDEVENT pEvent)
1972{
1973 AssertPtrReturn(pCmdCtx, VERR_INVALID_POINTER);
1974 AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER);
1975 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1976
1977 LogFunc(("Handling idMsg=%RU32 (%s), cParms=%RU32\n", idMsg, ShClHostMsgToStr(idMsg), cParms));
1978
1979 int rc;
1980 if (!pCmdCtx->fUseLegacyProtocol)
1981 {
1982 bool fErrorSent = false; /* Whether an error has been reported back to the host already. */
1983
1984 switch (idMsg)
1985 {
1986 case VBOX_SHCL_HOST_MSG_TRANSFER_STATUS:
1987 {
1988 SHCLTRANSFERDIR enmDir;
1989 SHCLTRANSFERREPORT transferReport;
1990 rc = VbglR3ClipboarTransferStatusRecv(pCmdCtx, &enmDir, &transferReport);
1991 if (RT_SUCCESS(rc))
1992 {
1993 const SHCLTRANSFERID uTransferID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
1994
1995 LogFlowFunc(("[Transfer %RU32] enmDir=%RU32, status=%s\n",
1996 uTransferID, enmDir, ShClTransferStatusToStr(transferReport.uStatus)));
1997
1998 switch (transferReport.uStatus)
1999 {
2000 case SHCLTRANSFERSTATUS_INITIALIZED:
2001 RT_FALL_THROUGH();
2002 case SHCLTRANSFERSTATUS_STARTED:
2003 {
2004 SHCLSOURCE enmSource = SHCLSOURCE_INVALID;
2005
2006 /* The host announces the transfer direction from its point of view, so inverse the direction here. */
2007 if (enmDir == SHCLTRANSFERDIR_TO_REMOTE)
2008 {
2009 enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
2010 enmSource = SHCLSOURCE_REMOTE;
2011 }
2012 else if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE)
2013 {
2014 enmDir = SHCLTRANSFERDIR_TO_REMOTE;
2015 enmSource = SHCLSOURCE_LOCAL;
2016 }
2017 else
2018 AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
2019
2020 rc = vbglR3ClipboardTransferStart(pCmdCtx, pTransferCtx, uTransferID,
2021 enmDir, enmSource, NULL /* ppTransfer */);
2022 break;
2023 }
2024
2025 case SHCLTRANSFERSTATUS_STOPPED:
2026 RT_FALL_THROUGH();
2027 case SHCLTRANSFERSTATUS_CANCELED:
2028 RT_FALL_THROUGH();
2029 case SHCLTRANSFERSTATUS_KILLED:
2030 RT_FALL_THROUGH();
2031 case SHCLTRANSFERSTATUS_ERROR:
2032 {
2033 rc = vbglR3ClipboardTransferStop(pCmdCtx, pTransferCtx,
2034 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2035 break;
2036 }
2037
2038 default:
2039 rc = VERR_NOT_SUPPORTED;
2040 break;
2041 }
2042
2043 if (RT_SUCCESS(rc))
2044 {
2045 pEvent->u.TransferStatus.enmDir = enmDir;
2046 pEvent->u.TransferStatus.Report = transferReport;
2047 pEvent->u.TransferStatus.uID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
2048
2049 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS;
2050
2051 LogRel2(("Shared Clipboard: Received status %s (rc=%Rrc) for transfer ID=%RU32\n",
2052 ShClTransferStatusToStr(pEvent->u.TransferStatus.Report.uStatus), pEvent->u.TransferStatus.Report.rc,
2053 pEvent->u.TransferStatus.uID));
2054 }
2055 }
2056 break;
2057 }
2058
2059 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ:
2060 {
2061 uint32_t fRoots;
2062 rc = VbglR3ClipboardRootListHdrReadReq(pCmdCtx, &fRoots);
2063
2064 /** @todo Validate / handle fRoots. */
2065
2066 if (RT_SUCCESS(rc))
2067 {
2068 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2069 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2070 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2071
2072 SHCLROOTLISTHDR rootListHdr;
2073 RT_ZERO(rootListHdr);
2074
2075 rootListHdr.cRoots = ShClTransferRootsCount(pTransfer);
2076
2077 LogFlowFunc(("cRoots=%RU32\n", rootListHdr.cRoots));
2078
2079 rc = VbglR3ClipboardRootListHdrReadReply(pCmdCtx, &rootListHdr);
2080 }
2081 break;
2082 }
2083
2084 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ:
2085 {
2086 uint32_t uIndex;
2087 uint32_t fInfo;
2088 rc = VbglR3ClipboardRootListEntryReadReq(pCmdCtx, &uIndex, &fInfo);
2089 if (RT_SUCCESS(rc))
2090 {
2091 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2092 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2093 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2094
2095 SHCLROOTLISTENTRY rootListEntry;
2096 rc = ShClTransferRootsEntry(pTransfer, uIndex, &rootListEntry);
2097 if (RT_SUCCESS(rc))
2098 rc = VbglR3ClipboardRootListEntryReadReply(pCmdCtx, uIndex, &rootListEntry);
2099 }
2100 break;
2101 }
2102
2103 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN:
2104 {
2105 SHCLLISTOPENPARMS openParmsList;
2106 rc = ShClTransferListOpenParmsInit(&openParmsList);
2107 if (RT_SUCCESS(rc))
2108 {
2109 rc = VbglR3ClipboardListOpenRecv(pCmdCtx, &openParmsList);
2110 if (RT_SUCCESS(rc))
2111 {
2112 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2113 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2114 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2115
2116 LogFlowFunc(("pszPath=%s\n", openParmsList.pszPath));
2117
2118 SHCLLISTHANDLE hList = SHCLLISTHANDLE_INVALID;
2119 rc = ShClTransferListOpen(pTransfer, &openParmsList, &hList);
2120
2121 /* Reply in any case. */
2122 int rc2 = VbglR3ClipboardListOpenReply(pCmdCtx, rc, hList);
2123 AssertRC(rc2);
2124 }
2125
2126 ShClTransferListOpenParmsDestroy(&openParmsList);
2127 }
2128
2129 break;
2130 }
2131
2132 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE:
2133 {
2134 SHCLLISTHANDLE hList;
2135 rc = VbglR3ClipboardListCloseRecv(pCmdCtx, &hList);
2136 if (RT_SUCCESS(rc))
2137 {
2138 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2139 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2140 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2141
2142 rc = ShClTransferListClose(pTransfer, hList);
2143
2144 /* Reply in any case. */
2145 int rc2 = VbglR3ClipboardListCloseReply(pCmdCtx, rc, hList);
2146 AssertRC(rc2);
2147 }
2148
2149 break;
2150 }
2151
2152 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ:
2153 {
2154 /** @todo Handle filter + list features. */
2155
2156 SHCLLISTHANDLE hList = SHCLLISTHANDLE_INVALID;
2157 uint32_t fFlags = 0;
2158 rc = VbglR3ClipboardListHdrReadRecvReq(pCmdCtx, &hList, &fFlags);
2159 if (RT_SUCCESS(rc))
2160 {
2161 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2162 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2163 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2164
2165 SHCLLISTHDR hdrList;
2166 rc = ShClTransferListGetHeader(pTransfer, hList, &hdrList);
2167 if (RT_SUCCESS(rc))
2168 {
2169 rc = VbglR3ClipboardListHdrWrite(pCmdCtx, hList, &hdrList);
2170
2171 ShClTransferListHdrDestroy(&hdrList);
2172 }
2173 }
2174
2175 break;
2176 }
2177
2178 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ:
2179 {
2180 LogFlowFunc(("VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ\n"));
2181
2182 SHCLLISTENTRY entryList;
2183 rc = ShClTransferListEntryInit(&entryList);
2184 if (RT_SUCCESS(rc))
2185 {
2186 SHCLLISTHANDLE hList;
2187 uint32_t fInfo;
2188 rc = VbglR3ClipboardListEntryReadRecvReq(pCmdCtx, &hList, &fInfo);
2189 if (RT_SUCCESS(rc))
2190 {
2191 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2192 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2193 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2194
2195 rc = ShClTransferListRead(pTransfer, hList, &entryList);
2196 if (RT_SUCCESS(rc))
2197 {
2198 PSHCLFSOBJINFO pObjInfo = (PSHCLFSOBJINFO)entryList.pvInfo;
2199 Assert(entryList.cbInfo == sizeof(SHCLFSOBJINFO));
2200
2201 RT_NOREF(pObjInfo);
2202
2203 LogFlowFunc(("\t%s (%RU64 bytes)\n", entryList.pszName, pObjInfo->cbObject));
2204
2205 rc = VbglR3ClipboardListEntryWrite(pCmdCtx, hList, &entryList);
2206 }
2207 }
2208
2209 ShClTransferListEntryDestroy(&entryList);
2210 }
2211
2212 break;
2213 }
2214
2215 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN:
2216 {
2217 SHCLOBJOPENCREATEPARMS openParms;
2218 rc = ShClTransferObjOpenParmsInit(&openParms);
2219 if (RT_SUCCESS(rc))
2220 {
2221 rc = VbglR3ClipboardObjOpenRecv(pCmdCtx, &openParms);
2222 if (RT_SUCCESS(rc))
2223 {
2224 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2225 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2226 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2227
2228 SHCLOBJHANDLE hObj;
2229 rc = ShClTransferObjOpen(pTransfer, &openParms, &hObj);
2230
2231 /* Reply in any case. */
2232 int rc2 = VbglR3ClipboardObjOpenReply(pCmdCtx, rc, hObj);
2233 AssertRC(rc2);
2234 }
2235
2236 ShClTransferObjOpenParmsDestroy(&openParms);
2237 }
2238
2239 break;
2240 }
2241
2242 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE:
2243 {
2244 SHCLOBJHANDLE hObj;
2245 rc = VbglR3ClipboardObjCloseRecv(pCmdCtx, &hObj);
2246 if (RT_SUCCESS(rc))
2247 {
2248 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2249 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2250 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2251
2252 rc = ShClTransferObjClose(pTransfer, hObj);
2253
2254 /* Reply in any case. */
2255 int rc2 = VbglR3ClipboardObjCloseReply(pCmdCtx, rc, hObj);
2256 AssertRC(rc2);
2257 }
2258
2259 break;
2260 }
2261
2262 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ:
2263 {
2264 SHCLOBJHANDLE hObj;
2265 uint32_t cbBuf;
2266 uint32_t fFlags;
2267 rc = VbglR3ClipboardObjReadRecv(pCmdCtx, &hObj, &cbBuf, &fFlags);
2268 if (RT_SUCCESS(rc))
2269 {
2270 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2271 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2272 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2273
2274 AssertBreakStmt(pCmdCtx->Transfers.cbChunkSize, rc = VERR_INVALID_PARAMETER);
2275
2276 const uint32_t cbToRead = RT_MIN(cbBuf, pCmdCtx->Transfers.cbChunkSize);
2277
2278 LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, fFlags=0x%x -> cbChunkSize=%RU32, cbToRead=%RU32\n",
2279 hObj, cbBuf, fFlags, pCmdCtx->Transfers.cbChunkSize, cbToRead));
2280
2281 void *pvBuf = RTMemAlloc(cbToRead);
2282 if (pvBuf)
2283 {
2284 uint32_t cbRead;
2285 rc = ShClTransferObjRead(pTransfer, hObj, pvBuf, cbToRead, fFlags, &cbRead);
2286 if (RT_SUCCESS(rc))
2287 rc = VbglR3ClipboardObjWriteSend(pCmdCtx, hObj, pvBuf, cbRead, NULL /* pcbWritten */);
2288
2289 RTMemFree(pvBuf);
2290 }
2291 else
2292 rc = VERR_NO_MEMORY;
2293 }
2294
2295 break;
2296 }
2297
2298 default:
2299 {
2300 rc = VbglR3ClipboardEventGetNext(idMsg, cParms, pCmdCtx, pEvent);
2301 if (RT_FAILURE(rc))
2302 fErrorSent = true;
2303 break;
2304 }
2305 }
2306
2307 if ( !fErrorSent
2308 && RT_FAILURE(rc))
2309 {
2310 /* Report error back to the host. */
2311 int rc2 = VbglR3ClipboardWriteError(pCmdCtx->idClient, rc);
2312 AssertRC(rc2);
2313 }
2314 }
2315 else
2316 {
2317 /*
2318 * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
2319 * !HACK ALERT! cParms is the format flag or flags.
2320 */
2321 rc = VINF_SUCCESS;
2322 switch (idMsg)
2323 {
2324 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2325 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2326 pEvent->u.fReportedFormats = cParms;
2327 break;
2328
2329 case VBOX_SHCL_HOST_MSG_READ_DATA:
2330 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2331 pEvent->u.fReadData = cParms;
2332 break;
2333
2334 case VBOX_SHCL_HOST_MSG_QUIT:
2335 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2336 break;
2337
2338 default:
2339 AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
2340 rc = VERR_NOT_SUPPORTED;
2341 break;
2342 }
2343 }
2344
2345 LogFlowFuncLeaveRC(rc);
2346 return rc;
2347}
2348
2349#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
2350
2351VBGLR3DECL(int) VbglR3ClipboardEventGetNext(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PVBGLR3CLIPBOARDEVENT pEvent)
2352{
2353 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2354 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2355
2356 RT_NOREF(cParms);
2357
2358 int rc;
2359 if (!pCtx->fUseLegacyProtocol)
2360 {
2361 LogFunc(("Handling idMsg=%RU32 (%s)\n", idMsg, ShClHostMsgToStr(idMsg)));
2362 switch (idMsg)
2363 {
2364 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2365 {
2366 rc = vbglR3ClipboardFormatsReportRecv(pCtx, &pEvent->u.fReportedFormats);
2367 if (RT_SUCCESS(rc))
2368 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2369 break;
2370 }
2371
2372 case VBOX_SHCL_HOST_MSG_READ_DATA_CID:
2373 {
2374 rc = vbglR3ClipboardFetchReadDataCid(pCtx, &pEvent->u.fReadData);
2375 if (RT_SUCCESS(rc))
2376 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2377 break;
2378 }
2379
2380 case VBOX_SHCL_HOST_MSG_READ_DATA:
2381 {
2382 rc = vbglR3ClipboardFetchReadData(pCtx, &pEvent->u.fReadData);
2383 if (RT_SUCCESS(rc))
2384 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2385 break;
2386 }
2387
2388 case VBOX_SHCL_HOST_MSG_QUIT:
2389 {
2390 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2391 rc = VINF_SUCCESS;
2392 break;
2393 }
2394
2395 default:
2396 {
2397 /** @todo r=bird: BUGBUG - need a skip command here! */
2398 rc = VERR_NOT_SUPPORTED;
2399 break;
2400 }
2401 }
2402
2403 if (RT_SUCCESS(rc))
2404 {
2405 /* Copy over our command context to the event. */
2406 pEvent->cmdCtx = *pCtx;
2407 }
2408 else
2409 {
2410 /* Report error back to the host. */
2411 int rc2 = VbglR3ClipboardWriteError(pCtx->idClient, rc);
2412 AssertRC(rc2);
2413 }
2414 }
2415 else
2416 {
2417 /*
2418 * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
2419 * !HACK ALERT! cParms is the format flag or flags.
2420 */
2421 rc = VINF_SUCCESS;
2422 switch (idMsg)
2423 {
2424 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2425 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2426 pEvent->u.fReportedFormats = cParms;
2427 break;
2428
2429 case VBOX_SHCL_HOST_MSG_READ_DATA:
2430 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2431 pEvent->u.fReadData = cParms;
2432 break;
2433
2434 case VBOX_SHCL_HOST_MSG_QUIT:
2435 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2436 break;
2437
2438 default:
2439 AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
2440 rc = VERR_NOT_SUPPORTED;
2441 break;
2442 }
2443 pEvent->cmdCtx = *pCtx;
2444 }
2445
2446 LogFlowFuncLeaveRC(rc);
2447 return rc;
2448}
2449
2450/**
2451 * Frees (destroys) a formerly allocated Shared Clipboard event.
2452 *
2453 * @returns IPRT status code.
2454 * @param pEvent Event to free (destroy).
2455 */
2456VBGLR3DECL(void) VbglR3ClipboardEventFree(PVBGLR3CLIPBOARDEVENT pEvent)
2457{
2458 if (!pEvent)
2459 return;
2460
2461 /* Some messages require additional cleanup. */
2462 switch (pEvent->enmType)
2463 {
2464 default:
2465 break;
2466 }
2467
2468 RTMemFree(pEvent);
2469 pEvent = NULL;
2470}
2471
2472/**
2473 * Reports (advertises) guest clipboard formats to the host.
2474 *
2475 * Legacy function, do not use anymore.
2476 *
2477 * @returns VBox status code.
2478 * @param idClient The client id returned by VbglR3ClipboardConnect().
2479 * @param fFormats The formats to report.
2480 */
2481VBGLR3DECL(int) VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats)
2482{
2483 struct
2484 {
2485 VBGLIOCHGCMCALL Hdr;
2486 VBoxShClParmReportFormats Parms;
2487 } Msg;
2488
2489 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_REPORT_FORMATS, VBOX_SHCL_CPARMS_REPORT_FORMATS);
2490 VbglHGCMParmUInt32Set(&Msg.Parms.f32Formats, fFormats);
2491
2492 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2493
2494 LogFlowFuncLeaveRC(rc);
2495 return rc;
2496}
2497
2498/**
2499 * Sends guest clipboard data to the host.
2500 *
2501 * Legacy function kept for compatibility, do not use anymore.
2502 *
2503 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
2504 * from the host.
2505 *
2506 * @returns VBox status code.
2507 * @param idClient The client id returned by VbglR3ClipboardConnect().
2508 * @param fFormat The format of the data.
2509 * @param pvData Pointer to the data to send. Can be NULL if @a cbData
2510 * is zero.
2511 * @param cbData Number of bytes of data to send. Zero is valid.
2512 */
2513VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
2514{
2515 LogFlowFuncEnter();
2516
2517 struct
2518 {
2519 VBGLIOCHGCMCALL Hdr;
2520 VBoxShClParmDataWriteOld Parms;
2521 } Msg;
2522
2523 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE_OLD);
2524 VbglHGCMParmUInt32Set(&Msg.Parms.f32Format, fFormat);
2525 VbglHGCMParmPtrSet(&Msg.Parms.pData, pv, cb);
2526
2527 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2528
2529 LogFlowFuncLeaveRC(rc);
2530 return rc;
2531}
2532
2533/**
2534 * Sends guest clipboard data to the host.
2535 *
2536 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
2537 * from the host.
2538 *
2539 * @returns VBox status code.
2540 * @param pCtx The command context returned by VbglR3ClipboardConnectEx().
2541 * @param fFormat Clipboard format to send.
2542 * @param pvData Pointer to the data to send. Can be NULL if @a cbData
2543 * is zero.
2544 * @param cbData Number of bytes of data to send. Zero is valid.
2545 */
2546VBGLR3DECL(int) VbglR3ClipboardWriteDataEx(PVBGLR3SHCLCMDCTX pCtx, SHCLFORMAT fFormat, void *pvData, uint32_t cbData)
2547{
2548 LogFlowFunc(("ENTER: fFormat=%#x pvData=%p cbData=%#x\n", fFormat, pvData, cbData));
2549 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2550 if (cbData > 0)
2551 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
2552
2553 int rc;
2554 if (pCtx->fUseLegacyProtocol)
2555 rc = VbglR3ClipboardWriteData(pCtx->idClient, fFormat, pvData, cbData);
2556 else
2557 {
2558 struct
2559 {
2560 VBGLIOCHGCMCALL Hdr;
2561 VBoxShClParmDataWrite Parms;
2562 } Msg;
2563
2564 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE);
2565 Msg.Parms.id64Context.SetUInt64(pCtx->idContext);
2566 Msg.Parms.f32Format.SetUInt32(fFormat);
2567 Msg.Parms.pData.SetPtr(pvData, cbData);
2568
2569 LogFlowFunc(("CID=%RU32\n", pCtx->idContext));
2570
2571 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2572 }
2573
2574 LogFlowFuncLeaveRC(rc);
2575 return rc;
2576}
2577
2578/**
2579 * Writes an error to the host.
2580 *
2581 * @returns IPRT status code.
2582 * @param idClient The client id returned by VbglR3ClipboardConnect().
2583 * @param rcErr Error (IPRT-style) to send.
2584 */
2585VBGLR3DECL(int) VbglR3ClipboardWriteError(HGCMCLIENTID idClient, int rcErr)
2586{
2587 AssertReturn(idClient, VERR_INVALID_PARAMETER);
2588
2589 VBoxShClWriteErrorMsg Msg;
2590 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_ERROR, VBOX_SHCL_CPARMS_ERROR);
2591
2592 /** @todo Context ID not used yet. */
2593 Msg.uContext.SetUInt64(0);
2594 Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
2595
2596 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
2597
2598 if (RT_FAILURE(rc))
2599 LogFlowFunc(("Sending error %Rrc failed with rc=%Rrc\n", rcErr, rc));
2600 if (rc == VERR_NOT_SUPPORTED)
2601 rc = VINF_SUCCESS;
2602
2603 if (RT_FAILURE(rc))
2604 LogRel(("Shared Clipboard: Reporting error %Rrc to the host failed with %Rrc\n", rcErr, rc));
2605
2606 LogFlowFuncLeaveRC(rc);
2607 return rc;
2608}
2609
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