VirtualBox

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

最後變更 在這個檔案從100317是 100291,由 vboxsync 提交於 21 月 前

Shared Clipboard: Renaming (ShClTransferCtxTransferUnregister() -> ShClTransferCtxTransferUnregisterById()). bugref:9437

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

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