int vbglR3GRPerform(VMMDevRequestHeader *pReq)
{
    PVBGLREQHDR    pReqHdr = (PVBGLREQHDR)pReq;
    uint32_t const cbReq   = pReqHdr->cbIn;
    Assert(pReqHdr->cbOut == 0 || pReqHdr->cbOut == cbReq);
    pReqHdr->cbOut = cbReq;
    if (pReq->size < _1K)
        return vbglR3DoIOCtl(VBGL_IOCTL_VMMDEV_REQUEST(cbReq), pReqHdr, cbReq);
    return vbglR3DoIOCtl(VBGL_IOCTL_VMMDEV_REQUEST_BIG, pReqHdr, cbReq);
}
/**
 * Wait for the host to signal one or more events and return which.
 *
 * The events will only be delivered by the host if they have been enabled
 * previously using @a VbglR3CtlFilterMask.  If one or several of the events
 * have already been signalled but not yet waited for, this function will return
 * immediately and return those events.
 *
 * @returns IPRT status code.
 *
 * @param   fMask       The events we want to wait for, or-ed together.
 * @param   cMillies    How long to wait before giving up and returning
 *                      (VERR_TIMEOUT). Use RT_INDEFINITE_WAIT to wait until we
 *                      are interrupted or one of the events is signalled.
 * @param   pfEvents    Where to store the events signalled. Optional.
 */
VBGLR3DECL(int) VbglR3WaitEvent(uint32_t fMask, uint32_t cMillies, uint32_t *pfEvents)
{
    LogFlow(("VbglR3WaitEvent: fMask=0x%x, cMillies=%u, pfEvents=%p\n",
             fMask, cMillies, pfEvents));
    AssertReturn((fMask & ~VMMDEV_EVENT_VALID_EVENT_MASK) == 0, VERR_INVALID_PARAMETER);
    AssertPtrNullReturn(pfEvents, VERR_INVALID_POINTER);

    VBoxGuestWaitEventInfo waitEvent;
    waitEvent.u32TimeoutIn = cMillies;
    waitEvent.u32EventMaskIn = fMask;
    waitEvent.u32Result = VBOXGUEST_WAITEVENT_ERROR;
    waitEvent.u32EventFlagsOut = 0;
    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_WAITEVENT, &waitEvent, sizeof(waitEvent));
    if (RT_SUCCESS(rc))
    {
        /*
         * If a guest requests for an event which is not available on the host side
         * (because of an older host version, a disabled feature or older Guest Additions),
         * don't trigger an assertion here even in debug builds - would be annoying.
         */
#if 0
        AssertMsg(waitEvent.u32Result == VBOXGUEST_WAITEVENT_OK, ("%d rc=%Rrc\n", waitEvent.u32Result, rc));
#endif
        if (pfEvents)
            *pfEvents = waitEvent.u32EventFlagsOut;
    }

    LogFlow(("VbglR3WaitEvent: rc=%Rrc, u32EventFlagsOut=0x%x. u32Result=%d\n",
             rc, waitEvent.u32EventFlagsOut, waitEvent.u32Result));
    return rc;
}
VBGLR3DECL(int) VbglR3DnDConnect(uint32_t *pu32ClientId)
{
    /* Validate input */
    AssertPtrReturn(pu32ClientId, VERR_INVALID_POINTER);

    /* Initialize header */
    VBoxGuestHGCMConnectInfo Info;
    RT_ZERO(Info.Loc.u);
    Info.result      = VERR_WRONG_ORDER;
    Info.u32ClientID = UINT32_MAX;  /* try make valgrind shut up. */
    /* Initialize parameter */
    Info.Loc.type    = VMMDevHGCMLoc_LocalHost_Existing;
    int rc = RTStrCopy(Info.Loc.u.host.achName, sizeof(Info.Loc.u.host.achName), "VBoxDragAndDropSvc");
    if (RT_FAILURE(rc)) return rc;
    /* Do request */
    rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CONNECT, &Info, sizeof(Info));
    if (RT_SUCCESS(rc))
    {
        rc = Info.result;
        if (RT_SUCCESS(rc))
            *pu32ClientId = Info.u32ClientID;
    }
    if (rc == VERR_HGCM_SERVICE_NOT_FOUND)
        rc = VINF_PERMISSION_DENIED;
    return rc;
}
static int vbglR3DnDQueryNextHostMessageType(uint32_t uClientId, uint32_t *puMsg, uint32_t *pcParms, bool fWait)
{
    /* Validate input */
    AssertPtrReturn(puMsg,   VERR_INVALID_POINTER);
    AssertPtrReturn(pcParms, VERR_INVALID_POINTER);

    /* Initialize header */
    DragAndDropSvc::VBOXDNDNEXTMSGMSG Msg;
    RT_ZERO(Msg);
    Msg.hdr.result      = VERR_WRONG_ORDER;
    Msg.hdr.u32ClientID = uClientId;
    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG;
    Msg.hdr.cParms      = 3;
    /* Initialize parameter */
    Msg.msg.SetUInt32(0);
    Msg.num_parms.SetUInt32(0);
    Msg.block.SetUInt32(fWait);
    /* Do request */
    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    if (RT_SUCCESS(rc))
    {
        rc = Msg.hdr.result;
        if (RT_SUCCESS(rc))
        {
            /* Fetch results */
            rc = Msg.msg.GetUInt32(puMsg);         AssertRC(rc);
            rc = Msg.num_parms.GetUInt32(pcParms); AssertRC(rc);
        }
    }
    return rc;
}
/**
 * Get a host message.
 *
 * This will block until a message becomes available.
 *
 * @returns VBox status code.
 * @param   u32ClientId     The client id returned by VbglR3ClipboardConnect().
 * @param   pMsg            Where to store the message id.
 * @param   pfFormats       Where to store the format(s) the message applies to.
 */
