VBGLR3DECL(int) VbglR3HostChannelQuery(const char *pszName,
                                       uint32_t u32HGCMClientId,
                                       uint32_t u32Code,
                                       void *pvParm,
                                       uint32_t cbParm,
                                       void *pvData,
                                       uint32_t cbData,
                                       uint32_t *pu32SizeDataReturned)
{
    /* Make a heap copy of the name, because HGCM can not use some of other memory types. */
    size_t cbName = strlen(pszName) + 1;
    char *pszCopy = (char *)RTMemAlloc(cbName);
    if (pszCopy == NULL)
    {
        return VERR_NO_MEMORY;
    }

    memcpy(pszCopy, pszName, cbName);

    VBoxHostChannelQuery parms;

    parms.hdr.result = VERR_WRONG_ORDER;
    parms.hdr.u32ClientID = u32HGCMClientId;
    parms.hdr.u32Function = VBOX_HOST_CHANNEL_FN_QUERY;
    parms.hdr.cParms = 5;

    VbglHGCMParmPtrSet(&parms.name, pszCopy, (uint32_t)cbName);
    VbglHGCMParmUInt32Set(&parms.code, u32Code);
    VbglHGCMParmPtrSet(&parms.parm, pvParm, cbParm);
    VbglHGCMParmPtrSet(&parms.data, pvData, cbData);
    VbglHGCMParmUInt32Set(&parms.sizeDataReturned, 0);

    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(parms)), &parms, sizeof(parms));

    if (RT_SUCCESS(rc))
    {
        rc = parms.hdr.result;

        if (RT_SUCCESS(rc))
        {
            *pu32SizeDataReturned = parms.sizeDataReturned.u.value32;
        }
    }

    RTMemFree(pszCopy);

    return rc;
}
VBGLR3DECL(int) VbglR3HostChannelEventWait(uint32_t *pu32ChannelHandle,
                                           uint32_t u32HGCMClientId,
                                           uint32_t *pu32EventId,
                                           void *pvParm,
                                           uint32_t cbParm,
                                           uint32_t *pu32SizeReturned)
{
    VBoxHostChannelEventWait parms;

    parms.hdr.result = VERR_WRONG_ORDER;
    parms.hdr.u32ClientID = u32HGCMClientId;
    parms.hdr.u32Function = VBOX_HOST_CHANNEL_FN_EVENT_WAIT;
    parms.hdr.cParms = 4;

    VbglHGCMParmUInt32Set(&parms.handle, 0);
    VbglHGCMParmUInt32Set(&parms.id, 0);
    VbglHGCMParmPtrSet(&parms.parm, pvParm, cbParm);
    VbglHGCMParmUInt32Set(&parms.sizeReturned, 0);

    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(parms)), &parms, sizeof(parms));

    if (RT_SUCCESS(rc))
    {
        rc = parms.hdr.result;

        if (RT_SUCCESS(rc))
        {
            *pu32ChannelHandle = parms.handle.u.value32;
            *pu32EventId = parms.id.u.value32;
            *pu32SizeReturned = parms.sizeReturned.u.value32;
        }
    }

    return rc;
}
VBGLR3DECL(int) VbglR3HostChannelRecv(uint32_t u32ChannelHandle,
                                      uint32_t u32HGCMClientId,
                                      void *pvData,
                                      uint32_t cbData,
                                      uint32_t *pu32SizeReceived,
                                      uint32_t *pu32SizeRemaining)
{
    VBoxHostChannelRecv parms;

    parms.hdr.result = VERR_WRONG_ORDER;
    parms.hdr.u32ClientID = u32HGCMClientId;
    parms.hdr.u32Function = VBOX_HOST_CHANNEL_FN_RECV;
    parms.hdr.cParms = 4;

    VbglHGCMParmUInt32Set(&parms.handle, u32ChannelHandle);
    VbglHGCMParmPtrSet(&parms.data, pvData, cbData);
    VbglHGCMParmUInt32Set(&parms.sizeReceived, 0);
    VbglHGCMParmUInt32Set(&parms.sizeRemaining, 0);

    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(parms)), &parms, sizeof(parms));

    if (RT_SUCCESS(rc))
    {
        rc = parms.hdr.result;

        if (RT_SUCCESS(rc))
        {
            *pu32SizeReceived = parms.sizeReceived.u.value32;
            *pu32SizeRemaining = parms.sizeRemaining.u.value32;
        }
    }

    return rc;
}
/**
 * Reads data from the host clipboard.
 *
 * @returns VBox status code.
 * @retval  VINF_BUFFER_OVERFLOW    If there is more data available than the caller provided buffer space for.
 *
 * @param   u32ClientId     The client id returned by VbglR3ClipboardConnect().
 * @param   fFormat         The format we're requesting the data in.
 * @param   pv              Where to store the data.
 * @param   cb              The size of the buffer pointed to by pv.
 * @param   pcb             The actual size of the host clipboard data. May be larger than cb.
 */
