void* VBoxClipboardService::_VBoxReadHostClipboard(uint32_t format, uint32_t *pcb) { uint32_t cb = 1024; void *pv; int rc; pv = malloc(cb); if (pv == NULL) return NULL; rc = VbglR3ClipboardReadData(fClientId, format, pv, cb, pcb); if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW)) return pv; if (rc == VINF_BUFFER_OVERFLOW) { free(pv); cb = *pcb; pv = malloc(cb); if (pv == NULL) return NULL; rc = VbglR3ClipboardReadData(fClientId, format, pv, cb, pcb); if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW)) return pv; free(pv); } return NULL; }
/** * Get clipboard data from the host. * * @returns VBox result code * @param u32Format The format of the data being requested * @retval ppv On success and if pcb > 0, this will point to a buffer * to be freed with RTMemFree containing the data read. * @retval pcb On success, this contains the number of bytes of data * returned */ int ClipRequestDataForX11(VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Format, void **ppv, uint32_t *pcb) { int rc = VINF_SUCCESS; uint32_t cb = 1024; void *pv = RTMemAlloc(cb); *ppv = 0; LogRelFlowFunc(("u32Format=%u\n", u32Format)); if (RT_UNLIKELY(!pv)) rc = VERR_NO_MEMORY; if (RT_SUCCESS(rc)) rc = VbglR3ClipboardReadData(g_ctx.client, u32Format, pv, cb, pcb); if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW)) *ppv = pv; /* A return value of VINF_BUFFER_OVERFLOW tells us to try again with a * larger buffer. The size of the buffer needed is placed in *pcb. * So we start all over again. */ if (rc == VINF_BUFFER_OVERFLOW) { cb = *pcb; RTMemFree(pv); pv = RTMemAlloc(cb); if (RT_UNLIKELY(!pv)) rc = VERR_NO_MEMORY; if (RT_SUCCESS(rc)) rc = VbglR3ClipboardReadData(g_ctx.client, u32Format, pv, cb, pcb); if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW)) *ppv = pv; } /* Catch other errors. This also catches the case in which the buffer was * too small a second time, possibly because the clipboard contents * changed half-way through the operation. Since we can't say whether or * not this is actually an error, we just return size 0. */ if (RT_FAILURE(rc) || (VINF_BUFFER_OVERFLOW == rc)) { *pcb = 0; if (pv != NULL) RTMemFree(pv); } LogRelFlowFunc(("returning %Rrc\n", rc)); if (RT_SUCCESS(rc)) LogRelFlow((" *pcb=%d\n", *pcb)); return rc; }
/** * Allocate memory for host buffer and receive it. * * @param u32ClientId Host connection. * @param fFormat Buffer data format. * @param pData Where to store received data. * @param cbDataSize The size of the received data. * @param cbMemSize The actual size of memory occupied by *pData. * * @returns IPRT status code. */ static int vbclClipboardReadHostData(uint32_t u32ClientId, uint32_t fFormat, void **pData, uint32_t *cbDataSize, uint32_t *cbMemSize) { int rc; AssertReturn(pData && cbDataSize && cbMemSize, VERR_INVALID_PARAMETER); uint32_t cbDataSizeInternal = _4K; uint32_t cbMemSizeInternal = cbDataSizeInternal; void *pDataInternal = RTMemPageAllocZ(cbDataSizeInternal); if (!pDataInternal) return VERR_NO_MEMORY; rc = VbglR3ClipboardReadData(u32ClientId, fFormat, pDataInternal, cbMemSizeInternal, &cbDataSizeInternal); if (rc == VINF_BUFFER_OVERFLOW) { /* Reallocate bigger buffer and receive all the data */ RTMemPageFree(pDataInternal, cbMemSizeInternal); cbDataSizeInternal = cbMemSizeInternal = RT_ALIGN_32(cbDataSizeInternal, PAGE_SIZE); pDataInternal = RTMemPageAllocZ(cbMemSizeInternal); if (!pDataInternal) return VERR_NO_MEMORY; rc = VbglR3ClipboardReadData(u32ClientId, fFormat, pDataInternal, cbMemSizeInternal, &cbDataSizeInternal); } /* Error occurred of zero-sized buffer */ if (RT_FAILURE(rc)) { RTMemPageFree(pDataInternal, cbMemSizeInternal); return VERR_NO_MEMORY; } *pData = pDataInternal; *cbDataSize = cbDataSizeInternal; *cbMemSize = cbMemSizeInternal; return rc; }
static LRESULT vboxClipboardProcessMsg(PVBOXCLIPBOARDCONTEXT pCtx, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { AssertPtr(pCtx); LRESULT rc = 0; switch (msg) { case WM_CLIPBOARDUPDATE: { Log(("WM_CLIPBOARDUPDATE\n")); if (GetClipboardOwner() != hwnd) { /* Clipboard was updated by another application. */ vboxClipboardChanged(pCtx); } } break; case WM_CHANGECBCHAIN: { if (vboxClipboardIsNewAPI(pCtx)) { rc = DefWindowProc(hwnd, msg, wParam, lParam); break; } HWND hwndRemoved = (HWND)wParam; HWND hwndNext = (HWND)lParam; LogFlowFunc(("WM_CHANGECBCHAIN: hwndRemoved %p, hwndNext %p, hwnd %p\n", hwndRemoved, hwndNext, pCtx->hwnd)); if (hwndRemoved == pCtx->hwndNextInChain) { /* The window that was next to our in the chain is being removed. * Relink to the new next window. */ pCtx->hwndNextInChain = hwndNext; } else { if (pCtx->hwndNextInChain) { /* Pass the message further. */ DWORD_PTR dwResult; rc = SendMessageTimeout(pCtx->hwndNextInChain, WM_CHANGECBCHAIN, wParam, lParam, 0, CBCHAIN_TIMEOUT, &dwResult); if (!rc) rc = (LRESULT) dwResult; } } } break; case WM_DRAWCLIPBOARD: { LogFlowFunc(("WM_DRAWCLIPBOARD, hwnd %p\n", pCtx->hwnd)); if (GetClipboardOwner() != hwnd) { /* Clipboard was updated by another application. */ /* WM_DRAWCLIPBOARD always expects a return code of 0, so don't change "rc" here. */ int vboxrc = vboxClipboardChanged(pCtx); if (RT_FAILURE(vboxrc)) LogFlowFunc(("vboxClipboardChanged failed, rc = %Rrc\n", vboxrc)); } if (pCtx->hwndNextInChain) { /* Pass the message to next windows in the clipboard chain. */ SendMessageTimeout(pCtx->hwndNextInChain, msg, wParam, lParam, 0, CBCHAIN_TIMEOUT, NULL); } } break; case WM_TIMER: { if (vboxClipboardIsNewAPI(pCtx)) break; HWND hViewer = GetClipboardViewer(); /* Re-register ourselves in the clipboard chain if our last ping * timed out or there seems to be no valid chain. */ if (!hViewer || pCtx->fCBChainPingInProcess) { vboxClipboardRemoveFromCBChain(pCtx); vboxClipboardAddToCBChain(pCtx); } /* Start a new ping by passing a dummy WM_CHANGECBCHAIN to be * processed by ourselves to the chain. */ pCtx->fCBChainPingInProcess = TRUE; hViewer = GetClipboardViewer(); if (hViewer) SendMessageCallback(hViewer, WM_CHANGECBCHAIN, (WPARAM)pCtx->hwndNextInChain, (LPARAM)pCtx->hwndNextInChain, vboxClipboardChainPingProc, (ULONG_PTR)pCtx); } break; case WM_CLOSE: { /* Do nothing. Ignore the message. */ } break; case WM_RENDERFORMAT: { /* Insert the requested clipboard format data into the clipboard. */ uint32_t u32Format = 0; UINT format = (UINT)wParam; LogFlowFunc(("WM_RENDERFORMAT, format = %x\n", format)); switch (format) { case CF_UNICODETEXT: u32Format |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT; break; case CF_DIB: u32Format |= 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) { u32Format |= VBOX_SHARED_CLIPBOARD_FMT_HTML; } } } break; } if (u32Format == 0) { /* Unsupported clipboard format is requested. */ LogFlowFunc(("Unsupported clipboard format requested: %ld\n", u32Format)); EmptyClipboard(); } else { const uint32_t cbPrealloc = 4096; /** @todo r=andy Make it dynamic for supporting larger text buffers! */ uint32_t cb = 0; /* Preallocate a buffer, most of small text transfers will fit into it. */ HANDLE hMem = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cbPrealloc); LogFlowFunc(("Preallocated handle hMem = %p\n", hMem)); if (hMem) { void *pMem = GlobalLock(hMem); LogFlowFunc(("Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem))); if (pMem) { /* Read the host data to the preallocated buffer. */ int vboxrc = VbglR3ClipboardReadData(pCtx->u32ClientID, u32Format, pMem, cbPrealloc, &cb); LogFlowFunc(("VbglR3ClipboardReadData returned with rc = %Rrc\n", vboxrc)); if (RT_SUCCESS(vboxrc)) { if (cb == 0) { /* 0 bytes returned means the clipboard is empty. * Deallocate the memory and set hMem to NULL to get to * the clipboard empty code path. */ GlobalUnlock(hMem); GlobalFree(hMem); hMem = NULL; } else if (cb > cbPrealloc) { GlobalUnlock(hMem); /* The preallocated buffer is too small, adjust the size. */ hMem = GlobalReAlloc(hMem, cb, 0); LogFlowFunc(("Reallocated hMem = %p\n", hMem)); if (hMem) { pMem = GlobalLock(hMem); LogFlowFunc(("Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem))); if (pMem) { /* Read the host data to the preallocated buffer. */ uint32_t cbNew = 0; vboxrc = VbglR3ClipboardReadData(pCtx->u32ClientID, u32Format, pMem, cb, &cbNew); LogFlowFunc(("VbglR3ClipboardReadData returned with rc = %Rrc, cb = %d, cbNew = %d\n", vboxrc, cb, cbNew)); if (RT_SUCCESS (vboxrc) && cbNew <= cb) { cb = cbNew; } else { GlobalUnlock(hMem); GlobalFree(hMem); hMem = NULL; } } else { GlobalFree(hMem); hMem = NULL; } } } if (hMem) { /* pMem is the address of the data. cb is the size of returned data. */ /* Verify the size of returned text, the memory block for clipboard * must have the exact string size. */ if (u32Format == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { size_t cbActual = 0; HRESULT hrc = StringCbLengthW((LPWSTR)pMem, cb, &cbActual); if (FAILED (hrc)) { /* Discard invalid data. */ GlobalUnlock(hMem); GlobalFree(hMem); hMem = NULL; } else { /* cbActual is the number of bytes, excluding those used * for the terminating null character. */ cb = (uint32_t)(cbActual + 2); } } } if (hMem) { GlobalUnlock(hMem); hMem = GlobalReAlloc(hMem, cb, 0); LogFlowFunc(("Reallocated hMem = %p\n", hMem)); if (hMem) { /* 'hMem' contains the host clipboard data. * size is 'cb' and format is 'format'. */ HANDLE hClip = SetClipboardData(format, hMem); LogFlowFunc(("WM_RENDERFORMAT hClip = %p\n", hClip)); if (hClip) { /* The hMem ownership has gone to the system. Finish the processing. */ break; } /* Cleanup follows. */ } } } if (hMem) GlobalUnlock(hMem); } if (hMem) GlobalFree(hMem); } /* Something went wrong. */ EmptyClipboard(); } } break; case WM_RENDERALLFORMATS: { /* Do nothing. The clipboard formats will be unavailable now, because the * windows is to be destroyed and therefore the guest side becomes inactive. */ int vboxrc = vboxOpenClipboard(hwnd); if (RT_SUCCESS(vboxrc)) { EmptyClipboard(); CloseClipboard(); } else { LogFlowFunc(("WM_RENDERALLFORMATS: Failed to open clipboard! rc: %Rrc\n", vboxrc)); } } break; case WM_USER: { /* Announce available formats. Do not insert data, they will be inserted in WM_RENDER*. */ uint32_t u32Formats = (uint32_t)lParam; int vboxrc = vboxOpenClipboard(hwnd); if (RT_SUCCESS(vboxrc)) { EmptyClipboard(); HANDLE hClip = NULL; if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { LogFlowFunc(("WM_USER: VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT\n")); hClip = SetClipboardData(CF_UNICODETEXT, NULL); } if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP) { LogFlowFunc(("WM_USER: VBOX_SHARED_CLIPBOARD_FMT_BITMAP\n")); hClip = SetClipboardData(CF_DIB, NULL); } if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML) { UINT format = RegisterClipboardFormat ("HTML Format"); LogFlowFunc(("WM_USER: VBOX_SHARED_CLIPBOARD_FMT_HTML 0x%04X\n", format)); if (format != 0) { hClip = SetClipboardData(format, NULL); } } CloseClipboard(); LogFlowFunc(("WM_USER: hClip = %p, err = %ld\n", hClip, GetLastError ())); } else { LogFlowFunc(("WM_USER: Failed to open clipboard! error = %Rrc\n", vboxrc)); } } break; case WM_USER + 1: { /* Send data in the specified format to the host. */ uint32_t u32Formats = (uint32_t)lParam; HANDLE hClip = NULL; int vboxrc = vboxOpenClipboard(hwnd); if (RT_SUCCESS(vboxrc)) { if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP) { hClip = GetClipboardData(CF_DIB); if (hClip != NULL) { LPVOID lp = GlobalLock(hClip); if (lp != NULL) { LogFlowFunc(("WM_USER + 1: CF_DIB\n")); vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_BITMAP, lp, GlobalSize(hClip)); GlobalUnlock(hClip); } else { hClip = NULL; } } } else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { hClip = GetClipboardData(CF_UNICODETEXT); if (hClip != NULL) { LPWSTR uniString = (LPWSTR)GlobalLock(hClip); if (uniString != NULL) { LogFlowFunc(("WM_USER + 1: CF_UNICODETEXT\n")); vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, uniString, (lstrlenW(uniString) + 1) * 2); GlobalUnlock(hClip); } else { hClip = NULL; } } } else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML) { UINT format = RegisterClipboardFormat ("HTML Format"); if (format != 0) { hClip = GetClipboardData(format); if (hClip != NULL) { LPVOID lp = GlobalLock(hClip); if (lp != NULL) { LogFlowFunc(("WM_USER + 1: CF_HTML\n")); vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_HTML, lp, GlobalSize(hClip)); GlobalUnlock(hClip); } else { hClip = NULL; } } } } CloseClipboard(); } else { LogFlowFunc(("WM_USER: Failed to open clipboard! rc: %Rrc\n", vboxrc)); } if (hClip == NULL) { /* Requested clipboard format is not available, send empty data. */ VbglR3ClipboardWriteData(pCtx->u32ClientID, 0, NULL, 0); } } break; case WM_DESTROY: { vboxClipboardRemoveFromCBChain(pCtx); if (pCtx->timerRefresh) KillTimer(pCtx->hwnd, 0); /* * don't need to call PostQuitMessage cause * the VBoxTray already finished a message loop */ } break; default: { rc = DefWindowProc(hwnd, msg, wParam, lParam); } } #ifndef DEBUG_andy LogFlowFunc(("vboxClipboardProcessMsg returned with rc = %ld\n", rc)); #endif return rc; }
static LRESULT vboxClipboardProcessMsg(PVBOXCLIPBOARDCONTEXT pCtx, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { AssertPtr(pCtx); const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win; LRESULT rc = 0; switch (msg) { case WM_CLIPBOARDUPDATE: { Log(("WM_CLIPBOARDUPDATE\n")); if (GetClipboardOwner() != hwnd) { /* Clipboard was updated by another application. */ uint32_t uFormats; int vboxrc = VBoxClipboardWinGetFormats(&pCtx->Win, &uFormats); if (RT_SUCCESS(vboxrc)) vboxrc = VbglR3ClipboardReportFormats(pCtx->u32ClientID, uFormats); } } break; case WM_CHANGECBCHAIN: { if (VBoxClipboardWinIsNewAPI(&pWinCtx->newAPI)) { rc = DefWindowProc(hwnd, msg, wParam, lParam); break; } HWND hWndRemoved = (HWND)wParam; HWND hWndNext = (HWND)lParam; LogFlowFunc(("WM_CHANGECBCHAIN: hWndRemoved=%p, hWndNext=%p, hWnd=%p\n", hWndRemoved, hWndNext, pWinCtx->hWnd)); if (hWndRemoved == pWinCtx->hWndNextInChain) { /* The window that was next to our in the chain is being removed. * Relink to the new next window. */ pWinCtx->hWndNextInChain = hWndNext; } else { if (pWinCtx->hWndNextInChain) { /* Pass the message further. */ DWORD_PTR dwResult; rc = SendMessageTimeout(pWinCtx->hWndNextInChain, WM_CHANGECBCHAIN, wParam, lParam, 0, VBOX_CLIPBOARD_CBCHAIN_TIMEOUT_MS, &dwResult); if (!rc) rc = (LRESULT)dwResult; } } } break; case WM_DRAWCLIPBOARD: { LogFlowFunc(("WM_DRAWCLIPBOARD, hwnd %p\n", pWinCtx->hWnd)); if (GetClipboardOwner() != hwnd) { /* Clipboard was updated by another application. */ /* WM_DRAWCLIPBOARD always expects a return code of 0, so don't change "rc" here. */ uint32_t uFormats; int vboxrc = VBoxClipboardWinGetFormats(pWinCtx, &uFormats); if (RT_SUCCESS(vboxrc)) vboxrc = VbglR3ClipboardReportFormats(pCtx->u32ClientID, uFormats); } if (pWinCtx->hWndNextInChain) { /* Pass the message to next windows in the clipboard chain. */ SendMessageTimeout(pWinCtx->hWndNextInChain, msg, wParam, lParam, 0, VBOX_CLIPBOARD_CBCHAIN_TIMEOUT_MS, NULL); } } break; case WM_TIMER: { if (VBoxClipboardWinIsNewAPI(&pWinCtx->newAPI)) break; HWND hViewer = GetClipboardViewer(); /* Re-register ourselves in the clipboard chain if our last ping * timed out or there seems to be no valid chain. */ if (!hViewer || pWinCtx->oldAPI.fCBChainPingInProcess) { VBoxClipboardWinRemoveFromCBChain(pWinCtx); VBoxClipboardWinAddToCBChain(pWinCtx); } /* Start a new ping by passing a dummy WM_CHANGECBCHAIN to be * processed by ourselves to the chain. */ pWinCtx->oldAPI.fCBChainPingInProcess = TRUE; hViewer = GetClipboardViewer(); if (hViewer) SendMessageCallback(hViewer, WM_CHANGECBCHAIN, (WPARAM)pWinCtx->hWndNextInChain, (LPARAM)pWinCtx->hWndNextInChain, VBoxClipboardWinChainPingProc, (ULONG_PTR)pWinCtx); } break; case WM_CLOSE: { /* Do nothing. Ignore the message. */ } break; case WM_RENDERFORMAT: { /* Insert the requested clipboard format data into the clipboard. */ uint32_t fFormat = VBOX_SHARED_CLIPBOARD_FMT_NONE; const UINT cfFormat = (UINT)wParam; switch (cfFormat) { case CF_UNICODETEXT: fFormat = VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT; break; case CF_DIB: fFormat = VBOX_SHARED_CLIPBOARD_FMT_BITMAP; break; #ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST case CF_HDROP: fFormat = VBOX_SHARED_CLIPBOARD_FMT_URI_LIST; break; #endif default: if (cfFormat >= 0xC000) /** @todo r=andy Explain. */ { TCHAR szFormatName[256]; /** @todo r=andy Do we need Unicode support here as well? */ int cActual = GetClipboardFormatName(cfFormat, szFormatName, sizeof(szFormatName) / sizeof(TCHAR)); if (cActual) { if (strcmp(szFormatName, "HTML Format") == 0) fFormat = VBOX_SHARED_CLIPBOARD_FMT_HTML; } } break; } LogFunc(("WM_RENDERFORMAT: format=%u -> fFormat=0x%x\n", cfFormat, fFormat)); if (fFormat == VBOX_SHARED_CLIPBOARD_FMT_NONE) { /* Unsupported clipboard format is requested. */ LogRel(("Clipboard: Unsupported clipboard format requested (0x%x)\n", fFormat)); VBoxClipboardWinClear(); } #ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST else if (fFormat == VBOX_SHARED_CLIPBOARD_FMT_URI_LIST) { } #endif else { const uint32_t cbPrealloc = _4K; uint32_t cb = 0; /* Preallocate a buffer, most of small text transfers will fit into it. */ HANDLE hMem = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cbPrealloc); LogFlowFunc(("Preallocated handle hMem = %p\n", hMem)); if (hMem) { void *pMem = GlobalLock(hMem); LogFlowFunc(("Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem))); if (pMem) { /* Read the host data to the preallocated buffer. */ int vboxrc = VbglR3ClipboardReadData(pCtx->u32ClientID, fFormat, pMem, cbPrealloc, &cb); LogFlowFunc(("VbglR3ClipboardReadData returned with rc = %Rrc\n", vboxrc)); if (RT_SUCCESS(vboxrc)) { if (cb == 0) { /* 0 bytes returned means the clipboard is empty. * Deallocate the memory and set hMem to NULL to get to * the clipboard empty code path. */ GlobalUnlock(hMem); GlobalFree(hMem); hMem = NULL; } else if (cb > cbPrealloc) { GlobalUnlock(hMem); /* The preallocated buffer is too small, adjust the size. */ hMem = GlobalReAlloc(hMem, cb, 0); LogFlowFunc(("Reallocated hMem = %p\n", hMem)); if (hMem) { pMem = GlobalLock(hMem); LogFlowFunc(("Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem))); if (pMem) { /* Read the host data to the preallocated buffer. */ uint32_t cbNew = 0; vboxrc = VbglR3ClipboardReadData(pCtx->u32ClientID, fFormat, pMem, cb, &cbNew); LogFlowFunc(("VbglR3ClipboardReadData returned with rc = %Rrc, cb = %d, cbNew = %d\n", vboxrc, cb, cbNew)); if (RT_SUCCESS(vboxrc) && cbNew <= cb) { cb = cbNew; } else { GlobalUnlock(hMem); GlobalFree(hMem); hMem = NULL; } } else { GlobalFree(hMem); hMem = NULL; } } } if (hMem) { /* pMem is the address of the data. cb is the size of returned data. */ /* Verify the size of returned text, the memory block for clipboard * must have the exact string size. */ if (fFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { size_t cbActual = 0; HRESULT hrc = StringCbLengthW((LPWSTR)pMem, cb, &cbActual); if (FAILED(hrc)) { /* Discard invalid data. */ GlobalUnlock(hMem); GlobalFree(hMem); hMem = NULL; } else { /* cbActual is the number of bytes, excluding those used * for the terminating null character. */ cb = (uint32_t)(cbActual + 2); } } } if (hMem) { GlobalUnlock(hMem); hMem = GlobalReAlloc(hMem, cb, 0); LogFlowFunc(("Reallocated hMem = %p\n", hMem)); if (hMem) { /* 'hMem' contains the host clipboard data. * size is 'cb' and format is 'format'. */ HANDLE hClip = SetClipboardData(cfFormat, hMem); LogFlowFunc(("WM_RENDERFORMAT hClip = %p\n", hClip)); if (hClip) { /* The hMem ownership has gone to the system. Finish the processing. */ break; } /* Cleanup follows. */ } } } if (hMem) GlobalUnlock(hMem); } if (hMem) GlobalFree(hMem); } /* Something went wrong. */ VBoxClipboardWinClear(); } } break; case WM_RENDERALLFORMATS: { /* Do nothing. The clipboard formats will be unavailable now, because the * windows is to be destroyed and therefore the guest side becomes inactive. */ int vboxrc = VBoxClipboardWinOpen(hwnd); if (RT_SUCCESS(vboxrc)) { VBoxClipboardWinClear(); VBoxClipboardWinClose(); } } break; case VBOX_CLIPBOARD_WM_SET_FORMATS: { /* Announce available formats. Do not insert data, they will be inserted in WM_RENDER*. */ VBOXCLIPBOARDFORMATS fFormats = (uint32_t)lParam; LogFlowFunc(("VBOX_WM_SHCLPB_SET_FORMATS: fFormats=0x%x\n", fFormats)); int vboxrc = VBoxClipboardWinOpen(hwnd); if (RT_SUCCESS(vboxrc)) { VBoxClipboardWinClear(); HANDLE hClip = NULL; if (fFormats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) hClip = SetClipboardData(CF_UNICODETEXT, NULL); if (fFormats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP) hClip = SetClipboardData(CF_DIB, NULL); if (fFormats & VBOX_SHARED_CLIPBOARD_FMT_HTML) { UINT format = RegisterClipboardFormat("HTML Format"); if (format != 0) hClip = SetClipboardData(format, NULL); } #ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST if (fFormats & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST) hClip = SetClipboardData(CF_HDROP, NULL); #endif /** @todo Implement more flexible clipboard precedence for supported formats. */ if (hClip == NULL) LogRel(("Clipboard: Unsupported format(s) from host (0x%x), ignoring\n", fFormats)); VBoxClipboardWinClose(); LogFlowFunc(("VBOX_WM_SHCLPB_SET_FORMATS: hClip=%p, lastErr=%ld\n", hClip, GetLastError())); } } break; case VBOX_CLIPBOARD_WM_READ_DATA: { /* Send data in the specified format to the host. */ uint32_t u32Formats = (uint32_t)lParam; HANDLE hClip = NULL; LogFlowFunc(("VBOX_WM_SHCLPB_READ_DATA: u32Formats=0x%x\n", u32Formats)); int vboxrc = VBoxClipboardWinOpen(hwnd); if (RT_SUCCESS(vboxrc)) { if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP) { hClip = GetClipboardData(CF_DIB); if (hClip != NULL) { LPVOID lp = GlobalLock(hClip); if (lp != NULL) { vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_BITMAP, lp, GlobalSize(hClip)); GlobalUnlock(hClip); } else { hClip = NULL; } } } else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { hClip = GetClipboardData(CF_UNICODETEXT); if (hClip != NULL) { LPWSTR uniString = (LPWSTR)GlobalLock(hClip); if (uniString != NULL) { vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, uniString, (lstrlenW(uniString) + 1) * 2); GlobalUnlock(hClip); } else { hClip = NULL; } } } else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML) { UINT format = RegisterClipboardFormat("HTML Format"); if (format != 0) { hClip = GetClipboardData(format); if (hClip != NULL) { LPVOID lp = GlobalLock(hClip); if (lp != NULL) { vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_HTML, lp, GlobalSize(hClip)); GlobalUnlock(hClip); } else { hClip = NULL; } } } } #ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST) { hClip = GetClipboardData(CF_HDROP); if (hClip) { HDROP hDrop = (HDROP)GlobalLock(hClip); if (hDrop) { /* vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_URI_LIST, );*/ GlobalUnlock(hClip); } else { hClip = NULL; } } } #endif VBoxClipboardWinClose(); } if (hClip == NULL) { /* Requested clipboard format is not available, send empty data. */ VbglR3ClipboardWriteData(pCtx->u32ClientID, 0, NULL, 0); } } break; case WM_DESTROY: { VBoxClipboardWinRemoveFromCBChain(pWinCtx); if (pWinCtx->oldAPI.timerRefresh) KillTimer(pWinCtx->hWnd, 0); /* * don't need to call PostQuitMessage cause * the VBoxTray already finished a message loop */ } break; default: { rc = DefWindowProc(hwnd, msg, wParam, lParam); } break; } #ifndef DEBUG_andy LogFlowFunc(("vboxClipboardProcessMsg returned with rc = %ld\n", rc)); #endif return rc; }