VBGLR3DECL(int) VbglR3ClipboardGetHostMsg(uint32_t u32ClientId, uint32_t *pMsg, uint32_t *pfFormats)
{
    VBoxClipboardGetHostMsg Msg;

    Msg.hdr.result = VERR_WRONG_ORDER;
    Msg.hdr.u32ClientID = u32ClientId;
    Msg.hdr.u32Function = VBOX_SHARED_CLIPBOARD_FN_GET_HOST_MSG;
    Msg.hdr.cParms = 2;
    VbglHGCMParmUInt32Set(&Msg.msg, 0);
    VbglHGCMParmUInt32Set(&Msg.formats, 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 u32Msg;
            rc = VbglHGCMParmUInt32Get(&Msg.msg, &u32Msg);
            if (RT_SUCCESS(rc))
            {
                uint32_t fFormats;
                rc = VbglHGCMParmUInt32Get(&Msg.formats, &fFormats);
                if (RT_SUCCESS(rc))
                {
                    *pMsg = u32Msg;
                    *pfFormats = fFormats;
                    return Msg.hdr.result;
                }
            }
        }
    }

    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;
}
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;
}
static int vbglR3DnDHGProcessMoreDataMessageInternal(uint32_t  uClientId,
                                                     void     *pvData,
                                                     uint32_t  cbData,
                                                     uint32_t *pcbDataRecv)
{
    /* Validate input */
    AssertPtrReturn(pvData,      VERR_INVALID_POINTER);
    AssertReturn(cbData,         VERR_INVALID_PARAMETER);
    AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);

    /* Initialize header */
    DragAndDropSvc::VBOXDNDHGSENDMOREDATAMSG Msg;
    RT_ZERO(Msg);
    Msg.hdr.u32ClientID = g_clientId;
    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA;
    Msg.hdr.cParms      = 2;
    /* Initialize parameter */
    Msg.pvData.SetPtr(pvData, cbData);
    Msg.cData.SetUInt32(0);
    /* Do request */
    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    if (RT_SUCCESS(rc))
    {
        rc = Msg.hdr.result;
        if (   RT_SUCCESS(rc)
            || rc == VERR_BUFFER_OVERFLOW)
        {
            /* Fetch results */
            rc = Msg.cData.GetUInt32(pcbDataRecv); AssertRC(rc);
            /* A little bit paranoia */
            AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA);
        }
    }
    return rc;
}
static int vbglR3DnDGHProcessRequestPendingMessage(uint32_t  uClientId,
                                                   uint32_t *puScreenId)
{
    /* Validate input */
    AssertPtrReturn(puScreenId, VERR_INVALID_POINTER);

    /* Initialize header */
    DragAndDropSvc::VBOXDNDGHREQPENDINGMSG Msg;
    RT_ZERO(Msg);
    Msg.hdr.u32ClientID = uClientId;
    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_REQ_PENDING;
    Msg.hdr.cParms      = 1;
    /* Initialize parameter */
    Msg.uScreenId.SetUInt32(0);
    /* Do request */
    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    if (RT_SUCCESS(rc))
    {
        rc = Msg.hdr.result;
        if (RT_SUCCESS(rc))
        {
            /* Fetch results */
            rc = Msg.uScreenId.GetUInt32(puScreenId); AssertRC(rc);
        }
    }
    return rc;
}
Beispiel #10
0
/**
 * Change the IRQ filter mask.
 *
 * @returns IPRT status code.
 * @param   fOr     The OR mask.
 * @param   fNo     The NOT mask.
 */
