summaryrefslogtreecommitdiffstats
path: root/include/VBox/GuestHost
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--include/VBox/GuestHost/DragAndDrop.h350
-rw-r--r--include/VBox/GuestHost/DragAndDropDefs.h112
-rw-r--r--include/VBox/GuestHost/GuestControl.h236
-rw-r--r--include/VBox/GuestHost/HGCMMock.h804
-rw-r--r--include/VBox/GuestHost/HGCMMockUtils.h428
-rw-r--r--include/VBox/GuestHost/Makefile.kup0
-rw-r--r--include/VBox/GuestHost/SharedClipboard-transfers.h993
-rw-r--r--include/VBox/GuestHost/SharedClipboard-win.h419
-rw-r--r--include/VBox/GuestHost/SharedClipboard-x11.h187
-rw-r--r--include/VBox/GuestHost/SharedClipboard.h354
-rw-r--r--include/VBox/GuestHost/clipboard-helper.h250
11 files changed, 4133 insertions, 0 deletions
diff --git a/include/VBox/GuestHost/DragAndDrop.h b/include/VBox/GuestHost/DragAndDrop.h
new file mode 100644
index 00000000..a9722c59
--- /dev/null
+++ b/include/VBox/GuestHost/DragAndDrop.h
@@ -0,0 +1,350 @@
+/* $Id: DragAndDrop.h $ */
+/** @file
+ * DnD - Shared functions between host and guest.
+ */
+
+/*
+ * Copyright (C) 2014-2022 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
+ */
+
+#ifndef VBOX_INCLUDED_GuestHost_DragAndDrop_h
+#define VBOX_INCLUDED_GuestHost_DragAndDrop_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <iprt/assert.h>
+#include <iprt/fs.h>
+#include <iprt/list.h>
+
+#include <VBox/GuestHost/DragAndDropDefs.h>
+
+/** DnDURIDroppedFiles flags. */
+typedef uint32_t DNDURIDROPPEDFILEFLAGS;
+
+/** No flags specified. */
+#define DNDURIDROPPEDFILE_FLAGS_NONE 0
+
+/**
+ * Structure for keeping a DnD dropped files entry.
+ */
+typedef struct DNDDROPPEDFILESENTRY
+{
+ RTLISTNODE Node;
+ char *pszPath;
+} DNDDROPPEDFILESENTRY;
+/** Pointer to a DnD dropped files entry. */
+typedef DNDDROPPEDFILESENTRY *PDNDDROPPEDFILESENTRY;
+
+/**
+ * Structure for maintaining a "dropped files" directory
+ * on the host or guest. This will contain all received files & directories
+ * for a single drag and drop operation.
+ *
+ * In case of a failed drag and drop operation this can also
+ * perform a gentle rollback if required.
+ */
+typedef struct DNDDROPPEDFILES
+{
+ /** Open flags. */
+ uint32_t m_fOpen;
+ /** Directory handle for drop directory. */
+ RTDIR m_hDir;
+ /** Absolute path to drop directory. */
+ char *pszPathAbs;
+ /** List for holding created directories in the case of a rollback. */
+ RTLISTANCHOR m_lstDirs;
+ /** List for holding created files in the case of a rollback. */
+ RTLISTANCHOR m_lstFiles;
+} DNDDROPPEDFILES;
+/** Pointer to a DnD dropped files directory. */
+typedef DNDDROPPEDFILES *PDNDDROPPEDFILES;
+
+int DnDDroppedFilesInit(PDNDDROPPEDFILES pDF);
+int DnDDroppedFilesInitEx(PDNDDROPPEDFILES pDF, const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags);
+void DnDDroppedFilesDestroy(PDNDDROPPEDFILES pDF);
+int DnDDroppedFilesAddFile(PDNDDROPPEDFILES pDF, const char *pszFile);
+int DnDDroppedFilesAddDir(PDNDDROPPEDFILES pDF, const char *pszDir);
+int DnDDroppedFilesClose(PDNDDROPPEDFILES pDF);
+bool DnDDroppedFilesIsOpen(PDNDDROPPEDFILES pDF);
+int DnDDroppedFilesOpenEx(PDNDDROPPEDFILES pDF, const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags);
+int DnDDroppedFilesOpenTemp(PDNDDROPPEDFILES pDF, DNDURIDROPPEDFILEFLAGS fFlags);
+const char *DnDDroppedFilesGetDirAbs(PDNDDROPPEDFILES pDF);
+int DnDDroppedFilesReopen(PDNDDROPPEDFILES pDF);
+int DnDDroppedFilesReset(PDNDDROPPEDFILES pDF, bool fDelete);
+int DnDDroppedFilesRollback(PDNDDROPPEDFILES pDF);
+
+const char *DnDHostMsgToStr(uint32_t uMsg);
+const char *DnDGuestMsgToStr(uint32_t uMsg);
+const char *DnDActionToStr(VBOXDNDACTION uAction);
+ char *DnDActionListToStrA(VBOXDNDACTIONLIST fActionList);
+const char *DnDStateToStr(VBOXDNDSTATE enmState);
+
+bool DnDMIMEHasFileURLs(const char *pcszFormat, size_t cchFormatMax);
+bool DnDMIMENeedsDropDir(const char *pcszFormat, size_t cchFormatMax);
+
+int DnDPathValidate(const char *pcszPath, bool fMustExist);
+
+/** DnD path conversion flags. */
+typedef uint32_t DNDPATHCONVERTFLAGS;
+
+/** No flags specified.
+ * This will convert the path to the universal tansport style. */
+#define DNDPATHCONVERT_FLAGS_TRANSPORT 0
+/** Converts the path to a OS-dependent path. */
+#define DNDPATHCONVERT_FLAGS_TO_DOS RT_BIT(0)
+
+/** Mask of all valid DnD path conversion flags. */
+#define DNDPATHCONVERT_FLAGS_VALID_MASK UINT32_C(0x1)
+
+int DnDPathConvert(char *pszPath, size_t cbPath, DNDPATHCONVERTFLAGS fFlags);
+int DnDPathSanitizeFileName(char *pszPath, size_t cbPath);
+int DnDPathRebase(const char *pcszPathAbs, const char *pcszBaseOld, const char *pcszBaseNew, char **ppszPath);
+
+/** DnDTransferObject flags. */
+typedef uint32_t DNDTRANSFEROBJECTFLAGS;
+
+/** No flags specified. */
+#define DNDTRANSFEROBJECT_FLAGS_NONE 0
+
+/** Mask of all valid DnD transfer object flags. */
+#define DNDTRANSFEROBJECT_FLAGS_VALID_MASK UINT32_C(0x0)
+
+/**
+ * Enumeration for specifying a transfer object type.
+ */
+typedef enum DNDTRANSFEROBJTYPE
+{
+ /** Unknown type, do not use. */
+ DNDTRANSFEROBJTYPE_UNKNOWN = 0,
+ /** Object is a file. */
+ DNDTRANSFEROBJTYPE_FILE,
+ /** Object is a directory. */
+ DNDTRANSFEROBJTYPE_DIRECTORY,
+ /** The usual 32-bit hack. */
+ DNDTRANSFEROBJTYPE_32BIT_HACK = 0x7fffffff
+} DNDTRANSFEROBJTYPE;
+
+/**
+ * Enumeration for specifying a path style.
+ */
+typedef enum DNDTRANSFEROBJPATHSTYLE
+{
+ /** Transport style (UNIX-y), the default. */
+ DNDTRANSFEROBJPATHSTYLE_TRANSPORT = 0,
+ /** DOS style, containing back slashes. */
+ DNDTRANSFEROBJPATHSTYLE_DOS,
+ /** The usual 32-bit hack. */
+ DNDTRANSFEROBJPATHSTYLE_32BIT_HACK = 0x7fffffff
+} DNDTRANSFEROBJPATHSTYLE;
+
+/**
+ * Structure for keeping a DnD transfer object.
+ */
+typedef struct DNDTRANSFEROBJECT
+{
+ RTLISTNODE Node;
+ /** The object's type. */
+ DNDTRANSFEROBJTYPE enmType;
+ /** Index (in characters, UTF-8) at which the first destination segment starts. */
+ uint16_t idxDst;
+ /** Allocated path. Includdes the absolute source path (if any) + destination segments.
+ * Transport (IPRT) style. */
+ char *pszPath;
+
+ /** Union containing data depending on the object's type. */
+ union
+ {
+ /** Structure containing members for objects that
+ * are files. */
+ struct
+ {
+ /** File handle. */
+ RTFILE hFile;
+ /** File system object information of this file. */
+ RTFSOBJINFO objInfo;
+ /** Bytes to proces for reading/writing. */
+ uint64_t cbToProcess;
+ /** Bytes processed reading/writing. */
+ uint64_t cbProcessed;
+ } File;
+ struct
+ {
+ /** Directory handle. */
+ RTDIR hDir;
+ /** File system object information of this directory. */
+ RTFSOBJINFO objInfo;
+ } Dir;
+ } u;
+} DNDTRANSFEROBJECT;
+/** Pointer to a DnD transfer object. */
+typedef DNDTRANSFEROBJECT *PDNDTRANSFEROBJECT;
+
+int DnDTransferObjectInit(PDNDTRANSFEROBJECT pObj);
+int DnDTransferObjectInitEx(PDNDTRANSFEROBJECT pObj, DNDTRANSFEROBJTYPE enmType, const char *pcszPathSrcAbs, const char *pcszPathDst);
+void DnDTransferObjectDestroy(PDNDTRANSFEROBJECT pObj);
+int DnDTransferObjectClose(PDNDTRANSFEROBJECT pObj);
+void DnDTransferObjectReset(PDNDTRANSFEROBJECT pObj);
+const char *DnDTransferObjectGetSourcePath(PDNDTRANSFEROBJECT pObj);
+const char *DnDTransferObjectGetDestPath(PDNDTRANSFEROBJECT pObj);
+int DnDTransferObjectGetDestPathEx(PDNDTRANSFEROBJECT pObj, DNDTRANSFEROBJPATHSTYLE enmStyle, char *pszBuf, size_t cbBuf);
+RTFMODE DnDTransferObjectGetMode(PDNDTRANSFEROBJECT pObj);
+uint64_t DnDTransferObjectGetProcessed(PDNDTRANSFEROBJECT pObj);
+uint64_t DnDTransferObjectGetSize(PDNDTRANSFEROBJECT pObj);
+DNDTRANSFEROBJTYPE DnDTransferObjectGetType(PDNDTRANSFEROBJECT pObj);
+int DnDTransferObjectSetSize(PDNDTRANSFEROBJECT pObj, uint64_t cbSize);
+bool DnDTransferObjectIsComplete(PDNDTRANSFEROBJECT pObj);
+bool DnDTransferObjectIsOpen(PDNDTRANSFEROBJECT pObj);
+int DnDTransferObjectOpen(PDNDTRANSFEROBJECT pObj, uint64_t fOpen, RTFMODE fMode, DNDTRANSFEROBJECTFLAGS fFlags);
+int DnDTransferObjectQueryInfo(PDNDTRANSFEROBJECT pObj);
+int DnDTransferObjectRead(PDNDTRANSFEROBJECT pObj, void *pvBuf, size_t cbBuf, uint32_t *pcbRead);
+int DnDTransferObjectWrite(PDNDTRANSFEROBJECT pObj, const void *pvBuf, size_t cbBuf, uint32_t *pcbWritten);
+
+/** Defines the default chunk size of DnD data transfers.
+ * Supported on all (older) Guest Additions which also support DnD. */
+#define DND_DEFAULT_CHUNK_SIZE _64K
+
+/** Separator for a formats list. */
+#define DND_FORMATS_SEPARATOR_STR "\r\n"
+
+/** Default URI list path separator, if not specified otherwise.
+ *
+ * This is there for hysterical raisins, to not break older Guest Additions.
+ ** @todo Get rid of this. */
+#define DND_PATH_SEPARATOR_STR "\r\n"
+
+/** DnDTransferList flags. */
+typedef uint32_t DNDTRANSFERLISTFLAGS;
+
+/** No flags specified. */
+#define DNDTRANSFERLIST_FLAGS_NONE 0
+/** Enables recurisve directory handling. */
+#define DNDTRANSFERLIST_FLAGS_RECURSIVE RT_BIT(0)
+/** Resolve all symlinks. Currently not supported and will be ignored. */
+#define DNDTRANSFERLIST_FLAGS_RESOLVE_SYMLINKS RT_BIT(1)
+/** Keep the files + directory entries open while
+ * being in this list. */
+#define DNDTRANSFERLIST_FLAGS_KEEP_OPEN RT_BIT(2)
+/** Lazy loading: Only enumerate sub directories when needed. Not implemented yet.
+ ** @todo Implement lazy loading. */
+#define DNDTRANSFERLIST_FLAGS_LAZY RT_BIT(3)
+
+/** Mask of all valid DnD transfer list flags. */
+#define DNDTRANSFERLIST_FLAGS_VALID_MASK UINT32_C(0xF)
+
+/**
+ * Enumeration for specifying a transfer list format.
+ */
+typedef enum DNDTRANSFERLISTFMT
+{
+ /** Unknown format, do not use. */
+ DNDTRANSFERLISTFMT_UNKNOWN = 0,
+ /** Native format. */
+ DNDTRANSFERLISTFMT_NATIVE,
+ /** URI format. */
+ DNDTRANSFERLISTFMT_URI,
+ /** The usual 32-bit hack. */
+ DNDTRANSFERLISTFMT_32BIT_HACK = 0x7fffffff
+} DNDTRANSFERLISTFMT;
+
+/**
+ * Structure for keeping a DnD transfer list root entry.
+ *
+ * A root entry always is relative to the parent list maintaining it.
+ */
+typedef struct DNDTRANSFERLISTROOT
+{
+ /** List node. */
+ RTLISTNODE Node;
+ /** Pointer to the allocated root path.
+ * - Relative to the list's root path
+ * - Always ends with a trailing slash
+ * - Always stored in transport style (UNIX-y). */
+ char *pszPathRoot;
+} DNDTRANSFERLISTROOT;
+/** Pointer to a DnD list root entry. */
+typedef DNDTRANSFERLISTROOT *PDNDTRANSFERLISTROOT;
+
+/**
+ * Struct for keeping a DnD transfer list.
+ *
+ * All entries must share a common (absolute) root path. For different root paths another transfer list is needed.
+ */
+typedef struct DNDTRANSFERLIST
+{
+ /** Absolute root path of this transfer list, in native path style.
+ * Always ends with a separator. */
+ char *pszPathRootAbs;
+ /** List of all relative (to \a pszPathRootAbs) top-level file/directory entries, of type DNDTRANSFERLISTROOT.
+ * Note: All paths are stored internally in transport style (UNIX paths) for
+ * easier conversion/handling! */
+ RTLISTANCHOR lstRoot;
+ /** Total number of all transfer root entries. */
+ uint64_t cRoots;
+ /** List of all transfer objects added, of type DNDTRANSFEROBJECT.
+ *
+ * The order of objects being added is crucial for traversing the tree.
+ * In other words, sub directories must come first before its contents. */
+ RTLISTANCHOR lstObj;
+ /** Total number of all transfer objects. */
+ uint64_t cObj;
+ /** Total size of all transfer objects, that is, the file
+ * size of all objects (in bytes).
+ * Note: Do *not* size_t here, as we also want to support large files
+ * on 32-bit guests. */
+ uint64_t cbObjTotal;
+} DNDTRANSFERLIST;
+/** Pointer to a DNDTRANSFERLIST struct. */
+typedef DNDTRANSFERLIST *PDNDTRANSFERLIST;
+
+int DnDTransferListInit(PDNDTRANSFERLIST pList);
+int DnDTransferListInitEx(PDNDTRANSFERLIST pList, const char *pcszRootPathAbs, DNDTRANSFERLISTFMT enmFmt);
+void DnDTransferListDestroy(PDNDTRANSFERLIST pList);
+void DnDTransferListReset(PDNDTRANSFERLIST pList);
+
+int DnDTransferListAppendPath(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char *pszPath, DNDTRANSFERLISTFLAGS fFlags);
+int DnDTransferListAppendPathsFromBuffer(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char *pszPaths, size_t cbPaths, const char *pcszSeparator, DNDTRANSFERLISTFLAGS fFlags);
+int DnDTransferListAppendPathsFromArray(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char * const *papcszPaths, size_t cPaths, DNDTRANSFERLISTFLAGS fFlags);
+int DnDTransferListAppendRootsFromBuffer(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char *pszPaths, size_t cbPaths, const char *pcszSeparator, DNDTRANSFERLISTFLAGS fFlags);
+int DnDTransferListAppendRootsFromArray(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char * const *papcszPaths, size_t cPaths, DNDTRANSFERLISTFLAGS fFlags);
+
+int DnDTransferListGetRootsEx(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char *pcszPathBase, const char *pcszSeparator, char **ppszBuffer, size_t *pcbBuffer);
+int DnDTransferListGetRoots(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, char **ppszBuffer, size_t *pcbBuffer);
+uint64_t DnDTransferListGetRootCount(PDNDTRANSFERLIST pList);
+const char *DnDTransferListGetRootPathAbs(PDNDTRANSFERLIST pList);
+
+PDNDTRANSFEROBJECT DnDTransferListObjGetFirst(PDNDTRANSFERLIST pList);
+void DnDTransferListObjRemove(PDNDTRANSFERLIST pList, PDNDTRANSFEROBJECT pObj);
+void DnDTransferListObjRemoveFirst(PDNDTRANSFERLIST pList);
+uint64_t DnDTransferListObjCount(PDNDTRANSFERLIST pList);
+uint64_t DnDTransferListObjTotalBytes(PDNDTRANSFERLIST pList);
+
+#endif /* !VBOX_INCLUDED_GuestHost_DragAndDrop_h */
+
diff --git a/include/VBox/GuestHost/DragAndDropDefs.h b/include/VBox/GuestHost/DragAndDropDefs.h
new file mode 100644
index 00000000..0968fa8a
--- /dev/null
+++ b/include/VBox/GuestHost/DragAndDropDefs.h
@@ -0,0 +1,112 @@
+/** @file
+ * Drag and Drop definitions - Common header for host service and guest clients.
+ */
+
+/*
+ * Copyright (C) 2018-2022 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
+ */
+
+#ifndef VBOX_INCLUDED_GuestHost_DragAndDropDefs_h
+#define VBOX_INCLUDED_GuestHost_DragAndDropDefs_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <iprt/types.h>
+
+/*
+ * The mode of operations.
+ */
+#define VBOX_DRAG_AND_DROP_MODE_OFF 0
+#define VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST 1
+#define VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST 2
+#define VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL 3
+
+#define VBOX_DND_ACTION_IGNORE UINT32_C(0)
+#define VBOX_DND_ACTION_COPY RT_BIT_32(0)
+#define VBOX_DND_ACTION_MOVE RT_BIT_32(1)
+#define VBOX_DND_ACTION_LINK RT_BIT_32(2)
+
+/** A single DnD action. */
+typedef uint32_t VBOXDNDACTION;
+/** A list of (OR'ed) DnD actions. */
+typedef uint32_t VBOXDNDACTIONLIST;
+
+#define hasDnDCopyAction(a) ((a) & VBOX_DND_ACTION_COPY)
+#define hasDnDMoveAction(a) ((a) & VBOX_DND_ACTION_MOVE)
+#define hasDnDLinkAction(a) ((a) & VBOX_DND_ACTION_LINK)
+
+#define isDnDIgnoreAction(a) ((a) == VBOX_DND_ACTION_IGNORE)
+#define isDnDCopyAction(a) ((a) == VBOX_DND_ACTION_COPY)
+#define isDnDMoveAction(a) ((a) == VBOX_DND_ACTION_MOVE)
+#define isDnDLinkAction(a) ((a) == VBOX_DND_ACTION_LINK)
+
+/** @def VBOX_DND_FORMATS_DEFAULT
+ * Default drag'n drop formats.
+ * Note: If you add new entries here, make sure you test those
+ * with all supported guest OSes!
+ */
+#define VBOX_DND_FORMATS_DEFAULT \
+ "text/uri-list", \
+ /* Text. */ \
+ "text/html", \
+ "text/plain;charset=utf-8", \
+ "text/plain;charset=utf-16", \
+ "text/plain", \
+ "text/richtext", \
+ "UTF8_STRING", \
+ "TEXT", \
+ "STRING", \
+ /* OpenOffice formats. */ \
+ /* See: https://wiki.openoffice.org/wiki/Documentation/DevGuide/OfficeDev/Common_Application_Features#OpenOffice.org_Clipboard_Data_Formats */ \
+ "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"", \
+ "application/x-openoffice;windows_formatname=\"Bitmap\""
+
+/**
+ * Enumeration for keeping a DnD state.
+ */
+typedef enum
+{
+ VBOXDNDSTATE_UNKNOWN = 0,
+ VBOXDNDSTATE_ENTERED,
+ VBOXDNDSTATE_LEFT,
+ VBOXDNDSTATE_QUERY_FORMATS,
+ VBOXDNDSTATE_QUERY_STATUS,
+ VBOXDNDSTATE_DRAGGING,
+ VBOXDNDSTATE_DROP_STARTED,
+ VBOXDNDSTATE_DROP_ENDED,
+ VBOXDNDSTATE_CANCELLED,
+ VBOXDNDSTATE_ERROR
+} VBOXDNDSTATE;
+/** Pointer to a DnD state. */
+typedef VBOXDNDSTATE *PVBOXDNDSTATE;
+
+#endif /* !VBOX_INCLUDED_GuestHost_DragAndDropDefs_h */
+
diff --git a/include/VBox/GuestHost/GuestControl.h b/include/VBox/GuestHost/GuestControl.h
new file mode 100644
index 00000000..3ecbc0a3
--- /dev/null
+++ b/include/VBox/GuestHost/GuestControl.h
@@ -0,0 +1,236 @@
+/* $Id: GuestControl.h $ */
+/** @file
+ * Guest Control - Common Guest and Host Code.
+ *
+ * @todo r=bird: Just merge this with GuestControlSvc.h!
+ */
+
+/*
+ * Copyright (C) 2016-2022 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
+ */
+
+#ifndef VBOX_INCLUDED_GuestHost_GuestControl_h
+#define VBOX_INCLUDED_GuestHost_GuestControl_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <iprt/types.h>
+
+/* Everything defined in this file lives in this namespace. */
+namespace guestControl {
+
+/**
+ * Process status when executed in the guest.
+ */
+enum eProcessStatus
+{
+ /** Process is in an undefined state. */
+ PROC_STS_UNDEFINED = 0,
+ /** Process has been started. */
+ PROC_STS_STARTED = 1,
+ /** Process terminated normally. */
+ PROC_STS_TEN = 2,
+ /** Process terminated via signal. */
+ PROC_STS_TES = 3,
+ /** Process terminated abnormally. */
+ PROC_STS_TEA = 4,
+ /** Process timed out and was killed. */
+ PROC_STS_TOK = 5,
+ /** Process timed out and was not killed successfully. */
+ PROC_STS_TOA = 6,
+ /** Service/OS is stopping, process was killed. */
+ PROC_STS_DWN = 7,
+ /** Something went wrong (error code in flags). */
+ PROC_STS_ERROR = 8
+};
+
+/**
+ * Input flags, set by the host. This is needed for
+ * handling flags on the guest side.
+ * Note: Has to match Main's ProcessInputFlag_* flags!
+ */
+#define GUEST_PROC_IN_FLAG_NONE 0x0
+#define GUEST_PROC_IN_FLAG_EOF RT_BIT(0)
+
+/**
+ * Guest session creation flags.
+ * Only handled internally at the moment.
+ */
+#define SESSIONCREATIONFLAG_NONE 0x0
+
+/** @name DIRREMOVEREC_FLAG_XXX - Guest directory removement flags.
+ * Essentially using what IPRT's RTDIRRMREC_F_
+ * defines have to offer.
+ * @{
+ */
+/** No remove flags specified. */
+#define DIRREMOVEREC_FLAG_NONE UINT32_C(0x0)
+/** Recursively deletes the directory contents. */
+#define DIRREMOVEREC_FLAG_RECURSIVE RT_BIT(0)
+/** Delete the content of the directory and the directory itself. */
+#define DIRREMOVEREC_FLAG_CONTENT_AND_DIR RT_BIT(1)
+/** Only delete the content of the directory, omit the directory it self. */
+#define DIRREMOVEREC_FLAG_CONTENT_ONLY RT_BIT(2)
+/** Mask of valid flags. */
+#define DIRREMOVEREC_FLAG_VALID_MASK UINT32_C(0x00000007)
+/** @} */
+
+/** @name GUEST_PROC_CREATE_FLAG_XXX - Guest process creation flags.
+ * @note Has to match Main's ProcessCreateFlag_* flags!
+ * @{
+ */
+#define GUEST_PROC_CREATE_FLAG_NONE UINT32_C(0x0)
+#define GUEST_PROC_CREATE_FLAG_WAIT_START RT_BIT(0)
+#define GUEST_PROC_CREATE_FLAG_IGNORE_ORPHANED RT_BIT(1)
+#define GUEST_PROC_CREATE_FLAG_HIDDEN RT_BIT(2)
+#define GUEST_PROC_CREATE_FLAG_PROFILE RT_BIT(3)
+#define GUEST_PROC_CREATE_FLAG_WAIT_STDOUT RT_BIT(4)
+#define GUEST_PROC_CREATE_FLAG_WAIT_STDERR RT_BIT(5)
+#define GUEST_PROC_CREATE_FLAG_EXPAND_ARGUMENTS RT_BIT(6)
+#define GUEST_PROC_CREATE_FLAG_UNQUOTED_ARGS RT_BIT(7)
+/** @} */
+
+/** @name GUEST_PROC_OUT_H_XXX - Pipe handle IDs used internally for referencing
+ * to a certain pipe buffer.
+ * @{
+ */
+#define GUEST_PROC_OUT_H_STDOUT_DEPRECATED 0 /**< Needed for VBox hosts < 4.1.0. */
+#define GUEST_PROC_OUT_H_STDOUT 1
+#define GUEST_PROC_OUT_H_STDERR 2
+/** @} */
+
+/** @name PATHRENAME_FLAG_XXX - Guest path rename flags.
+ * Essentially using what IPRT's RTPATHRENAME_FLAGS_XXX have to offer.
+ * @{
+ */
+/** Do not replace anything. */
+#define PATHRENAME_FLAG_NO_REPLACE UINT32_C(0)
+/** This will replace attempt any target which isn't a directory. */
+#define PATHRENAME_FLAG_REPLACE RT_BIT(0)
+/** Don't allow symbolic links as part of the path. */
+#define PATHRENAME_FLAG_NO_SYMLINKS RT_BIT(1)
+/** Mask of valid flags. */
+#define PATHRENAME_FLAG_VALID_MASK UINT32_C(0x00000003)
+/** @} */
+
+/** @name GUEST_SHUTDOWN_FLAG_XXX - Guest shutdown flags.
+ * Must match Main's GuestShutdownFlag_ definitions.
+ * @{
+ */
+#define GUEST_SHUTDOWN_FLAG_NONE UINT32_C(0)
+#define GUEST_SHUTDOWN_FLAG_POWER_OFF RT_BIT(0)
+#define GUEST_SHUTDOWN_FLAG_REBOOT RT_BIT(1)
+#define GUEST_SHUTDOWN_FLAG_FORCE RT_BIT(2)
+/** @} */
+
+/** @name Defines for default (initial) guest process buffer lengths.
+ * Note: These defaults were the maximum values before; so be careful when raising those in order to
+ * not break running with older Guest Additions.
+ * @{
+ */
+#define GUEST_PROC_DEF_CMD_LEN _1K
+#define GUEST_PROC_DEF_ARGS_LEN _1K
+#define GUEST_PROC_DEF_ENV_LEN _1K
+#define GUEST_PROC_DEF_USER_LEN 128
+#define GUEST_PROC_DEF_PASSWORD_LEN 128
+#define GUEST_PROC_DEF_DOMAIN_LEN 256
+/** @} */
+
+/** @name Defines for maximum guest process buffer lengths.
+ * @{
+ */
+#define GUEST_PROC_MAX_CMD_LEN _1M
+#define GUEST_PROC_MAX_ARGS_LEN _2M
+#define GUEST_PROC_MAX_ENV_LEN _4M
+#define GUEST_PROC_MAX_USER_LEN _64K
+#define GUEST_PROC_MAX_PASSWORD_LEN _64K
+#define GUEST_PROC_MAX_DOMAIN_LEN _64K
+/** @} */
+
+/** @name Internal tools built into VBoxService which are used in order
+ * to accomplish tasks host<->guest.
+ * @{
+ */
+#define VBOXSERVICE_TOOL_CAT "vbox_cat"
+#define VBOXSERVICE_TOOL_LS "vbox_ls"
+#define VBOXSERVICE_TOOL_RM "vbox_rm"
+#define VBOXSERVICE_TOOL_MKDIR "vbox_mkdir"
+#define VBOXSERVICE_TOOL_MKTEMP "vbox_mktemp"
+#define VBOXSERVICE_TOOL_STAT "vbox_stat"
+/** @} */
+
+/** Special process exit codes for "vbox_cat". */
+typedef enum VBOXSERVICETOOLBOX_CAT_EXITCODE
+{
+ VBOXSERVICETOOLBOX_CAT_EXITCODE_ACCESS_DENIED = RTEXITCODE_END,
+ VBOXSERVICETOOLBOX_CAT_EXITCODE_FILE_NOT_FOUND,
+ VBOXSERVICETOOLBOX_CAT_EXITCODE_PATH_NOT_FOUND,
+ VBOXSERVICETOOLBOX_CAT_EXITCODE_SHARING_VIOLATION,
+ VBOXSERVICETOOLBOX_CAT_EXITCODE_IS_A_DIRECTORY,
+ /** The usual 32-bit type hack. */
+ VBOXSERVICETOOLBOX_CAT_32BIT_HACK = 0x7fffffff
+} VBOXSERVICETOOLBOX_CAT_EXITCODE;
+
+/** Special process exit codes for "vbox_stat". */
+typedef enum VBOXSERVICETOOLBOX_STAT_EXITCODE
+{
+ VBOXSERVICETOOLBOX_STAT_EXITCODE_ACCESS_DENIED = RTEXITCODE_END,
+ VBOXSERVICETOOLBOX_STAT_EXITCODE_FILE_NOT_FOUND,
+ VBOXSERVICETOOLBOX_STAT_EXITCODE_PATH_NOT_FOUND,
+ VBOXSERVICETOOLBOX_STAT_EXITCODE_NET_PATH_NOT_FOUND,
+ VBOXSERVICETOOLBOX_STAT_EXITCODE_INVALID_NAME,
+ /** The usual 32-bit type hack. */
+ VBOXSERVICETOOLBOX_STAT_32BIT_HACK = 0x7fffffff
+} VBOXSERVICETOOLBOX_STAT_EXITCODE;
+
+/**
+ * Input status, reported by the client.
+ */
+enum eInputStatus
+{
+ /** Input is in an undefined state. */
+ INPUT_STS_UNDEFINED = 0,
+ /** Input was written (partially, see cbProcessed). */
+ INPUT_STS_WRITTEN = 1,
+ /** Input failed with an error (see flags for rc). */
+ INPUT_STS_ERROR = 20,
+ /** Process has abandoned / terminated input handling. */
+ INPUT_STS_TERMINATED = 21,
+ /** Too much input data. */
+ INPUT_STS_OVERFLOW = 30
+};
+
+
+
+} /* namespace guestControl */
+
+#endif /* !VBOX_INCLUDED_GuestHost_GuestControl_h */
+
diff --git a/include/VBox/GuestHost/HGCMMock.h b/include/VBox/GuestHost/HGCMMock.h
new file mode 100644
index 00000000..3aabed57
--- /dev/null
+++ b/include/VBox/GuestHost/HGCMMock.h
@@ -0,0 +1,804 @@
+/* $Id: HGCMMock.h $ */
+/** @file
+ * HGCMMock.h: Mocking framework for testing HGCM-based host services +
+ * Vbgl code on the host side.
+ *
+ * Goal is to run host service + Vbgl code as unmodified as
+ * possible as part of testcases to gain test coverage which
+ * otherwise wouldn't possible for heavily user-centric features
+ * like Shared Clipboard or drag'n drop (DnD).
+ */
+
+/*
+ * Copyright (C) 2022 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
+ */
+
+#ifndef VBOX_INCLUDED_GuestHost_HGCMMock_h
+#define VBOX_INCLUDED_GuestHost_HGCMMock_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <iprt/types.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/list.h>
+#include <iprt/mem.h>
+#include <iprt/rand.h>
+#include <iprt/semaphore.h>
+#include <iprt/test.h>
+#include <iprt/time.h>
+#include <iprt/thread.h>
+#include <iprt/utf16.h>
+
+#include <VBox/err.h>
+#include <VBox/VBoxGuestLib.h>
+#include <VBox/hgcmsvc.h>
+
+
+/*********************************************************************************************************************************
+* Definitions. *
+*********************************************************************************************************************************/
+
+#if defined(IN_RING3) /* Only R3 parts implemented so far. */
+
+RT_C_DECLS_BEGIN
+
+DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *ptable);
+
+RT_C_DECLS_END
+
+# define VBGLR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL
+
+/** Simple call handle structure for the guest call completion callback. */
+typedef struct VBOXHGCMCALLHANDLE_TYPEDEF
+{
+ /** Where to store the result code on call completion. */
+ int32_t rc;
+} VBOXHGCMCALLHANDLE_TYPEDEF;
+
+/**
+ * Enumeration for a HGCM mock function type.
+ */
+typedef enum TSTHGCMMOCKFNTYPE
+{
+ TSTHGCMMOCKFNTYPE_NONE = 0,
+ TSTHGCMMOCKFNTYPE_CONNECT,
+ TSTHGCMMOCKFNTYPE_DISCONNECT,
+ TSTHGCMMOCKFNTYPE_CALL,
+ TSTHGCMMOCKFNTYPE_HOST_CALL
+} TSTHGCMMOCKFNTYPE;
+
+/** Pointer to a mock HGCM service. */
+typedef struct TSTHGCMMOCKSVC *PTSTHGCMMOCKSVC;
+
+/**
+ * Structure for mocking a server-side HGCM client.
+ */
+typedef struct TSTHGCMMOCKCLIENT
+{
+ /** Pointer to to mock service instance this client belongs to. */
+ PTSTHGCMMOCKSVC pSvc;
+ /** Assigned HGCM client ID. */
+ uint32_t idClient;
+ /** Opaque pointer to service-specific client data.
+ * Can be NULL if not being used. */
+ void *pvClient;
+ /** Size (in bytes) of \a pvClient. */
+ size_t cbClient;
+ /** The client's current HGCM call handle. */
+ VBOXHGCMCALLHANDLE_TYPEDEF hCall;
+ /** Whether the current client call has an asynchronous
+ * call pending or not. */
+ bool fAsyncExec;
+ /** Event semaphore to signal call completion. */
+ RTSEMEVENT hEvent;
+} TSTHGCMMOCKCLIENT;
+/** Pointer to a mock HGCM client. */
+typedef TSTHGCMMOCKCLIENT *PTSTHGCMMOCKCLIENT;
+
+/**
+ * Structure for keeping HGCM mock function parameters.
+ */
+typedef struct TSTHGCMMOCKFN
+{
+ /** List node for storing this struct into a queue. */
+ RTLISTNODE Node;
+ /** Function type. */
+ TSTHGCMMOCKFNTYPE enmType;
+ /** Pointer to associated client. */
+ PTSTHGCMMOCKCLIENT pClient;
+ /** Union keeping function-specific parameters,
+ * depending on \a enmType. */
+ union
+ {
+ struct
+ {
+ int32_t iFunc;
+ uint32_t cParms;
+ PVBOXHGCMSVCPARM pParms;
+ VBOXHGCMCALLHANDLE hCall;
+ } Call;
+ struct
+ {
+ int32_t iFunc;
+ uint32_t cParms;
+ PVBOXHGCMSVCPARM pParms;
+ } HostCall;
+ } u;
+} TSTHGCMMOCKFN;
+/** Pointer to a HGCM mock function parameters structure. */
+typedef TSTHGCMMOCKFN *PTSTHGCMMOCKFN;
+
+/**
+ * Structure for keeping a HGCM mock service instance.
+ */
+typedef struct TSTHGCMMOCKSVC
+{
+ /** HGCM helper table to use. */
+ VBOXHGCMSVCHELPERS fnHelpers;
+ /** HGCM service function table to use. */
+ VBOXHGCMSVCFNTABLE fnTable;
+ /** Next HGCM client ID to assign.
+ * 0 is considered as being invalid. */
+ HGCMCLIENTID uNextClientId;
+ /** Size (in bytes) of opaque pvClient area to reserve
+ * for a connected client. */
+ size_t cbClient;
+ /** Array of connected HGCM mock clients.
+ * Currently limited to 4 clients maximum. */
+ TSTHGCMMOCKCLIENT aHgcmClient[4];
+ /** Thread handle for the service's main loop. */
+ RTTHREAD hThread;
+ /** Event semaphore for signalling a message
+ * queue change. */
+ RTSEMEVENT hEventQueue;
+ /** Event semaphore for clients connecting to the server. */
+ RTSEMEVENT hEventConnect;
+ /** Number of current host calls being served.
+ * Currently limited to one call at a time. */
+ uint8_t cHostCallers;
+ /** Result code of last returned host call. */
+ int rcHostCall;
+ /** Event semaphore for host calls. */
+ RTSEMEVENT hEventHostCall;
+ /** List (queue) of function calls to process. */
+ RTLISTANCHOR lstCall;
+ /** Shutdown indicator flag. */
+ volatile bool fShutdown;
+} TSTHGCMMOCKSVC;
+
+/** Static HGCM service to mock. */
+static TSTHGCMMOCKSVC s_tstHgcmSvc;
+
+/*********************************************************************************************************************************
+* Prototypes. *
+*********************************************************************************************************************************/
+PTSTHGCMMOCKSVC TstHgcmMockSvcInst(void);
+PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnectEx(PTSTHGCMMOCKSVC pSvc, RTMSINTERVAL msTimeout);
+PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnect(PTSTHGCMMOCKSVC pSvc);
+int TstHgcmMockSvcCreate(PTSTHGCMMOCKSVC pSvc, size_t cbClient);
+int TstHgcmMockSvcDestroy(PTSTHGCMMOCKSVC pSvc);
+int TstHgcmMockSvcStart(PTSTHGCMMOCKSVC pSvc);
+int TstHgcmMockSvcStop(PTSTHGCMMOCKSVC pSvc);
+
+int TstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
+
+VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient);
+VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient);
+VBGLR3DECL(int) VbglR3HGCMCall(PVBGLIOCHGCMCALL pInfo, size_t cbInfo);
+
+
+
+/*********************************************************************************************************************************
+* Internal functions *
+*********************************************************************************************************************************/
+
+/**
+ * Initializes a HGCM mock client.
+ *
+ * @return VBox status code.
+ * @param pClient Client instance to initialize.
+ * @param idClient HGCM client ID to assign.
+ * @param cbClient Size (in bytes) of service-specific (opaque) client data to allocate.
+ */
+static int tstHgcmMockClientInit(PTSTHGCMMOCKCLIENT pClient, uint32_t idClient, size_t cbClient)
+{
+ RT_BZERO(pClient, sizeof(TSTHGCMMOCKCLIENT));
+
+ pClient->idClient = idClient;
+ if (cbClient)
+ {
+ pClient->pvClient = RTMemAllocZ(cbClient);
+ AssertPtrReturn(pClient->pvClient, VERR_NO_MEMORY);
+ pClient->cbClient = cbClient;
+ }
+
+ return RTSemEventCreate(&pClient->hEvent);
+}
+
+/**
+ * Destroys a HGCM mock client.
+ *
+ * @return VBox status code.
+ * @param pClient Client instance to destroy.
+ */
+static int tstHgcmMockClientDestroy(PTSTHGCMMOCKCLIENT pClient)
+{
+ int rc = RTSemEventDestroy(pClient->hEvent);
+ if (RT_SUCCESS(rc))
+ {
+ if (pClient->pvClient)
+ {
+ Assert(pClient->cbClient);
+ RTMemFree(pClient->pvClient);
+ pClient->pvClient = NULL;
+ pClient->cbClient = 0;
+ }
+
+ pClient->hEvent = NIL_RTSEMEVENT;
+ }
+
+ return rc;
+}
+
+/* @copydoc VBOXHGCMSVCFNTABLE::pfnConnect */
+static DECLCALLBACK(int) tstHgcmMockSvcConnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t *pidClient)
+{
+ RT_NOREF(pvService);
+
+ PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
+ AssertPtrReturn(pFn, VERR_NO_MEMORY);
+
+ PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[pSvc->uNextClientId];
+
+ int rc = tstHgcmMockClientInit(pClient, pSvc->uNextClientId, pSvc->cbClient);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ pFn->enmType = TSTHGCMMOCKFNTYPE_CONNECT;
+ pFn->pClient = pClient;
+
+ RTListAppend(&pSvc->lstCall, &pFn->Node);
+ pFn = NULL; /* Thread takes ownership now. */
+
+ int rc2 = RTSemEventSignal(pSvc->hEventQueue);
+ AssertRCReturn(rc2, rc2);
+ rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC);
+ AssertRCReturn(rc2, rc2);
+
+ ASMAtomicIncU32(&pSvc->uNextClientId);
+
+ rc2 = RTSemEventSignal(pSvc->hEventConnect);
+ AssertRCReturn(rc2, rc2);
+
+ *pidClient = pClient->idClient;
+
+ return VINF_SUCCESS;
+}
+
+/* @copydoc VBOXHGCMSVCFNTABLE::pfnDisconnect */
+static DECLCALLBACK(int) tstHgcmMockSvcDisconnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t idClient)
+{
+ RT_NOREF(pvService);
+
+ PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient];
+
+ PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
+ AssertPtrReturn(pFn, VERR_NO_MEMORY);
+
+ pFn->enmType = TSTHGCMMOCKFNTYPE_DISCONNECT;
+ pFn->pClient = pClient;
+
+ RTListAppend(&pSvc->lstCall, &pFn->Node);
+ pFn = NULL; /* Thread takes ownership now. */
+
+ int rc2 = RTSemEventSignal(pSvc->hEventQueue);
+ AssertRCReturn(rc2, rc2);
+
+ rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC);
+ AssertRCReturn(rc2, rc2);
+
+ return tstHgcmMockClientDestroy(pClient);
+}
+
+/* @copydoc VBOXHGCMSVCFNTABLE::pfnCall */
+static DECLCALLBACK(int) tstHgcmMockSvcCall(PTSTHGCMMOCKSVC pSvc, void *pvService, VBOXHGCMCALLHANDLE callHandle, uint32_t idClient, void *pvClient,
+ int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+{
+ RT_NOREF(pvService, pvClient);
+
+ PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient];
+
+ PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
+ AssertPtrReturn(pFn, VERR_NO_MEMORY);
+
+ const size_t cbParms = cParms * sizeof(VBOXHGCMSVCPARM);
+
+ pFn->enmType = TSTHGCMMOCKFNTYPE_CALL;
+ pFn->pClient = pClient;
+
+ pFn->u.Call.hCall = callHandle;
+ pFn->u.Call.iFunc = function;
+ pFn->u.Call.pParms = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cbParms);
+ AssertPtrReturn(pFn->u.Call.pParms, VERR_NO_MEMORY);
+ pFn->u.Call.cParms = cParms;
+
+ RTListAppend(&pSvc->lstCall, &pFn->Node);
+
+ int rc2 = RTSemEventSignal(pSvc->hEventQueue);
+ AssertRCReturn(rc2, rc2);
+
+ rc2 = RTSemEventWait(pClient->hEvent, RT_INDEFINITE_WAIT);
+ AssertRCReturn(rc2, rc2);
+
+ memcpy(paParms, pFn->u.Call.pParms, cbParms);
+
+ return VINF_SUCCESS; /** @todo Return host call rc */
+}
+
+/* @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall */
+/** Note: Public for also being able to test host calls via testcases. */
+int TstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+{
+ RT_NOREF(pvService);
+ AssertReturn(pSvc->cHostCallers == 0, VERR_WRONG_ORDER); /* Only one host call at a time. */
+
+ pSvc->cHostCallers++;
+
+ PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
+ AssertPtrReturn(pFn, VERR_INVALID_POINTER);
+
+ pFn->enmType = TSTHGCMMOCKFNTYPE_HOST_CALL;
+ pFn->u.HostCall.iFunc = function;
+ if (cParms)
+ {
+ pFn->u.HostCall.pParms = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cParms * sizeof(VBOXHGCMSVCPARM));
+ AssertPtrReturn(pFn->u.HostCall.pParms, VERR_NO_MEMORY);
+ pFn->u.HostCall.cParms = cParms;
+ }
+
+ RTListAppend(&pSvc->lstCall, &pFn->Node);
+ pFn = NULL; /* Thread takes ownership now. */
+
+ int rc2 = RTSemEventSignal(pSvc->hEventQueue);
+ AssertRC(rc2);
+
+ rc2 = RTSemEventWait(pSvc->hEventHostCall, RT_INDEFINITE_WAIT);
+ AssertRCReturn(rc2, rc2);
+
+ Assert(pSvc->cHostCallers);
+ pSvc->cHostCallers--;
+
+ return pSvc->rcHostCall;
+}
+
+/**
+ * Call completion callback for guest calls.
+ *
+ * @return VBox status code.
+ * @param callHandle Call handle to complete.
+ * @param rc Return code to return to the caller.
+ */
+static DECLCALLBACK(int) tstHgcmMockSvcCallComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)
+{
+ PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
+
+ size_t i = 0;
+ for (; RT_ELEMENTS(pSvc->aHgcmClient); i++)
+ {
+ PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[i];
+ if (&pClient->hCall == callHandle) /* Slow, but works for now. */
+ {
+ if (rc == VINF_HGCM_ASYNC_EXECUTE)
+ {
+ Assert(pClient->fAsyncExec == false);
+ }
+ else /* Complete call + notify client. */
+ {
+ callHandle->rc = rc;
+
+ int rc2 = RTSemEventSignal(pClient->hEvent);
+ AssertRCReturn(rc2, rc2);
+ }
+
+ return VINF_SUCCESS;
+ }
+ }
+
+ return VERR_NOT_FOUND;
+}
+
+/**
+ * Main thread of HGCM mock service.
+ *
+ * @return VBox status code.
+ * @param hThread Thread handle.
+ * @param pvUser User-supplied data of type PTSTHGCMMOCKSVC.
+ */
+static DECLCALLBACK(int) tstHgcmMockSvcThread(RTTHREAD hThread, void *pvUser)
+{
+ RT_NOREF(hThread);
+ PTSTHGCMMOCKSVC pSvc = (PTSTHGCMMOCKSVC)pvUser;
+
+ pSvc->uNextClientId = 0;
+
+ pSvc->fnTable.cbSize = sizeof(pSvc->fnTable);
+ pSvc->fnTable.u32Version = VBOX_HGCM_SVC_VERSION;
+
+ RT_ZERO(pSvc->fnHelpers);
+ pSvc->fnHelpers.pfnCallComplete = tstHgcmMockSvcCallComplete;
+ pSvc->fnTable.pHelpers = &pSvc->fnHelpers;
+
+ int rc = VBoxHGCMSvcLoad(&pSvc->fnTable);
+ if (RT_SUCCESS(rc))
+ {
+ RTThreadUserSignal(hThread);
+
+ for (;;)
+ {
+ rc = RTSemEventWait(pSvc->hEventQueue, 10 /* ms */);
+ if (ASMAtomicReadBool(&pSvc->fShutdown))
+ {
+ rc = VINF_SUCCESS;
+ break;
+ }
+ if (rc == VERR_TIMEOUT)
+ continue;
+
+ PTSTHGCMMOCKFN pFn = RTListGetFirst(&pSvc->lstCall, TSTHGCMMOCKFN, Node);
+ if (pFn)
+ {
+ switch (pFn->enmType)
+ {
+ case TSTHGCMMOCKFNTYPE_CONNECT:
+ {
+ rc = pSvc->fnTable.pfnConnect(pSvc->fnTable.pvService,
+ pFn->pClient->idClient, pFn->pClient->pvClient,
+ VMMDEV_REQUESTOR_USR_NOT_GIVEN /* fRequestor */, false /* fRestoring */);
+
+ int rc2 = RTSemEventSignal(pFn->pClient->hEvent);
+ AssertRC(rc2);
+ break;
+ }
+
+ case TSTHGCMMOCKFNTYPE_DISCONNECT:
+ {
+ rc = pSvc->fnTable.pfnDisconnect(pSvc->fnTable.pvService,
+ pFn->pClient->idClient, pFn->pClient->pvClient);
+
+ int rc2 = RTSemEventSignal(pFn->pClient->hEvent);
+ AssertRC(rc2);
+ break;
+ }
+
+ case TSTHGCMMOCKFNTYPE_CALL:
+ {
+ pSvc->fnTable.pfnCall(NULL, pFn->u.Call.hCall, pFn->pClient->idClient, pFn->pClient->pvClient,
+ pFn->u.Call.iFunc, pFn->u.Call.cParms, pFn->u.Call.pParms, RTTimeMilliTS());
+
+ /* Note: Call will be completed in the call completion callback. */
+ break;
+ }
+
+ case TSTHGCMMOCKFNTYPE_HOST_CALL:
+ {
+ pSvc->rcHostCall = pSvc->fnTable.pfnHostCall(NULL, pFn->u.HostCall.iFunc, pFn->u.HostCall.cParms, pFn->u.HostCall.pParms);
+
+ int rc2 = RTSemEventSignal(pSvc->hEventHostCall);
+ AssertRC(rc2);
+ break;
+ }
+
+ default:
+ AssertFailed();
+ break;
+ }
+ RTListNodeRemove(&pFn->Node);
+ RTMemFree(pFn);
+ }
+ }
+ }
+
+ return rc;
+}
+
+
+/*********************************************************************************************************************************
+* Public functions *
+*********************************************************************************************************************************/
+
+/**
+ * Returns the pointer to the HGCM mock service instance.
+ *
+ * @return Pointer to HGCM mock service instance.
+ */
+PTSTHGCMMOCKSVC TstHgcmMockSvcInst(void)
+{
+ return &s_tstHgcmSvc;
+}
+
+/**
+ * Waits for a HGCM mock client to connect, extended version.
+ *
+ * @return Pointer to connected client, or NULL if ran into timeout.
+ * @param pSvc HGCM mock service instance.
+ * @param msTimeout Timeout (in ms) to wait for connection.
+ */
+PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnectEx(PTSTHGCMMOCKSVC pSvc, RTMSINTERVAL msTimeout)
+{
+ int rc = RTSemEventWait(pSvc->hEventConnect, msTimeout);
+ if (RT_SUCCESS(rc))
+ {
+ Assert(pSvc->uNextClientId);
+ return &pSvc->aHgcmClient[pSvc->uNextClientId - 1];
+ }
+ return NULL;
+}
+
+/**
+ * Waits for a HGCM mock client to connect.
+ *
+ * @return Pointer to connected client, or NULL if waiting for connection was aborted.
+ * @param pSvc HGCM mock service instance.
+ */
+PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnect(PTSTHGCMMOCKSVC pSvc)
+{
+ return TstHgcmMockSvcWaitForConnectEx(pSvc, RT_MS_30SEC);
+}
+
+/**
+ * Creates a HGCM mock service instance.
+ *
+ * @return VBox status code.
+ * @param pSvc HGCM mock service instance to create.
+ * @param cbClient Size (in bytes) of service-specific client data to
+ * allocate for a HGCM mock client.
+ */
+int TstHgcmMockSvcCreate(PTSTHGCMMOCKSVC pSvc, size_t cbClient)
+{
+ AssertReturn(cbClient, VERR_INVALID_PARAMETER);
+
+ RT_ZERO(pSvc->aHgcmClient);
+ pSvc->fShutdown = false;
+ int rc = RTSemEventCreate(&pSvc->hEventQueue);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemEventCreate(&pSvc->hEventHostCall);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemEventCreate(&pSvc->hEventConnect);
+ if (RT_SUCCESS(rc))
+ {
+ RTListInit(&pSvc->lstCall);
+
+ pSvc->cbClient = cbClient;
+ }
+ }
+ }
+
+ return rc;
+}
+
+/**
+ * Destroys a HGCM mock service instance.
+ *
+ * @return VBox status code.
+ * @param pSvc HGCM mock service instance to destroy.
+ */
+int TstHgcmMockSvcDestroy(PTSTHGCMMOCKSVC pSvc)
+{
+ int rc = RTSemEventDestroy(pSvc->hEventQueue);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemEventDestroy(pSvc->hEventHostCall);
+ if (RT_SUCCESS(rc))
+ RTSemEventDestroy(pSvc->hEventConnect);
+ }
+ return rc;
+}
+
+/**
+ * Starts a HGCM mock service instance.
+ *
+ * @return VBox status code.
+ * @param pSvc HGCM mock service instance to start.
+ */
+int TstHgcmMockSvcStart(PTSTHGCMMOCKSVC pSvc)
+{
+ int rc = RTThreadCreate(&pSvc->hThread, tstHgcmMockSvcThread, pSvc, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
+ "MockSvc");
+ if (RT_SUCCESS(rc))
+ rc = RTThreadUserWait(pSvc->hThread, RT_MS_30SEC);
+
+ return rc;
+}
+
+/**
+ * Stops a HGCM mock service instance.
+ *
+ * @return VBox status code.
+ * @param pSvc HGCM mock service instance to stop.
+ */
+int TstHgcmMockSvcStop(PTSTHGCMMOCKSVC pSvc)
+{
+ ASMAtomicWriteBool(&pSvc->fShutdown, true);
+
+ int rcThread;
+ int rc = RTThreadWait(pSvc->hThread, RT_MS_30SEC, &rcThread);
+ if (RT_SUCCESS(rc))
+ rc = rcThread;
+ if (RT_SUCCESS(rc))
+ {
+ pSvc->hThread = NIL_RTTHREAD;
+ }
+
+ return rc;
+}
+
+
+/*********************************************************************************************************************************
+* VbglR3 stubs *
+*********************************************************************************************************************************/
+
+/**
+ * Connects to an HGCM mock service.
+ *
+ * @returns VBox status code
+ * @param pszServiceName Name of the host service.
+ * @param pidClient Where to put the client ID on success. The client ID
+ * must be passed to all the other calls to the service.
+ */
+VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient)
+{
+ RT_NOREF(pszServiceName);
+
+ PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
+
+ return tstHgcmMockSvcConnect(pSvc, pSvc->fnTable.pvService, pidClient);
+}
+
+/**
+ * Disconnect from an HGCM mock service.
+ *
+ * @returns VBox status code.
+ * @param idClient The client id returned by VbglR3HGCMConnect().
+ */
+VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient)
+{
+ PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
+
+ return tstHgcmMockSvcDisconnect(pSvc, pSvc->fnTable.pvService, idClient);
+}
+
+/**
+ * Makes a fully prepared HGCM call to an HGCM mock service.
+ *
+ * @returns VBox status code.
+ * @param pInfo Fully prepared HGCM call info.
+ * @param cbInfo Size of the info. This may sometimes be larger than
+ * what the parameter count indicates because of
+ * parameter changes between versions and such.
+ */
+VBGLR3DECL(int) VbglR3HGCMCall(PVBGLIOCHGCMCALL pInfo, size_t cbInfo)
+{
+ RT_NOREF(cbInfo);
+
+ AssertMsg(pInfo->Hdr.cbIn == cbInfo, ("cbIn=%#x cbInfo=%#zx\n", pInfo->Hdr.cbIn, cbInfo));
+ AssertMsg(pInfo->Hdr.cbOut == cbInfo, ("cbOut=%#x cbInfo=%#zx\n", pInfo->Hdr.cbOut, cbInfo));
+ Assert(sizeof(*pInfo) + pInfo->cParms * sizeof(HGCMFunctionParameter) <= cbInfo);
+
+ HGCMFunctionParameter *offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo);
+ PVBOXHGCMSVCPARM paDstParms = (PVBOXHGCMSVCPARM)RTMemAlloc(pInfo->cParms * sizeof(VBOXHGCMSVCPARM));
+
+ uint16_t i = 0;
+ for (; i < pInfo->cParms; i++)
+ {
+ switch (offSrcParms->type)
+ {
+ case VMMDevHGCMParmType_32bit:
+ {
+ paDstParms[i].type = VBOX_HGCM_SVC_PARM_32BIT;
+ paDstParms[i].u.uint32 = offSrcParms->u.value32;
+ break;
+ }
+
+ case VMMDevHGCMParmType_64bit:
+ {
+ paDstParms[i].type = VBOX_HGCM_SVC_PARM_64BIT;
+ paDstParms[i].u.uint64 = offSrcParms->u.value64;
+ break;
+ }
+
+ case VMMDevHGCMParmType_LinAddr:
+ {
+ paDstParms[i].type = VBOX_HGCM_SVC_PARM_PTR;
+ paDstParms[i].u.pointer.addr = (void *)offSrcParms->u.LinAddr.uAddr;
+ paDstParms[i].u.pointer.size = offSrcParms->u.LinAddr.cb;
+ break;
+ }
+
+ default:
+ AssertFailed();
+ break;
+ }
+
+ offSrcParms++;
+ }
+
+ PTSTHGCMMOCKSVC const pSvc = TstHgcmMockSvcInst();
+
+ int rc2 = tstHgcmMockSvcCall(pSvc, pSvc->fnTable.pvService, &pSvc->aHgcmClient[pInfo->u32ClientID].hCall,
+ pInfo->u32ClientID, pSvc->aHgcmClient[pInfo->u32ClientID].pvClient,
+ pInfo->u32Function, pInfo->cParms, paDstParms);
+ if (RT_SUCCESS(rc2))
+ {
+ offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo);
+
+ for (i = 0; i < pInfo->cParms; i++)
+ {
+ paDstParms[i].type = offSrcParms->type;
+ switch (paDstParms[i].type)
+ {
+ case VMMDevHGCMParmType_32bit:
+ offSrcParms->u.value32 = paDstParms[i].u.uint32;
+ break;
+
+ case VMMDevHGCMParmType_64bit:
+ offSrcParms->u.value64 = paDstParms[i].u.uint64;
+ break;
+
+ case VMMDevHGCMParmType_LinAddr:
+ {
+ offSrcParms->u.LinAddr.cb = paDstParms[i].u.pointer.size;
+ break;
+ }
+
+ default:
+ AssertFailed();
+ break;
+ }
+
+ offSrcParms++;
+ }
+ }
+
+ RTMemFree(paDstParms);
+
+ if (RT_SUCCESS(rc2))
+ rc2 = pSvc->aHgcmClient[pInfo->u32ClientID].hCall.rc;
+
+ return rc2;
+}
+
+#endif /* IN_RING3 */
+
+#endif /* !VBOX_INCLUDED_GuestHost_HGCMMock_h */
diff --git a/include/VBox/GuestHost/HGCMMockUtils.h b/include/VBox/GuestHost/HGCMMockUtils.h
new file mode 100644
index 00000000..8eb9f943
--- /dev/null
+++ b/include/VBox/GuestHost/HGCMMockUtils.h
@@ -0,0 +1,428 @@
+/* $Id */
+/** @file
+ * HGCMMockUtils.h: Utility functions for the HGCM Mocking framework.
+ *
+ * The utility functions are optional to the actual HGCM Mocking framework and
+ * can support testcases which require a more advanced setup.
+ *
+ * With this one can setup host and guest side threads, which in turn can simulate
+ * specific host (i.e. HGCM service) + guest (i.e. like in the Guest Addditions
+ * via VbglR3) scenarios.
+ *
+ * Glossary:
+ *
+ * Host thread:
+ * - The host thread is used as part of the actual HGCM service being tested and
+ * provides callbacks (@see TSTHGCMUTILSHOSTCALLBACKS) for the unit test.
+ * Guest thread:
+ * - The guest thread is used as part of the guest side and mimics
+ * VBoxClient / VBoxTray / VBoxService parts. (i.e. for VbglR3 calls).
+ * Task:
+ * - A task is the simplest unit of test execution and used between the guest
+ * and host mocking threads.
+ *
+ ** @todo Add TstHGCMSimpleHost / TstHGCMSimpleGuest wrappers along those lines:
+ * Callback.pfnOnClientConnected = tstOnHostClientConnected()
+ * TstHGCMSimpleHostInitAndStart(&Callback)
+ * Callback.pfnOnConnected = tstOnGuestConnected()
+ * TstHGCMSimpleClientInitAndStart(&Callback)
+ */
+
+/*
+ * Copyright (C) 2022 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
+ */
+
+#ifndef VBOX_INCLUDED_GuestHost_HGCMMockUtils_h
+#define VBOX_INCLUDED_GuestHost_HGCMMockUtils_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <iprt/err.h>
+#include <iprt/semaphore.h>
+#include <iprt/thread.h>
+#include <iprt/types.h>
+
+
+#include <VBox/GuestHost/HGCMMock.h>
+#include <VBox/VBoxGuestLib.h>
+
+
+#if defined(IN_RING3) /* Only R3 parts implemented so far. */
+
+/** Pointer to a HGCM Mock utils context. */
+typedef struct TSTHGCMUTILSCTX *PTSTHGCMUTILSCTX;
+
+/**
+ * Structure for keeping a HGCM Mock utils host service callback table.
+ */
+typedef struct TSTHGCMUTILSHOSTCALLBACKS
+{
+ DECLCALLBACKMEMBER(int, pfnOnClientConnected,(PTSTHGCMUTILSCTX pCtx, PTSTHGCMMOCKCLIENT pClient, void *pvUser));
+} TSTHGCMUTILSHOSTCALLBACKS;
+/** Pointer to a HGCM Mock utils host callbacks table. */
+typedef TSTHGCMUTILSHOSTCALLBACKS *PTSTHGCMUTILSHOSTCALLBACKS;
+
+/**
+ * Structure for keeping a generic HGCM Mock utils task.
+ *
+ * A task is a single test unit / entity.
+ */
+typedef struct TSTHGCMUTILSTASK
+{
+ /** Completion event. */
+ RTSEMEVENT hEvent;
+ /** Completion rc.
+ * Set to VERR_IPE_UNINITIALIZED_STATUS if not completed yet. */
+ int rcCompleted;
+ /** Expected completion rc. */
+ int rcExpected;
+ /** Pointer to opaque (testcase-specific) task parameters.
+ * Might be NULL if not needed / used. */
+ void *pvUser;
+} TSTHGCMUTILSTASK;
+/** Pointer to a HGCM Mock utils task. */
+typedef TSTHGCMUTILSTASK *PTSTHGCMUTILSTASK;
+
+/** Callback function for HGCM Mock utils threads. */
+typedef DECLCALLBACKTYPE(int, FNTSTHGCMUTILSTHREAD,(PTSTHGCMUTILSCTX pCtx, void *pvUser));
+/** Pointer to a HGCM Mock utils guest thread callback. */
+typedef FNTSTHGCMUTILSTHREAD *PFNTSTHGCMUTILSTHREAD;
+
+/**
+ * Structure for keeping a HGCM Mock utils context.
+ */
+typedef struct TSTHGCMUTILSCTX
+{
+ /** Pointer to the HGCM Mock service instance to use. */
+ PTSTHGCMMOCKSVC pSvc;
+ /** Currently we only support one task at a time. */
+ TSTHGCMUTILSTASK Task;
+ struct
+ {
+ RTTHREAD hThread;
+ volatile bool fShutdown;
+ PFNTSTHGCMUTILSTHREAD pfnThread;
+ void *pvUser;
+ } Guest;
+ struct
+ {
+ RTTHREAD hThread;
+ volatile bool fShutdown;
+ TSTHGCMUTILSHOSTCALLBACKS Callbacks;
+ void *pvUser;
+ } Host;
+} TSTHGCMUTILSCTX;
+
+
+/*********************************************************************************************************************************
+* Prototypes. *
+*********************************************************************************************************************************/
+/** @name Context handling.
+ * @{ */
+void TstHGCMUtilsCtxInit(PTSTHGCMUTILSCTX pCtx, PTSTHGCMMOCKSVC pSvc);
+/** @} */
+
+/** @name Task handling.
+ * @{ */
+PTSTHGCMUTILSTASK TstHGCMUtilsTaskGetCurrent(PTSTHGCMUTILSCTX pCtx);
+int TstHGCMUtilsTaskInit(PTSTHGCMUTILSTASK pTask);
+void TstHGCMUtilsTaskDestroy(PTSTHGCMUTILSTASK pTask);
+int TstHGCMUtilsTaskWait(PTSTHGCMUTILSTASK pTask, RTMSINTERVAL msTimeout);
+bool TstHGCMUtilsTaskOk(PTSTHGCMUTILSTASK pTask);
+bool TstHGCMUtilsTaskCompleted(PTSTHGCMUTILSTASK pTask);
+void TstHGCMUtilsTaskSignal(PTSTHGCMUTILSTASK pTask, int rc);
+/** @} */
+
+/** @name Threading.
+ * @{ */
+int TstHGCMUtilsGuestThreadStart(PTSTHGCMUTILSCTX pCtx, PFNTSTHGCMUTILSTHREAD pFnThread, void *pvUser);
+int TstHGCMUtilsGuestThreadStop(PTSTHGCMUTILSCTX pCtx);
+int TstHGCMUtilsHostThreadStart(PTSTHGCMUTILSCTX pCtx, PTSTHGCMUTILSHOSTCALLBACKS pCallbacks, void *pvUser);
+int TstHGCMUtilsHostThreadStop(PTSTHGCMUTILSCTX pCtx);
+/** @} */
+
+
+/*********************************************************************************************************************************
+ * Context *
+ ********************************************************************************************************************************/
+/**
+ * Initializes a HGCM Mock utils context.
+ *
+ * @param pCtx Context to intiialize.
+ * @param pSvc HGCM Mock service instance to use.
+ */
+void TstHGCMUtilsCtxInit(PTSTHGCMUTILSCTX pCtx, PTSTHGCMMOCKSVC pSvc)
+{
+ RT_BZERO(pCtx, sizeof(TSTHGCMUTILSCTX));
+
+ pCtx->pSvc = pSvc;
+}
+
+
+/*********************************************************************************************************************************
+ * Tasks *
+ ********************************************************************************************************************************/
+/**
+ * Returns the current task of a HGCM Mock utils context.
+ *
+ * @returns Current task of a HGCM Mock utils context. NULL if no current task found.
+ * @param pCtx HGCM Mock utils context.
+ */
+PTSTHGCMUTILSTASK TstHGCMUtilsTaskGetCurrent(PTSTHGCMUTILSCTX pCtx)
+{
+ /* Currently we only support one task at a time. */
+ return &pCtx->Task;
+}
+
+/**
+ * Initializes a HGCM Mock utils task.
+ *
+ * @returns VBox status code.
+ * @param pTask Task to initialize.
+ */
+int TstHGCMUtilsTaskInit(PTSTHGCMUTILSTASK pTask)
+{
+ pTask->pvUser = NULL;
+ pTask->rcCompleted = pTask->rcExpected = VERR_IPE_UNINITIALIZED_STATUS;
+ return RTSemEventCreate(&pTask->hEvent);
+}
+
+/**
+ * Destroys a HGCM Mock utils task.
+ *
+ * @returns VBox status code.
+ * @param pTask Task to destroy.
+ */
+void TstHGCMUtilsTaskDestroy(PTSTHGCMUTILSTASK pTask)
+{
+ RTSemEventDestroy(pTask->hEvent);
+}
+
+/**
+ * Waits for a HGCM Mock utils task to complete.
+ *
+ * @returns VBox status code.
+ * @param pTask Task to wait for.
+ * @param msTimeout Timeout (in ms) to wait.
+ */
+int TstHGCMUtilsTaskWait(PTSTHGCMUTILSTASK pTask, RTMSINTERVAL msTimeout)
+{
+ return RTSemEventWait(pTask->hEvent, msTimeout);
+}
+
+/**
+ * Returns if the HGCM Mock utils task has been completed successfully.
+ *
+ * @returns \c true if successful, \c false if not.
+ * @param pTask Task to check.
+ */
+bool TstHGCMUtilsTaskOk(PTSTHGCMUTILSTASK pTask)
+{
+ return pTask->rcCompleted == pTask->rcExpected;
+}
+
+/**
+ * Returns if the HGCM Mock utils task has been completed (failed or succeeded).
+ *
+ * @returns \c true if completed, \c false if (still) running.
+ * @param pTask Task to check.
+ */
+bool TstHGCMUtilsTaskCompleted(PTSTHGCMUTILSTASK pTask)
+{
+ return pTask->rcCompleted != VERR_IPE_UNINITIALIZED_STATUS;
+}
+
+/**
+ * Signals a HGCM Mock utils task to complete its operation.
+ *
+ * @param pTask Task to complete.
+ * @param rc Task result to set for completion.
+ */
+void TstHGCMUtilsTaskSignal(PTSTHGCMUTILSTASK pTask, int rc)
+{
+ AssertMsg(pTask->rcCompleted == VERR_IPE_UNINITIALIZED_STATUS, ("Task already completed\n"));
+ pTask->rcCompleted = rc;
+ int rc2 = RTSemEventSignal(pTask->hEvent);
+ AssertRC(rc2);
+}
+
+
+/*********************************************************************************************************************************
+ * Threading *
+ ********************************************************************************************************************************/
+
+/**
+ * Thread worker for the guest side thread.
+ *
+ * @returns VBox status code.
+ * @param hThread Thread handle.
+ * @param pvUser Pointer of type PTSTHGCMUTILSCTX.
+ *
+ * @note Runs in the guest thread.
+ */
+static DECLCALLBACK(int) tstHGCMUtilsGuestThread(RTTHREAD hThread, void *pvUser)
+{
+ RT_NOREF(hThread);
+ PTSTHGCMUTILSCTX pCtx = (PTSTHGCMUTILSCTX)pvUser;
+ AssertPtr(pCtx);
+
+ RTThreadUserSignal(hThread);
+
+ if (pCtx->Guest.pfnThread)
+ return pCtx->Guest.pfnThread(pCtx, pCtx->Guest.pvUser);
+
+ return VINF_SUCCESS;
+}
+
+/**
+ * Starts the guest side thread.
+ *
+ * @returns VBox status code.
+ * @param pCtx HGCM Mock utils context to start guest thread for.
+ * @param pFnThread Pointer to custom thread worker function to call within the guest side thread.
+ * @param pvUser User-supplied pointer to guest thread context data. Optional and can be NULL.
+ */
+int TstHGCMUtilsGuestThreadStart(PTSTHGCMUTILSCTX pCtx, PFNTSTHGCMUTILSTHREAD pFnThread, void *pvUser)
+{
+ pCtx->Guest.pfnThread = pFnThread;
+ pCtx->Guest.pvUser = pvUser;
+
+ int rc = RTThreadCreate(&pCtx->Guest.hThread, tstHGCMUtilsGuestThread, pCtx, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
+ "tstShClGst");
+ if (RT_SUCCESS(rc))
+ rc = RTThreadUserWait(pCtx->Guest.hThread, RT_MS_30SEC);
+
+ return rc;
+}
+
+/**
+ * Stops the guest side thread.
+ *
+ * @returns VBox status code.
+ * @param pCtx HGCM Mock utils context to stop guest thread for.
+ */
+int TstHGCMUtilsGuestThreadStop(PTSTHGCMUTILSCTX pCtx)
+{
+ ASMAtomicWriteBool(&pCtx->Guest.fShutdown, true);
+
+ int rcThread;
+ int rc = RTThreadWait(pCtx->Guest.hThread, RT_MS_30SEC, &rcThread);
+ if (RT_SUCCESS(rc))
+ rc = rcThread;
+ if (RT_SUCCESS(rc))
+ pCtx->Guest.hThread = NIL_RTTHREAD;
+
+ return rc;
+}
+
+/**
+ * Thread worker function for the host side HGCM service.
+ *
+ * @returns VBox status code.
+ * @param hThread Thread handle.
+ * @param pvUser Pointer of type PTSTHGCMUTILSCTX.
+ *
+ * @note Runs in the host service thread.
+ */
+static DECLCALLBACK(int) tstHGCMUtilsHostThreadWorker(RTTHREAD hThread, void *pvUser)
+{
+ RT_NOREF(hThread);
+ PTSTHGCMUTILSCTX pCtx = (PTSTHGCMUTILSCTX)pvUser;
+ AssertPtr(pCtx);
+
+ int rc = VINF_SUCCESS;
+
+ RTThreadUserSignal(hThread);
+
+ PTSTHGCMMOCKSVC const pSvc = TstHgcmMockSvcInst();
+
+ for (;;)
+ {
+ if (ASMAtomicReadBool(&pCtx->Host.fShutdown))
+ break;
+
+ /* Wait for a new (mock) HGCM client to connect. */
+ PTSTHGCMMOCKCLIENT pMockClient = TstHgcmMockSvcWaitForConnectEx(pSvc, 100 /* ms */);
+ if (pMockClient) /* Might be NULL when timed out. */
+ {
+ if (pCtx->Host.Callbacks.pfnOnClientConnected)
+ /* ignore rc */ pCtx->Host.Callbacks.pfnOnClientConnected(pCtx, pMockClient, pCtx->Host.pvUser);
+ }
+ }
+
+ return rc;
+}
+
+/**
+ * Starts the host side thread.
+ *
+ * @returns VBox status code.
+ * @param pCtx HGCM Mock utils context to start host thread for.
+ * @param pCallbacks Pointer to host callback table to use.
+ * @param pvUser User-supplied pointer to reach into the host thread callbacks.
+ */
+int TstHGCMUtilsHostThreadStart(PTSTHGCMUTILSCTX pCtx, PTSTHGCMUTILSHOSTCALLBACKS pCallbacks, void *pvUser)
+{
+ memcpy(&pCtx->Host.Callbacks, pCallbacks, sizeof(TSTHGCMUTILSHOSTCALLBACKS));
+ pCtx->Host.pvUser = pvUser;
+
+ int rc = RTThreadCreate(&pCtx->Host.hThread, tstHGCMUtilsHostThreadWorker, pCtx, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
+ "tstShClHst");
+ if (RT_SUCCESS(rc))
+ rc = RTThreadUserWait(pCtx->Host.hThread, RT_MS_30SEC);
+
+ return rc;
+}
+
+/**
+ * Stops the host side thread.
+ *
+ * @returns VBox status code.
+ * @param pCtx HGCM Mock utils context to stop host thread for.
+ */
+int TstHGCMUtilsHostThreadStop(PTSTHGCMUTILSCTX pCtx)
+{
+ ASMAtomicWriteBool(&pCtx->Host.fShutdown, true);
+
+ int rcThread;
+ int rc = RTThreadWait(pCtx->Host.hThread, RT_MS_30SEC, &rcThread);
+ if (RT_SUCCESS(rc))
+ rc = rcThread;
+ if (RT_SUCCESS(rc))
+ pCtx->Host.hThread = NIL_RTTHREAD;
+
+ return rc;
+}
+
+#endif /* IN_RING3 */
+
+#endif /* !VBOX_INCLUDED_GuestHost_HGCMMockUtils_h */
+
diff --git a/include/VBox/GuestHost/Makefile.kup b/include/VBox/GuestHost/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/include/VBox/GuestHost/Makefile.kup
diff --git a/include/VBox/GuestHost/SharedClipboard-transfers.h b/include/VBox/GuestHost/SharedClipboard-transfers.h
new file mode 100644
index 00000000..32e5b814
--- /dev/null
+++ b/include/VBox/GuestHost/SharedClipboard-transfers.h
@@ -0,0 +1,993 @@
+/* $Id: SharedClipboard-transfers.h $ */
+/** @file
+ * Shared Clipboard - Shared transfer functions between host and guest.
+ */
+
+/*
+ * Copyright (C) 2019-2022 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
+ */
+
+#ifndef VBOX_INCLUDED_GuestHost_SharedClipboard_transfers_h
+#define VBOX_INCLUDED_GuestHost_SharedClipboard_transfers_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <map>
+
+#include <iprt/assert.h>
+#include <iprt/critsect.h>
+#include <iprt/fs.h>
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
+# include <iprt/http-server.h>
+#endif
+#include <iprt/list.h>
+
+#include <iprt/cpp/list.h>
+#include <iprt/cpp/ministring.h>
+
+#include <VBox/GuestHost/SharedClipboard.h>
+#include <VBox/HostServices/VBoxClipboardSvc.h>
+
+
+struct SHCLTRANSFER;
+/** Pointer to a single shared clipboard transfer */
+typedef struct SHCLTRANSFER *PSHCLTRANSFER;
+
+
+/** @name Shared Clipboard transfer definitions.
+ * @{
+ */
+
+/** Defines the maximum length (in chars) a Shared Clipboard transfer path can have. */
+#define SHCL_TRANSFER_PATH_MAX RTPATH_MAX
+
+/**
+ * Defines the transfer status codes.
+ */
+typedef enum
+{
+ /** No status set. */
+ SHCLTRANSFERSTATUS_NONE = 0,
+ /** The transfer has been initialized but is not running yet. */
+ SHCLTRANSFERSTATUS_INITIALIZED,
+ /** The transfer is active and running. */
+ SHCLTRANSFERSTATUS_STARTED,
+ /** The transfer has been stopped. */
+ SHCLTRANSFERSTATUS_STOPPED,
+ /** The transfer has been canceled. */
+ SHCLTRANSFERSTATUS_CANCELED,
+ /** The transfer has been killed. */
+ SHCLTRANSFERSTATUS_KILLED,
+ /** The transfer ran into an unrecoverable error. */
+ SHCLTRANSFERSTATUS_ERROR,
+ /** The usual 32-bit hack. */
+ SHCLTRANSFERSTATUS_32BIT_SIZE_HACK = 0x7fffffff
+} SHCLTRANSFERSTATUSENUM;
+
+/** Defines a transfer status. */
+typedef uint32_t SHCLTRANSFERSTATUS;
+
+/** @} */
+
+/** @name Shared Clipboard handles.
+ * @{
+ */
+
+/** A Shared Clipboard list handle. */
+typedef uint64_t SHCLLISTHANDLE;
+/** Pointer to a Shared Clipboard list handle. */
+typedef SHCLLISTHANDLE *PSHCLLISTHANDLE;
+/** Specifies an invalid Shared Clipboard list handle.
+ * @todo r=bird: The convention is NIL_SHCLLISTHANDLE. */
+#define SHCLLISTHANDLE_INVALID ((SHCLLISTHANDLE)UINT64_MAX)
+
+/** A Shared Clipboard object handle. */
+typedef uint64_t SHCLOBJHANDLE;
+/** Pointer to a Shared Clipboard object handle. */
+typedef SHCLOBJHANDLE *PSHCLOBJHANDLE;
+/** Specifies an invalid Shared Clipboard object handle.
+ * @todo r=bird: The convention is NIL_SHCLOBJHANDLE. */
+#define SHCLOBJHANDLE_INVALID ((SHCLOBJHANDLE)UINT64_MAX)
+
+/** @} */
+
+/** @name Shared Clipboard open/create flags.
+ * @{
+ */
+/** No flags. Initialization value. */
+#define SHCL_OBJ_CF_NONE UINT32_C(0x00000000)
+
+#if 0 /* These probably won't be needed either */
+/** Lookup only the object, do not return a handle. All other flags are ignored. */
+#define SHCL_OBJ_CF_LOOKUP UINT32_C(0x00000001)
+/** Create/open a directory. */
+#define SHCL_OBJ_CF_DIRECTORY UINT32_C(0x00000004)
+#endif
+
+/** Read/write requested access for the object. */
+#define SHCL_OBJ_CF_ACCESS_MASK_RW UINT32_C(0x00001000)
+/** No access requested. */
+#define SHCL_OBJ_CF_ACCESS_NONE UINT32_C(0x00000000)
+/** Read access requested. */
+#define SHCL_OBJ_CF_ACCESS_READ UINT32_C(0x00001000)
+
+/** Requested share access for the object. */
+#define SHCL_OBJ_CF_ACCESS_MASK_DENY UINT32_C(0x00008000)
+/** Allow any access. */
+#define SHCL_OBJ_CF_ACCESS_DENYNONE UINT32_C(0x00000000)
+/** Do not allow write. */
+#define SHCL_OBJ_CF_ACCESS_DENYWRITE UINT32_C(0x00008000)
+
+/** Requested access to attributes of the object. */
+#define SHCL_OBJ_CF_ACCESS_MASK_ATTR UINT32_C(0x00010000)
+/** No access requested. */
+#define SHCL_OBJ_CF_ACCESS_ATTR_NONE UINT32_C(0x00000000)
+/** Read access requested. */
+#define SHCL_OBJ_CF_ACCESS_ATTR_READ UINT32_C(0x00010000)
+
+/** Valid bits. */
+#define SHCL_OBJ_CF_VALID_MASK UINT32_C(0x00019000)
+/** @} */
+
+/**
+ * The available additional information in a SHCLFSOBJATTR object.
+ * @sa RTFSOBJATTRADD
+ */
+typedef enum _SHCLFSOBJATTRADD
+{
+ /** No additional information is available / requested. */
+ SHCLFSOBJATTRADD_NOTHING = 1,
+ /** The additional unix attributes (SHCLFSOBJATTR::u::Unix) are
+ * available / requested. */
+ SHCLFSOBJATTRADD_UNIX,
+ /** The additional extended attribute size (SHCLFSOBJATTR::u::EASize) is
+ * available / requested. */
+ SHCLFSOBJATTRADD_EASIZE,
+ /** The last valid item (inclusive).
+ * The valid range is SHCLFSOBJATTRADD_NOTHING thru
+ * SHCLFSOBJATTRADD_LAST. */
+ SHCLFSOBJATTRADD_LAST = SHCLFSOBJATTRADD_EASIZE,
+ /** The usual 32-bit hack. */
+ SHCLFSOBJATTRADD_32BIT_SIZE_HACK = 0x7fffffff
+} SHCLFSOBJATTRADD;
+
+
+/* Assert sizes of the IRPT types we're using below. */
+AssertCompileSize(RTFMODE, 4);
+AssertCompileSize(RTFOFF, 8);
+AssertCompileSize(RTINODE, 8);
+AssertCompileSize(RTTIMESPEC, 8);
+AssertCompileSize(RTDEV, 4);
+AssertCompileSize(RTUID, 4);
+
+/**
+ * Shared Clipboard filesystem object attributes.
+ *
+ * @sa RTFSOBJATTR
+ */
+typedef struct _SHCLFSOBJATTR
+{
+ /** Mode flags (st_mode). RTFS_UNIX_*, RTFS_TYPE_*, and RTFS_DOS_*.
+ * @remarks We depend on a number of RTFS_ defines to remain unchanged.
+ * Fortuntately, these are depending on windows, dos and unix
+ * standard values, so this shouldn't be much of a pain. */
+ RTFMODE fMode;
+
+ /** The additional attributes available. */
+ SHCLFSOBJATTRADD enmAdditional;
+
+ /**
+ * Additional attributes.
+ *
+ * Unless explicitly specified to an API, the API can provide additional
+ * data as it is provided by the underlying OS.
+ */
+ union SHCLFSOBJATTRUNION
+ {
+ /** Additional Unix Attributes
+ * These are available when SHCLFSOBJATTRADD is set in fUnix.
+ */
+ struct SHCLFSOBJATTRUNIX
+ {
+ /** The user owning the filesystem object (st_uid).
+ * This field is ~0U if not supported. */
+ RTUID uid;
+
+ /** The group the filesystem object is assigned (st_gid).
+ * This field is ~0U if not supported. */
+ RTGID gid;
+
+ /** Number of hard links to this filesystem object (st_nlink).
+ * This field is 1 if the filesystem doesn't support hardlinking or
+ * the information isn't available.
+ */
+ uint32_t cHardlinks;
+
+ /** The device number of the device which this filesystem object resides on (st_dev).
+ * This field is 0 if this information is not available. */
+ RTDEV INodeIdDevice;
+
+ /** The unique identifier (within the filesystem) of this filesystem object (st_ino).
+ * Together with INodeIdDevice, this field can be used as a OS wide unique id
+ * when both their values are not 0.
+ * This field is 0 if the information is not available. */
+ RTINODE INodeId;
+
+ /** User flags (st_flags).
+ * This field is 0 if this information is not available. */
+ uint32_t fFlags;
+
+ /** The current generation number (st_gen).
+ * This field is 0 if this information is not available. */
+ uint32_t GenerationId;
+
+ /** The device number of a character or block device type object (st_rdev).
+ * This field is 0 if the file isn't of a character or block device type and
+ * when the OS doesn't subscribe to the major+minor device idenfication scheme. */
+ RTDEV Device;
+ } Unix;
+
+ /**
+ * Extended attribute size.
+ */
+ struct SHCLFSOBJATTREASIZE
+ {
+ /** Size of EAs. */
+ RTFOFF cb;
+ } EASize;
+
+ /** Padding the structure to a multiple of 8 bytes. */
+ uint64_t au64Padding[5];
+ } u;
+} SHCLFSOBJATTR;
+AssertCompileSize(SHCLFSOBJATTR, 48);
+/** Pointer to a Shared Clipboard filesystem object attributes structure. */
+typedef SHCLFSOBJATTR *PSHCLFSOBJATTR;
+/** Pointer to a const Shared Clipboard filesystem object attributes structure. */
+typedef const SHCLFSOBJATTR *PCSHCLFSOBJATTR;
+
+/**
+ * Shared Clipboard file system object information structure.
+ *
+ * @sa RTFSOBJINFO
+ */
+typedef struct _SHCLFSOBJINFO
+{
+ /** Logical size (st_size).
+ * For normal files this is the size of the file.
+ * For symbolic links, this is the length of the path name contained
+ * in the symbolic link.
+ * For other objects this fields needs to be specified.
+ */
+ RTFOFF cbObject;
+
+ /** Disk allocation size (st_blocks * DEV_BSIZE). */
+ RTFOFF cbAllocated;
+
+ /** Time of last access (st_atime).
+ * @remarks Here (and other places) we depend on the IPRT timespec to
+ * remain unchanged. */
+ RTTIMESPEC AccessTime;
+
+ /** Time of last data modification (st_mtime). */
+ RTTIMESPEC ModificationTime;
+
+ /** Time of last status change (st_ctime).
+ * If not available this is set to ModificationTime.
+ */
+ RTTIMESPEC ChangeTime;
+
+ /** Time of file birth (st_birthtime).
+ * If not available this is set to ChangeTime.
+ */
+ RTTIMESPEC BirthTime;
+
+ /** Attributes. */
+ SHCLFSOBJATTR Attr;
+
+} SHCLFSOBJINFO;
+AssertCompileSize(SHCLFSOBJINFO, 96);
+/** Pointer to a Shared Clipboard filesystem object information structure. */
+typedef SHCLFSOBJINFO *PSHCLFSOBJINFO;
+/** Pointer to a const Shared Clipboard filesystem object information
+ * structure. */
+typedef const SHCLFSOBJINFO *PCSHCLFSOBJINFO;
+
+/**
+ * Structure for keeping object open/create parameters.
+ */
+typedef struct _SHCLOBJOPENCREATEPARMS
+{
+ /** Path to object to open / create. */
+ char *pszPath;
+ /** Size (in bytes) of path to to object. */
+ uint32_t cbPath;
+ /** SHCL_OBJ_CF_* */
+ uint32_t fCreate;
+ /**
+ * Attributes of object to open/create and
+ * returned actual attributes of opened/created object.
+ */
+ SHCLFSOBJINFO ObjInfo;
+} SHCLOBJOPENCREATEPARMS, *PSHCLOBJOPENCREATEPARMS;
+
+/**
+ * Structure for keeping a reply message.
+ */
+typedef struct _SHCLREPLY
+{
+ /** Message type of type VBOX_SHCL_REPLYMSGTYPE_XXX. */
+ uint32_t uType;
+ /** IPRT result of overall operation. Note: int vs. uint32! */
+ uint32_t rc;
+ union
+ {
+ struct
+ {
+ SHCLTRANSFERSTATUS uStatus;
+ } TransferStatus;
+ struct
+ {
+ SHCLLISTHANDLE uHandle;
+ } ListOpen;
+ struct
+ {
+ SHCLLISTHANDLE uHandle;
+ } ListClose;
+ struct
+ {
+ SHCLOBJHANDLE uHandle;
+ } ObjOpen;
+ struct
+ {
+ SHCLOBJHANDLE uHandle;
+ } ObjClose;
+ } u;
+ /** Pointer to optional payload. */
+ void *pvPayload;
+ /** Payload size (in bytes). */
+ uint32_t cbPayload;
+} SHCLREPLY, *PSHCLREPLY;
+
+struct _SHCLLISTENTRY;
+typedef _SHCLLISTENTRY SHCLLISTENTRY;
+
+/** Defines a single root list entry. Currently the same as a regular list entry. */
+typedef SHCLLISTENTRY SHCLROOTLISTENTRY;
+/** Defines a pointer to a single root list entry. Currently the same as a regular list entry pointer. */
+typedef SHCLROOTLISTENTRY *PSHCLROOTLISTENTRY;
+
+/**
+ * Structure for keeping Shared Clipboard root list headers.
+ */
+typedef struct _SHCLROOTLISTHDR
+{
+ /** Roots listing flags; unused at the moment. */
+ uint32_t fRoots;
+ /** Number of root list entries. */
+ uint32_t cRoots;
+} SHCLROOTLISTHDR, *PSHCLROOTLISTHDR;
+
+/**
+ * Structure for maintaining a Shared Clipboard root list.
+ */
+typedef struct _SHCLROOTLIST
+{
+ /** Root list header. */
+ SHCLROOTLISTHDR Hdr;
+ /** Root list entries. */
+ SHCLROOTLISTENTRY *paEntries;
+} SHCLROOTLIST, *PSHCLROOTLIST;
+
+/**
+ * Structure for maintaining Shared Clipboard list open paramters.
+ */
+typedef struct _SHCLLISTOPENPARMS
+{
+ /** Listing flags (see VBOX_SHCL_LIST_FLAG_XXX). */
+ uint32_t fList;
+ /** Size (in bytes) of the filter string. */
+ uint32_t cbFilter;
+ /** Filter string. DOS wilcard-style. */
+ char *pszFilter;
+ /** Size (in bytes) of the listing path. */
+ uint32_t cbPath;
+ /** Listing path (absolute). If empty or NULL the listing's root path will be opened. */
+ char *pszPath;
+} SHCLLISTOPENPARMS, *PSHCLLISTOPENPARMS;
+
+/**
+ * Structure for keeping a Shared Clipboard list header.
+ */
+typedef struct _SHCLLISTHDR
+{
+ /** Feature flag(s). Not being used atm. */
+ uint32_t fFeatures;
+ /** Total objects returned. */
+ uint64_t cTotalObjects;
+ /** Total size (in bytes) returned. */
+ uint64_t cbTotalSize;
+} SHCLLISTHDR, *PSHCLLISTHDR;
+
+/**
+ * Structure for a Shared Clipboard list entry.
+ */
+typedef struct _SHCLLISTENTRY
+{
+ /** Entry name. */
+ char *pszName;
+ /** Size (in bytes) of entry name. */
+ uint32_t cbName;
+ /** Information flag(s). */
+ uint32_t fInfo;
+ /** Size (in bytes) of the actual list entry. */
+ uint32_t cbInfo;
+ /** Data of the actual list entry. */
+ void *pvInfo;
+} SHCLLISTENTRY, *PSHCLLISTENTRY;
+
+/** Maximum length (in UTF-8 characters) of a list entry name. */
+#define SHCLLISTENTRY_MAX_NAME RTPATH_MAX /** @todo Improve this to be more dynamic. */
+
+/**
+ * Structure for maintaining a Shared Clipboard list.
+ */
+typedef struct _SHCLLIST
+{
+ /** List header. */
+ SHCLLISTHDR Hdr;
+ /** List entries. */
+ SHCLROOTLISTENTRY *paEntries;
+} SHCLLIST, *PSHCLLIST;
+
+/**
+ * Structure for keeping a Shared Clipboard object data chunk.
+ */
+typedef struct _SHCLOBJDATACHUNK
+{
+ /** Handle of object this data chunk is related to. */
+ uint64_t uHandle;
+ /** Pointer to actual data chunk. */
+ void *pvData;
+ /** Size (in bytes) of data chunk. */
+ uint32_t cbData;
+} SHCLOBJDATACHUNK, *PSHCLOBJDATACHUNK;
+
+/**
+ * Structure for handling a single transfer object context.
+ */
+typedef struct _SHCLCLIENTTRANSFEROBJCTX
+{
+ SHCLTRANSFER *pTransfer;
+ SHCLOBJHANDLE uHandle;
+} SHCLCLIENTTRANSFEROBJCTX, *PSHCLCLIENTTRANSFEROBJCTX;
+
+typedef struct _SHCLTRANSFEROBJSTATE
+{
+ /** How many bytes were processed (read / write) so far. */
+ uint64_t cbProcessed;
+} SHCLTRANSFEROBJSTATE, *PSHCLTRANSFEROBJSTATE;
+
+typedef struct _SHCLTRANSFEROBJ
+{
+ SHCLOBJHANDLE uHandle;
+ char *pszPathAbs;
+ SHCLFSOBJINFO objInfo;
+ SHCLSOURCE enmSource;
+ SHCLTRANSFEROBJSTATE State;
+} SHCLTRANSFEROBJ, *PSHCLTRANSFEROBJ;
+
+/**
+ * Enumeration for specifying a Shared Clipboard object type.
+ */
+typedef enum _SHCLOBJTYPE
+{
+ /** Invalid object type. */
+ SHCLOBJTYPE_INVALID = 0,
+ /** Object is a directory. */
+ SHCLOBJTYPE_DIRECTORY,
+ /** Object is a file. */
+ SHCLOBJTYPE_FILE,
+ /** Object is a symbolic link. */
+ SHCLOBJTYPE_SYMLINK,
+ /** The usual 32-bit hack. */
+ SHCLOBJTYPE_32BIT_SIZE_HACK = 0x7fffffff
+} SHCLOBJTYPE;
+
+/**
+ * Structure for keeping transfer list handle information.
+ * This is using to map own (local) handles to the underlying file system.
+ */
+typedef struct _SHCLLISTHANDLEINFO
+{
+ /** The list node. */
+ RTLISTNODE Node;
+ /** The list's handle. */
+ SHCLLISTHANDLE hList;
+ /** Type of list handle. */
+ SHCLOBJTYPE enmType;
+ /** Absolute local path of the list object. */
+ char *pszPathLocalAbs;
+ union
+ {
+ /** Local data, based on enmType. */
+ struct
+ {
+ union
+ {
+ RTDIR hDir;
+ RTFILE hFile;
+ };
+ } Local;
+ } u;
+} SHCLLISTHANDLEINFO, *PSHCLLISTHANDLEINFO;
+
+/**
+ * Structure for keeping transfer object handle information.
+ * This is using to map own (local) handles to the underlying file system.
+ */
+typedef struct _SHCLOBJHANDLEINFO
+{
+ /** The list node. */
+ RTLISTNODE Node;
+ /** The object's handle. */
+ SHCLOBJHANDLE hObj;
+ /** Type of object handle. */
+ SHCLOBJTYPE enmType;
+ /** Absolute local path of the object. */
+ char *pszPathLocalAbs;
+ union
+ {
+ /** Local data, based on enmType. */
+ struct
+ {
+ union
+ {
+ RTDIR hDir;
+ RTFILE hFile;
+ };
+ } Local;
+ } u;
+} SHCLOBJHANDLEINFO, *PSHCLOBJHANDLEINFO;
+
+/**
+ * Structure for keeping a single root list entry.
+ */
+typedef struct _SHCLLISTROOT
+{
+ /** The list node. */
+ RTLISTNODE Node;
+ /** Absolute path of entry. */
+ char *pszPathAbs;
+} SHCLLISTROOT, *PSHCLLISTROOT;
+
+/**
+ * Structure for maintaining an Shared Clipboard transfer state.
+ * Everything in here will be part of a saved state (later).
+ */
+typedef struct _SHCLTRANSFERSTATE
+{
+ /** The transfer's (local) ID. */
+ SHCLTRANSFERID uID;
+ /** The transfer's current status. */
+ SHCLTRANSFERSTATUS enmStatus;
+ /** The transfer's direction, seen from the perspective who created the transfer. */
+ SHCLTRANSFERDIR enmDir;
+ /** The transfer's source, seen from the perspective who created the transfer. */
+ SHCLSOURCE enmSource;
+} SHCLTRANSFERSTATE, *PSHCLTRANSFERSTATE;
+
+/**
+ * Structure maintaining clipboard transfer provider context data.
+ * This is handed in to the provider interface implementations.
+ */
+typedef struct _SHCLTXPROVIDERCTX
+{
+ /** Pointer to the related Shared Clipboard transfer. */
+ PSHCLTRANSFER pTransfer;
+ /** User-defined data pointer. Can be NULL if not needed. */
+ void *pvUser;
+ /** Size (in bytes) of data at user pointer. */
+ size_t cbUser;
+} SHCLTXPROVIDERCTX, *PSHCLTXPROVIDERCTX;
+
+struct SHCLTRANSFERCTX;
+typedef struct SHCLTRANSFERCTX *PSHCLTRANSFERCTX;
+
+/**
+ * Shared Clipboard transfer provider interface table.
+ *
+ * A transfer provider inteface implementation realizes all low level functions
+ * needed for making a Shared Clipboard transfer happen.
+ */
+typedef struct _SHCLTXPROVIDERIFACE
+{
+ DECLCALLBACKMEMBER(int, pfnRootsGet,(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList));
+ DECLCALLBACKMEMBER(int, pfnListOpen,(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList));
+ DECLCALLBACKMEMBER(int, pfnListClose,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList));
+ DECLCALLBACKMEMBER(int, pfnListHdrRead,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr));
+ DECLCALLBACKMEMBER(int, pfnListHdrWrite,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr));
+ DECLCALLBACKMEMBER(int, pfnListEntryRead,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry));
+ DECLCALLBACKMEMBER(int, pfnListEntryWrite,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry));
+ DECLCALLBACKMEMBER(int, pfnObjOpen,(PSHCLTXPROVIDERCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj));
+ DECLCALLBACKMEMBER(int, pfnObjClose,(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj));
+ DECLCALLBACKMEMBER(int, pfnObjRead,(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData,
+ uint32_t fFlags, uint32_t *pcbRead));
+ DECLCALLBACKMEMBER(int, pfnObjWrite,(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData,
+ uint32_t fFlags, uint32_t *pcbWritten));
+} SHCLTXPROVIDERIFACE, *PSHCLTXPROVIDERIFACE;
+
+/**
+ * Structure for the Shared Clipboard transfer provider creation context.
+ */
+typedef struct _SHCLTXPROVIDERCREATIONCTX
+{
+ /** Specifies what the source of the provider is. */
+ SHCLSOURCE enmSource;
+ /** The provider interface table. */
+ SHCLTXPROVIDERIFACE Interface;
+ /** User-provided callback data. */
+ void *pvUser;
+ /** Size (in bytes) of data at user pointer. */
+ size_t cbUser;
+} SHCLTXPROVIDERCREATIONCTX, *PSHCLTXPROVIDERCREATIONCTX;
+
+/**
+ * Structure maintaining clipboard transfer callback context data.
+ */
+typedef struct _SHCLTRANSFERCALLBACKCTX
+{
+ /** Pointer to the related Shared Clipboard transfer. */
+ PSHCLTRANSFER pTransfer;
+ /** User-defined data pointer. Can be NULL if not needed. */
+ void *pvUser;
+ /** Size (in bytes) of data at user pointer. */
+ size_t cbUser;
+} SHCLTRANSFERCALLBACKCTX, *PSHCLTRANSFERCALLBACKCTX;
+
+/**
+ * Shared Clipboard transfer callback table.
+ *
+ * All callbacks are optional and can provide additional information / feedback to a frontend.
+ */
+typedef struct _SHCLTRANSFERCALLBACKTABLE
+{
+ /**
+ * Called when the transfer gets initialized.
+ *
+ * @param pCbCtx Pointer to callback context to use.
+ */
+ DECLCALLBACKMEMBER(int, pfnOnInitialize,(PSHCLTRANSFERCALLBACKCTX pCbCtx));
+ /**
+ * Called before the transfer will be started.
+ *
+ * @param pCbCtx Pointer to callback context to use.
+ */
+ DECLCALLBACKMEMBER(int, pfnOnStart,(PSHCLTRANSFERCALLBACKCTX pCbCtx));
+ /**
+ * Called when the transfer has been complete.
+ *
+ * @param pCbCtx Pointer to callback context to use.
+ * @param rcCompletion Completion result.
+ * VERR_CANCELED if transfer has been canceled.
+ */
+ DECLCALLBACKMEMBER(void, pfnOnCompleted,(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcCompletion));
+ /**
+ * Called when transfer resulted in an unrecoverable error.
+ *
+ * @param pCbCtx Pointer to callback context to use.
+ * @param rcError Error reason, IPRT-style.
+ */
+ DECLCALLBACKMEMBER(void, pfnOnError,(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcError));
+ /**
+ * Called when transfer got registered to a transfer context.
+ *
+ * @param pCbCtx Pointer to callback context to use.
+ * @param pTransferCtx Transfer context transfer was registered to.
+ */
+ DECLCALLBACKMEMBER(void, pfnOnRegistered,(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx));
+ /**
+ * Called when transfer got unregistered from a transfer context.
+ *
+ * @param pCbCtx Pointer to callback context to use.
+ * @param pTransferCtx Transfer context transfer was unregistered from.
+ */
+ DECLCALLBACKMEMBER(void, pfnOnUnregistered,(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx));
+
+ /** User-provided callback data. Can be NULL if not used. */
+ void *pvUser;
+ /** Size (in bytes) of data pointer at \a pvUser. */
+ size_t cbUser;
+} SHCLTRANSFERCALLBACKTABLE, *PSHCLTRANSFERCALLBACKTABLE;
+
+/**
+ * Structure for thread-related members for a single Shared Clipboard transfer.
+ */
+typedef struct _SHCLTRANSFERTHREAD
+{
+ /** Thread handle for the reading / writing thread.
+ * Can be NIL_RTTHREAD if not being used. */
+ RTTHREAD hThread;
+ /** Thread started indicator. */
+ volatile bool fStarted;
+ /** Thread stop flag. */
+ volatile bool fStop;
+ /** Thread cancelled flag / indicator. */
+ volatile bool fCancelled;
+} SHCLTRANSFERTHREAD, *PSHCLTRANSFERTHREAD;
+
+/**
+ * A single Shared Clipboard transfer.
+ *
+ ** @todo Not yet thread safe.
+ */
+typedef struct SHCLTRANSFER
+{
+ /** The node member for using this struct in a RTList. */
+ RTLISTNODE Node;
+ /** The transfer's state (for SSM, later). */
+ SHCLTRANSFERSTATE State;
+ /** Absolute path to root entries. */
+ char *pszPathRootAbs;
+ /** Timeout (in ms) for waiting of events. Default is 30s. */
+ RTMSINTERVAL uTimeoutMs;
+ /** Maximum data chunk size (in bytes) to transfer. Default is 64K. */
+ uint32_t cbMaxChunkSize;
+ /** The transfer's own event source. */
+ SHCLEVENTSOURCE Events;
+ /** Current number of concurrent list handles. */
+ uint32_t cListHandles;
+ /** Maximum number of concurrent list handles. */
+ uint32_t cMaxListHandles;
+ /** Next upcoming list handle. */
+ SHCLLISTHANDLE uListHandleNext;
+ /** List of all list handles elated to this transfer. */
+ RTLISTANCHOR lstList;
+ /** Number of root entries in list. */
+ uint64_t cRoots;
+ /** List of root entries of this transfer. */
+ RTLISTANCHOR lstRoots;
+ /** Current number of concurrent object handles. */
+ uint32_t cObjHandles;
+ /** Maximum number of concurrent object handles. */
+ uint32_t cMaxObjHandles;
+ /** Next upcoming object handle. */
+ SHCLOBJHANDLE uObjHandleNext;
+ /** Map of all objects handles related to this transfer. */
+ RTLISTANCHOR lstObj;
+ /** The transfer's own provider context. */
+ SHCLTXPROVIDERCTX ProviderCtx;
+ /** The transfer's provider interface. */
+ SHCLTXPROVIDERIFACE ProviderIface;
+ /** The transfer's callback context. */
+ SHCLTRANSFERCALLBACKCTX CallbackCtx;
+ /** The transfer's callback table. */
+ SHCLTRANSFERCALLBACKTABLE Callbacks;
+ /** Opaque pointer to implementation-specific parameters. */
+ void *pvUser;
+ /** Size (in bytes) of implementation-specific parameters. */
+ size_t cbUser;
+ /** Contains thread-related attributes. */
+ SHCLTRANSFERTHREAD Thread;
+ /** Critical section for serializing access. */
+ RTCRITSECT CritSect;
+} SHCLTRANSFER, *PSHCLTRANSFER;
+
+/**
+ * Structure for keeping an Shared Clipboard transfer status report.
+ */
+typedef struct _SHCLTRANSFERREPORT
+{
+ /** Actual status to report. */
+ SHCLTRANSFERSTATUS uStatus;
+ /** Result code (rc) to report; might be unused / invalid, based on enmStatus. */
+ int rc;
+ /** Reporting flags. Currently unused and must be 0. */
+ uint32_t fFlags;
+} SHCLTRANSFERREPORT, *PSHCLTRANSFERREPORT;
+
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
+typedef struct _SHCLHTTPSERVER
+{
+ /** Critical section for serializing access. */
+ RTCRITSECT CritSect;
+ /** Handle of the HTTP server instance. */
+ RTHTTPSERVER hHTTPServer;
+ /** Port number the HTTP server is running on. 0 if not running. */
+ uint16_t uPort;
+ /** List of registered HTTP transfers. */
+ RTLISTANCHOR lstTransfers;
+ /** Number of registered HTTP transfers. */
+ uint32_t cTransfers;
+ /** Cached response data. */
+ RTHTTPSERVERRESP Resp;
+} SHCLHTTPSERVER;
+typedef SHCLHTTPSERVER *PSHCLHTTPSERVER;
+
+typedef struct _SHCLHTTPCONTEXT
+{
+ /** HTTP server instance data. */
+ SHCLHTTPSERVER HttpServer;
+} SHCLHTTPCONTEXT;
+typedef SHCLHTTPCONTEXT *PSHCLHTTPCONTEXT;
+
+#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
+
+/**
+ * Structure for keeping Shared Clipboard transfer context around.
+ */
+struct SHCLTRANSFERCTX
+{
+ /** Critical section for serializing access. */
+ RTCRITSECT CritSect;
+ /** List of transfers. */
+ RTLISTANCHOR List;
+ /** Transfer ID allocation bitmap; clear bits are free, set bits are busy. */
+ uint64_t bmTransferIds[VBOX_SHCL_MAX_TRANSFERS / sizeof(uint64_t) / 8];
+ /** Number of running (concurrent) transfers. */
+ uint16_t cRunning;
+ /** Maximum Number of running (concurrent) transfers. */
+ uint16_t cMaxRunning;
+ /** Number of total transfers (in list). */
+ uint16_t cTransfers;
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
+ /** HTTP server instance for this transfer context. */
+ SHCLHTTPSERVER HttpServer;
+#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
+};
+
+int ShClTransferObjCtxInit(PSHCLCLIENTTRANSFEROBJCTX pObjCtx);
+void ShClTransferObjCtxDestroy(PSHCLCLIENTTRANSFEROBJCTX pObjCtx);
+bool ShClTransferObjCtxIsValid(PSHCLCLIENTTRANSFEROBJCTX pObjCtx);
+
+int ShClTransferObjHandleInfoInit(PSHCLOBJHANDLEINFO pInfo);
+void ShClTransferObjHandleInfoDestroy(PSHCLOBJHANDLEINFO pInfo);
+
+int ShClTransferObjOpenParmsInit(PSHCLOBJOPENCREATEPARMS pParms);
+int ShClTransferObjOpenParmsCopy(PSHCLOBJOPENCREATEPARMS pParmsDst, PSHCLOBJOPENCREATEPARMS pParmsSrc);
+void ShClTransferObjOpenParmsDestroy(PSHCLOBJOPENCREATEPARMS pParms);
+
+int ShClTransferObjOpen(PSHCLTRANSFER pTransfer, PSHCLOBJOPENCREATEPARMS pOpenCreateParms, PSHCLOBJHANDLE phObj);
+int ShClTransferObjClose(PSHCLTRANSFER pTransfer, SHCLOBJHANDLE hObj);
+int ShClTransferObjRead(PSHCLTRANSFER pTransfer, SHCLOBJHANDLE hObj, void *pvBuf, uint32_t cbBuf, uint32_t fFlags, uint32_t *pcbRead);
+int ShClTransferObjWrite(PSHCLTRANSFER pTransfer, SHCLOBJHANDLE hObj, void *pvBuf, uint32_t cbBuf, uint32_t fFlags, uint32_t *pcbWritten);
+
+PSHCLOBJDATACHUNK ShClTransferObjDataChunkDup(PSHCLOBJDATACHUNK pDataChunk);
+void ShClTransferObjDataChunkDestroy(PSHCLOBJDATACHUNK pDataChunk);
+void ShClTransferObjDataChunkFree(PSHCLOBJDATACHUNK pDataChunk);
+
+int ShClTransferCreate(PSHCLTRANSFER *ppTransfer);
+int ShClTransferInit(PSHCLTRANSFER pTransfer, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource);
+int ShClTransferDestroy(PSHCLTRANSFER pTransfer);
+
+int ShClTransferListOpen(PSHCLTRANSFER pTransfer, PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList);
+int ShClTransferListClose(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList);
+int ShClTransferListGetHeader(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, PSHCLLISTHDR pHdr);
+PSHCLTRANSFEROBJ ShClTransferListGetObj(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, uint64_t uIdx);
+int ShClTransferListRead(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry);
+int ShClTransferListWrite(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry);
+bool ShClTransferListHandleIsValid(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList);
+
+int ShClPathSanitizeFilename(char *pszPath, size_t cbPath);
+int ShClPathSanitize(char *pszPath, size_t cbPath);
+
+PSHCLROOTLIST ShClTransferRootListAlloc(void);
+void ShClTransferRootListFree(PSHCLROOTLIST pRootList);
+
+PSHCLROOTLISTHDR ShClTransferRootListHdrDup(PSHCLROOTLISTHDR pRoots);
+int ShClTransferRootListHdrInit(PSHCLROOTLISTHDR pRoots);
+void ShClTransferRootListHdrDestroy(PSHCLROOTLISTHDR pRoots);
+
+int ShClTransferRootListEntryCopy(PSHCLROOTLISTENTRY pDst, PSHCLROOTLISTENTRY pSrc);
+int ShClTransferRootListEntryInit(PSHCLROOTLISTENTRY pRootListEntry);
+void ShClTransferRootListEntryDestroy(PSHCLROOTLISTENTRY pRootListEntry);
+PSHCLROOTLISTENTRY ShClTransferRootListEntryDup(PSHCLROOTLISTENTRY pRootListEntry);
+
+int ShClTransferListHandleInfoInit(PSHCLLISTHANDLEINFO pInfo);
+void ShClTransferListHandleInfoDestroy(PSHCLLISTHANDLEINFO pInfo);
+
+int ShClTransferListHdrAlloc(PSHCLLISTHDR *ppListHdr);
+void ShClTransferListHdrFree(PSHCLLISTHDR pListHdr);
+PSHCLLISTHDR ShClTransferListHdrDup(PSHCLLISTHDR pListHdr);
+int ShClTransferListHdrInit(PSHCLLISTHDR pListHdr);
+void ShClTransferListHdrDestroy(PSHCLLISTHDR pListHdr);
+void ShClTransferListHdrReset(PSHCLLISTHDR pListHdr);
+bool ShClTransferListHdrIsValid(PSHCLLISTHDR pListHdr);
+
+int ShClTransferListOpenParmsCopy(PSHCLLISTOPENPARMS pDst, PSHCLLISTOPENPARMS pSrc);
+PSHCLLISTOPENPARMS ShClTransferListOpenParmsDup(PSHCLLISTOPENPARMS pParms);
+int ShClTransferListOpenParmsInit(PSHCLLISTOPENPARMS pParms);
+void ShClTransferListOpenParmsDestroy(PSHCLLISTOPENPARMS pParms);
+
+int ShClTransferListEntryAlloc(PSHCLLISTENTRY *ppListEntry);
+void ShClTransferListEntryFree(PSHCLLISTENTRY pListEntry);
+int ShClTransferListEntryCopy(PSHCLLISTENTRY pDst, PSHCLLISTENTRY pSrc);
+PSHCLLISTENTRY ShClTransferListEntryDup(PSHCLLISTENTRY pListEntry);
+int ShClTransferListEntryInit(PSHCLLISTENTRY pListEntry);
+void ShClTransferListEntryDestroy(PSHCLLISTENTRY pListEntry);
+bool ShClTransferListEntryIsValid(PSHCLLISTENTRY pListEntry);
+
+void ShClTransferCopyCallbacks(PSHCLTRANSFERCALLBACKTABLE pCallbacksDst, PSHCLTRANSFERCALLBACKTABLE pCallbacksSrc);
+void ShClTransferSetCallbacks(PSHCLTRANSFER pTransfer, PSHCLTRANSFERCALLBACKTABLE pCallbacks);
+int ShClTransferSetProviderIface(PSHCLTRANSFER pTransfer, PSHCLTXPROVIDERCREATIONCTX pCreationCtx);
+int ShClTransferRootsSet(PSHCLTRANSFER pTransfer, const char *pszRoots, size_t cbRoots);
+void ShClTransferReset(PSHCLTRANSFER pTransfer);
+
+uint32_t ShClTransferRootsCount(PSHCLTRANSFER pTransfer);
+int ShClTransferRootsEntry(PSHCLTRANSFER pTransfer, uint64_t uIndex, PSHCLROOTLISTENTRY pEntry);
+int ShClTransferRootsGet(PSHCLTRANSFER pTransfer, PSHCLROOTLIST *ppRootList);
+
+SHCLTRANSFERID ShClTransferGetID(PSHCLTRANSFER pTransfer);
+SHCLTRANSFERDIR ShClTransferGetDir(PSHCLTRANSFER pTransfer);
+SHCLSOURCE ShClTransferGetSource(PSHCLTRANSFER pTransfer);
+SHCLTRANSFERSTATUS ShClTransferGetStatus(PSHCLTRANSFER pTransfer);
+int ShClTransferRun(PSHCLTRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser);
+int ShClTransferStart(PSHCLTRANSFER pTransfer);
+
+int ShClTransferCtxInit(PSHCLTRANSFERCTX pTransferCtx);
+void ShClTransferCtxDestroy(PSHCLTRANSFERCTX pTransferCtx);
+void ShClTransferCtxReset(PSHCLTRANSFERCTX pTransferCtx);
+PSHCLTRANSFER ShClTransferCtxGetTransferById(PSHCLTRANSFERCTX pTransferCtx, uint32_t uID);
+PSHCLTRANSFER ShClTransferCtxGetTransferByIndex(PSHCLTRANSFERCTX pTransferCtx, uint32_t uIdx);
+uint32_t ShClTransferCtxGetRunningTransfers(PSHCLTRANSFERCTX pTransferCtx);
+uint32_t ShClTransferCtxGetTotalTransfers(PSHCLTRANSFERCTX pTransferCtx);
+void ShClTransferCtxCleanup(PSHCLTRANSFERCTX pTransferCtx);
+bool ShClTransferCtxTransfersMaximumReached(PSHCLTRANSFERCTX pTransferCtx);
+int ShClTransferCtxTransferRegister(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERID *pidTransfer);
+int ShClTransferCtxTransferRegisterById(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERID idTransfer);
+int ShClTransferCtxTransferUnregister(PSHCLTRANSFERCTX pTransferCtx, SHCLTRANSFERID idTransfer);
+
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
+int ShClHttpTransferRegister(PSHCLHTTPCONTEXT pCtx, PSHCLTRANSFER pTransfer);
+int ShClHttpTransferUnregister(PSHCLHTTPCONTEXT pCtx, PSHCLTRANSFER pTransfer);
+
+int ShClTransferHttpServerCreate(PSHCLHTTPSERVER pSrv, uint16_t *puPort);
+int ShClTransferHttpServerCreateEx(PSHCLHTTPSERVER pSrv, uint16_t uPort);
+int ShClTransferHttpServerDestroy(PSHCLHTTPSERVER pSrv);
+void ShClTransferHttpServerInit(PSHCLHTTPSERVER pSrv);
+int ShClTransferHttpServerRegisterTransfer(PSHCLHTTPSERVER pSrv, PSHCLTRANSFER pTransfer);
+int ShClTransferHttpServerUnregisterTransfer(PSHCLHTTPSERVER pSrv, PSHCLTRANSFER pTransfer);
+bool ShClTransferHttpServerHasTransfer(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer);
+uint16_t ShClTransferHttpServerGetPort(PSHCLHTTPSERVER pSrv);
+uint32_t ShClTransferHttpServerGetTransferCount(PSHCLHTTPSERVER pSrv);
+char *ShClTransferHttpServerGetAddressA(PSHCLHTTPSERVER pSrv);
+char *ShClTransferHttpServerGetUrlA(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer);
+bool ShClTransferHttpServerIsRunning(PSHCLHTTPSERVER pSrv);
+#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
+
+void ShClFsObjFromIPRT(PSHCLFSOBJINFO pDst, PCRTFSOBJINFO pSrc);
+
+bool ShClMIMEHasFileURLs(const char *pcszFormat, size_t cchFormatMax);
+bool ShClMIMENeedsCache(const char *pcszFormat, size_t cchFormatMax);
+
+const char *ShClTransferStatusToStr(SHCLTRANSFERSTATUS enmStatus);
+
+#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_transfers_h */
diff --git a/include/VBox/GuestHost/SharedClipboard-win.h b/include/VBox/GuestHost/SharedClipboard-win.h
new file mode 100644
index 00000000..0e35b409
--- /dev/null
+++ b/include/VBox/GuestHost/SharedClipboard-win.h
@@ -0,0 +1,419 @@
+/** @file
+ * Shared Clipboard - Common Guest and Host Code, for Windows OSes.
+ */
+
+/*
+ * Copyright (C) 2006-2022 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
+ */
+
+#ifndef VBOX_INCLUDED_GuestHost_SharedClipboard_win_h
+#define VBOX_INCLUDED_GuestHost_SharedClipboard_win_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <iprt/critsect.h>
+#include <iprt/types.h>
+#include <iprt/win/windows.h>
+
+#include <VBox/GuestHost/SharedClipboard.h>
+
+# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+# include <vector>
+
+# include <iprt/cpp/ministring.h> /* For RTCString. */
+# include <iprt/win/shlobj.h> /* For DROPFILES and friends. */
+# include <VBox/com/string.h> /* For Utf8Str. */
+# include <oleidl.h>
+
+# include <VBox/GuestHost/SharedClipboard-transfers.h>
+
+using namespace com;
+# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
+
+#ifndef WM_CLIPBOARDUPDATE
+# define WM_CLIPBOARDUPDATE 0x031D
+#endif
+
+#define SHCL_WIN_WNDCLASS_NAME "VBoxSharedClipboardClass"
+
+/** See: https://docs.microsoft.com/en-us/windows/desktop/dataxchg/html-clipboard-format
+ * Do *not* change the name, as this will break compatbility with other (legacy) applications! */
+#define SHCL_WIN_REGFMT_HTML "HTML Format"
+
+/** Default timeout (in ms) for passing down messages down the clipboard chain. */
+#define SHCL_WIN_CBCHAIN_TIMEOUT_MS 5000
+
+/** Reports clipboard formats. */
+#define SHCL_WIN_WM_REPORT_FORMATS WM_USER
+/** Reads data from the clipboard and sends it to the destination. */
+#define SHCL_WIN_WM_READ_DATA WM_USER + 1
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+/** Starts a transfer on the guest.
+ * This creates the necessary IDataObject in the matching window thread. */
+# define SHCL_WIN_WM_TRANSFER_START WM_USER + 2
+#endif
+
+/* Dynamically load clipboard functions from User32.dll. */
+typedef BOOL WINAPI FNADDCLIPBOARDFORMATLISTENER(HWND);
+typedef FNADDCLIPBOARDFORMATLISTENER *PFNADDCLIPBOARDFORMATLISTENER;
+
+typedef BOOL WINAPI FNREMOVECLIPBOARDFORMATLISTENER(HWND);
+typedef FNREMOVECLIPBOARDFORMATLISTENER *PFNREMOVECLIPBOARDFORMATLISTENER;
+
+/**
+ * Structure for keeping function pointers for the new clipboard API.
+ * If the new API is not available, those function pointer are NULL.
+ */
+typedef struct _SHCLWINAPINEW
+{
+ PFNADDCLIPBOARDFORMATLISTENER pfnAddClipboardFormatListener;
+ PFNREMOVECLIPBOARDFORMATLISTENER pfnRemoveClipboardFormatListener;
+} SHCLWINAPINEW, *PSHCLWINAPINEW;
+
+/**
+ * Structure for keeping variables which are needed to drive the old clipboard API.
+ */
+typedef struct _SHCLWINAPIOLD
+{
+ /** Timer ID for the refresh timer. */
+ UINT timerRefresh;
+ /** Whether "pinging" the clipboard chain currently is in progress or not. */
+ bool fCBChainPingInProcess;
+} SHCLWINAPIOLD, *PSHCLWINAPIOLD;
+
+/**
+ * Structure for maintaining a Shared Clipboard context on Windows platforms.
+ */
+typedef struct _SHCLWINCTX
+{
+ /** Critical section to serialize access. */
+ RTCRITSECT CritSect;
+ /** Window handle of our (invisible) clipbaord window. */
+ HWND hWnd;
+ /** Window handle which is next to us in the clipboard chain. */
+ HWND hWndNextInChain;
+ /** Window handle of the clipboard owner *if* we are the owner.
+ * @todo r=bird: Ignore the misleading statement above. This is only set to
+ * NULL by the initialization code and then it's set to the clipboard owner
+ * after we announce data to the clipboard. So, essentially this will be our
+ * windows handle or NULL. End of story. */
+ HWND hWndClipboardOwnerUs;
+ /** Structure for maintaining the new clipboard API. */
+ SHCLWINAPINEW newAPI;
+ /** Structure for maintaining the old clipboard API. */
+ SHCLWINAPIOLD oldAPI;
+} SHCLWINCTX, *PSHCLWINCTX;
+
+int SharedClipboardWinOpen(HWND hWnd);
+int SharedClipboardWinClose(void);
+int SharedClipboardWinClear(void);
+
+int SharedClipboardWinCtxInit(PSHCLWINCTX pWinCtx);
+void SharedClipboardWinCtxDestroy(PSHCLWINCTX pWinCtx);
+
+int SharedClipboardWinCheckAndInitNewAPI(PSHCLWINAPINEW pAPI);
+bool SharedClipboardWinIsNewAPI(PSHCLWINAPINEW pAPI);
+
+int SharedClipboardWinDataWrite(UINT cfFormat, void *pvData, uint32_t cbData);
+
+int SharedClipboardWinChainAdd(PSHCLWINCTX pCtx);
+int SharedClipboardWinChainRemove(PSHCLWINCTX pCtx);
+VOID CALLBACK SharedClipboardWinChainPingProc(HWND hWnd, UINT uMsg, ULONG_PTR dwData, LRESULT lResult) RT_NOTHROW_DEF;
+LRESULT SharedClipboardWinChainPassToNext(PSHCLWINCTX pWinCtx, UINT msg, WPARAM wParam, LPARAM lParam);
+
+SHCLFORMAT SharedClipboardWinClipboardFormatToVBox(UINT uFormat);
+int SharedClipboardWinGetFormats(PSHCLWINCTX pCtx, PSHCLFORMATS pfFormats);
+
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+int SharedClipboardWinGetRoots(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
+int SharedClipboardWinDropFilesToStringList(DROPFILES *pDropFiles, char **papszList, uint32_t *pcbList);
+#endif
+
+int SharedClipboardWinGetCFHTMLHeaderValue(const char *pszSrc, const char *pszOption, uint32_t *puValue);
+bool SharedClipboardWinIsCFHTML(const char *pszSource);
+int SharedClipboardWinConvertCFHTMLToMIME(const char *pszSource, const uint32_t cch, char **ppszOutput, uint32_t *pcbOutput);
+int SharedClipboardWinConvertMIMEToCFHTML(const char *pszSource, size_t cb, char **ppszOutput, uint32_t *pcbOutput);
+
+LRESULT SharedClipboardWinHandleWMChangeCBChain(PSHCLWINCTX pWinCtx, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+int SharedClipboardWinHandleWMDestroy(PSHCLWINCTX pWinCtx);
+int SharedClipboardWinHandleWMRenderAllFormats(PSHCLWINCTX pWinCtx, HWND hWnd);
+int SharedClipboardWinHandleWMTimer(PSHCLWINCTX pWinCtx);
+
+int SharedClipboardWinClearAndAnnounceFormats(PSHCLWINCTX pWinCtx, SHCLFORMATS fFormats, HWND hWnd);
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+int SharedClipboardWinTransferCreate(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
+void SharedClipboardWinTransferDestroy(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer);
+#endif
+
+# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+class SharedClipboardTransferList;
+# ifndef FILEGROUPDESCRIPTOR
+class FILEGROUPDESCRIPTOR;
+# endif
+
+class SharedClipboardWinDataObject : public IDataObject //, public IDataObjectAsyncCapability
+{
+public:
+
+ enum Status
+ {
+ /** The object is uninitialized (not ready). */
+ Uninitialized = 0,
+ /** The object is initialized and ready to use. */
+ Initialized,
+ /** The operation has been successfully completed. */
+ Completed,
+ /** The operation has been canceled. */
+ Canceled,
+ /** An (unrecoverable) error occurred. */
+ Error
+ };
+
+public:
+
+ SharedClipboardWinDataObject(PSHCLTRANSFER pTransfer,
+ LPFORMATETC pFormatEtc = NULL, LPSTGMEDIUM pStgMed = NULL, ULONG cFormats = 0);
+ virtual ~SharedClipboardWinDataObject(void);
+
+public: /* IUnknown methods. */
+
+ STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+public: /* IDataObject methods. */
+
+ STDMETHOD(GetData)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium);
+ STDMETHOD(GetDataHere)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium);
+ STDMETHOD(QueryGetData)(LPFORMATETC pFormatEtc);
+ STDMETHOD(GetCanonicalFormatEtc)(LPFORMATETC pFormatEct, LPFORMATETC pFormatEtcOut);
+ STDMETHOD(SetData)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium, BOOL fRelease);
+ STDMETHOD(EnumFormatEtc)(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc);
+ STDMETHOD(DAdvise)(LPFORMATETC pFormatEtc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
+ STDMETHOD(DUnadvise)(DWORD dwConnection);
+ STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppEnumAdvise);
+
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC
+public: /* IDataObjectAsyncCapability methods. */
+
+ STDMETHOD(EndOperation)(HRESULT hResult, IBindCtx* pbcReserved, DWORD dwEffects);
+ STDMETHOD(GetAsyncMode)(BOOL* pfIsOpAsync);
+ STDMETHOD(InOperation)(BOOL* pfInAsyncOp);
+ STDMETHOD(SetAsyncMode)(BOOL fDoOpAsync);
+ STDMETHOD(StartOperation)(IBindCtx* pbcReserved);
+#endif /* VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC */
+
+public:
+
+ int Init(void);
+ void OnTransferComplete(int rc = VINF_SUCCESS);
+ void OnTransferCanceled();
+
+public:
+
+ static DECLCALLBACK(int) readThread(RTTHREAD ThreadSelf, void *pvUser);
+
+ static void logFormat(CLIPFORMAT fmt);
+
+protected:
+
+ static int Thread(RTTHREAD hThread, void *pvUser);
+
+ int readDir(PSHCLTRANSFER pTransfer, const Utf8Str &strPath);
+
+ int copyToHGlobal(const void *pvData, size_t cbData, UINT fFlags, HGLOBAL *phGlobal);
+ int createFileGroupDescriptorFromTransfer(PSHCLTRANSFER pTransfer,
+ bool fUnicode, HGLOBAL *phGlobal);
+
+ bool lookupFormatEtc(LPFORMATETC pFormatEtc, ULONG *puIndex);
+ void registerFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat, TYMED tyMed = TYMED_HGLOBAL,
+ LONG lindex = -1, DWORD dwAspect = DVASPECT_CONTENT, DVTARGETDEVICE *pTargetDevice = NULL);
+protected:
+
+ /**
+ * Structure for keeping a single file system object entry.
+ */
+ struct FSOBJENTRY
+ {
+ /** Relative path of the object. */
+ Utf8Str strPath;
+ /** Related (cached) object information. */
+ SHCLFSOBJINFO objInfo;
+ };
+
+ /** Vector containing file system objects with its (cached) objection information. */
+ typedef std::vector<FSOBJENTRY> FsObjEntryList;
+
+ /** The object's current status. */
+ Status m_enmStatus;
+ /** The object's current reference count. */
+ LONG m_lRefCount;
+ /** How many formats have been registered. */
+ ULONG m_cFormats;
+ LPFORMATETC m_pFormatEtc;
+ LPSTGMEDIUM m_pStgMedium;
+ /** Pointer to the associated transfer object being handled. */
+ PSHCLTRANSFER m_pTransfer;
+ /** Current stream object being used. */
+ IStream *m_pStream;
+ /** Current object index being handled by the data object.
+ * This is needed to create the next IStream object for e.g. the next upcoming file/dir/++ in the transfer. */
+ ULONG m_uObjIdx;
+ /** List of (cached) file system objects. */
+ FsObjEntryList m_lstEntries;
+ /** Whether the transfer thread is running. */
+ bool m_fRunning;
+ /** Event being triggered when reading the transfer list been completed. */
+ RTSEMEVENT m_EventListComplete;
+ /** Event being triggered when the transfer has been completed. */
+ RTSEMEVENT m_EventTransferComplete;
+ /** Registered format for CFSTR_FILEDESCRIPTORA. */
+ UINT m_cfFileDescriptorA;
+ /** Registered format for CFSTR_FILEDESCRIPTORW. */
+ UINT m_cfFileDescriptorW;
+ /** Registered format for CFSTR_FILECONTENTS. */
+ UINT m_cfFileContents;
+ /** Registered format for CFSTR_PERFORMEDDROPEFFECT. */
+ UINT m_cfPerformedDropEffect;
+};
+
+class SharedClipboardWinEnumFormatEtc : public IEnumFORMATETC
+{
+public:
+
+ SharedClipboardWinEnumFormatEtc(LPFORMATETC pFormatEtc, ULONG cFormats);
+ virtual ~SharedClipboardWinEnumFormatEtc(void);
+
+public: /* IUnknown methods. */
+
+ STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+public: /* IEnumFORMATETC methods. */
+
+ STDMETHOD(Next)(ULONG cFormats, LPFORMATETC pFormatEtc, ULONG *pcFetched);
+ STDMETHOD(Skip)(ULONG cFormats);
+ STDMETHOD(Reset)(void);
+ STDMETHOD(Clone)(IEnumFORMATETC **ppEnumFormatEtc);
+
+public:
+
+ static void CopyFormat(LPFORMATETC pFormatDest, LPFORMATETC pFormatSource);
+ static HRESULT CreateEnumFormatEtc(UINT cFormats, LPFORMATETC pFormatEtc, IEnumFORMATETC **ppEnumFormatEtc);
+
+private:
+
+ LONG m_lRefCount;
+ ULONG m_nIndex;
+ ULONG m_nNumFormats;
+ LPFORMATETC m_pFormatEtc;
+};
+
+/**
+ * Own IStream implementation to implement file-based clipboard operations
+ * through HGCM. Needed on Windows hosts and guests.
+ */
+class SharedClipboardWinStreamImpl : public IStream
+{
+public:
+
+ SharedClipboardWinStreamImpl(SharedClipboardWinDataObject *pParent, PSHCLTRANSFER pTransfer,
+ const Utf8Str &strPath, PSHCLFSOBJINFO pObjInfo);
+ virtual ~SharedClipboardWinStreamImpl(void);
+
+public: /* IUnknown methods. */
+
+ STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject);
+ STDMETHOD_(ULONG, AddRef)(void);
+ STDMETHOD_(ULONG, Release)(void);
+
+public: /* IStream methods. */
+
+ STDMETHOD(Clone)(IStream** ppStream);
+ STDMETHOD(Commit)(DWORD dwFrags);
+ STDMETHOD(CopyTo)(IStream* pDestStream, ULARGE_INTEGER nBytesToCopy, ULARGE_INTEGER* nBytesRead, ULARGE_INTEGER* nBytesWritten);
+ STDMETHOD(LockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes,DWORD dwFlags);
+ STDMETHOD(Read)(void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead);
+ STDMETHOD(Revert)(void);
+ STDMETHOD(Seek)(LARGE_INTEGER nMove, DWORD dwOrigin, ULARGE_INTEGER* nNewPos);
+ STDMETHOD(SetSize)(ULARGE_INTEGER nNewSize);
+ STDMETHOD(Stat)(STATSTG* statstg, DWORD dwFlags);
+ STDMETHOD(UnlockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes, DWORD dwFlags);
+ STDMETHOD(Write)(const void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead);
+
+public: /* Own methods. */
+
+ static HRESULT Create(SharedClipboardWinDataObject *pParent, PSHCLTRANSFER pTransfer, const Utf8Str &strPath,
+ PSHCLFSOBJINFO pObjInfo, IStream **ppStream);
+private:
+
+ /** Pointer to the parent data object. */
+ SharedClipboardWinDataObject *m_pParent;
+ /** The stream object's current reference count. */
+ LONG m_lRefCount;
+ /** Pointer to the associated Shared Clipboard transfer. */
+ PSHCLTRANSFER m_pTransfer;
+ /** The object handle to use. */
+ SHCLOBJHANDLE m_hObj;
+ /** Object path. */
+ Utf8Str m_strPath;
+ /** (Cached) object information. */
+ SHCLFSOBJINFO m_objInfo;
+ /** Number of bytes already processed. */
+ uint64_t m_cbProcessed;
+ /** Whether this object already is in completed state or not. */
+ bool m_fIsComplete;
+};
+
+/**
+ * Class for Windows-specifics for maintaining a single Shared Clipboard transfer.
+ * Set as pvUser / cbUser in SHCLTRANSFERCTX.
+ */
+class SharedClipboardWinTransferCtx
+{
+public:
+ SharedClipboardWinTransferCtx()
+ : pDataObj(NULL) { }
+
+ virtual ~SharedClipboardWinTransferCtx()
+ {
+ if (pDataObj)
+ delete pDataObj;
+ }
+
+ /** Pointer to data object to use for this transfer.
+ * Can be NULL if not being used. */
+ SharedClipboardWinDataObject *pDataObj;
+};
+# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
+#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_win_h */
+
diff --git a/include/VBox/GuestHost/SharedClipboard-x11.h b/include/VBox/GuestHost/SharedClipboard-x11.h
new file mode 100644
index 00000000..c06f2dd2
--- /dev/null
+++ b/include/VBox/GuestHost/SharedClipboard-x11.h
@@ -0,0 +1,187 @@
+/** @file
+ * Shared Clipboard - Common X11 code.
+ */
+
+/*
+ * Copyright (C) 2006-2022 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
+ */
+
+#ifndef VBOX_INCLUDED_GuestHost_SharedClipboard_x11_h
+#define VBOX_INCLUDED_GuestHost_SharedClipboard_x11_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <X11/Intrinsic.h>
+
+#include <iprt/thread.h>
+
+#include <VBox/GuestHost/SharedClipboard.h>
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+# include <VBox/GuestHost/SharedClipboard-transfers.h>
+#endif
+
+/**
+ * The maximum number of simultaneous connections to shared clipboard service.
+ * This constant limits amount of GUEST -> HOST connections to shared clipboard host service
+ * for X11 host only. Once amount of connections reaches this number, all the
+ * further attempts to CONNECT will be dropped on an early stage. Possibility to connect
+ * is available again after one of existing connections is closed by DISCONNECT call.
+ */
+#define VBOX_SHARED_CLIPBOARD_X11_CONNECTIONS_MAX (20)
+
+/** Enables the Xt busy / update handling. */
+#define VBOX_WITH_SHARED_CLIPBOARD_XT_BUSY 1
+
+/**
+ * Enumeration for all clipboard formats which we support on X11.
+ */
+typedef enum _SHCLX11FMT
+{
+ SHCLX11FMT_INVALID = 0,
+ SHCLX11FMT_TARGETS,
+ SHCLX11FMT_TEXT, /* Treat this as UTF-8, but it may really be ascii */
+ SHCLX11FMT_UTF8,
+ SHCLX11FMT_BMP,
+ SHCLX11FMT_HTML
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+ , SHCLX11FMT_URI_LIST
+#endif
+} SHCLX11FMT;
+
+/**
+ * The table maps X11 names to data formats
+ * and to the corresponding VBox clipboard formats.
+ */
+typedef struct SHCLX11FMTTABLE
+{
+ /** The X11 atom name of the format (several names can match one format). */
+ const char *pcszAtom;
+ /** The format corresponding to the name. */
+ SHCLX11FMT enmFmtX11;
+ /** The corresponding VBox clipboard format. */
+ SHCLFORMAT uFmtVBox;
+} SHCLX11FMTTABLE;
+
+#define NIL_CLIPX11FORMAT 0
+
+/** Defines an index of the X11 clipboad format table. */
+typedef unsigned SHCLX11FMTIDX;
+
+/**
+ * Structure for maintaining a Shared Clipboard context on X11 platforms.
+ */
+typedef struct _SHCLX11CTX
+{
+ /** Opaque data structure describing the front-end. */
+ PSHCLCONTEXT pFrontend;
+ /** Our callback table to use. */
+ SHCLCALLBACKS Callbacks;
+ /** Is an X server actually available? */
+ bool fHaveX11;
+ /** The X Toolkit application context structure. */
+ XtAppContext pAppContext;
+ /** We have a separate thread to wait for window and clipboard events. */
+ RTTHREAD Thread;
+ /** Flag indicating that the thread is in a started state. */
+ bool fThreadStarted;
+ /** The X Toolkit widget which we use as our clipboard client. It is never made visible. */
+ Widget pWidget;
+ /** Should we try to grab the clipboard on startup? */
+ bool fGrabClipboardOnStart;
+ /** The best text format X11 has to offer, as an index into the formats table. */
+ SHCLX11FMTIDX idxFmtText;
+ /** The best bitmap format X11 has to offer, as an index into the formats table. */
+ SHCLX11FMTIDX idxFmtBmp;
+ /** The best HTML format X11 has to offer, as an index into the formats table. */
+ SHCLX11FMTIDX idxFmtHTML;
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+ /** The best HTML format X11 has to offer, as an index into the formats table. */
+ SHCLX11FMTIDX idxFmtURI;
+# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
+ /** HTTP transfer context data. */
+ SHCLHTTPCONTEXT HttpCtx;
+# endif
+#endif
+ /** What kind of formats does VBox have to offer? */
+ SHCLFORMATS vboxFormats;
+ /** Cache of the last unicode data that we received. */
+ void *pvUnicodeCache;
+ /** Size of the unicode data in the cache. */
+ uint32_t cbUnicodeCache;
+ /** When we wish the clipboard to exit, we have to wake up the event
+ * loop. We do this by writing into a pipe. This end of the pipe is
+ * the end that another thread can write to. */
+ int wakeupPipeWrite;
+ /** The reader end of the pipe. */
+ int wakeupPipeRead;
+ /** A pointer to the XFixesSelectSelectionInput function. */
+ void (*fixesSelectInput)(Display *, Window, Atom, unsigned long);
+ /** The first XFixes event number. */
+ int fixesEventBase;
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_XT_BUSY
+ /** XtGetSelectionValue on some versions of libXt isn't re-entrant
+ * so block overlapping requests on this flag. */
+ bool fXtBusy;
+ /** If a request is blocked on the previous flag, set this flag to request
+ * an update later - the first callback should check and clear this flag
+ * before processing the callback event. */
+ bool fXtNeedsUpdate;
+#endif
+} SHCLX11CTX, *PSHCLX11CTX;
+
+/**
+ * Structure for keeping a X11 read data request.
+ */
+typedef struct _SHCLX11READDATAREQ
+{
+ /** Actual read request to handle. */
+ CLIPREADCBREQ *pReq;
+ /** Result code of the operation on completion. */
+ int rcCompletion;
+} SHCLX11READDATAREQ;
+/** Pointer to a send data request. */
+typedef SHCLX11READDATAREQ *PSHCLX11READDATAREQ;
+
+/** @name Shared Clipboard APIs for X11.
+ * @{
+ */
+int ShClX11Init(PSHCLX11CTX pCtx, PSHCLCALLBACKS pCallbacks, PSHCLCONTEXT pParent, bool fHeadless);
+void ShClX11Destroy(PSHCLX11CTX pCtx);
+int ShClX11ThreadStart(PSHCLX11CTX pCtx, bool grab);
+int ShClX11ThreadStartEx(PSHCLX11CTX pCtx, const char *pszName, bool fGrab);
+int ShClX11ThreadStop(PSHCLX11CTX pCtx);
+int ShClX11ReportFormatsToX11(PSHCLX11CTX pCtx, SHCLFORMATS vboxFormats);
+int ShClX11ReadDataFromX11(PSHCLX11CTX pCtx, SHCLFORMATS vboxFormat, CLIPREADCBREQ *pReq);
+void ShClX11SetCallbacks(PSHCLX11CTX pCtx, PSHCLCALLBACKS pCallbacks);
+/** @} */
+
+#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_x11_h */
+
diff --git a/include/VBox/GuestHost/SharedClipboard.h b/include/VBox/GuestHost/SharedClipboard.h
new file mode 100644
index 00000000..ef61bc6c
--- /dev/null
+++ b/include/VBox/GuestHost/SharedClipboard.h
@@ -0,0 +1,354 @@
+/** @file
+ * Shared Clipboard - Common guest and host Code.
+ */
+
+/*
+ * Copyright (C) 2006-2022 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
+ */
+
+#ifndef VBOX_INCLUDED_GuestHost_SharedClipboard_h
+#define VBOX_INCLUDED_GuestHost_SharedClipboard_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <iprt/critsect.h>
+#include <iprt/types.h>
+#include <iprt/list.h>
+
+/** @name VBOX_SHCL_FMT_XXX - Data formats (flags) for Shared Clipboard.
+ * @{
+ */
+/** No format set. */
+#define VBOX_SHCL_FMT_NONE 0
+/** Shared Clipboard format is an Unicode text. */
+#define VBOX_SHCL_FMT_UNICODETEXT RT_BIT(0)
+/** Shared Clipboard format is bitmap (BMP / DIB). */
+#define VBOX_SHCL_FMT_BITMAP RT_BIT(1)
+/** Shared Clipboard format is HTML. */
+#define VBOX_SHCL_FMT_HTML RT_BIT(2)
+#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
+/** Shared Clipboard format is a transfer list. */
+# define VBOX_SHCL_FMT_URI_LIST RT_BIT(3)
+#endif
+/** @} */
+
+
+/** A single Shared Clipboard format (VBOX_SHCL_FMT_XXX). */
+typedef uint32_t SHCLFORMAT;
+/** Pointer to a single Shared Clipboard format (VBOX_SHCL_FMT_XXX). */
+typedef SHCLFORMAT *PSHCLFORMAT;
+
+/** Bit map (flags) of Shared Clipboard formats (VBOX_SHCL_FMT_XXX). */
+typedef uint32_t SHCLFORMATS;
+/** Pointer to a bit map of Shared Clipboard formats (VBOX_SHCL_FMT_XXX). */
+typedef SHCLFORMATS *PSHCLFORMATS;
+
+
+/**
+ * Shared Clipboard transfer direction.
+ */
+typedef enum SHCLTRANSFERDIR
+{
+ /** Unknown transfer directory. */
+ SHCLTRANSFERDIR_UNKNOWN = 0,
+ /** Read transfer (from source). */
+ SHCLTRANSFERDIR_FROM_REMOTE,
+ /** Write transfer (to target). */
+ SHCLTRANSFERDIR_TO_REMOTE,
+ /** The usual 32-bit hack. */
+ SHCLTRANSFERDIR_32BIT_HACK = 0x7fffffff
+} SHCLTRANSFERDIR;
+/** Pointer to a shared clipboard transfer direction. */
+typedef SHCLTRANSFERDIR *PSHCLTRANSFERDIR;
+
+
+/**
+ * Shared Clipboard data read request.
+ */
+typedef struct SHCLDATAREQ
+{
+ /** In which format the data needs to be sent. */
+ SHCLFORMAT uFmt;
+ /** Read flags; currently unused. */
+ uint32_t fFlags;
+ /** Maximum data (in byte) can be sent. */
+ uint32_t cbSize;
+} SHCLDATAREQ;
+/** Pointer to a shared clipboard data request. */
+typedef SHCLDATAREQ *PSHCLDATAREQ;
+
+/**
+ * Shared Clipboard event payload (optional).
+ */
+typedef struct SHCLEVENTPAYLOAD
+{
+ /** Payload ID; currently unused. */
+ uint32_t uID;
+ /** Size (in bytes) of actual payload data. */
+ uint32_t cbData;
+ /** Pointer to actual payload data. */
+ void *pvData;
+} SHCLEVENTPAYLOAD;
+/** Pointer to a shared clipboard event payload. */
+typedef SHCLEVENTPAYLOAD *PSHCLEVENTPAYLOAD;
+
+/** A shared clipboard event source ID. */
+typedef uint16_t SHCLEVENTSOURCEID;
+/** Pointer to a shared clipboard event source ID. */
+typedef SHCLEVENTSOURCEID *PSHCLEVENTSOURCEID;
+
+/** A shared clipboard session ID. */
+typedef uint16_t SHCLSESSIONID;
+/** Pointer to a shared clipboard session ID. */
+typedef SHCLSESSIONID *PSHCLSESSIONID;
+/** NIL shared clipboard session ID. */
+#define NIL_SHCLSESSIONID UINT16_MAX
+
+/** A shared clipboard transfer ID. */
+typedef uint16_t SHCLTRANSFERID;
+/** Pointer to a shared clipboard transfer ID. */
+typedef SHCLTRANSFERID *PSHCLTRANSFERID;
+/** NIL shared clipboardtransfer ID. */
+#define NIL_SHCLTRANSFERID UINT16_MAX
+
+/** A shared clipboard event ID. */
+typedef uint32_t SHCLEVENTID;
+/** Pointer to a shared clipboard event source ID. */
+typedef SHCLEVENTID *PSHCLEVENTID;
+/** NIL shared clipboard event ID. */
+#define NIL_SHCLEVENTID UINT32_MAX
+
+/** Pointer to a shared clipboard event source.
+ * Forward declaration, needed for SHCLEVENT. */
+typedef struct SHCLEVENTSOURCE *PSHCLEVENTSOURCE;
+
+/**
+ * Shared Clipboard event.
+ */
+typedef struct SHCLEVENT
+{
+ /** List node. */
+ RTLISTNODE Node;
+ /** Parent (source) this event belongs to. */
+ PSHCLEVENTSOURCE pParent;
+ /** The event's ID, for self-reference. */
+ SHCLEVENTID idEvent;
+ /** Reference count to this event. */
+ uint32_t cRefs;
+ /** Event semaphore for signalling the event. */
+ RTSEMEVENTMULTI hEvtMulSem;
+ /** Payload to this event, optional (NULL). */
+ PSHCLEVENTPAYLOAD pPayload;
+} SHCLEVENT;
+/** Pointer to a shared clipboard event. */
+typedef SHCLEVENT *PSHCLEVENT;
+
+/**
+ * Shared Clipboard event source.
+ *
+ * Each event source maintains an own counter for events, so that it can be used
+ * in different contexts.
+ */
+typedef struct SHCLEVENTSOURCE
+{
+ /** The event source ID. */
+ SHCLEVENTSOURCEID uID;
+ /** Critical section for serializing access. */
+ RTCRITSECT CritSect;
+ /** Next upcoming event ID. */
+ SHCLEVENTID idNextEvent;
+ /** List of events (PSHCLEVENT). */
+ RTLISTANCHOR lstEvents;
+} SHCLEVENTSOURCE;
+
+/** @name Shared Clipboard data payload functions.
+ * @{
+ */
+int ShClPayloadAlloc(uint32_t uID, const void *pvData, uint32_t cbData, PSHCLEVENTPAYLOAD *ppPayload);
+void ShClPayloadFree(PSHCLEVENTPAYLOAD pPayload);
+/** @} */
+
+/** @name Shared Clipboard event source functions.
+ * @{
+ */
+int ShClEventSourceCreate(PSHCLEVENTSOURCE pSource, SHCLEVENTSOURCEID idEvtSrc);
+int ShClEventSourceDestroy(PSHCLEVENTSOURCE pSource);
+void ShClEventSourceReset(PSHCLEVENTSOURCE pSource);
+int ShClEventSourceGenerateAndRegisterEvent(PSHCLEVENTSOURCE pSource, PSHCLEVENT *ppEvent);
+PSHCLEVENT ShClEventSourceGetFromId(PSHCLEVENTSOURCE pSource, SHCLEVENTID idEvent);
+PSHCLEVENT ShClEventSourceGetLast(PSHCLEVENTSOURCE pSource);
+/** @} */
+
+/** @name Shared Clipboard event functions.
+ * @{
+ */
+uint32_t ShClEventGetRefs(PSHCLEVENT pEvent);
+uint32_t ShClEventRetain(PSHCLEVENT pEvent);
+uint32_t ShClEventRelease(PSHCLEVENT pEvent);
+int ShClEventSignal(PSHCLEVENT pEvent, PSHCLEVENTPAYLOAD pPayload);
+int ShClEventWait(PSHCLEVENT pEvent, RTMSINTERVAL uTimeoutMs, PSHCLEVENTPAYLOAD *ppPayload);
+/** @} */
+
+/**
+ * Shared Clipboard transfer source type.
+ * @note Part of saved state!
+ */
+typedef enum SHCLSOURCE
+{
+ /** Invalid source type. */
+ SHCLSOURCE_INVALID = 0,
+ /** Source is local. */
+ SHCLSOURCE_LOCAL,
+ /** Source is remote. */
+ SHCLSOURCE_REMOTE,
+ /** The usual 32-bit hack. */
+ SHCLSOURCE_32BIT_HACK = 0x7fffffff
+} SHCLSOURCE;
+
+/** Opaque data structure for the X11/VBox frontend/glue code.
+ * @{ */
+struct SHCLCONTEXT;
+typedef struct SHCLCONTEXT SHCLCONTEXT;
+/** @} */
+/** Pointer to opaque data structure the X11/VBox frontend/glue code. */
+typedef SHCLCONTEXT *PSHCLCONTEXT;
+
+/**
+ * @name Shared Clipboard callback table.
+ *
+ * This table gets used by
+ * - the backends on the host (where required)
+ * - guest side implementations (e.g. VBoxClient)
+ * - by the underlying core code (e.g. X11 backend -> X11 common code -> callback)
+ *
+ * Some clipboard mechanisms (e.g. X11) require asynchronous and/or event-driven handling
+ * of clipboard data, making it hard to control our program flow when testing stuff.
+ *
+ * So overriding required callbacks on runtime for testing purposes makes this approach much
+ * more flexible without implementing separate code paths for production code and test units.
+ *
+ * @{
+ */
+typedef struct _SHCLCALLBACKS
+{
+ /**
+ * Callback for reporting supported clipoard formats of current clipboard data.
+ *
+ * @note On X11:
+ * Runs in Xt event thread for the X11 code.
+ *
+ * @returns VBox status code.
+ * @param pCtx Opaque context pointer for the glue code.
+ * @param fFormats The formats available.
+ * @param pvUser Implementation-dependent pointer to data for fullfilling the request.
+ * Optional and can be NULL.
+ */
+ DECLCALLBACKMEMBER(int, pfnReportFormats, (PSHCLCONTEXT pCtx, SHCLFORMATS fFormats, void *pvUser));
+
+ /**
+ * Callback for reading data from the clipboard.
+ * Optional and can be NULL.
+ *
+ * @note Used for testing X11 clipboard code.
+ *
+ * @returns VBox status code.
+ * @param pCtx Opaque context pointer for the glue code.
+ * @param uFmt The format in which the data should be read
+ * (VBOX_SHCL_FMT_XXX).
+ * @param ppv Returns an allocated buffer with data from on success.
+ * Needs to be free'd with RTMemFree() by the caller.
+ * @param pcb Returns the amount of data read (in bytes) on success.
+ * @param pvUser Implementation-dependent pointer to data for fullfilling the request.
+ * Optional and can be NULL.
+ */
+ DECLCALLBACKMEMBER(int, pfnOnClipboardRead, (PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppv, size_t *pcb, void *pvUser));
+
+ /**
+ * Callback for writing data to the clipboard.
+ * Optional and can be NULL.
+ *
+ * @note Used for testing X11 clipboard code.
+ *
+ * @returns VBox status code.
+ * @param pCtx Opaque context pointer for the glue code.
+ * @param uFmt The format in which the data should be written as
+ * (VBOX_SHCL_FMT_XXX).
+ * @param pv The clipboard data to write.
+ * @param cb The size of the data in @a pv.
+ * @param pvUser Implementation-dependent pointer to data for fullfilling the request.
+ * Optional and can be NULL.
+ */
+ DECLCALLBACKMEMBER(int, pfnOnClipboardWrite, (PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void *pv, size_t cb, void *pvUser));
+
+ /**
+ * Callback for requesting clipboard data from the source.
+ *
+ * @note On X11:
+ * The function will be invoked for every single target the clipboard requests.
+ * Runs in Xt event thread for the X11 code.
+ *
+ * @returns VBox status code. VERR_NO_DATA if no data available.
+ * @param pCtx Opaque context pointer for the glue code.
+ * @param uFmt The format in which the data should be transferred
+ * (VBOX_SHCL_FMT_XXX).
+ * @param ppv Returns an allocated buffer with data read from the guest on success.
+ * Needs to be free'd with RTMemFree() by the caller.
+ * @param pcb Returns the amount of data read (in bytes) on success.
+ * @param pvUser Implementation-dependent pointer to data for fullfilling the request.
+ * Optional and can be NULL.
+ * On X11: Of type PSHCLX11READDATAREQ; We RTMemFree() this in this function.
+ */
+ DECLCALLBACKMEMBER(int, pfnOnRequestDataFromSource, (PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser));
+
+ /**
+ * Callback for sending clipboard data to the destination.
+ *
+ * @returns VBox status code.
+ * @param pCtx Opaque context pointer for the glue code.
+ * @param pv The clipboard data returned if the request succeeded.
+ * @param cb The size of the data in @a pv.
+ * @param pvUser Implementation-dependent pointer to data for fullfilling the request.
+ * Optional and can be NUL
+ * On X11: Of type PSHCLX11READDATAREQ.
+ */
+ DECLCALLBACKMEMBER(int, pfnOnSendDataToDest, (PSHCLCONTEXT pCtx, void *pv, uint32_t cb, void *pvUser));
+} SHCLCALLBACKS;
+typedef SHCLCALLBACKS *PSHCLCALLBACKS;
+/** @} */
+
+/** Opaque request structure for X11 clipboard data.
+ * @{ */
+struct CLIPREADCBREQ;
+typedef struct CLIPREADCBREQ CLIPREADCBREQ;
+/** @} */
+
+#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_h */
+
diff --git a/include/VBox/GuestHost/clipboard-helper.h b/include/VBox/GuestHost/clipboard-helper.h
new file mode 100644
index 00000000..e1c4ad9d
--- /dev/null
+++ b/include/VBox/GuestHost/clipboard-helper.h
@@ -0,0 +1,250 @@
+/* $Id: clipboard-helper.h $ */
+/** @file
+ * Shared Clipboard - Some helper function for converting between the various EOLs.
+ */
+
+/*
+ * Copyright (C) 2006-2022 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
+ */
+
+#ifndef VBOX_INCLUDED_GuestHost_clipboard_helper_h
+#define VBOX_INCLUDED_GuestHost_clipboard_helper_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <iprt/string.h>
+
+#include <VBox/GuestHost/SharedClipboard.h>
+
+/** Constants needed for string conversions done by the Linux/Mac clipboard code. */
+enum
+{
+ /** In Linux, lines end with a linefeed character. */
+ VBOX_SHCL_LINEFEED = 0xa,
+ /** In Windows, lines end with a carriage return and a linefeed character. */
+ VBOX_SHCL_CARRIAGERETURN = 0xd,
+ /** Little endian "real" UTF-16 strings start with this marker. */
+ VBOX_SHCL_UTF16LEMARKER = 0xfeff,
+ /** Big endian "real" UTF-16 strings start with this marker. */
+ VBOX_SHCL_UTF16BEMARKER = 0xfffe
+};
+
+/**
+ * Returns the length (in UTF-8 characters) of an UTF-16 string with LF EOL.
+ *
+ * @returns VBox status code.
+ * @param pcwszSrc UTF-16 string to return size for.
+ * @param cwcSrc Length of the string in RTUTF16 units.
+ * @param pchLen Where to return the length (in UTF-8 characters).
+ * Does not include terminator.
+ */
+int ShClUtf16LFLenUtf8(PCRTUTF16 pcwszSrc, size_t cwcSrc, size_t *pchLen);
+
+/**
+ * Returns the length (in UTF-8 characters) of an UTF-16 string with CRLF EOL.
+ *
+ * @returns VBox status code.
+ * @param pcwszSrc UTF-16 string to return size for.
+ * @param cwcSrc Length of the source string in RTUTF16 units.
+ * @param pchLen Where to return the length (in UTF-8 characters).
+ * Does not include terminator.
+ */
+int ShClUtf16CRLFLenUtf8(PCRTUTF16 pcwszSrc, size_t cwcSrc, size_t *pchLen);
+
+/**
+ * Returns the length (in characters) of an UTF-16 string, including terminator.
+ *
+ * @returns VBox status code.
+ * @param pcwszSrc UTF-16 string to return size for.
+ * @param cwcSrc Length of the source string in RTUTF16 units.
+ * @param pchLen Where to return the length (in UTF-8 characters).
+ * Does not include terminator.
+ */
+int ShClUtf16LenUtf8(PCRTUTF16 pcwszSrc, size_t cwcSrc, size_t *pchLen);
+
+/**
+ * Converts an UTF-16 string with LF EOL to an UTF-16 string with CRLF EOL.
+ *
+ * @returns VBox status code.
+ * @param pcwszSrc UTF-16 string to convert.
+ * @param cwcSrc Size of the string int RTUTF16 units.
+ * @param pwszDst Buffer to store the converted string to.
+ * @param cwcDst The size of \a pwszDst in RTUTF16 units.
+ */
+int ShClConvUtf16LFToCRLF(PCRTUTF16 pcwszSrc, size_t cwcSrc, PRTUTF16 pwszDst, size_t cwcDst);
+
+/**
+ * Converts an UTF-16 string with LF EOL to an UTF-16 string with CRLF EOL.
+ *
+ * Convenience function which returns the allocated + converted string on success.
+ *
+ * @returns VBox status code.
+ * @param pcwszSrc UTF-16 string to convert.
+ * @param cwcSrc Size of the string int RTUTF16 units.
+ * @param ppwszDst Where to return the allocated converted string. Must be free'd by the caller.
+ * @param pcwDst Where to return the size of the converted string in RTUTF16 units.
+ * Does not include the terminator.
+ */
+int ShClConvUtf16LFToCRLFA(PCRTUTF16 pcwszSrc, size_t cwcSrc, PRTUTF16 *ppwszDst, size_t *pcwDst);
+
+/**
+ * Converts an UTF-16 string with CRLF EOL to an UTF-16 string with LF EOL.
+ *
+ * @returns VBox status code.
+ * @param pcwszSrc UTF-16 string to convert.
+ * @param cwcSrc Size of the string in RTUTF16 units.
+ * @param pwszDst Where to store the converted string to.
+ * @param cwcDst The size of \a pwszDst in RTUTF16 units.
+ */
+int ShClConvUtf16CRLFToLF(PCRTUTF16 pcwszSrc, size_t cwcSrc, PRTUTF16 pwszDst, size_t cwcDst);
+
+/**
+ * Converts an UTF-16 string with CRLF EOL to UTF-8 LF.
+ *
+ * @returns VBox status code. Will return VERR_NO_DATA if no data was converted.
+ * @param pcwszSrc UTF-16 string to convert.
+ * @param cbSrc Length of @a pwszSrc (in bytes).
+ * @param pszBuf Where to write the converted string.
+ * @param cbBuf The size of the buffer pointed to by @a pszBuf.
+ * @param pcbLen Where to store the size (in bytes) of the converted string.
+ * Does not include terminator.
+ */
+int ShClConvUtf16CRLFToUtf8LF(PCRTUTF16 pcwszSrc, size_t cbSrc, char *pszBuf, size_t cbBuf, size_t *pcbLen);
+
+/**
+* Converts an HTML string from UTF-16 into UTF-8.
+*
+* @returns VBox status code.
+* @param pcwszSrc UTF-16 string to convert.
+* @param cwcSrc Length (in RTUTF16 units) of the source text.
+* @param ppszDst Where to store the converted result on success.
+* @param pcbDst Where to store the number of bytes written.
+*/
+int ShClConvUtf16ToUtf8HTML(PCRTUTF16 pcwszSrc, size_t cwcSrc, char **ppszDst, size_t *pcbDst);
+
+/**
+ * Converts an UTF-8 string with LF EOL into UTF-16 CRLF.
+ *
+ * @returns VBox status code.
+ * @param pcszSrc UTF-8 string to convert.
+ * @param cbSrc Size of UTF-8 string to convert (in bytes), not counting the terminating zero.
+ * @param ppwszDst Where to return the allocated buffer on success.
+ * @param pcwDst Where to return the size (in RTUTF16 units) of the allocated buffer on success.
+ * Does not include terminator.
+ */
+int ShClConvUtf8LFToUtf16CRLF(const char *pcszSrc, size_t cbSrc, PRTUTF16 *ppwszDst, size_t *pcwDst);
+
+/**
+ * Converts a Latin-1 string with LF EOL into UTF-16 CRLF.
+ *
+ * @returns VBox status code.
+ * @param pcszSrc UTF-8 string to convert.
+ * @param cbSrc Size of string (in bytes), not counting the terminating zero.
+ * @param ppwszDst Where to return the allocated buffer on success.
+ * @param pcwDst Where to return the size (in RTUTF16 units) of the allocated buffer on success.
+ * Does not include terminator.
+ */
+int ShClConvLatin1LFToUtf16CRLF(const char *pcszSrc, size_t cbSrc, PRTUTF16 *ppwszDst, size_t *pcwDst);
+
+/**
+ * Convert CF_DIB data to full BMP data by prepending the BM header.
+ * Allocates with RTMemAlloc.
+ *
+ * @returns VBox status code.
+ * @param pvSrc DIB data to convert
+ * @param cbSrc Size of the DIB data to convert in bytes
+ * @param ppvDst Where to store the pointer to the buffer for the
+ * destination data
+ * @param pcbDst Pointer to the size of the buffer for the destination
+ * data in bytes.
+ */
+int ShClDibToBmp(const void *pvSrc, size_t cbSrc, void **ppvDst, size_t *pcbDst);
+
+/**
+ * Get the address and size of CF_DIB data in a full BMP data in the input buffer.
+ * Does not do any allocation.
+ *
+ * @returns VBox status code.
+ * @param pvSrc BMP data to convert
+ * @param cbSrc Size of the BMP data to convert in bytes
+ * @param ppvDst Where to store the pointer to the destination data
+ * @param pcbDst Pointer to the size of the destination data in bytes
+ */
+int ShClBmpGetDib(const void *pvSrc, size_t cbSrc, const void **ppvDst, size_t *pcbDst);
+
+#ifdef LOG_ENABLED
+/**
+ * Dumps HTML data to the debug log.
+ *
+ * @returns VBox status code.
+ * @param pszSrc HTML data to dump.
+ * @param cbSrc Size (in bytes) of HTML data to dump.
+ */
+int ShClDbgDumpHtml(const char *pszSrc, size_t cbSrc);
+
+/**
+ * Dumps data using a specified clipboard format.
+ *
+ * @param pv Pointer to data to dump.
+ * @param cb Size (in bytes) of data to dump.
+ * @param u32Format Clipboard format to use for dumping.
+ */
+void ShClDbgDumpData(const void *pv, size_t cb, SHCLFORMAT u32Format);
+#endif /* LOG_ENABLED */
+
+/**
+ * Translates a Shared Clipboard host function number to a string.
+ *
+ * @returns Function ID string name.
+ * @param uFn The function to translate.
+ */
+const char *ShClHostFunctionToStr(uint32_t uFn);
+
+/**
+ * Translates a Shared Clipboard host message enum to a string.
+ *
+ * @returns Message ID string name.
+ * @param uMsg The message to translate.
+ */
+const char *ShClHostMsgToStr(uint32_t uMsg);
+
+/**
+ * Translates a Shared Clipboard guest message enum to a string.
+ *
+ * @returns Message ID string name.
+ * @param uMsg The message to translate.
+ */
+const char *ShClGuestMsgToStr(uint32_t uMsg);
+
+char *ShClFormatsToStrA(SHCLFORMATS fFormats);
+
+#endif /* !VBOX_INCLUDED_GuestHost_clipboard_helper_h */
+