summaryrefslogtreecommitdiffstats
path: root/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp')
-rw-r--r--src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp2609
1 files changed, 2609 insertions, 0 deletions
diff --git a/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp b/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp
new file mode 100644
index 00000000..f44b923a
--- /dev/null
+++ b/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp
@@ -0,0 +1,2609 @@
+/* $Id: VBoxGuestR3LibClipboard.cpp $ */
+/** @file
+ * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, Shared Clipboard.
+ */
+
+/*
+ * Copyright (C) 2007-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <VBox/GuestHost/SharedClipboard.h>
+#include <VBox/GuestHost/clipboard-helper.h>
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+# include <VBox/GuestHost/SharedClipboard-transfers.h>
+#endif
+#include <VBox/HostServices/VBoxClipboardSvc.h>
+#include <VBox/err.h>
+#include <iprt/assert.h>
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+# include <iprt/dir.h>
+# include <iprt/file.h>
+# include <iprt/path.h>
+#endif
+#include <iprt/string.h>
+#include <iprt/cpp/ministring.h>
+
+#include "VBoxGuestR3LibInternal.h"
+
+
+/*
+ * Function naming convention:
+ *
+ * FunctionNameRecv = Receives a host message (request).
+ * FunctionNameReply = Replies to a host message (request).
+ * FunctionNameSend = Sends a guest message to the host.
+ */
+
+
+/*********************************************************************************************************************************
+* Prototypes *
+*********************************************************************************************************************************/
+
+
+/**
+ * Connects to the Shared Clipboard service, legacy version, do not use anymore.
+ *
+ * @returns VBox status code
+ * @param pidClient Where to put the client id on success. The client id
+ * must be passed to all the other clipboard calls.
+ */
+VBGLR3DECL(int) VbglR3ClipboardConnect(HGCMCLIENTID *pidClient)
+{
+ int rc = VbglR3HGCMConnect("VBoxSharedClipboard", pidClient);
+ if (RT_FAILURE(rc))
+ {
+ if (rc == VERR_HGCM_SERVICE_NOT_FOUND)
+ LogRel(("Shared Clipboard: Unabled to connect, as host service was not found, skipping\n"));
+ else
+ LogRel(("Shared Clipboard: Unabled to connect to host service, rc=%Rrc\n", rc));
+ }
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+
+/**
+ * Connects to the Shared Clipboard service, extended version.
+ *
+ * @returns VBox status code.
+ * @param pCtx Command context. This will be initialized by this
+ * call.
+ * @param fGuestFeatures The guest features supported by this client,
+ * VBOX_SHCL_GF_0_XXX.
+ */
+VBGLR3DECL(int) VbglR3ClipboardConnectEx(PVBGLR3SHCLCMDCTX pCtx, uint64_t fGuestFeatures)
+{
+ /*
+ * Intialize the context structure.
+ */
+ pCtx->idClient = 0;
+ pCtx->fGuestFeatures = fGuestFeatures;
+ pCtx->fHostFeatures = 0;
+ pCtx->fUseLegacyProtocol = true;
+ pCtx->cParmsRecived = 0;
+ pCtx->idContext = 0;
+
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+ /* Init callback table. */
+ RT_ZERO(pCtx->Transfers.Callbacks);
+ /* Indicate that this guest supports Shared Clipboard file transfers. */
+ pCtx->fGuestFeatures |= VBOX_SHCL_GF_0_TRANSFERS;
+# ifdef RT_OS_WINDOWS
+ /* Indicate that on Windows guest OSes we have our own IDataObject implementation which
+ * integrates nicely into the guest's Windows Explorer showing / handling the Shared Clipboard file transfers. */
+ pCtx->fGuestFeatures |= VBOX_SHCL_GF_0_TRANSFERS_FRONTEND;
+# endif
+ pCtx->Transfers.cbChunkSize = VBOX_SHCL_DEFAULT_CHUNK_SIZE; /** @todo Make this configurable. */
+ pCtx->Transfers.cbMaxChunkSize = VBOX_SHCL_MAX_CHUNK_SIZE; /** @todo Ditto. */
+#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
+
+ /*
+ * First step is connecting to the HGCM service.
+ */
+ int rc = VbglR3ClipboardConnect(&pCtx->idClient);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Next is reporting our features. If this fails, assume older host.
+ */
+ rc = VbglR3ClipboardReportFeatures(pCtx->idClient, pCtx->fGuestFeatures, &pCtx->fHostFeatures);
+ if (RT_SUCCESS(rc))
+ {
+ LogRel2(("Shared Clipboard: Guest features: %#RX64 - Host features: %#RX64\n",
+ pCtx->fGuestFeatures, pCtx->fHostFeatures));
+
+ if ( (pCtx->fHostFeatures & VBOX_SHCL_HF_0_CONTEXT_ID)
+ && (pCtx->fGuestFeatures & VBOX_SHCL_GF_0_CONTEXT_ID) )
+ {
+ pCtx->fUseLegacyProtocol = false;
+
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+ if ( (pCtx->fHostFeatures & VBOX_SHCL_HF_0_TRANSFERS)
+ && (pCtx->fGuestFeatures & VBOX_SHCL_GF_0_TRANSFERS) )
+ {
+ VBoxShClParmNegotiateChunkSize MsgChunkSize;
+ do
+ {
+ VBGL_HGCM_HDR_INIT(&MsgChunkSize.hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_NEGOTIATE_CHUNK_SIZE,
+ VBOX_SHCL_CPARMS_NEGOTIATE_CHUNK_SIZE);
+ MsgChunkSize.cb32MaxChunkSize.SetUInt32(pCtx->Transfers.cbMaxChunkSize);
+ MsgChunkSize.cb32ChunkSize.SetUInt32(0); /* If set to 0, let the host choose. */
+ rc = VbglR3HGCMCall(&MsgChunkSize.hdr, sizeof(MsgChunkSize));
+ } while (rc == VERR_INTERRUPTED);
+ if (RT_SUCCESS(rc))
+ {
+ Assert(MsgChunkSize.cb32ChunkSize.type == VMMDevHGCMParmType_32bit);
+ pCtx->Transfers.cbChunkSize = RT_MIN(MsgChunkSize.cb32ChunkSize.u.value32, pCtx->Transfers.cbChunkSize);
+ Assert(MsgChunkSize.cb32MaxChunkSize.type == VMMDevHGCMParmType_32bit);
+ pCtx->Transfers.cbMaxChunkSize = RT_MIN(MsgChunkSize.cb32MaxChunkSize.u.value32, pCtx->Transfers.cbMaxChunkSize);
+
+ LogRel2(("Shared Clipboard: Using chunk size %RU32 (maximum is %RU32)\n",
+ pCtx->Transfers.cbChunkSize, pCtx->Transfers.cbMaxChunkSize));
+ }
+ }
+ else
+ {
+ if (!(pCtx->fHostFeatures & VBOX_SHCL_HF_0_TRANSFERS))
+ LogRel2(("Shared Clipboard: Host does not support transfers\n"));
+ }
+#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
+ }
+ else
+ {
+ if (!(pCtx->fHostFeatures & VBOX_SHCL_HF_0_CONTEXT_ID))
+ LogRel(("Shared Clipboard: Host does not support context IDs, using legacy protocol\n"));
+
+ pCtx->fUseLegacyProtocol = true;
+ }
+ }
+ else
+ {
+ AssertLogRelMsg(rc == VERR_NOT_SUPPORTED || rc == VERR_NOT_IMPLEMENTED,
+ ("Reporting features failed: %Rrc\n", rc));
+ pCtx->fUseLegacyProtocol = true;
+ }
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+
+/**
+ * Reports features to the host and retrieve host feature set.
+ *
+ * @returns VBox status code.
+ * @param idClient The client ID returned by VbglR3ClipboardConnect().
+ * @param fGuestFeatures Features to report, VBOX_SHCL_GF_XXX.
+ * @param pfHostFeatures Where to store the features VBOX_SHCL_HF_XXX.
+ */
+VBGLR3DECL(int) VbglR3ClipboardReportFeatures(uint32_t idClient, uint64_t fGuestFeatures, uint64_t *pfHostFeatures)
+{
+ int rc;
+ do
+ {
+ struct
+ {
+ VBGLIOCHGCMCALL Hdr;
+ HGCMFunctionParameter f64Features0;
+ HGCMFunctionParameter f64Features1;
+ } Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_REPORT_FEATURES, 2);
+ VbglHGCMParmUInt64Set(&Msg.f64Features0, fGuestFeatures);
+ VbglHGCMParmUInt64Set(&Msg.f64Features1, VBOX_SHCL_GF_1_MUST_BE_ONE);
+
+ rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ Assert(Msg.f64Features0.type == VMMDevHGCMParmType_64bit);
+ Assert(Msg.f64Features1.type == VMMDevHGCMParmType_64bit);
+ if (Msg.f64Features1.u.value64 & VBOX_SHCL_GF_1_MUST_BE_ONE)
+ rc = VERR_NOT_SUPPORTED;
+ else if (pfHostFeatures)
+ *pfHostFeatures = Msg.f64Features0.u.value64;
+ break;
+ }
+ } while (rc == VERR_INTERRUPTED);
+ return rc;
+
+}
+
+
+/**
+ * Disconnects from the Shared Clipboard service, legacy version, do not use anymore.
+ *
+ * @returns VBox status code.
+ * @param idClient The client id returned by VbglR3ClipboardConnect().
+ */
+VBGLR3DECL(int) VbglR3ClipboardDisconnect(HGCMCLIENTID idClient)
+{
+ return VbglR3HGCMDisconnect(idClient);
+}
+
+
+/**
+ * Disconnects from the Shared Clipboard service, extended version.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ */
+VBGLR3DECL(int) VbglR3ClipboardDisconnectEx(PVBGLR3SHCLCMDCTX pCtx)
+{
+ int rc = VbglR3ClipboardDisconnect(pCtx->idClient);
+ if (RT_SUCCESS(rc))
+ {
+ pCtx->idClient = 0;
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+
+/**
+ * Receives reported formats from the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the
+ * connection.
+ * @param pfFormats Where to store the received formats from the host.
+ */
+static int vbglR3ClipboardFormatsReportRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMATS pfFormats)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pfFormats, VERR_INVALID_POINTER);
+
+ *pfFormats = 0;
+
+ struct
+ {
+ VBGLIOCHGCMCALL Hdr;
+ HGCMFunctionParameter id64Context;
+ HGCMFunctionParameter f32Formats;
+ } Msg;
+
+ VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_GET, 2);
+ Msg.id64Context.SetUInt32(VBOX_SHCL_HOST_MSG_FORMATS_REPORT);
+ Msg.f32Formats.SetUInt32(0);
+
+ int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.f32Formats.GetUInt32(pfFormats);
+ AssertRC(rc);
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+
+/**
+ * Fetches a VBOX_SHCL_HOST_MSG_READ_DATA_CID message.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param pfFormat Where to return the requested format.
+ */
+static int vbglR3ClipboardFetchReadDataCid(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMAT pfFormat)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pfFormat, VERR_INVALID_POINTER);
+
+ struct
+ {
+ VBGLIOCHGCMCALL Hdr;
+ HGCMFunctionParameter id64Context;
+ HGCMFunctionParameter f32Format;
+ } Msg;
+
+ VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_GET, 2);
+ Msg.id64Context.SetUInt64(VBOX_SHCL_HOST_MSG_READ_DATA_CID);
+ Msg.f32Format.SetUInt32(0);
+
+ int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.id64Context.GetUInt64(&pCtx->idContext);
+ AssertRC(rc);
+ int rc2 = Msg.f32Format.GetUInt32(pfFormat);
+ AssertRCStmt(rc2, rc = rc2);
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+
+/**
+ * Fetches a VBOX_SHCL_HOST_MSG_READ_DATA message.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param pfFormat Where to return the requested format.
+ */
+static int vbglR3ClipboardFetchReadData(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMAT pfFormat)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pfFormat, VERR_INVALID_POINTER);
+
+ struct
+ {
+ VBGLIOCHGCMCALL Hdr;
+ HGCMFunctionParameter id32Msg;
+ HGCMFunctionParameter f32Format;
+ } Msg;
+
+ VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_GET, 2);
+ Msg.id32Msg.SetUInt32(VBOX_SHCL_HOST_MSG_READ_DATA);
+ Msg.f32Format.SetUInt32(0);
+
+ int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.f32Format.GetUInt32(pfFormat);
+ AssertRC(rc);
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+
+/**
+ * Get a host message, legacy version (which does not have VBOX_SHCL_GUEST_FN_MSG_GET). Do not use anymore.
+ *
+ * Note: This is the old message which still is being used for the non-URI Shared Clipboard transfers,
+ * to not break compatibility with older additions / VBox versions.
+ *
+ * This will block until a message becomes available.
+ *
+ * @returns VBox status code.
+ * @param idClient The client id returned by VbglR3ClipboardConnect().
+ * @param pidMsg Where to store the message id.
+ * @param pfFormats Where to store the format(s) the message applies to.
+ */
+VBGLR3DECL(int) VbglR3ClipboardGetHostMsgOld(HGCMCLIENTID idClient, uint32_t *pidMsg, uint32_t *pfFormats)
+{
+ VBoxShClGetHostMsgOld Msg;
+
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, VBOX_SHCL_CPARMS_GET_HOST_MSG_OLD);
+ VbglHGCMParmUInt32Set(&Msg.msg, 0);
+ VbglHGCMParmUInt32Set(&Msg.formats, 0);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = VbglHGCMParmUInt32Get(&Msg.msg, pidMsg);
+ if (RT_SUCCESS(rc))
+ {
+ rc2 = VbglHGCMParmUInt32Get(&Msg.formats, pfFormats);
+ if (RT_SUCCESS(rc2))
+ return rc;
+ }
+ rc = rc2;
+ }
+ *pidMsg = UINT32_MAX - 1;
+ *pfFormats = UINT32_MAX;
+ return rc;
+}
+
+
+/**
+ * Reads data from the host clipboard.
+ *
+ * Legacy function, do not use anymore.
+ *
+ * @returns VBox status code.
+ * @retval VINF_BUFFER_OVERFLOW If there is more data available than the caller provided buffer space for.
+ *
+ * @param idClient The client id returned by VbglR3ClipboardConnect().
+ * @param fFormat The format we're requesting the data in.
+ * @param pvData Where to store the data.
+ * @param cbData The size of the buffer pointed to by \a pvData.
+ * @param pcbRead The actual size of the host clipboard data. May be larger than \a cbData.
+ */
+VBGLR3DECL(int) VbglR3ClipboardReadData(HGCMCLIENTID idClient, uint32_t fFormat, void *pvData, uint32_t cbData,
+ uint32_t *pcbRead)
+{
+ LogFlowFuncEnter();
+
+ struct
+ {
+ VBGLIOCHGCMCALL Hdr;
+ VBoxShClParmDataRead Parms;
+ } Msg;
+
+ VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_DATA_READ, VBOX_SHCL_CPARMS_DATA_READ);
+ VbglHGCMParmUInt32Set(&Msg.Parms.f32Format, fFormat);
+ VbglHGCMParmPtrSet( &Msg.Parms.pData, pvData, cbData);
+ VbglHGCMParmUInt32Set(&Msg.Parms.cb32Needed, 0);
+
+ int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t cbRead;
+ rc = VbglHGCMParmUInt32Get(&Msg.Parms.cb32Needed, &cbRead);
+ if (RT_SUCCESS(rc))
+ {
+ LogFlowFunc(("cbRead=%RU32\n", cbRead));
+
+ if (cbRead > cbData)
+ rc = VINF_BUFFER_OVERFLOW;
+
+ *pcbRead = cbRead;
+ }
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+
+/**
+ * Reads clipboard data from the host clipboard.
+ *
+ * @returns VBox status code.
+ * @retval VINF_BUFFER_OVERFLOW If there is more data available than the caller provided buffer space for.
+ *
+ * @param pCtx The command context returned by VbglR3ClipboardConnectEx().
+ * @param uFormat Clipboard format of clipboard data to be read.
+ * @param pvData Buffer where to store the read data.
+ * @param cbData Size (in bytes) of data buffer where to store the read data.
+ * @param pcbRead The actual size of the host clipboard data.
+ */
+VBGLR3DECL(int) VbglR3ClipboardReadDataEx(PVBGLR3SHCLCMDCTX pCtx,
+ SHCLFORMAT uFormat, void *pvData, uint32_t cbData, uint32_t *pcbRead)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pvData, VERR_INVALID_POINTER);
+ return VbglR3ClipboardReadData(pCtx->idClient, uFormat, pvData, cbData, pcbRead);
+}
+
+
+/**
+ * Query the host features.
+ *
+ * @returns VBox status code.
+ * @param idClient The client ID returned by VbglR3ClipboardConnect().
+ * @param pfHostFeatures Where to store the host feature, VBOX_SHCL_HF_XXX.
+ */
+VBGLR3DECL(int) VbglR3ClipboardQueryFeatures(uint32_t idClient, uint64_t *pfHostFeatures)
+{
+ int rc;
+ do
+ {
+ struct
+ {
+ VBGLIOCHGCMCALL Hdr;
+ HGCMFunctionParameter f64Features0;
+ HGCMFunctionParameter f64Features1;
+ } Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_QUERY_FEATURES, 2);
+ VbglHGCMParmUInt64Set(&Msg.f64Features0, 0);
+ VbglHGCMParmUInt64Set(&Msg.f64Features1, RT_BIT_64(63));
+
+ rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ Assert(Msg.f64Features0.type == VMMDevHGCMParmType_64bit);
+ Assert(Msg.f64Features1.type == VMMDevHGCMParmType_64bit);
+ if (Msg.f64Features1.u.value64 & RT_BIT_64(63))
+ rc = VERR_NOT_SUPPORTED;
+ else if (pfHostFeatures)
+ *pfHostFeatures = Msg.f64Features0.u.value64;
+ break;
+ }
+ } while (rc == VERR_INTERRUPTED);
+ return rc;
+
+}
+
+/**
+ * Peeks at the next host message, waiting for one to turn up.
+ *
+ * This glosses over the difference between new (6.1) and old (1.3.2) host
+ * service versions, however it does so by abusing @a pcParameters, so don't use
+ * it directly when in legacy mode, always pass it on to
+ * VbglR3ClipboardEventGetNext() or VbglR3ClipboardEventGetNextEx().
+ *
+ * @returns VBox status code.
+ * @retval VERR_INTERRUPTED if interrupted. Does the necessary cleanup, so
+ * caller just have to repeat this call.
+ * @retval VERR_VM_RESTORED if the VM has been restored (idRestoreCheck).
+ *
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param pidMsg Where to store the message id.
+ * @param pcParameters Where to store the number of parameters which will
+ * be received in a second call to the host.
+ * @param pidRestoreCheck Pointer to the VbglR3GetSessionId() variable to use
+ * for the VM restore check. Optional.
+ *
+ * @note Restore check is only performed optimally with a 6.0 host.
+ */
+VBGLR3DECL(int) VbglR3ClipboardMsgPeekWait(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pidMsg,
+ uint32_t *pcParameters, uint64_t *pidRestoreCheck)
+{
+ AssertPtrReturn(pidMsg, VERR_INVALID_POINTER);
+ AssertPtrReturn(pcParameters, VERR_INVALID_POINTER);
+
+ struct
+ {
+ VBGLIOCHGCMCALL Hdr;
+ HGCMFunctionParameter idMsg; /* Doubles as restore check on input. */
+ HGCMFunctionParameter cParameters;
+ } Msg;
+ int rc;
+ if (!pCtx->fUseLegacyProtocol)
+ {
+ VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT, 2);
+ VbglHGCMParmUInt64Set(&Msg.idMsg, pidRestoreCheck ? *pidRestoreCheck : 0);
+ VbglHGCMParmUInt32Set(&Msg.cParameters, 0);
+ rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
+ LogFlowFunc(("VbglR3HGCMCall -> %Rrc\n", rc));
+ if (RT_SUCCESS(rc))
+ {
+ AssertMsgReturn( Msg.idMsg.type == VMMDevHGCMParmType_64bit
+ && Msg.cParameters.type == VMMDevHGCMParmType_32bit,
+ ("msg.type=%d num_parms.type=%d\n", Msg.idMsg.type, Msg.cParameters.type),
+ VERR_INTERNAL_ERROR_3);
+
+ *pidMsg = (uint32_t)Msg.idMsg.u.value64;
+ *pcParameters = Msg.cParameters.u.value32;
+ return rc;
+ }
+
+ /*
+ * If restored, update pidRestoreCheck.
+ */
+ if (rc == VERR_VM_RESTORED && pidRestoreCheck)
+ *pidRestoreCheck = Msg.idMsg.u.value64;
+ }
+ else
+ {
+ /*
+ * We do some crude stuff here by putting the 2nd parameter (foramts) in the parameter count,
+ * however it's supposed to be passed directly to VbglR3ClipboardEventGetNext or
+ * VbglR3ClipboardEventGetNextEx, so that's fine...
+ */
+ rc = VbglR3ClipboardGetHostMsgOld(pCtx->idClient, pidMsg, pcParameters);
+ if (RT_SUCCESS(rc))
+ return rc;
+ }
+
+ /*
+ * If interrupted we must cancel the call so it doesn't prevent us from making another one.
+ */
+ if (rc == VERR_INTERRUPTED)
+ {
+ VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_CANCEL, 0);
+ int rc2 = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg.Hdr));
+ AssertRC(rc2);
+ }
+
+ *pidMsg = UINT32_MAX - 1;
+ *pcParameters = UINT32_MAX - 2;
+ return rc;
+}
+
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+
+/**
+ * Reads a root list header from the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param pRootListHdr Where to store the received root list header.
+ */
+static int vbglR3ClipboardRootListHdrRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLISTHDR pRootListHdr)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pRootListHdr, VERR_INVALID_POINTER);
+
+ VBoxShClRootListHdrMsg Msg;
+
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ);
+
+ Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
+ Msg.ReqParms.fRoots.SetUInt32(0);
+
+ Msg.cRoots.SetUInt32(0);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.ReqParms.fRoots.GetUInt32(&pRootListHdr->fRoots); AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.cRoots.GetUInt32(&pRootListHdr->cRoots);
+ AssertRC(rc);
+ }
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Reads a root list entry from the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param uIndex Index of root list entry to read.
+ * @param pRootListEntry Where to store the root list entry read from the host.
+ */
+static int vbglR3ClipboardRootListEntryRead(PVBGLR3SHCLCMDCTX pCtx, uint32_t uIndex, PSHCLROOTLISTENTRY pRootListEntry)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pRootListEntry, VERR_INVALID_POINTER);
+
+ VBoxShClRootListEntryMsg Msg;
+
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ);
+
+ Msg.Parms.uContext.SetUInt64(pCtx->idContext);
+ Msg.Parms.fInfo.SetUInt32(pRootListEntry->fInfo);
+ Msg.Parms.uIndex.SetUInt32(uIndex);
+
+ Msg.szName.SetPtr(pRootListEntry->pszName, pRootListEntry->cbName);
+ Msg.cbInfo.SetUInt32(pRootListEntry->cbInfo);
+ Msg.pvInfo.SetPtr(pRootListEntry->pvInfo, pRootListEntry->cbInfo);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.Parms.fInfo.GetUInt32(&pRootListEntry->fInfo); AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t cbInfo = 0;
+ rc = Msg.cbInfo.GetUInt32(&cbInfo); AssertRC(rc);
+ if (pRootListEntry->cbInfo != cbInfo)
+ rc = VERR_INVALID_PARAMETER;
+ }
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Reads the root list from the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param ppRootList Where to store the (allocated) root list. Must be free'd by the caller with
+ * SharedClipboardTransferRootListFree().
+ */
+VBGLR3DECL(int) VbglR3ClipboardRootListRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLIST *ppRootList)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(ppRootList, VERR_INVALID_POINTER);
+
+ int rc;
+
+ PSHCLROOTLIST pRootList = ShClTransferRootListAlloc();
+ if (pRootList)
+ {
+ SHCLROOTLISTHDR srcRootListHdr;
+ rc = vbglR3ClipboardRootListHdrRead(pCtx, &srcRootListHdr);
+ if (RT_SUCCESS(rc))
+ {
+ pRootList->Hdr.cRoots = srcRootListHdr.cRoots;
+ pRootList->Hdr.fRoots = 0; /** @todo Implement this. */
+
+ if (srcRootListHdr.cRoots)
+ {
+ pRootList->paEntries =
+ (PSHCLROOTLISTENTRY)RTMemAllocZ(srcRootListHdr.cRoots * sizeof(SHCLROOTLISTENTRY));
+ if (pRootList->paEntries)
+ {
+ for (uint32_t i = 0; i < srcRootListHdr.cRoots; i++)
+ {
+ SHCLROOTLISTENTRY *pEntry = &pRootList->paEntries[i];
+ AssertPtr(pEntry);
+
+ rc = ShClTransferRootListEntryInit(pEntry);
+ if (RT_SUCCESS(rc))
+ rc = vbglR3ClipboardRootListEntryRead(pCtx, i, pEntry);
+
+ if (RT_FAILURE(rc))
+ break;
+ }
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ *ppRootList = pRootList;
+ }
+ else
+ ShClTransferRootListFree(pRootList);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Receives a transfer status from the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param pEnmDir Where to store the transfer direction for the reported transfer.
+ * @param pReport Where to store the transfer (status) report.
+ */
+VBGLR3DECL(int) VbglR3ClipboarTransferStatusRecv(PVBGLR3SHCLCMDCTX pCtx,
+ PSHCLTRANSFERDIR pEnmDir, PSHCLTRANSFERREPORT pReport)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pReport, VERR_INVALID_POINTER);
+ AssertPtrReturn(pEnmDir, VERR_INVALID_POINTER);
+
+ VBoxShClTransferStatusMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_TRANSFER_STATUS);
+
+ Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_STATUS);
+ Msg.enmDir.SetUInt32(0);
+ Msg.enmStatus.SetUInt32(0);
+ Msg.rc.SetUInt32(0);
+ Msg.fFlags.SetUInt32(0);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.enmDir.GetUInt32((uint32_t *)pEnmDir);
+ AssertRC(rc);
+ }
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.enmStatus.GetUInt32(&pReport->uStatus);
+ AssertRC(rc);
+ }
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.rc.GetUInt32((uint32_t *)&pReport->rc);
+ AssertRC(rc);
+ }
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.fFlags.GetUInt32(&pReport->fFlags);
+ AssertRC(rc);
+ }
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Replies to a transfer report from the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param pTransfer Transfer of report to reply to.
+ * @param uStatus Tranfer status to reply.
+ * @param rcTransfer Result code (rc) to reply.
+ */
+VBGLR3DECL(int) VbglR3ClipboardTransferStatusReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFER pTransfer,
+ SHCLTRANSFERSTATUS uStatus, int rcTransfer)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
+
+ RT_NOREF(pTransfer);
+
+ VBoxShClReplyMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
+
+ Msg.uContext.SetUInt64(pCtx->idContext);
+ Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS);
+ Msg.rc.SetUInt32((uint32_t )rcTransfer); /* int vs. uint32_t */
+ Msg.pvPayload.SetPtr(NULL, 0);
+
+ Msg.u.TransferStatus.enmStatus.SetUInt32((uint32_t)uStatus);
+
+ LogFlowFunc(("%s\n", ShClTransferStatusToStr(uStatus)));
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Receives a host request to read a root list header from the guest.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param pfRoots Where to store the root list header flags to use, requested by the host.
+ */
+VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReq(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pfRoots)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pfRoots, VERR_INVALID_POINTER);
+
+ VBoxShClRootListReadReqMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ_REQ);
+
+ Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ);
+ Msg.ReqParms.fRoots.SetUInt32(0);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.ReqParms.fRoots.GetUInt32(pfRoots);
+ AssertRC(rc);
+ }
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Replies to a root list header request.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param pRootListHdr Root lsit header to reply to the host.
+ */
+VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLISTHDR pRootListHdr)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pRootListHdr, VERR_INVALID_POINTER);
+
+ VBoxShClRootListHdrMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_WRITE);
+
+ Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
+ Msg.ReqParms.fRoots.SetUInt32(pRootListHdr->fRoots);
+
+ Msg.cRoots.SetUInt32(pRootListHdr->cRoots);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Receives a host request to read a root list entry from the guest.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param puIndex Where to return the index of the root list entry the host wants to read.
+ * @param pfInfo Where to return the read flags the host wants to use.
+ */
+VBGLR3DECL(int) VbglR3ClipboardRootListEntryReadReq(PVBGLR3SHCLCMDCTX pCtx, uint32_t *puIndex, uint32_t *pfInfo)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(puIndex, VERR_INVALID_POINTER);
+ AssertPtrReturn(pfInfo, VERR_INVALID_POINTER);
+
+ VBoxShClRootListEntryReadReqMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ);
+
+ Msg.Parms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ);
+ Msg.Parms.fInfo.SetUInt32(0);
+ Msg.Parms.uIndex.SetUInt32(0);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.Parms.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.Parms.fInfo.GetUInt32(pfInfo);
+ AssertRC(rc);
+ }
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.Parms.uIndex.GetUInt32(puIndex);
+ AssertRC(rc);
+ }
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Replies to a root list entry read request from the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param uIndex Index of root list entry to reply.
+ * @param pEntry Actual root list entry to reply.
+ */
+VBGLR3DECL(int) VbglR3ClipboardRootListEntryReadReply(PVBGLR3SHCLCMDCTX pCtx, uint32_t uIndex, PSHCLROOTLISTENTRY pEntry)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pEntry, VERR_INVALID_POINTER);
+
+ VBoxShClRootListEntryMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_WRITE);
+
+ Msg.Parms.uContext.SetUInt64(pCtx->idContext);
+ Msg.Parms.fInfo.SetUInt32(0);
+ Msg.Parms.uIndex.SetUInt32(uIndex);
+
+ Msg.szName.SetPtr(pEntry->pszName, pEntry->cbName);
+ Msg.cbInfo.SetUInt32(pEntry->cbInfo);
+ Msg.pvInfo.SetPtr(pEntry->pvInfo, pEntry->cbInfo);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Sends a request to open a list handle to the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param pOpenParms List open parameters to use for the open request.
+ * @param phList Where to return the list handle received from the host.
+ */
+VBGLR3DECL(int) VbglR3ClipboardListOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
+ PSHCLLISTHANDLE phList)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
+ AssertPtrReturn(phList, VERR_INVALID_POINTER);
+
+ VBoxShClListOpenMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_LIST_OPEN, VBOX_SHCL_CPARMS_LIST_OPEN);
+
+ Msg.uContext.SetUInt64(pCtx->idContext);
+ Msg.fList.SetUInt32(0);
+ Msg.pvFilter.SetPtr(pOpenParms->pszFilter, pOpenParms->cbFilter);
+ Msg.pvPath.SetPtr(pOpenParms->pszPath, pOpenParms->cbPath);
+ Msg.uHandle.SetUInt64(0);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.uHandle.GetUInt64(phList); AssertRC(rc);
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Receives a host request to open a list handle on the guest.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param pOpenParms Where to store the open parameters the host wants to use for opening the list handle.
+ */
+VBGLR3DECL(int) VbglR3ClipboardListOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
+
+ VBoxShClListOpenMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_OPEN);
+
+ Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN);
+ Msg.fList.SetUInt32(0);
+ Msg.pvPath.SetPtr(pOpenParms->pszPath, pOpenParms->cbPath);
+ Msg.pvFilter.SetPtr(pOpenParms->pszFilter, pOpenParms->cbFilter);
+ Msg.uHandle.SetUInt64(0);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.uContext.GetUInt64(&pCtx->idContext);
+ if (RT_SUCCESS(rc))
+ rc = Msg.fList.GetUInt32(&pOpenParms->fList);
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Replies to a list open request from the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param rcReply Return code to reply to the host.
+ * @param hList List handle of (guest) list to reply to the host.
+ */
+VBGLR3DECL(int) VbglR3ClipboardListOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ VBoxShClReplyMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
+
+ Msg.uContext.SetUInt64(pCtx->idContext);
+ Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN);
+ Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
+ Msg.pvPayload.SetPtr(NULL, 0);
+
+ Msg.u.ListOpen.uHandle.SetUInt64(hList);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Receives a host request to close a list handle on the guest.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param phList Where to store the list handle to close, received from the host.
+ */
+VBGLR3DECL(int) VbglR3ClipboardListCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(phList, VERR_INVALID_POINTER);
+
+ VBoxShClListCloseMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_CLOSE);
+
+ Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE);
+ Msg.uHandle.SetUInt64(0);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.uContext.GetUInt64(&pCtx->idContext);
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.uHandle.GetUInt64(phList);
+ AssertRC(rc);
+ }
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Replies to a list handle close request from the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param rcReply Return code to reply to the host.
+ * @param hList List handle the send the close reply for.
+ */
+VBGLR3DECL(int) VbglR3ClipboardListCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ VBoxShClReplyMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
+
+ Msg.uContext.SetUInt64(pCtx->idContext);
+ Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_LIST_CLOSE);
+ Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
+ Msg.pvPayload.SetPtr(NULL, 0);
+
+ Msg.u.ListOpen.uHandle.SetUInt64(hList);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Sends a request to close a list handle to the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param hList List handle to request for closing on the host.
+ */
+VBGLR3DECL(int) VbglR3ClipboardListCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ VBoxShClListCloseMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_LIST_CLOSE, VBOX_SHCL_CPARMS_LIST_CLOSE);
+
+ Msg.uContext.SetUInt64(pCtx->idContext);
+ Msg.uHandle.SetUInt64(hList);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Sends a request to read a list header to the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param hList List handle to read list header for.
+ * @param fFlags List header read flags to use.
+ * @param pListHdr Where to return the list header received from the host.
+ */
+VBGLR3DECL(int) VbglR3ClipboardListHdrRead(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList, uint32_t fFlags,
+ PSHCLLISTHDR pListHdr)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
+
+ VBoxShClListHdrMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_LIST_HDR_READ, VBOX_SHCL_CPARMS_LIST_HDR);
+
+ Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
+ Msg.ReqParms.uHandle.SetUInt64(hList);
+ Msg.ReqParms.fFlags.SetUInt32(fFlags);
+
+ Msg.fFeatures.SetUInt32(0);
+ Msg.cbTotalSize.SetUInt32(0);
+ Msg.cTotalObjects.SetUInt64(0);
+ Msg.cbTotalSize.SetUInt64(0);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.fFeatures.GetUInt32(&pListHdr->fFeatures);
+ if (RT_SUCCESS(rc))
+ rc = Msg.cTotalObjects.GetUInt64(&pListHdr->cTotalObjects);
+ if (RT_SUCCESS(rc))
+ rc = Msg.cbTotalSize.GetUInt64(&pListHdr->cbTotalSize);
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Receives a host request to read a list header on the guest.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param phList Where to return the list handle to read list header for.
+ * @param pfFlags Where to return the List header read flags to use.
+ */
+VBGLR3DECL(int) VbglR3ClipboardListHdrReadRecvReq(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList, uint32_t *pfFlags)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(phList, VERR_INVALID_POINTER);
+ AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
+
+ VBoxShClListHdrReadReqMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_HDR_READ_REQ);
+
+ Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ);
+ Msg.ReqParms.uHandle.SetUInt64(0);
+ Msg.ReqParms.fFlags.SetUInt32(0);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
+ if (RT_SUCCESS(rc))
+ rc = Msg.ReqParms.uHandle.GetUInt64(phList);
+ if (RT_SUCCESS(rc))
+ rc = Msg.ReqParms.fFlags.GetUInt32(pfFlags);
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Sends (writes) a list header to the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param hList List handle to write list header for.
+ * @param pListHdr List header to write.
+ */
+VBGLR3DECL(int) VbglR3ClipboardListHdrWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
+ PSHCLLISTHDR pListHdr)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
+
+ VBoxShClListHdrMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE, VBOX_SHCL_CPARMS_LIST_HDR);
+
+ Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
+ Msg.ReqParms.uHandle.SetUInt64(hList);
+ Msg.ReqParms.fFlags.SetUInt32(0);
+
+ Msg.fFeatures.SetUInt32(0);
+ Msg.cbTotalSize.SetUInt32(pListHdr->fFeatures);
+ Msg.cTotalObjects.SetUInt64(pListHdr->cTotalObjects);
+ Msg.cbTotalSize.SetUInt64(pListHdr->cbTotalSize);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Sends a request to read a list entry from the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param hList List handle to request to read a list entry for.
+ * @param pListEntry Where to return the list entry read from the host.
+ */
+VBGLR3DECL(int) VbglR3ClipboardListEntryRead(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
+ PSHCLLISTENTRY pListEntry)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
+
+ VBoxShClListEntryMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ, VBOX_SHCL_CPARMS_LIST_ENTRY);
+
+ Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
+ Msg.ReqParms.uHandle.SetUInt64(hList);
+ Msg.ReqParms.fInfo.SetUInt32(0);
+
+ Msg.szName.SetPtr(pListEntry->pszName, pListEntry->cbName);
+ Msg.cbInfo.SetUInt32(pListEntry->cbInfo);
+ Msg.pvInfo.SetPtr(pListEntry->pvInfo, pListEntry->cbInfo);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.cbInfo.GetUInt32(&pListEntry->cbInfo); AssertRC(rc);
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Receives a host request to read a list entry from the guest.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param phList Where to return the list handle to read a list entry for.
+ * @param pfInfo Where to return the list read flags.
+ */
+VBGLR3DECL(int) VbglR3ClipboardListEntryReadRecvReq(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList, uint32_t *pfInfo)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(phList, VERR_INVALID_POINTER);
+ AssertPtrReturn(pfInfo, VERR_INVALID_POINTER);
+
+ VBoxShClListEntryReadReqMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_ENTRY_READ);
+
+ Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ);
+ Msg.ReqParms.uHandle.SetUInt64(0);
+ Msg.ReqParms.fInfo.SetUInt32(0);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.ReqParms.uHandle.GetUInt64(phList);
+ AssertRC(rc);
+ }
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.ReqParms.fInfo.GetUInt32(pfInfo);
+ AssertRC(rc);
+ }
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Sends (writes) a list entry to the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param hList List handle to write a list etnry for.
+ * @param pListEntry List entry to write.
+ */
+VBGLR3DECL(int) VbglR3ClipboardListEntryWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
+ PSHCLLISTENTRY pListEntry)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
+
+ VBoxShClListEntryMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE, VBOX_SHCL_CPARMS_LIST_ENTRY);
+
+ Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
+ Msg.ReqParms.uHandle.SetUInt64(hList);
+ Msg.ReqParms.fInfo.SetUInt32(pListEntry->fInfo);
+
+ Msg.szName.SetPtr(pListEntry->pszName, pListEntry->cbName);
+ Msg.cbInfo.SetUInt32(pListEntry->cbInfo);
+ Msg.pvInfo.SetPtr(pListEntry->pvInfo, pListEntry->cbInfo);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Receives a host request to open an object on the guest.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param pCreateParms Where to store the object open/create parameters received from the host.
+ */
+VBGLR3DECL(int) VbglR3ClipboardObjOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCreateParms, VERR_INVALID_POINTER);
+
+ VBoxShClObjOpenMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_OPEN);
+
+ Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN);
+ Msg.uHandle.SetUInt64(0);
+ Msg.szPath.SetPtr(pCreateParms->pszPath, pCreateParms->cbPath);
+ Msg.fCreate.SetUInt32(0);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.uContext.GetUInt64(&pCtx->idContext);
+ if (RT_SUCCESS(rc))
+ rc = Msg.fCreate.GetUInt32(&pCreateParms->fCreate);
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Replies a host request to open an object.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param rcReply Return code to reply to the host.
+ * @param hObj Object handle of opened object to reply to the host.
+ */
+VBGLR3DECL(int) VbglR3ClipboardObjOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ VBoxShClReplyMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
+
+ Msg.uContext.SetUInt64(pCtx->idContext);
+ Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN);
+ Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
+ Msg.pvPayload.SetPtr(NULL, 0);
+
+ Msg.u.ObjOpen.uHandle.SetUInt64(hObj);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Sends an object open request to the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param pCreateParms Object open/create parameters to use for opening the object on the host.
+ * @param phObj Where to return the object handle from the host.
+ */
+VBGLR3DECL(int) VbglR3ClipboardObjOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms,
+ PSHCLOBJHANDLE phObj)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCreateParms, VERR_INVALID_POINTER);
+ AssertPtrReturn(phObj, VERR_INVALID_POINTER);
+
+ VBoxShClObjOpenMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_OBJ_OPEN, VBOX_SHCL_CPARMS_OBJ_OPEN);
+
+ Msg.uContext.SetUInt64(pCtx->idContext);
+ Msg.uHandle.SetUInt64(0);
+ Msg.szPath.SetPtr((void *)pCreateParms->pszPath, pCreateParms->cbPath);
+ Msg.fCreate.SetUInt32(pCreateParms->fCreate);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ Msg.uHandle.GetUInt64(phObj);
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Receives a host request to close an object on the guest.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param phObj Where to return the object handle to close from the host.
+ */
+VBGLR3DECL(int) VbglR3ClipboardObjCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(phObj, VERR_INVALID_POINTER);
+
+ VBoxShClObjCloseMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_CLOSE);
+
+ Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE);
+ Msg.uHandle.SetUInt64(0);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.uContext.GetUInt64(&pCtx->idContext);
+ if (RT_SUCCESS(rc))
+ rc = Msg.uHandle.GetUInt64(phObj);
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Replies to an object open request from the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param rcReply Return code to reply to the host.
+ * @param hObj Object handle to reply to the host.
+ */
+VBGLR3DECL(int) VbglR3ClipboardObjCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ VBoxShClReplyMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
+
+ Msg.uContext.SetUInt64(pCtx->idContext);
+ Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE);
+ Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
+ Msg.pvPayload.SetPtr(NULL, 0);
+
+ Msg.u.ObjClose.uHandle.SetUInt64(hObj);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Sends a request to close an object to the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param hObj Object handle to close on the host.
+ */
+VBGLR3DECL(int) VbglR3ClipboardObjCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ VBoxShClObjCloseMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_OBJ_CLOSE, VBOX_SHCL_CPARMS_OBJ_CLOSE);
+
+ Msg.uContext.SetUInt64(pCtx->idContext);
+ Msg.uHandle.SetUInt64(hObj);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Receives a host request to read from an object on the guest.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param phObj Where to return the object handle to read from.
+ * @param pcbToRead Where to return the amount (in bytes) to read.
+ * @param pfFlags Where to return the read flags.
+ */
+VBGLR3DECL(int) VbglR3ClipboardObjReadRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj, uint32_t *pcbToRead,
+ uint32_t *pfFlags)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(phObj, VERR_INVALID_POINTER);
+ AssertPtrReturn(pcbToRead, VERR_INVALID_POINTER);
+ AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
+
+ VBoxShClObjReadReqMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_READ_REQ);
+
+ Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ);
+ Msg.ReqParms.uHandle.SetUInt64(0);
+ Msg.ReqParms.cbToRead.SetUInt32(0);
+ Msg.ReqParms.fRead.SetUInt32(0);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
+ if (RT_SUCCESS(rc))
+ rc = Msg.ReqParms.uHandle.GetUInt64(phObj);
+ if (RT_SUCCESS(rc))
+ rc = Msg.ReqParms.cbToRead.GetUInt32(pcbToRead);
+ if (RT_SUCCESS(rc))
+ rc = Msg.ReqParms.fRead.GetUInt32(pfFlags);
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Sends a request to read from an object to the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param hObj Object handle of object to read from.
+ * @param pvData Buffer where to store the read object data.
+ * @param cbData Size (in bytes) of buffer.
+ * @param pcbRead Where to store the amount (in bytes) read from the object.
+ */
+VBGLR3DECL(int) VbglR3ClipboardObjReadSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj,
+ void *pvData, uint32_t cbData, uint32_t *pcbRead)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pvData, VERR_INVALID_POINTER);
+ AssertReturn(cbData, VERR_INVALID_PARAMETER);
+ /* pcbRead is optional. */
+
+ VBoxShClObjReadWriteMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_OBJ_READ, VBOX_SHCL_CPARMS_OBJ_READ);
+
+ Msg.uContext.SetUInt64(pCtx->idContext);
+ Msg.uHandle.SetUInt64(hObj);
+ Msg.cbData.SetUInt32(cbData);
+ Msg.pvData.SetPtr(pvData, cbData);
+ Msg.cbChecksum.SetUInt32(0);
+ Msg.pvChecksum.SetPtr(NULL, 0);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ /** @todo Add checksum support. */
+
+ if (pcbRead)
+ {
+ rc = Msg.cbData.GetUInt32(pcbRead); AssertRC(rc);
+ AssertReturn(cbData >= *pcbRead, VERR_TOO_MUCH_DATA);
+ }
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Sends a request to write to an object to the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx Shared Clipboard command context to use for the connection.
+ * @param hObj Object handle of object to write to.
+ * @param pvData Buffer of data to write to object.
+ * @param cbData Size (in bytes) of buffer.
+ * @param pcbWritten Where to store the amount (in bytes) written to the object.
+ */
+VBGLR3DECL(int) VbglR3ClipboardObjWriteSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj,
+ void *pvData, uint32_t cbData, uint32_t *pcbWritten)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pvData, VERR_INVALID_POINTER);
+ /* cbData can be 0. */
+ /* pcbWritten is optional. */
+
+ VBoxShClObjReadWriteMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
+ VBOX_SHCL_GUEST_FN_OBJ_WRITE, VBOX_SHCL_CPARMS_OBJ_WRITE);
+
+ Msg.uContext.SetUInt64(pCtx->idContext);
+ Msg.uHandle.SetUInt64(hObj);
+ Msg.pvData.SetPtr(pvData, cbData);
+ Msg.pvChecksum.SetPtr(NULL, 0);
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ /** @todo Add checksum support. */
+
+ if (pcbWritten)
+ *pcbWritten = cbData; /** @todo For now return all as being written. */
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+
+/*********************************************************************************************************************************
+* Transfer interface implementations *
+*********************************************************************************************************************************/
+
+static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceGetRoots(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList)
+{
+ LogFlowFuncEnter();
+
+ PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
+ AssertPtr(pCmdCtx);
+
+ int rc = VbglR3ClipboardRootListRead(pCmdCtx, ppRootList);
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
+ PSHCLLISTHANDLE phList)
+{
+ LogFlowFuncEnter();
+
+ PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
+ AssertPtr(pCmdCtx);
+
+ int rc = VbglR3ClipboardListOpenSend(pCmdCtx, pOpenParms, phList);
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
+{
+ LogFlowFuncEnter();
+
+ PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
+ AssertPtr(pCmdCtx);
+
+ int rc = VbglR3ClipboardListCloseSend(pCmdCtx, hList);
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListHdrRead(PSHCLTXPROVIDERCTX pCtx,
+ SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
+{
+ LogFlowFuncEnter();
+
+ PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
+ AssertPtr(pCmdCtx);
+
+ int rc = ShClTransferListHdrInit(pListHdr);
+ if (RT_SUCCESS(rc))
+ {
+ if (RT_SUCCESS(rc))
+ {
+ rc = VbglR3ClipboardListHdrRead(pCmdCtx, hList, 0 /* fFlags */, pListHdr);
+ }
+ else
+ ShClTransferListHdrDestroy(pListHdr);
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListEntryRead(PSHCLTXPROVIDERCTX pCtx,
+ SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry)
+{
+ LogFlowFuncEnter();
+
+ PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
+ AssertPtr(pCmdCtx);
+
+ int rc = VbglR3ClipboardListEntryRead(pCmdCtx, hList, pEntry);
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceObjOpen(PSHCLTXPROVIDERCTX pCtx,
+ PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)
+{
+ LogFlowFuncEnter();
+
+ PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
+ AssertPtr(pCmdCtx);
+
+ int rc = VbglR3ClipboardObjOpenSend(pCmdCtx, pCreateParms, phObj);
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
+{
+ LogFlowFuncEnter();
+
+ PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
+ AssertPtr(pCmdCtx);
+
+ int rc = VbglR3ClipboardObjCloseSend(pCmdCtx, hObj);
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceObjRead(PSHCLTXPROVIDERCTX pCtx,
+ SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData,
+ uint32_t fFlags, uint32_t *pcbRead)
+{
+ LogFlowFuncEnter();
+
+ PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
+ AssertPtr(pCmdCtx);
+
+ RT_NOREF(fFlags); /* Not used yet. */
+
+ int rc = VbglR3ClipboardObjReadSend(pCmdCtx, hObj, pvData, cbData, pcbRead);
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Starts a transfer on the guest side.
+ *
+ * @returns VBox status code.
+ * @param pCmdCtx Command context to use.
+ * @param pTransferCtx Transfer context to create transfer for.
+ * @param uTransferID ID to use for transfer to start.
+ * @param enmDir Direction of transfer to start.
+ * @param enmSource Source of transfer to start.
+ * @param ppTransfer Where to return the transfer object on success. Optional.
+ */
+static int vbglR3ClipboardTransferStart(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
+ SHCLTRANSFERID uTransferID, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource,
+ PSHCLTRANSFER *ppTransfer)
+{
+ PSHCLTRANSFER pTransfer;
+ int rc = ShClTransferCreate(&pTransfer);
+ if (RT_SUCCESS(rc))
+ {
+ ShClTransferSetCallbacks(pTransfer, &pCmdCtx->Transfers.Callbacks);
+
+ rc = ShClTransferInit(pTransfer, enmDir, enmSource);
+ if (RT_SUCCESS(rc))
+ {
+ rc = ShClTransferCtxTransferRegisterById(pTransferCtx, pTransfer, uTransferID);
+ if (RT_SUCCESS(rc))
+ {
+ /* If this is a read transfer (reading data from host), set the interface to use
+ * our VbglR3 routines here. */
+ if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE)
+ {
+ SHCLTXPROVIDERCREATIONCTX creationCtx;
+ RT_ZERO(creationCtx);
+
+ creationCtx.Interface.pfnRootsGet = vbglR3ClipboardTransferIfaceGetRoots;
+
+ creationCtx.Interface.pfnListOpen = vbglR3ClipboardTransferIfaceListOpen;
+ creationCtx.Interface.pfnListClose = vbglR3ClipboardTransferIfaceListClose;
+ creationCtx.Interface.pfnListHdrRead = vbglR3ClipboardTransferIfaceListHdrRead;
+ creationCtx.Interface.pfnListEntryRead = vbglR3ClipboardTransferIfaceListEntryRead;
+
+ creationCtx.Interface.pfnObjOpen = vbglR3ClipboardTransferIfaceObjOpen;
+ creationCtx.Interface.pfnObjClose = vbglR3ClipboardTransferIfaceObjClose;
+ creationCtx.Interface.pfnObjRead = vbglR3ClipboardTransferIfaceObjRead;
+
+ creationCtx.pvUser = pCmdCtx;
+
+ rc = ShClTransferSetProviderIface(pTransfer, &creationCtx);
+ }
+
+ if (RT_SUCCESS(rc))
+ rc = ShClTransferStart(pTransfer);
+ }
+
+ if (RT_FAILURE(rc))
+ ShClTransferCtxTransferUnregister(pTransferCtx, uTransferID);
+ }
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ if (ppTransfer)
+ *ppTransfer = pTransfer;
+
+ LogRel2(("Shared Clipboard: Transfer ID=%RU32 (%s %s) successfully started\n",
+ uTransferID,
+ enmDir == SHCLTRANSFERDIR_FROM_REMOTE ? "reading from" : "writing to",
+ enmSource == SHCLSOURCE_LOCAL ? "local" : "remote"));
+ }
+ else
+ LogRel(("Shared Clipboard: Unable to start transfer ID=%RU32, rc=%Rrc\n", uTransferID, rc));
+
+ /* Send a reply in any case. */
+ int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
+ RT_SUCCESS(rc)
+ ? SHCLTRANSFERSTATUS_STARTED : SHCLTRANSFERSTATUS_ERROR, rc);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+
+ if (RT_FAILURE(rc))
+ {
+ ShClTransferDestroy(pTransfer);
+ pTransfer = NULL;
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Stops a transfer on the guest side.
+ *
+ * @returns VBox status code, or VERR_NOT_FOUND if transfer has not been found.
+ * @param pCmdCtx Command context to use.
+ * @param pTransferCtx Transfer context to stop transfer for.
+ * @param uTransferID ID of transfer to stop.
+ */
+static int vbglR3ClipboardTransferStop(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
+ SHCLTRANSFERID uTransferID)
+{
+ int rc;
+
+ PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, uTransferID);
+ if (pTransfer)
+ {
+ rc = ShClTransferCtxTransferUnregister(pTransferCtx, uTransferID);
+ if (RT_SUCCESS(rc))
+ {
+ LogRel2(("Shared Clipboard: Transfer ID=%RU32 successfully stopped\n", uTransferID));
+ }
+ else
+ LogRel(("Shared Clipboard: Unable to stop transfer ID=%RU32, rc=%Rrc\n", uTransferID, rc));
+
+ /* Send a reply in any case. */
+ int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
+ RT_SUCCESS(rc)
+ ? SHCLTRANSFERSTATUS_STOPPED : SHCLTRANSFERSTATUS_ERROR, rc);
+ AssertRC(rc2);
+ }
+ else
+ rc = VERR_NOT_FOUND;
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Sets transfer callbacks of a Shared Clipboard command context.
+ *
+ * @param pCmdCtx Command context to set callbacks for.
+ * @param pCallbacks Pointer to callback table to set.
+ */
+VBGLR3DECL(void) VbglR3ClipboardTransferSetCallbacks(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCALLBACKTABLE pCallbacks)
+{
+ AssertPtrReturnVoid(pCmdCtx);
+ AssertPtrReturnVoid(pCallbacks);
+
+ ShClTransferCopyCallbacks(&pCmdCtx->Transfers.Callbacks, pCallbacks);
+}
+
+VBGLR3DECL(int) VbglR3ClipboardEventGetNextEx(uint32_t idMsg, uint32_t cParms,
+ PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
+ PVBGLR3CLIPBOARDEVENT pEvent)
+{
+ AssertPtrReturn(pCmdCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
+
+ LogFunc(("Handling idMsg=%RU32 (%s), cParms=%RU32\n", idMsg, ShClHostMsgToStr(idMsg), cParms));
+
+ int rc;
+ if (!pCmdCtx->fUseLegacyProtocol)
+ {
+ bool fErrorSent = false; /* Whether an error has been reported back to the host already. */
+
+ switch (idMsg)
+ {
+ case VBOX_SHCL_HOST_MSG_TRANSFER_STATUS:
+ {
+ SHCLTRANSFERDIR enmDir;
+ SHCLTRANSFERREPORT transferReport;
+ rc = VbglR3ClipboarTransferStatusRecv(pCmdCtx, &enmDir, &transferReport);
+ if (RT_SUCCESS(rc))
+ {
+ const SHCLTRANSFERID uTransferID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
+
+ LogFlowFunc(("[Transfer %RU32] enmDir=%RU32, status=%s\n",
+ uTransferID, enmDir, ShClTransferStatusToStr(transferReport.uStatus)));
+
+ switch (transferReport.uStatus)
+ {
+ case SHCLTRANSFERSTATUS_INITIALIZED:
+ RT_FALL_THROUGH();
+ case SHCLTRANSFERSTATUS_STARTED:
+ {
+ SHCLSOURCE enmSource = SHCLSOURCE_INVALID;
+
+ /* The host announces the transfer direction from its point of view, so inverse the direction here. */
+ if (enmDir == SHCLTRANSFERDIR_TO_REMOTE)
+ {
+ enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
+ enmSource = SHCLSOURCE_REMOTE;
+ }
+ else if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE)
+ {
+ enmDir = SHCLTRANSFERDIR_TO_REMOTE;
+ enmSource = SHCLSOURCE_LOCAL;
+ }
+ else
+ AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
+
+ rc = vbglR3ClipboardTransferStart(pCmdCtx, pTransferCtx, uTransferID,
+ enmDir, enmSource, NULL /* ppTransfer */);
+ break;
+ }
+
+ case SHCLTRANSFERSTATUS_STOPPED:
+ RT_FALL_THROUGH();
+ case SHCLTRANSFERSTATUS_CANCELED:
+ RT_FALL_THROUGH();
+ case SHCLTRANSFERSTATUS_KILLED:
+ RT_FALL_THROUGH();
+ case SHCLTRANSFERSTATUS_ERROR:
+ {
+ rc = vbglR3ClipboardTransferStop(pCmdCtx, pTransferCtx,
+ VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
+ break;
+ }
+
+ default:
+ rc = VERR_NOT_SUPPORTED;
+ break;
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ pEvent->u.TransferStatus.enmDir = enmDir;
+ pEvent->u.TransferStatus.Report = transferReport;
+ pEvent->u.TransferStatus.uID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
+
+ pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS;
+
+ LogRel2(("Shared Clipboard: Received status %s (rc=%Rrc) for transfer ID=%RU32\n",
+ ShClTransferStatusToStr(pEvent->u.TransferStatus.Report.uStatus), pEvent->u.TransferStatus.Report.rc,
+ pEvent->u.TransferStatus.uID));
+ }
+ }
+ break;
+ }
+
+ case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ:
+ {
+ uint32_t fRoots;
+ rc = VbglR3ClipboardRootListHdrReadReq(pCmdCtx, &fRoots);
+
+ /** @todo Validate / handle fRoots. */
+
+ if (RT_SUCCESS(rc))
+ {
+ PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
+ VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
+ AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
+
+ SHCLROOTLISTHDR rootListHdr;
+ RT_ZERO(rootListHdr);
+
+ rootListHdr.cRoots = ShClTransferRootsCount(pTransfer);
+
+ LogFlowFunc(("cRoots=%RU32\n", rootListHdr.cRoots));
+
+ rc = VbglR3ClipboardRootListHdrReadReply(pCmdCtx, &rootListHdr);
+ }
+ break;
+ }
+
+ case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ:
+ {
+ uint32_t uIndex;
+ uint32_t fInfo;
+ rc = VbglR3ClipboardRootListEntryReadReq(pCmdCtx, &uIndex, &fInfo);
+ if (RT_SUCCESS(rc))
+ {
+ PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
+ VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
+ AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
+
+ SHCLROOTLISTENTRY rootListEntry;
+ rc = ShClTransferRootsEntry(pTransfer, uIndex, &rootListEntry);
+ if (RT_SUCCESS(rc))
+ rc = VbglR3ClipboardRootListEntryReadReply(pCmdCtx, uIndex, &rootListEntry);
+ }
+ break;
+ }
+
+ case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN:
+ {
+ SHCLLISTOPENPARMS openParmsList;
+ rc = ShClTransferListOpenParmsInit(&openParmsList);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VbglR3ClipboardListOpenRecv(pCmdCtx, &openParmsList);
+ if (RT_SUCCESS(rc))
+ {
+ PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
+ VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
+ AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
+
+ LogFlowFunc(("pszPath=%s\n", openParmsList.pszPath));
+
+ SHCLLISTHANDLE hList = SHCLLISTHANDLE_INVALID;
+ rc = ShClTransferListOpen(pTransfer, &openParmsList, &hList);
+
+ /* Reply in any case. */
+ int rc2 = VbglR3ClipboardListOpenReply(pCmdCtx, rc, hList);
+ AssertRC(rc2);
+ }
+
+ ShClTransferListOpenParmsDestroy(&openParmsList);
+ }
+
+ break;
+ }
+
+ case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE:
+ {
+ SHCLLISTHANDLE hList;
+ rc = VbglR3ClipboardListCloseRecv(pCmdCtx, &hList);
+ if (RT_SUCCESS(rc))
+ {
+ PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
+ VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
+ AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
+
+ rc = ShClTransferListClose(pTransfer, hList);
+
+ /* Reply in any case. */
+ int rc2 = VbglR3ClipboardListCloseReply(pCmdCtx, rc, hList);
+ AssertRC(rc2);
+ }
+
+ break;
+ }
+
+ case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ:
+ {
+ /** @todo Handle filter + list features. */
+
+ SHCLLISTHANDLE hList = SHCLLISTHANDLE_INVALID;
+ uint32_t fFlags = 0;
+ rc = VbglR3ClipboardListHdrReadRecvReq(pCmdCtx, &hList, &fFlags);
+ if (RT_SUCCESS(rc))
+ {
+ PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
+ VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
+ AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
+
+ SHCLLISTHDR hdrList;
+ rc = ShClTransferListGetHeader(pTransfer, hList, &hdrList);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VbglR3ClipboardListHdrWrite(pCmdCtx, hList, &hdrList);
+
+ ShClTransferListHdrDestroy(&hdrList);
+ }
+ }
+
+ break;
+ }
+
+ case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ:
+ {
+ LogFlowFunc(("VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ\n"));
+
+ SHCLLISTENTRY entryList;
+ rc = ShClTransferListEntryInit(&entryList);
+ if (RT_SUCCESS(rc))
+ {
+ SHCLLISTHANDLE hList;
+ uint32_t fInfo;
+ rc = VbglR3ClipboardListEntryReadRecvReq(pCmdCtx, &hList, &fInfo);
+ if (RT_SUCCESS(rc))
+ {
+ PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
+ VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
+ AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
+
+ rc = ShClTransferListRead(pTransfer, hList, &entryList);
+ if (RT_SUCCESS(rc))
+ {
+ PSHCLFSOBJINFO pObjInfo = (PSHCLFSOBJINFO)entryList.pvInfo;
+ Assert(entryList.cbInfo == sizeof(SHCLFSOBJINFO));
+
+ RT_NOREF(pObjInfo);
+
+ LogFlowFunc(("\t%s (%RU64 bytes)\n", entryList.pszName, pObjInfo->cbObject));
+
+ rc = VbglR3ClipboardListEntryWrite(pCmdCtx, hList, &entryList);
+ }
+ }
+
+ ShClTransferListEntryDestroy(&entryList);
+ }
+
+ break;
+ }
+
+ case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN:
+ {
+ SHCLOBJOPENCREATEPARMS openParms;
+ rc = ShClTransferObjOpenParmsInit(&openParms);
+ if (RT_SUCCESS(rc))
+ {
+ rc = VbglR3ClipboardObjOpenRecv(pCmdCtx, &openParms);
+ if (RT_SUCCESS(rc))
+ {
+ PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
+ VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
+ AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
+
+ SHCLOBJHANDLE hObj;
+ rc = ShClTransferObjOpen(pTransfer, &openParms, &hObj);
+
+ /* Reply in any case. */
+ int rc2 = VbglR3ClipboardObjOpenReply(pCmdCtx, rc, hObj);
+ AssertRC(rc2);
+ }
+
+ ShClTransferObjOpenParmsDestroy(&openParms);
+ }
+
+ break;
+ }
+
+ case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE:
+ {
+ SHCLOBJHANDLE hObj;
+ rc = VbglR3ClipboardObjCloseRecv(pCmdCtx, &hObj);
+ if (RT_SUCCESS(rc))
+ {
+ PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
+ VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
+ AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
+
+ rc = ShClTransferObjClose(pTransfer, hObj);
+
+ /* Reply in any case. */
+ int rc2 = VbglR3ClipboardObjCloseReply(pCmdCtx, rc, hObj);
+ AssertRC(rc2);
+ }
+
+ break;
+ }
+
+ case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ:
+ {
+ SHCLOBJHANDLE hObj;
+ uint32_t cbBuf;
+ uint32_t fFlags;
+ rc = VbglR3ClipboardObjReadRecv(pCmdCtx, &hObj, &cbBuf, &fFlags);
+ if (RT_SUCCESS(rc))
+ {
+ PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
+ VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
+ AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
+
+ AssertBreakStmt(pCmdCtx->Transfers.cbChunkSize, rc = VERR_INVALID_PARAMETER);
+
+ const uint32_t cbToRead = RT_MIN(cbBuf, pCmdCtx->Transfers.cbChunkSize);
+
+ LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, fFlags=0x%x -> cbChunkSize=%RU32, cbToRead=%RU32\n",
+ hObj, cbBuf, fFlags, pCmdCtx->Transfers.cbChunkSize, cbToRead));
+
+ void *pvBuf = RTMemAlloc(cbToRead);
+ if (pvBuf)
+ {
+ uint32_t cbRead;
+ rc = ShClTransferObjRead(pTransfer, hObj, pvBuf, cbToRead, fFlags, &cbRead);
+ if (RT_SUCCESS(rc))
+ rc = VbglR3ClipboardObjWriteSend(pCmdCtx, hObj, pvBuf, cbRead, NULL /* pcbWritten */);
+
+ RTMemFree(pvBuf);
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ }
+
+ break;
+ }
+
+ default:
+ {
+ rc = VbglR3ClipboardEventGetNext(idMsg, cParms, pCmdCtx, pEvent);
+ if (RT_FAILURE(rc))
+ fErrorSent = true;
+ break;
+ }
+ }
+
+ if ( !fErrorSent
+ && RT_FAILURE(rc))
+ {
+ /* Report error back to the host. */
+ int rc2 = VbglR3ClipboardWriteError(pCmdCtx->idClient, rc);
+ AssertRC(rc2);
+ }
+ }
+ else
+ {
+ /*
+ * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
+ * !HACK ALERT! cParms is the format flag or flags.
+ */
+ rc = VINF_SUCCESS;
+ switch (idMsg)
+ {
+ case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
+ pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
+ pEvent->u.fReportedFormats = cParms;
+ break;
+
+ case VBOX_SHCL_HOST_MSG_READ_DATA:
+ pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
+ pEvent->u.fReadData = cParms;
+ break;
+
+ case VBOX_SHCL_HOST_MSG_QUIT:
+ pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
+ break;
+
+ default:
+ AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
+ rc = VERR_NOT_SUPPORTED;
+ break;
+ }
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
+
+VBGLR3DECL(int) VbglR3ClipboardEventGetNext(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PVBGLR3CLIPBOARDEVENT pEvent)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
+
+ RT_NOREF(cParms);
+
+ int rc;
+ if (!pCtx->fUseLegacyProtocol)
+ {
+ LogFunc(("Handling idMsg=%RU32 (%s)\n", idMsg, ShClHostMsgToStr(idMsg)));
+ switch (idMsg)
+ {
+ case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
+ {
+ rc = vbglR3ClipboardFormatsReportRecv(pCtx, &pEvent->u.fReportedFormats);
+ if (RT_SUCCESS(rc))
+ pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
+ break;
+ }
+
+ case VBOX_SHCL_HOST_MSG_READ_DATA_CID:
+ {
+ rc = vbglR3ClipboardFetchReadDataCid(pCtx, &pEvent->u.fReadData);
+ if (RT_SUCCESS(rc))
+ pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
+ break;
+ }
+
+ case VBOX_SHCL_HOST_MSG_READ_DATA:
+ {
+ rc = vbglR3ClipboardFetchReadData(pCtx, &pEvent->u.fReadData);
+ if (RT_SUCCESS(rc))
+ pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
+ break;
+ }
+
+ case VBOX_SHCL_HOST_MSG_QUIT:
+ {
+ pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
+ rc = VINF_SUCCESS;
+ break;
+ }
+
+ default:
+ {
+ /** @todo r=bird: BUGBUG - need a skip command here! */
+ rc = VERR_NOT_SUPPORTED;
+ break;
+ }
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ /* Copy over our command context to the event. */
+ pEvent->cmdCtx = *pCtx;
+ }
+ else
+ {
+ /* Report error back to the host. */
+ int rc2 = VbglR3ClipboardWriteError(pCtx->idClient, rc);
+ AssertRC(rc2);
+ }
+ }
+ else
+ {
+ /*
+ * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
+ * !HACK ALERT! cParms is the format flag or flags.
+ */
+ rc = VINF_SUCCESS;
+ switch (idMsg)
+ {
+ case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
+ pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
+ pEvent->u.fReportedFormats = cParms;
+ break;
+
+ case VBOX_SHCL_HOST_MSG_READ_DATA:
+ pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
+ pEvent->u.fReadData = cParms;
+ break;
+
+ case VBOX_SHCL_HOST_MSG_QUIT:
+ pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
+ break;
+
+ default:
+ AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
+ rc = VERR_NOT_SUPPORTED;
+ break;
+ }
+ pEvent->cmdCtx = *pCtx;
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Frees (destroys) a formerly allocated Shared Clipboard event.
+ *
+ * @returns IPRT status code.
+ * @param pEvent Event to free (destroy).
+ */
+VBGLR3DECL(void) VbglR3ClipboardEventFree(PVBGLR3CLIPBOARDEVENT pEvent)
+{
+ if (!pEvent)
+ return;
+
+ /* Some messages require additional cleanup. */
+ switch (pEvent->enmType)
+ {
+ default:
+ break;
+ }
+
+ RTMemFree(pEvent);
+ pEvent = NULL;
+}
+
+/**
+ * Reports (advertises) guest clipboard formats to the host.
+ *
+ * Legacy function, do not use anymore.
+ *
+ * @returns VBox status code.
+ * @param idClient The client id returned by VbglR3ClipboardConnect().
+ * @param fFormats The formats to report.
+ */
+VBGLR3DECL(int) VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats)
+{
+ struct
+ {
+ VBGLIOCHGCMCALL Hdr;
+ VBoxShClParmReportFormats Parms;
+ } Msg;
+
+ VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_REPORT_FORMATS, VBOX_SHCL_CPARMS_REPORT_FORMATS);
+ VbglHGCMParmUInt32Set(&Msg.Parms.f32Formats, fFormats);
+
+ int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Sends guest clipboard data to the host.
+ *
+ * Legacy function kept for compatibility, do not use anymore.
+ *
+ * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
+ * from the host.
+ *
+ * @returns VBox status code.
+ * @param idClient The client id returned by VbglR3ClipboardConnect().
+ * @param fFormat The format of the data.
+ * @param pvData Pointer to the data to send. Can be NULL if @a cbData
+ * is zero.
+ * @param cbData Number of bytes of data to send. Zero is valid.
+ */
+VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
+{
+ LogFlowFuncEnter();
+
+ struct
+ {
+ VBGLIOCHGCMCALL Hdr;
+ VBoxShClParmDataWriteOld Parms;
+ } Msg;
+
+ VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE_OLD);
+ VbglHGCMParmUInt32Set(&Msg.Parms.f32Format, fFormat);
+ VbglHGCMParmPtrSet(&Msg.Parms.pData, pv, cb);
+
+ int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Sends guest clipboard data to the host.
+ *
+ * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
+ * from the host.
+ *
+ * @returns VBox status code.
+ * @param pCtx The command context returned by VbglR3ClipboardConnectEx().
+ * @param fFormat Clipboard format to send.
+ * @param pvData Pointer to the data to send. Can be NULL if @a cbData
+ * is zero.
+ * @param cbData Number of bytes of data to send. Zero is valid.
+ */
+VBGLR3DECL(int) VbglR3ClipboardWriteDataEx(PVBGLR3SHCLCMDCTX pCtx, SHCLFORMAT fFormat, void *pvData, uint32_t cbData)
+{
+ LogFlowFunc(("ENTER: fFormat=%#x pvData=%p cbData=%#x\n", fFormat, pvData, cbData));
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ if (cbData > 0)
+ AssertPtrReturn(pvData, VERR_INVALID_POINTER);
+
+ int rc;
+ if (pCtx->fUseLegacyProtocol)
+ rc = VbglR3ClipboardWriteData(pCtx->idClient, fFormat, pvData, cbData);
+ else
+ {
+ struct
+ {
+ VBGLIOCHGCMCALL Hdr;
+ VBoxShClParmDataWrite Parms;
+ } Msg;
+
+ VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE);
+ Msg.Parms.id64Context.SetUInt64(pCtx->idContext);
+ Msg.Parms.f32Format.SetUInt32(fFormat);
+ Msg.Parms.pData.SetPtr(pvData, cbData);
+
+ LogFlowFunc(("CID=%RU32\n", pCtx->idContext));
+
+ rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
+ }
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+
+/**
+ * Writes an error to the host.
+ *
+ * @returns IPRT status code.
+ * @param idClient The client id returned by VbglR3ClipboardConnect().
+ * @param rcErr Error (IPRT-style) to send.
+ */
+VBGLR3DECL(int) VbglR3ClipboardWriteError(HGCMCLIENTID idClient, int rcErr)
+{
+ AssertReturn(idClient, VERR_INVALID_PARAMETER);
+
+ VBoxShClWriteErrorMsg Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_ERROR, VBOX_SHCL_CPARMS_ERROR);
+
+ /** @todo Context ID not used yet. */
+ Msg.uContext.SetUInt64(0);
+ Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
+
+ int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+
+ if (RT_FAILURE(rc))
+ LogFlowFunc(("Sending error %Rrc failed with rc=%Rrc\n", rcErr, rc));
+ if (rc == VERR_NOT_SUPPORTED)
+ rc = VINF_SUCCESS;
+
+ if (RT_FAILURE(rc))
+ LogRel(("Shared Clipboard: Reporting error %Rrc to the host failed with %Rrc\n", rcErr, rc));
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
+