VBGLR3DECL(int) VbglR3CtlFilterMask(uint32_t fOr, uint32_t fNot)
{
    VBoxGuestFilterMaskInfo Info;
    Info.u32OrMask = fOr;
    Info.u32NotMask = fNot;
    return vbglR3DoIOCtl(VBOXGUEST_IOCTL_CTL_FILTER_MASK, &Info, sizeof(Info));
}
/**
 * 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;
}
/**
 * Write guest core dump.
 *
 * @returns IPRT status code.
 */
VBGLR3DECL(int) VbglR3WriteCoreDump(void)
{
    VBGLIOCWRITECOREDUMP Req;
    VBGLREQHDR_INIT(&Req.Hdr, WRITE_CORE_DUMP);
    Req.u.In.fFlags = 0;
    return vbglR3DoIOCtl(VBGL_IOCTL_WRITE_CORE_DUMP, &Req.Hdr, sizeof(Req));
}
VBGLR3DECL(void) VbglR3HostChannelTerm(uint32_t u32HGCMClientId)
{
    VBoxGuestHGCMDisconnectInfo disconnectInfo;
    disconnectInfo.result = VERR_WRONG_ORDER;
    disconnectInfo.u32ClientID = u32HGCMClientId;

    vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_DISCONNECT, &disconnectInfo, sizeof(disconnectInfo));
}
Beispiel #14
0
/**
 * Report a change in the capabilities that we support to the host.
 *
 * @returns IPRT status code.
 * @param   fOr     Capabilities which have been added.
 * @param   fNot    Capabilities which have been removed.
 *
 * @todo    Move to a different file.
 */
VBGLR3DECL(int) VbglR3SetGuestCaps(uint32_t fOr, uint32_t fNot)
{
    VBoxGuestSetCapabilitiesInfo Info;
    Info.u32OrMask = fOr;
    Info.u32NotMask = fNot;
    return vbglR3DoIOCtl(VBOXGUEST_IOCTL_SET_GUEST_CAPABILITIES, &Info,
                         sizeof(Info));
}
/**
 * Write to the backdoor logger from ring 3 guest code.
 *
 * @returns IPRT status code.
 *
 * @param   pch     The string to log.  Does not need to be terminated.
 * @param   cch     The number of chars (bytes) to log.
 *
 * @remarks This currently does not accept more than 255 bytes of data at
 *          one time. It should probably be rewritten to use pass a pointer
 *          in the IOCtl.
 */
VBGLR3DECL(int) VbglR3WriteLog(const char *pch, size_t cch)
{
    /*
     * Quietly skip NULL strings.
     * (Happens in the RTLogBackdoorPrintf case.)
     */
    if (!cch)
        return VINF_SUCCESS;
    if (!VALID_PTR(pch))
        return VERR_INVALID_POINTER;

#ifdef RT_OS_WINDOWS
    /*
     * Duplicate the string as it may be read only (a C string).
     */
    void *pvTmp = RTMemDup(pch, cch);
    if (!pvTmp)
        return VERR_NO_MEMORY;
    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_LOG(cch), pvTmp, cch);
    RTMemFree(pvTmp);
    return rc;

#elif 0 /** @todo Several OSes could take this route (solaris and freebsd for instance). */
    /*
     * Handle the entire request in one go.
     */
    return vbglR3DoIOCtl(VBOXGUEST_IOCTL_LOG(cch), pvTmp, cch);

#else
    /*
     * *BSD does not accept more than 4KB per ioctl request, while
     * Linux can't express sizes above 8KB, so, split it up into 2KB chunks.
     */
# define STEP 2048
    int rc = VINF_SUCCESS;
    for (size_t off = 0; off < cch && RT_SUCCESS(rc); off += STEP)
    {
        size_t cbStep = RT_MIN(cch - off, STEP);
        rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_LOG(cbStep), (char *)pch + off, cbStep);
    }