VBGLR3DECL(int) VbglR3ClipboardReadData(uint32_t u32ClientId, uint32_t fFormat, void *pv, uint32_t cb, uint32_t *pcb)
{
    VBoxClipboardReadData Msg;

    Msg.hdr.result = VERR_WRONG_ORDER;
    Msg.hdr.u32ClientID = u32ClientId;
    Msg.hdr.u32Function = VBOX_SHARED_CLIPBOARD_FN_READ_DATA;
    Msg.hdr.cParms = 3;
    VbglHGCMParmUInt32Set(&Msg.format, fFormat);
    VbglHGCMParmPtrSet(&Msg.ptr, pv, cb);
    VbglHGCMParmUInt32Set(&Msg.size, 0);

    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    if (RT_SUCCESS(rc))
    {
        rc = Msg.hdr.result;
        if (RT_SUCCESS(rc))
        {
            uint32_t cbActual;
            rc = VbglHGCMParmUInt32Get(&Msg.size, &cbActual);
            if (RT_SUCCESS(rc))
            {
                *pcb = cbActual;
                if (cbActual > cb)
                    return VINF_BUFFER_OVERFLOW;
                return Msg.hdr.result;
            }
        }
    }
    return rc;
}
VBGLR3DECL(int) VbglR3HostChannelControl(uint32_t u32ChannelHandle,
                                         uint32_t u32HGCMClientId,
                                         uint32_t u32Code,
                                         void *pvParm,
                                         uint32_t cbParm,
                                         void *pvData,
                                         uint32_t cbData,
                                         uint32_t *pu32SizeDataReturned)
{
    VBoxHostChannelControl parms;

    parms.hdr.result = VERR_WRONG_ORDER;
    parms.hdr.u32ClientID = u32HGCMClientId;
    parms.hdr.u32Function = VBOX_HOST_CHANNEL_FN_CONTROL;
    parms.hdr.cParms = 5;

    VbglHGCMParmUInt32Set(&parms.handle, u32ChannelHandle);
    VbglHGCMParmUInt32Set(&parms.code, u32Code);
    VbglHGCMParmPtrSet(&parms.parm, pvParm, cbParm);
    VbglHGCMParmPtrSet(&parms.data, pvData, cbData);
    VbglHGCMParmUInt32Set(&parms.sizeDataReturned, 0);

    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(parms)), &parms, sizeof(parms));

    if (RT_SUCCESS(rc))
    {
        rc = parms.hdr.result;

        if (RT_SUCCESS(rc))
        {
            *pu32SizeDataReturned = parms.sizeDataReturned.u.value32;
        }
    }

    return rc;
}
/**
 * Send guest clipboard data to the host.
 *
 * This is usually called in reply to a VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA message
 * from the host.
 *
 * @returns VBox status code.
 * @param   u32ClientId     The client id returned by VbglR3ClipboardConnect().
 * @param   fFormat         The format of the data.
 * @param   pv              The data.
 * @param   cb              The size of the data.
 */
