static DECLCALLBACK(int) extCallback (uint32_t u32Function, uint32_t u32Format, void *pvData, uint32_t cbData) { if (g_pClient != NULL) { switch (u32Function) { case VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE: { LogRelFlow(("ANNOUNCE: g_fReadingData = %d\n", g_fReadingData)); if (g_fReadingData) { g_fDelayedAnnouncement = true; g_u32DelayedFormats = u32Format; } else { vboxSvcClipboardReportMsg (g_pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, u32Format); } } break; case VBOX_CLIPBOARD_EXT_FN_DATA_READ: { vboxSvcClipboardReportMsg (g_pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA, u32Format); } break; default: return VERR_NOT_SUPPORTED; } } return VINF_SUCCESS; }
static void vboxClipboardChanged (VBOXCLIPBOARDCONTEXT *pCtx) { LogFlow(("vboxClipboardChanged\n")); if (pCtx->pClient == NULL) { return; } /* Query list of available formats and report to host. */ if (OpenClipboard (pCtx->hwnd)) { uint32_t u32Formats = 0; UINT format = 0; while ((format = EnumClipboardFormats (format)) != 0) { LogFlow(("vboxClipboardChanged format %#x\n", format)); switch (format) { case CF_UNICODETEXT: case CF_TEXT: u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT; break; case CF_DIB: case CF_BITMAP: u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP; break; default: if (format >= 0xC000) { TCHAR szFormatName[256]; int cActual = GetClipboardFormatName(format, szFormatName, sizeof(szFormatName)/sizeof (TCHAR)); if (cActual) { if (strcmp (szFormatName, "HTML Format") == 0) { u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_HTML; } } } break; } } CloseClipboard (); LogFlow(("vboxClipboardChanged u32Formats %02X\n", u32Formats)); vboxSvcClipboardReportMsg (pCtx->pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, u32Formats); } }
/** * The guest is taking possession of the shared clipboard. Called by the HGCM clipboard * subsystem. * * @param pClient Context data for the guest system * @param u32Formats Clipboard formats the guest is offering */ void vboxClipboardFormatAnnounce(VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Formats) { Log(("vboxClipboardFormatAnnounce u32Formats %02X\n", u32Formats)); if (u32Formats == 0) { /* This is just an automatism, not a genuine announcement */ return; } vboxSvcClipboardReportMsg(pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA, u32Formats); }
/** * Disconnect the host side of the shared clipboard and send a "host disconnected" message * to the guest side. */ static DECLCALLBACK(int) svcDisconnect (void *, uint32_t u32ClientID, void *pvClient) { VBOXCLIPBOARDCLIENTDATA *pClient = (VBOXCLIPBOARDCLIENTDATA *)pvClient; vboxSvcClipboardReportMsg (pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT, 0); vboxClipboardDisconnect (pClient); memset (pClient, 0, sizeof (*pClient)); g_pClient = NULL; return VINF_SUCCESS; }
/** * Checks if something is present on the clipboard and calls vboxSvcClipboardReportMsg. * * @returns IPRT status code (ignored). * @param pCtx The context. */ static int vboxClipboardChanged(VBOXCLIPBOARDCONTEXT *pCtx) { if (pCtx->pClient == NULL) return VINF_SUCCESS; uint32_t fFormats = 0; bool fChanged = false; /* Retrieve the formats currently in the clipboard and supported by vbox */ int rc = queryNewPasteboardFormats(pCtx->pasteboard, &fFormats, &fChanged); if (RT_SUCCESS(rc) && fChanged) { vboxSvcClipboardReportMsg(pCtx->pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_REPORT_FORMATS, fFormats); Log(("vboxClipboardChanged fFormats %02X\n", fFormats)); } return rc; }
static int vboxClipboardReadDataFromClient (VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Format) { Assert(pCtx->pClient); Assert(pCtx->pClient->data.pv == NULL && pCtx->pClient->data.cb == 0 && pCtx->pClient->data.u32Format == 0); LogFlow(("vboxClipboardReadDataFromClient u32Format = %02X\n", u32Format)); ResetEvent (pCtx->hRenderEvent); vboxSvcClipboardReportMsg (pCtx->pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA, u32Format); WaitForSingleObject(pCtx->hRenderEvent, INFINITE); LogFlow(("vboxClipboardReadDataFromClient wait completed\n")); return VINF_SUCCESS; }
/** * Disconnect the host side of the shared clipboard and send a "host disconnected" message * to the guest side. */ static DECLCALLBACK(int) svcDisconnect (void *, uint32_t u32ClientID, void *pvClient) { VBOXCLIPBOARDCLIENTDATA *pClient = (VBOXCLIPBOARDCLIENTDATA *)pvClient; LogRel2(("svcDisconnect: u32ClientID = %d\n", u32ClientID)); vboxSvcClipboardReportMsg (pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT, 0); vboxSvcClipboardCompleteReadData(pClient, VERR_NO_DATA, 0); vboxClipboardDisconnect (pClient); memset (pClient, 0, sizeof (*pClient)); g_pClient = NULL; return VINF_SUCCESS; }
static DECLCALLBACK(void) svcCall (void *, VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) { int rc = VINF_SUCCESS; LogRel2(("svcCall: u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n", u32ClientID, u32Function, cParms, paParms)); VBOXCLIPBOARDCLIENTDATA *pClient = (VBOXCLIPBOARDCLIENTDATA *)pvClient; bool fAsynchronousProcessing = false; #ifdef DEBUG uint32_t i; for (i = 0; i < cParms; i++) { /** @todo parameters other than 32 bit */ LogRel2((" pparms[%d]: type %d value %d\n", i, paParms[i].type, paParms[i].u.uint32)); } #endif switch (u32Function) { case VBOX_SHARED_CLIPBOARD_FN_GET_HOST_MSG: { /* The quest requests a host message. */ LogRel2(("svcCall: VBOX_SHARED_CLIPBOARD_FN_GET_HOST_MSG\n")); if (cParms != VBOX_SHARED_CLIPBOARD_CPARMS_GET_HOST_MSG) { rc = VERR_INVALID_PARAMETER; } else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* msg */ || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* formats */ ) { rc = VERR_INVALID_PARAMETER; } else { /* Atomically verify the client's state. */ if (vboxSvcClipboardLock ()) { bool fMessageReturned = vboxSvcClipboardReturnMsg (pClient, paParms); if (fMessageReturned) { /* Just return to the caller. */ pClient->fAsync = false; } else { /* No event available at the time. Process asynchronously. */ fAsynchronousProcessing = true; pClient->fAsync = true; pClient->async.callHandle = callHandle; pClient->async.paParms = paParms; LogRel2(("svcCall: async.\n")); } vboxSvcClipboardUnlock (); } else { rc = VERR_NOT_SUPPORTED; } } } break; case VBOX_SHARED_CLIPBOARD_FN_FORMATS: { /* The guest reports that some formats are available. */ LogRel2(("svcCall: VBOX_SHARED_CLIPBOARD_FN_FORMATS\n")); if (cParms != VBOX_SHARED_CLIPBOARD_CPARMS_FORMATS) { rc = VERR_INVALID_PARAMETER; } else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* formats */ ) { rc = VERR_INVALID_PARAMETER; } else { uint32_t u32Formats; rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Formats); if (RT_SUCCESS (rc)) { if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_GUEST_TO_HOST && vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL) { rc = VERR_NOT_SUPPORTED; break; } if (g_pfnExtension) { VBOXCLIPBOARDEXTPARMS parms; parms.u32Format = u32Formats; g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE, &parms, sizeof (parms)); } else { vboxClipboardFormatAnnounce (pClient, u32Formats); } } } } break; case VBOX_SHARED_CLIPBOARD_FN_READ_DATA: { /* The guest wants to read data in the given format. */ LogRel2(("svcCall: VBOX_SHARED_CLIPBOARD_FN_READ_DATA\n")); if (cParms != VBOX_SHARED_CLIPBOARD_CPARMS_READ_DATA) { rc = VERR_INVALID_PARAMETER; } else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* format */ || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* ptr */ || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* size */ ) { rc = VERR_INVALID_PARAMETER; } else { uint32_t u32Format; void *pv; uint32_t cb; rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Format); if (RT_SUCCESS (rc)) { rc = VBoxHGCMParmPtrGet (&paParms[1], &pv, &cb); if (RT_SUCCESS (rc)) { if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_HOST_TO_GUEST && vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL) { rc = VERR_NOT_SUPPORTED; break; } uint32_t cbActual = 0; if (g_pfnExtension) { VBOXCLIPBOARDEXTPARMS parms; parms.u32Format = u32Format; parms.u.pvData = pv; parms.cbData = cb; g_fReadingData = true; rc = g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_DATA_READ, &parms, sizeof (parms)); LogRelFlow(("DATA: g_fDelayedAnnouncement = %d, g_u32DelayedFormats = 0x%x\n", g_fDelayedAnnouncement, g_u32DelayedFormats)); if (g_fDelayedAnnouncement) { vboxSvcClipboardReportMsg (g_pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, g_u32DelayedFormats); g_fDelayedAnnouncement = false; g_u32DelayedFormats = 0; } g_fReadingData = false; if (RT_SUCCESS (rc)) { cbActual = parms.cbData; } } else { /* Release any other pending read, as we only * support one pending read at one time. */ vboxSvcClipboardCompleteReadData(pClient, VERR_NO_DATA, 0); rc = vboxClipboardReadData (pClient, u32Format, pv, cb, &cbActual); } /* Remember our read request until it is completed. * See the protocol description above for more * information. */ if (rc == VINF_HGCM_ASYNC_EXECUTE) { if (vboxSvcClipboardLock()) { pClient->asyncRead.callHandle = callHandle; pClient->asyncRead.paParms = paParms; pClient->fReadPending = true; fAsynchronousProcessing = true; vboxSvcClipboardUnlock(); } else rc = VERR_NOT_SUPPORTED; } else if (RT_SUCCESS (rc)) { VBoxHGCMParmUInt32Set (&paParms[2], cbActual); } } } } } break; case VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA: { /* The guest writes the requested data. */ LogRel2(("svcCall: VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA\n")); if (cParms != VBOX_SHARED_CLIPBOARD_CPARMS_WRITE_DATA) { rc = VERR_INVALID_PARAMETER; } else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* format */ || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* ptr */ ) { rc = VERR_INVALID_PARAMETER; } else { void *pv; uint32_t cb; uint32_t u32Format; rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Format); if (RT_SUCCESS (rc)) { rc = VBoxHGCMParmPtrGet (&paParms[1], &pv, &cb); if (RT_SUCCESS (rc)) { if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_GUEST_TO_HOST && vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL) { rc = VERR_NOT_SUPPORTED; break; } if (g_pfnExtension) { VBOXCLIPBOARDEXTPARMS parms; parms.u32Format = u32Format; parms.u.pvData = pv; parms.cbData = cb; g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_DATA_WRITE, &parms, sizeof (parms)); } else { vboxClipboardWriteData (pClient, pv, cb, u32Format); } } } } } break; default: { rc = VERR_NOT_IMPLEMENTED; } } LogRelFlow(("svcCall: rc = %Rrc\n", rc)); if (!fAsynchronousProcessing) { g_pHelpers->pfnCallComplete (callHandle, rc); } }