# undef STEP
    return rc;
#endif
}
static int vbglR3DnDHGProcessActionMessage(uint32_t  uClientId,
                                           uint32_t  uMsg,
                                           uint32_t *puScreenId,
                                           uint32_t *puX,
                                           uint32_t *puY,
                                           uint32_t *puDefAction,
                                           uint32_t *puAllActions,
                                           char     *pszFormats,
                                           uint32_t  cbFormats,
                                           uint32_t *pcbFormatsRecv)
{
    /* Validate input */
    AssertPtrReturn(puScreenId,     VERR_INVALID_POINTER);
    AssertPtrReturn(puX,            VERR_INVALID_POINTER);
    AssertPtrReturn(puY,            VERR_INVALID_POINTER);
    AssertPtrReturn(puDefAction,    VERR_INVALID_POINTER);
    AssertPtrReturn(puAllActions,   VERR_INVALID_POINTER);
    AssertPtrReturn(pszFormats,     VERR_INVALID_POINTER);
    AssertReturn(cbFormats,         VERR_INVALID_PARAMETER);
    AssertPtrReturn(pcbFormatsRecv, VERR_INVALID_POINTER);

    /* Initialize header */
    DragAndDropSvc::VBOXDNDHGACTIONMSG Msg;
    RT_ZERO(Msg);
    Msg.hdr.u32ClientID = uClientId;
    Msg.hdr.u32Function = uMsg;
    Msg.hdr.cParms      = 7;
    /* Initialize parameter */
    Msg.uScreenId.SetUInt32(0);
    Msg.uX.SetUInt32(0);
    Msg.uY.SetUInt32(0);
    Msg.uDefAction.SetUInt32(0);
    Msg.uAllActions.SetUInt32(0);
    Msg.pvFormats.SetPtr(pszFormats, cbFormats);
    Msg.cFormats.SetUInt32(0);
    /* Do request */
    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    if (RT_SUCCESS(rc))
    {
        rc = Msg.hdr.result;
        if (RT_SUCCESS(rc))
        {
            /* Fetch results */
            rc = Msg.uScreenId.GetUInt32(puScreenId);     AssertRC(rc);
            rc = Msg.uX.GetUInt32(puX);                   AssertRC(rc);
            rc = Msg.uY.GetUInt32(puY);                   AssertRC(rc);
            rc = Msg.uDefAction.GetUInt32(puDefAction);   AssertRC(rc);
            rc = Msg.uAllActions.GetUInt32(puAllActions); AssertRC(rc);
            rc = Msg.cFormats.GetUInt32(pcbFormatsRecv);  AssertRC(rc);
            /* A little bit paranoia */
            AssertReturn(cbFormats >= *pcbFormatsRecv, VERR_TOO_MUCH_DATA);
        }
    }
    return rc;
}
Beispiel #17
0
/**
 * Disconnect from an HGCM service.
 *
 * @returns VBox status code.
 * @param   idClient        The client id returned by VbglR3InfoSvcConnect().
 */
VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient)
{
    VBoxGuestHGCMDisconnectInfo Info;
    Info.result = VERR_WRONG_ORDER;
    Info.u32ClientID = idClient;

    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_DISCONNECT, &Info, sizeof(Info));
    if (RT_SUCCESS(rc))
        rc = Info.result;
    return rc;
}
/**
 * Disconnect from the shared folder service.
 *
 * @returns VBox status code.
 * @param   u32ClientId     The client id returned by VbglR3InfoSvcConnect().
 */