VBGLR3DECL(int) VbglR3ClipboardWriteData(uint32_t u32ClientId, uint32_t fFormat, void *pv, uint32_t cb)
{
    VBoxClipboardWriteData Msg;
    Msg.hdr.result = VERR_WRONG_ORDER;
    Msg.hdr.u32ClientID = u32ClientId;
    Msg.hdr.u32Function = VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA;
    Msg.hdr.cParms = 2;
    VbglHGCMParmUInt32Set(&Msg.format, fFormat);
    VbglHGCMParmPtrSet(&Msg.ptr, pv, cb);

    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    if (RT_SUCCESS(rc))
        rc = Msg.hdr.result;
    return rc;
}
/**
 * Get the real name of a shared folder.
 *
 * @returns VBox status code.
 * @param   u32ClientId     The client id returned by VbglR3InvsSvcConnect().
 * @param   u32Root         Root ID of shared folder to get the name for.
 * @param   ppszName        Where to return the name string.  This shall be
 *                          freed by calling RTStrFree.
 */
VBGLR3DECL(int) VbglR3SharedFolderGetName(uint32_t u32ClientId, uint32_t u32Root, char **ppszName)
{
    AssertPtr(ppszName);

    VBoxSFQueryMapName Msg;

    Msg.callInfo.result = VERR_WRONG_ORDER;
    Msg.callInfo.u32ClientID = u32ClientId;
    Msg.callInfo.u32Function = SHFL_FN_QUERY_MAP_NAME;
    Msg.callInfo.cParms = 2;

    int         rc;
    uint32_t    cbString = SHFLSTRING_HEADER_SIZE + SHFL_MAX_LEN;
    PSHFLSTRING pString = (PSHFLSTRING)RTMemAlloc(cbString);
    if (pString)
    {
        if (!ShflStringInitBuffer(pString, cbString))
        {
            RTMemFree(pString);
            return VERR_INVALID_PARAMETER;
        }

        VbglHGCMParmUInt32Set(&Msg.root, u32Root);
        VbglHGCMParmPtrSet(&Msg.name, pString, cbString);

        rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
        if (RT_SUCCESS(rc))
        {
            rc = Msg.callInfo.result;
            if (RT_SUCCESS(rc))
            {
                *ppszName = NULL;
                rc = RTUtf16ToUtf8(&pString->String.ucs2[0], ppszName);
            }
        }
        RTMemFree(pString);
    }
    else
        rc = VERR_INVALID_PARAMETER;
    return rc;
}
VBGLR3DECL(int) VbglR3HostChannelAttach(uint32_t *pu32ChannelHandle,
                                        uint32_t u32HGCMClientId,
                                        const char *pszName,
                                        uint32_t u32Flags)
{
    /* Make a heap copy of the name, because HGCM can not use some of other memory types. */
    size_t cbName = strlen(pszName) + 1;
    char *pszCopy = (char *)RTMemAlloc(cbName);
    if (pszCopy == NULL)
    {
        return VERR_NO_MEMORY;
    }

    memcpy(pszCopy, pszName, cbName);

    VBoxHostChannelAttach parms;

    parms.hdr.result = VERR_WRONG_ORDER;
    parms.hdr.u32ClientID = u32HGCMClientId;
    parms.hdr.u32Function = VBOX_HOST_CHANNEL_FN_ATTACH;
    parms.hdr.cParms = 3;

    VbglHGCMParmPtrSet(&parms.name, pszCopy, (uint32_t)cbName);
    VbglHGCMParmUInt32Set(&parms.flags, u32Flags);
    VbglHGCMParmUInt32Set(&parms.handle, 0);

    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(parms)), &parms, sizeof(parms));

    if (RT_SUCCESS(rc))
    {
        rc = parms.hdr.result;
        if (RT_SUCCESS(rc))
        {
            *pu32ChannelHandle = parms.handle.u.value32;
        }
    }

    RTMemFree(pszCopy);

    return rc;
}
VBGLR3DECL(int) VbglR3HostChannelSend(uint32_t u32ChannelHandle,
                                      uint32_t u32HGCMClientId,
                                      void *pvData,
                                      uint32_t cbData)
{
    VBoxHostChannelSend parms;

    parms.hdr.result = VERR_WRONG_ORDER;
    parms.hdr.u32ClientID = u32HGCMClientId;
    parms.hdr.u32Function = VBOX_HOST_CHANNEL_FN_SEND;
    parms.hdr.cParms = 2;

    VbglHGCMParmUInt32Set(&parms.handle, u32ChannelHandle);
    VbglHGCMParmPtrSet(&parms.data, pvData, cbData);

    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(parms)), &parms, sizeof(parms));

    if (RT_SUCCESS(rc))
    {
        rc = parms.hdr.result;
    }

    return rc;
}
/**
 * Get the list of available shared folders.
 *
 * @returns VBox status code.
 * @param   u32ClientId     The client id returned by VbglR3SharedFolderConnect().
 * @param   fAutoMountOnly  Flag whether only auto-mounted shared folders
 *                          should be reported.
 * @param   ppaMappings     Allocated array which will retrieve the mapping info.  Needs
 *                          to be freed with VbglR3SharedFolderFreeMappings() later.
 * @param   pcMappings      The number of mappings returned in @a ppaMappings.
 */
