Пример #1
0
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;
}
Пример #2
0
/**
 * 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;
}
Пример #4
0
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;
}