VBGLR3DECL(int) VbglR3SharedFolderDisconnect(uint32_t u32ClientId)
{
    VBoxGuestHGCMDisconnectInfo Info;
    Info.result = VERR_WRONG_ORDER;
    Info.u32ClientID = u32ClientId;

    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_DISCONNECT, &Info, sizeof(Info));
    if (RT_SUCCESS(rc))
        rc = Info.result;
    return rc;
}
VBGLR3DECL(int) VbglR3DnDDisconnect(uint32_t u32ClientId)
{
    /* Initialize header */
    VBoxGuestHGCMDisconnectInfo Info;
    Info.result      = VERR_WRONG_ORDER;
    Info.u32ClientID = u32ClientId;
    /* Do request */
    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_DISCONNECT, &Info, sizeof(Info));
    if (RT_SUCCESS(rc))
        rc = Info.result;
    return rc;
}
VBGLR3DECL(void) VbglR3HostChannelDetach(uint32_t u32ChannelHandle,
                                         uint32_t u32HGCMClientId)
{
    VBoxHostChannelDetach parms;

    parms.hdr.result = VERR_WRONG_ORDER;
    parms.hdr.u32ClientID = u32HGCMClientId;
    parms.hdr.u32Function = VBOX_HOST_CHANNEL_FN_DETACH;
    parms.hdr.cParms = 1;

    VbglHGCMParmUInt32Set(&parms.handle, u32ChannelHandle);

    vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(parms)), &parms, sizeof(parms));
}
static int vbglR3DnDHGProcessCancelMessage(uint32_t uClientId)
{
    /* Initialize header */
    DragAndDropSvc::VBOXDNDHGCANCELMSG Msg;
    RT_ZERO(Msg);
    Msg.hdr.u32ClientID = uClientId;
    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_CANCEL;
    Msg.hdr.cParms      = 0;
    /* Do request */
    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    if (RT_SUCCESS(rc))
        rc = Msg.hdr.result;
    return rc;
}
VBGLR3DECL(int) VbglR3DnDGHSendData(void *pvData, uint32_t cbData)
{
    DO(("DATA: %x (%u)\n", pvData, cbData));
    /* Validate input */
    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
    AssertReturn(cbData,    VERR_INVALID_PARAMETER);

    /* Todo: URI support. Currently only data is send over to the host. For URI
     * support basically the same as in the H->G case (see
     * HostServices/DragAndDrop/dndmanager.h/cpp) has to be done:
     * 1. Parse the urilist
     * 2. Recursively send "create dir" and "transfer file" msg to the host
     * 3. Patch the urilist by removing all base dirnames
     * 4. On the host all needs to received and the urilist patched afterwards
     *    to point to the new location
     */

    /* Initialize header */
    DragAndDropSvc::VBOXDNDGHSENDDATAMSG Msg;
    RT_ZERO(Msg);
    Msg.hdr.result      = VERR_WRONG_ORDER;
    Msg.hdr.u32ClientID = g_clientId;
    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DATA;
    Msg.hdr.cParms      = 2;
    Msg.uSize.SetUInt32(cbData);
    int rc          = VINF_SUCCESS;
    uint32_t cbMax  = _1M;
    uint32_t cbSend = 0;
    while(cbSend < cbData)
    {
        /* Initialize parameter */
        uint32_t cbToSend = RT_MIN(cbData - cbSend, cbMax);
        Msg.pData.SetPtr(static_cast<uint8_t*>(pvData) + cbSend, cbToSend);
        /* Do request */
        rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
        if (RT_SUCCESS(rc))
        {
            rc = Msg.hdr.result;
            /* Did the host cancel the event? */
            if (rc == VERR_CANCELLED)
                break;
        }
        else
            break;
        cbSend += cbToSend;
//        RTThreadSleep(500);
    }
    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;
}
/**
 * Advertises guest clipboard formats to the host.
 *
 * @returns VBox status code.
 * @param   u32ClientId     The client id returned by VbglR3ClipboardConnect().
 * @param   fFormats        The formats to advertise.
 */