VBGLR3DECL(int) VbglR3SharedFolderGetMappings(uint32_t u32ClientId, bool fAutoMountOnly,
                                              PVBGLR3SHAREDFOLDERMAPPING *ppaMappings, uint32_t *pcMappings)
{
    AssertPtrReturn(pcMappings, VERR_INVALID_PARAMETER);
    AssertPtrReturn(ppaMappings, VERR_INVALID_PARAMETER);

    *pcMappings = 0;
    *ppaMappings = NULL;

    VBoxSFQueryMappings Msg;

    Msg.callInfo.result = VERR_WRONG_ORDER;
    Msg.callInfo.u32ClientID = u32ClientId;
    Msg.callInfo.u32Function = SHFL_FN_QUERY_MAPPINGS;
    Msg.callInfo.cParms = 3;

    /* Set the mapping flags. */
    uint32_t u32Flags = 0; /** @todo SHFL_MF_UTF8 is not implemented yet. */
    if (fAutoMountOnly) /* We only want the mappings which get auto-mounted. */
        u32Flags |= SHFL_MF_AUTOMOUNT;
    VbglHGCMParmUInt32Set(&Msg.flags, u32Flags);

    /*
     * Prepare and get the actual mappings from the host service.
     */
    int rc = VINF_SUCCESS;
    uint32_t cMappings = 8; /* Should be a good default value. */
    uint32_t cbSize = cMappings * sizeof(VBGLR3SHAREDFOLDERMAPPING);
    VBGLR3SHAREDFOLDERMAPPING *ppaMappingsTemp = (PVBGLR3SHAREDFOLDERMAPPING)RTMemAllocZ(cbSize);
    if (!ppaMappingsTemp)
        return VERR_NO_MEMORY;

    do
    {
        VbglHGCMParmUInt32Set(&Msg.numberOfMappings, cMappings);
        VbglHGCMParmPtrSet(&Msg.mappings, ppaMappingsTemp, cbSize);

        rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
        if (RT_SUCCESS(rc))
        {
            rc = Msg.callInfo.result;
            if (RT_SUCCESS(rc))
            {
                VbglHGCMParmUInt32Get(&Msg.numberOfMappings, pcMappings);

                /* Do we have more mappings than we have allocated space for? */
                if (rc == VINF_BUFFER_OVERFLOW)
                {
                    cMappings = *pcMappings;
                    cbSize = cMappings * sizeof(VBGLR3SHAREDFOLDERMAPPING);
                    void *pvNew = RTMemRealloc(ppaMappingsTemp, cbSize);
                    AssertPtrBreakStmt(pvNew, rc = VERR_NO_MEMORY);
                    ppaMappingsTemp = (PVBGLR3SHAREDFOLDERMAPPING)pvNew;
                }
            }
        }
    } while (rc == VINF_BUFFER_OVERFLOW);

    if (   RT_FAILURE(rc)
        || !*pcMappings)
    {
        RTMemFree(ppaMappingsTemp);
        ppaMappingsTemp = NULL;
    }

    /* In this case, just return success with 0 mappings */
    if (   rc == VERR_INVALID_PARAMETER
        && fAutoMountOnly)
        rc = VINF_SUCCESS;

    *ppaMappings = ppaMappingsTemp;

    return rc;
}