/** * Shut down the shared clipboard subsystem and "disconnect" the guest. */ void vboxClipboardDisconnect (VBOXCLIPBOARDCLIENTDATA *pClient) { Log (("vboxClipboardDisconnect\n")); vboxSvcClipboardLock(); pClient->pCtx->pClient = NULL; vboxSvcClipboardUnlock(); }
/** * Called by the HGCM clipboard subsystem when we have requested data and that data arrives. * * @param pClient Context information about the guest VM * @param pv Buffer to which the data was written * @param cb The size of the data written * @param u32Format The format of the data written */ void vboxClipboardWriteData (VBOXCLIPBOARDCLIENTDATA *pClient, void *pv, uint32_t cb, uint32_t u32Format) { vboxSvcClipboardLock(); writeToPasteboard (pClient->pCtx->pasteboard, pv, cb, u32Format); vboxSvcClipboardUnlock(); }
/** * Synchronise the contents of the host clipboard with the guest, called by the HGCM layer * after a save and restore of the guest. */ int vboxClipboardSync (VBOXCLIPBOARDCLIENTDATA *pClient) { /* Sync the host clipboard content with the client. */ vboxSvcClipboardLock(); int rc = vboxClipboardChanged (pClient->pCtx); vboxSvcClipboardUnlock(); return rc; }
/** * Called by the HGCM clipboard subsystem when the guest wants to read the host clipboard. * * @param pClient Context information about the guest VM * @param u32Format The format that the guest would like to receive the data in * @param pv Where to write the data to * @param cb The size of the buffer to write the data to * @param pcbActual Where to write the actual size of the written data */ int vboxClipboardReadData (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Format, void *pv, uint32_t cb, uint32_t * pcbActual) { vboxSvcClipboardLock(); /* Default to no data available. */ *pcbActual = 0; int rc = readFromPasteboard (pClient->pCtx->pasteboard, u32Format, pv, cb, pcbActual); vboxSvcClipboardUnlock(); return rc; }
/** If the client in the guest is waiting for a read operation to complete * then complete it, otherwise return. See the protocol description in the * shared clipboard module description. */ void vboxSvcClipboardCompleteReadData(VBOXCLIPBOARDCLIENTDATA *pClient, int rc, uint32_t cbActual) { VBOXHGCMCALLHANDLE callHandle = NULL; VBOXHGCMSVCPARM *paParms = NULL; bool fReadPending = false; if (vboxSvcClipboardLock()) /* if not can we do anything useful? */ { callHandle = pClient->asyncRead.callHandle; paParms = pClient->asyncRead.paParms; fReadPending = pClient->fReadPending; pClient->fReadPending = false; vboxSvcClipboardUnlock(); } if (fReadPending) { VBoxHGCMParmUInt32Set (&paParms[2], cbActual); g_pHelpers->pfnCallComplete (callHandle, rc); } }
/** * Enable the shared clipboard - called by the hgcm clipboard subsystem. * * @param pClient Structure containing context information about the guest system * @returns RT status code */ int vboxClipboardConnect (VBOXCLIPBOARDCLIENTDATA *pClient, bool) { if (g_ctx.pClient != NULL) { /* One client only. */ return VERR_NOT_SUPPORTED; } vboxSvcClipboardLock(); pClient->pCtx = &g_ctx; pClient->pCtx->pClient = pClient; /* Initially sync the host clipboard content with the client. */ int rc = vboxClipboardSync (pClient); vboxSvcClipboardUnlock(); return rc; }
/** * The poller thread. * * This thread will check for the arrival of new data on the clipboard. * * @returns VINF_SUCCESS (not used). * @param Thread Our thread handle. * @param pvUser Pointer to the VBOXCLIPBOARDCONTEXT structure. * */ static int vboxClipboardThread (RTTHREAD ThreadSelf, void *pvUser) { Log (("vboxClipboardThread: starting clipboard thread\n")); AssertPtrReturn (pvUser, VERR_INVALID_PARAMETER); VBOXCLIPBOARDCONTEXT *pCtx = (VBOXCLIPBOARDCONTEXT *) pvUser; while (!pCtx->fTerminate) { /* call this behind the lock because we don't know if the api is thread safe and in any case we're calling several methods. */ vboxSvcClipboardLock(); vboxClipboardChanged (pCtx); vboxSvcClipboardUnlock(); /* Sleep for 200 msecs before next poll */ RTThreadUserWait (ThreadSelf, 200); } Log (("vboxClipboardThread: clipboard thread terminated successfully with return code %Rrc\n", VINF_SUCCESS)); 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); } }
void vboxSvcClipboardReportMsg (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Msg, uint32_t u32Formats) { if (vboxSvcClipboardLock ()) { switch (u32Msg) { case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT: { LogRelFlow(("vboxSvcClipboardReportMsg: Quit\n")); pClient->fMsgQuit = true; } break; case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA: { if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_GUEST_TO_HOST && vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL) { /* Skip the message. */ break; } LogRelFlow(("vboxSvcClipboardReportMsg: ReadData %02X\n", u32Formats)); pClient->u32RequestedFormat = u32Formats; pClient->fMsgReadData = true; } break; case VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS: { if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_HOST_TO_GUEST && vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL) { /* Skip the message. */ break; } LogRelFlow(("vboxSvcClipboardReportMsg: Formats %02X\n", u32Formats)); pClient->u32AvailableFormats = u32Formats; pClient->fMsgFormats = true; } break; default: { /* Invalid message. */ LogRelFlow(("vboxSvcClipboardReportMsg: invalid message %d\n", u32Msg)); } break; } if (pClient->fAsync) { /* The client waits for a response. */ bool fMessageReturned = vboxSvcClipboardReturnMsg (pClient, pClient->async.paParms); /* Make a copy of the handle. */ VBOXHGCMCALLHANDLE callHandle = pClient->async.callHandle; if (fMessageReturned) { /* There is a response. */ pClient->fAsync = false; } vboxSvcClipboardUnlock (); if (fMessageReturned) { LogRelFlow(("vboxSvcClipboardReportMsg: CallComplete\n")); g_pHelpers->pfnCallComplete (callHandle, VINF_SUCCESS); } } else { vboxSvcClipboardUnlock (); } } }