VBGLR3DECL(int) VbglR3ClipboardReportFormats(uint32_t u32ClientId, uint32_t fFormats)
{
    VBoxClipboardFormats Msg;

    Msg.hdr.result = VERR_WRONG_ORDER;
    Msg.hdr.u32ClientID = u32ClientId;
    Msg.hdr.u32Function = VBOX_SHARED_CLIPBOARD_FN_FORMATS;
    Msg.hdr.cParms = 1;
    VbglHGCMParmUInt32Set(&Msg.formats, fFormats);

    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    if (RT_SUCCESS(rc))
        rc = Msg.hdr.result;
    return rc;
}
static int vbglR3DnDHGProcessSendFileMessage(uint32_t  uClientId,
                                             char     *pszFilename,
                                             uint32_t  cbFilename,
                                             uint32_t *pcbFilenameRecv,
                                             void     *pvData,
                                             uint32_t  cbData,
                                             uint32_t *pcbDataRecv,
                                             uint32_t *pfMode)
{
    /* Validate input */
    AssertPtrReturn(pszFilename,     VERR_INVALID_POINTER);
    AssertReturn(cbFilename,         VERR_INVALID_PARAMETER);
    AssertPtrReturn(pcbFilenameRecv, VERR_INVALID_POINTER);
    AssertPtrReturn(pvData,          VERR_INVALID_POINTER);
    AssertReturn(cbData,             VERR_INVALID_PARAMETER);
    AssertPtrReturn(pcbDataRecv,     VERR_INVALID_POINTER);
    AssertPtrReturn(pfMode,          VERR_INVALID_POINTER);

    /* Initialize header */
    DragAndDropSvc::VBOXDNDHGSENDFILEMSG Msg;
    RT_ZERO(Msg);
    Msg.hdr.u32ClientID = uClientId;
    Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_FILE;
    Msg.hdr.cParms      = 5;
    /* Initialize parameter */
    Msg.pvName.SetPtr(pszFilename, cbFilename);
    Msg.cName.SetUInt32(0);
    Msg.pvData.SetPtr(pvData, cbData);
    Msg.cData.SetUInt32(0);
    Msg.fMode.SetUInt32(0);
    /* Do request */
    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    if (RT_SUCCESS(rc))
    {
        rc = Msg.hdr.result;
        if (RT_SUCCESS(rc))
        {
            /* Fetch results */
            rc = Msg.cName.GetUInt32(pcbFilenameRecv); AssertRC(rc);
            rc = Msg.cData.GetUInt32(pcbDataRecv);     AssertRC(rc);
            rc = Msg.fMode.GetUInt32(pfMode);          AssertRC(rc);
            /* A little bit paranoia */
            AssertReturn(cbFilename >= *pcbFilenameRecv, VERR_TOO_MUCH_DATA);
            AssertReturn(cbData     >= *pcbDataRecv,     VERR_TOO_MUCH_DATA);
        }
    }
    return rc;
}
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) VbglR3DnDHGAcknowledgeOperation(uint32_t uAction)
{
    DO(("ACK: %u\n", uAction));
    /* Initialize header */
    DragAndDropSvc::VBOXDNDHGACKOPMSG Msg;
    RT_ZERO(Msg);
    Msg.hdr.result      = VERR_WRONG_ORDER;
    Msg.hdr.u32ClientID = g_clientId;
    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_ACK_OP;
    Msg.hdr.cParms      = 1;
    /* Initialize parameter */
    Msg.uAction.SetUInt32(uAction);
    /* Do request */
    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    if (RT_SUCCESS(rc))
        rc = Msg.hdr.result;
    return rc;
}
/**
 * Connects to the shared folder service.
 *
 * @returns VBox status code
 * @param   pu32ClientId    Where to put the client id on success. The client id
 *                          must be passed to all the other calls to the service.
 */
VBGLR3DECL(int) VbglR3SharedFolderConnect(uint32_t *pu32ClientId)
{
    VBoxGuestHGCMConnectInfo Info;
    Info.result = VERR_WRONG_ORDER;
    Info.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
    RT_ZERO(Info.Loc.u);
    strcpy(Info.Loc.u.host.achName, "VBoxSharedFolders");
    Info.u32ClientID = UINT32_MAX;  /* try make valgrind shut up. */

    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CONNECT, &Info, sizeof(Info));
    if (RT_SUCCESS(rc))
    {
        rc = Info.result;
        if (RT_SUCCESS(rc))
            *pu32ClientId = Info.u32ClientID;
    }
    return rc;
}
VBGLR3DECL(int) VbglR3DnDGHErrorEvent(int rcOp)
{
    DO(("GH_ERROR\n"));

    /* Initialize header */
    DragAndDropSvc::VBOXDNDGHEVTERRORMSG Msg;
    RT_ZERO(Msg);
    Msg.hdr.result      = VERR_WRONG_ORDER;
    Msg.hdr.u32ClientID = g_clientId;
    Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_EVT_ERROR;
    Msg.hdr.cParms      = 1;
    /* Initialize parameter */
    Msg.uRC.SetUInt32(rcOp);
    /* Do request */
    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    if (RT_SUCCESS(rc))
        rc = Msg.hdr.result;
    return rc;
}
VBGLR3DECL(int) VbglR3HostChannelEventCancel(uint32_t u32ChannelHandle,
                                             uint32_t u32HGCMClientId)
{
    VBoxHostChannelEventCancel parms;

    parms.hdr.result = VERR_WRONG_ORDER;
    parms.hdr.u32ClientID = u32HGCMClientId;
    parms.hdr.u32Function = VBOX_HOST_CHANNEL_FN_EVENT_CANCEL;
    parms.hdr.cParms = 0;

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

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

    return rc;
}