Ticket #1: hostservices.diff

File hostservices.diff, 26.4 KB (added by Valery V. Sedletski, 9 years ago)

Host services

  • \src\VBox\HostServices/auth/Makefile.kmk

    diff -urN vbox-trunk-bk\src\VBox\HostServices/auth/Makefile.kmk vbox-trunk\src\VBox\HostServices/auth/Makefile.kmk
    old new  
    4444endif
    4545VBoxAuthSimple_TEMPLATE = VBOXMAINCLIENTDLL
    4646VBoxAuthSimple_SOURCES = simple/VBoxAuthSimple.cpp
     47VBoxAuthSimple_NAME.os2 = VBoxAuS
    4748VBoxAuthSimple_SOURCES.win = simple/VBoxAuthSimple.rc
    4849
    4950# Install the SDK samples.
  • \src\VBox\HostServices/HostChannel/Makefile.kmk

    diff -urN vbox-trunk-bk\src\VBox\HostServices/HostChannel/Makefile.kmk vbox-trunk\src\VBox\HostServices/HostChannel/Makefile.kmk
    old new  
    2323#
    2424DLLS += VBoxHostChannel
    2525VBoxHostChannel_TEMPLATE  = VBOXR3
     26VBoxHostChannel_NAME.os2  = VBoxHC
    2627VBoxHostChannel_DEFS      = VBOX_WITH_HGCM
    2728VBoxHostChannel_INCS.win  = \
    2829        $(VBOX_PATH_SDK)
  • \src\VBox\HostServices/SharedClipboard/Makefile.kmk

    diff -urN vbox-trunk-bk\src\VBox\HostServices/SharedClipboard/Makefile.kmk vbox-trunk\src\VBox\HostServices/SharedClipboard/Makefile.kmk
    old new  
    2727DLLS += VBoxSharedClipboard
    2828VBoxSharedClipboard_TEMPLATE  = VBOXR3
    2929VBoxSharedClipboard_DEFS      = VBOX_WITH_HGCM
     30VBoxSharedClipboard_NAME.os2  = VBoxSC
    3031VBoxSharedClipboard_INCS.win  = \
    3132        $(VBOX_PATH_SDK)
    3233
     
    3536VBoxSharedClipboard_SOURCES.win = \
    3637        VBoxClipboard-win.cpp \
    3738        VBoxSharedClipboard.rc
     39VBoxSharedClipboard_SOURCES.os2 = \
     40        VBoxClipboard-pm.cpp
    3841VBoxSharedClipboard_SOURCES.darwin = \
    3942        darwin.cpp \
    4043        $(PATH_ROOT)/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp \
  • \src\VBox\HostServices/SharedClipboard/VBoxClipboard-pm.cpp

    diff -urN vbox-trunk-bk\src\VBox\HostServices/SharedClipboard/VBoxClipboard-pm.cpp vbox-trunk\src\VBox\HostServices/SharedClipboard/VBoxClipboard-pm.cpp
    old new  
     1/** @file
     2 * Shared Clipboard: Win32 host.
     3 */
     4
     5/*
     6 * Copyright (C) 2006-2011 Oracle Corporation
     7 *
     8 * This file is part of VirtualBox Open Source Edition (OSE), as
     9 * available from http://www.virtualbox.org. This file is free software;
     10 * you can redistribute it and/or modify it under the terms of the GNU
     11 * General Public License (GPL) as published by the Free Software
     12 * Foundation, in version 2 as it comes in the "COPYING" file of the
     13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
     14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
     15 */
     16
     17//#include <windows.h>
     18#define INCL_WINCLIPBOARD /* Or use INCL_WIN, INCL_PM, */
     19#include <os2.h>
     20
     21#include <VBox/HostServices/VBoxClipboardSvc.h>
     22
     23#include <iprt/alloc.h>
     24#include <iprt/string.h>
     25#include <iprt/asm.h>
     26#include <iprt/assert.h>
     27#include <iprt/thread.h>
     28#include <process.h>
     29
     30#include "VBoxClipboard.h"
     31
     32#define dprintf Log
     33
     34static char gachWindowClassName[] = "VBoxSharedClipboardClass";
     35
     36enum { CBCHAIN_TIMEOUT = 5000 /* ms */ };
     37
     38struct _VBOXCLIPBOARDCONTEXT
     39{
     40    HWND    hwnd;
     41    HWND    hwndNextInChain;
     42
     43    UINT     timerRefresh;
     44
     45    bool     fCBChainPingInProcess;
     46
     47    RTTHREAD thread;
     48    bool volatile fTerminate;
     49
     50    HANDLE hRenderEvent;
     51
     52    VBOXCLIPBOARDCLIENTDATA *pClient;
     53};
     54
     55/* Only one client is supported. There seems to be no need for more clients. */
     56static VBOXCLIPBOARDCONTEXT g_ctx;
     57
     58
     59#ifdef LOG_ENABLED
     60void vboxClipboardDump(const void *pv, size_t cb, uint32_t u32Format)
     61{
     62    if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
     63    {
     64        Log(("DUMP: VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT:\n"));
     65        if (pv && cb)
     66        {
     67            Log(("%ls\n", pv));
     68        }
     69        else
     70        {
     71            Log(("%p %d\n", pv, cb));
     72        }
     73    }
     74    else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
     75    {
     76        dprintf(("DUMP: VBOX_SHARED_CLIPBOARD_FMT_BITMAP\n"));
     77    }
     78    else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_HTML)
     79    {
     80        Log(("DUMP: VBOX_SHARED_CLIPBOARD_FMT_HTML:\n"));
     81        if (pv && cb)
     82        {
     83            Log(("%s\n", pv));
     84        }
     85        else
     86        {
     87            Log(("%p %d\n", pv, cb));
     88        }
     89    }
     90    else
     91    {
     92        dprintf(("DUMP: invalid format %02X\n", u32Format));
     93    }
     94}
     95#else
     96#define vboxClipboardDump(__pv, __cb, __format) do { NOREF(__pv); NOREF(__cb); NOREF(__format); } while (0)
     97#endif /* LOG_ENABLED */
     98
     99static void vboxClipboardGetData (uint32_t u32Format, const void *pvSrc, uint32_t cbSrc,
     100                                  void *pvDst, uint32_t cbDst, uint32_t *pcbActualDst)
     101{
     102    dprintf (("vboxClipboardGetData.\n"));
     103
     104    *pcbActualDst = cbSrc;
     105
     106    LogFlow(("vboxClipboardGetData cbSrc = %d, cbDst = %d\n", cbSrc, cbDst));
     107
     108    if (cbSrc > cbDst)
     109    {
     110        /* Do not copy data. The dst buffer is not enough. */
     111        return;
     112    }
     113
     114    memcpy (pvDst, pvSrc, cbSrc);
     115
     116    vboxClipboardDump(pvDst, cbSrc, u32Format);
     117
     118    return;
     119}
     120
     121static int vboxClipboardReadDataFromClient (VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Format)
     122{
     123    Assert(pCtx->pClient);
     124    Assert(pCtx->pClient->data.pv == NULL && pCtx->pClient->data.cb == 0 && pCtx->pClient->data.u32Format == 0);
     125
     126    LogFlow(("vboxClipboardReadDataFromClient u32Format = %02X\n", u32Format));
     127
     128    ResetEvent (pCtx->hRenderEvent);
     129
     130    vboxSvcClipboardReportMsg (pCtx->pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA, u32Format);
     131
     132    WaitForSingleObject(pCtx->hRenderEvent, INFINITE);
     133
     134    LogFlow(("vboxClipboardReadDataFromClient wait completed\n"));
     135
     136    return VINF_SUCCESS;
     137}
     138
     139static void vboxClipboardChanged (VBOXCLIPBOARDCONTEXT *pCtx)
     140{
     141    LogFlow(("vboxClipboardChanged\n"));
     142
     143    if (pCtx->pClient == NULL)
     144    {
     145        return;
     146    }
     147
     148    /* Query list of available formats and report to host. */
     149    if (OpenClipboard (pCtx->hwnd))
     150    {
     151        uint32_t u32Formats = 0;
     152
     153        UINT format = 0;
     154
     155        while ((format = EnumClipboardFormats (format)) != 0)
     156        {
     157            LogFlow(("vboxClipboardChanged format %#x\n", format));
     158            switch (format)
     159            {
     160                case CF_UNICODETEXT:
     161                case CF_TEXT:
     162                    u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
     163                    break;
     164
     165                case CF_DIB:
     166                case CF_BITMAP:
     167                    u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
     168                    break;
     169
     170                default:
     171                    if (format >= 0xC000)
     172                    {
     173                        TCHAR szFormatName[256];
     174
     175                        int cActual = GetClipboardFormatName(format, szFormatName, sizeof(szFormatName)/sizeof (TCHAR));
     176
     177                        if (cActual)
     178                        {
     179                            if (strcmp (szFormatName, "HTML Format") == 0)
     180                            {
     181                                u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_HTML;
     182                            }
     183                        }
     184                    }
     185                    break;
     186            }
     187        }
     188
     189        CloseClipboard ();
     190
     191        LogFlow(("vboxClipboardChanged u32Formats %02X\n", u32Formats));
     192
     193        vboxSvcClipboardReportMsg (pCtx->pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, u32Formats);
     194    }
     195}
     196
     197/* Add ourselves into the chain of cliboard listeners */
     198static void addToCBChain (VBOXCLIPBOARDCONTEXT *pCtx)
     199{
     200    pCtx->hwndNextInChain = SetClipboardViewer (pCtx->hwnd);
     201}
     202
     203/* Remove ourselves from the chain of cliboard listeners */
     204static void removeFromCBChain (VBOXCLIPBOARDCONTEXT *pCtx)
     205{
     206    ChangeClipboardChain (pCtx->hwnd, pCtx->hwndNextInChain);
     207    pCtx->hwndNextInChain = NULL;
     208}
     209
     210/* Callback which is invoked when we have successfully pinged ourselves down the
     211 * clipboard chain.  We simply unset a boolean flag to say that we are responding.
     212 * There is a race if a ping returns after the next one is initiated, but nothing
     213 * very bad is likely to happen. */
     214VOID CALLBACK CBChainPingProc(HWND hwnd, UINT uMsg, ULONG_PTR dwData, LRESULT lResult)
     215{
     216    (void) hwnd;
     217    (void) uMsg;
     218    (void) lResult;
     219    VBOXCLIPBOARDCONTEXT *pCtx = (VBOXCLIPBOARDCONTEXT *)dwData;
     220    pCtx->fCBChainPingInProcess = FALSE;
     221}
     222
     223static LRESULT CALLBACK vboxClipboardWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
     224{
     225    LRESULT rc = 0;
     226
     227    VBOXCLIPBOARDCONTEXT *pCtx = &g_ctx;
     228
     229    switch (msg)
     230    {
     231        case WM_CHANGECBCHAIN:
     232        {
     233            Log(("WM_CHANGECBCHAIN\n"));
     234
     235            HWND hwndRemoved = (HWND)wParam;
     236            HWND hwndNext    = (HWND)lParam;
     237
     238            if (hwndRemoved == pCtx->hwndNextInChain)
     239            {
     240                /* The window that was next to our in the chain is being removed.
     241                 * Relink to the new next window.
     242                 */
     243                pCtx->hwndNextInChain = hwndNext;
     244            }
     245            else
     246            {
     247                if (pCtx->hwndNextInChain)
     248                {
     249                    /* Pass the message further. */
     250                    DWORD_PTR dwResult;
     251                    rc = SendMessageTimeout(pCtx->hwndNextInChain, WM_CHANGECBCHAIN, wParam, lParam, 0, CBCHAIN_TIMEOUT, &dwResult);
     252                    if (!rc)
     253                        rc = (LRESULT)dwResult;
     254                }
     255            }
     256        } break;
     257
     258        case WM_DRAWCLIPBOARD:
     259        {
     260            Log(("WM_DRAWCLIPBOARD next %p\n", pCtx->hwndNextInChain));
     261
     262            if (GetClipboardOwner () != hwnd)
     263            {
     264                /* Clipboard was updated by another application. */
     265                vboxClipboardChanged (pCtx);
     266            }
     267
     268            if (pCtx->hwndNextInChain)
     269            {
     270                /* Pass the message to next windows in the clipboard chain. */
     271                DWORD_PTR dwResult;
     272                rc = SendMessageTimeout(pCtx->hwndNextInChain, msg, wParam, lParam, 0, CBCHAIN_TIMEOUT, &dwResult);
     273                if (!rc)
     274                    rc = dwResult;
     275            }
     276        } break;
     277
     278        case WM_TIMER:
     279        {
     280            HWND hViewer = GetClipboardViewer();
     281
     282            /* Re-register ourselves in the clipboard chain if our last ping
     283             * timed out or there seems to be no valid chain. */
     284            if (!hViewer || pCtx->fCBChainPingInProcess)
     285            {
     286                removeFromCBChain(pCtx);
     287                addToCBChain(pCtx);
     288            }
     289            /* Start a new ping by passing a dummy WM_CHANGECBCHAIN to be
     290             * processed by ourselves to the chain. */
     291            pCtx->fCBChainPingInProcess = TRUE;
     292            hViewer = GetClipboardViewer();
     293            if (hViewer)
     294                SendMessageCallback(hViewer, WM_CHANGECBCHAIN, (WPARAM)pCtx->hwndNextInChain, (LPARAM)pCtx->hwndNextInChain, CBChainPingProc, (ULONG_PTR) pCtx);
     295        } break;
     296
     297        case WM_CLOSE:
     298        {
     299            /* Do nothing. Ignore the message. */
     300        } break;
     301
     302        case WM_RENDERFORMAT:
     303        {
     304            /* Insert the requested clipboard format data into the clipboard. */
     305            uint32_t u32Format = 0;
     306
     307            UINT format = (UINT)wParam;
     308
     309            Log(("WM_RENDERFORMAT %d\n", format));
     310
     311            switch (format)
     312            {
     313                case CF_UNICODETEXT:
     314                    u32Format |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
     315                    break;
     316
     317                case CF_DIB:
     318                    u32Format |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
     319                    break;
     320
     321                default:
     322                    if (format >= 0xC000)
     323                    {
     324                        TCHAR szFormatName[256];
     325
     326                        int cActual = GetClipboardFormatName(format, szFormatName, sizeof(szFormatName)/sizeof (TCHAR));
     327
     328                        if (cActual)
     329                        {
     330                            if (strcmp (szFormatName, "HTML Format") == 0)
     331                            {
     332                                u32Format |= VBOX_SHARED_CLIPBOARD_FMT_HTML;
     333                            }
     334                        }
     335                    }
     336                    break;
     337            }
     338
     339            if (u32Format == 0 || pCtx->pClient == NULL)
     340            {
     341                /* Unsupported clipboard format is requested. */
     342                Log(("WM_RENDERFORMAT unsupported format requested or client is not active.\n"));
     343                EmptyClipboard ();
     344            }
     345            else
     346            {
     347                int vboxrc = vboxClipboardReadDataFromClient (pCtx, u32Format);
     348
     349                dprintf(("vboxClipboardReadDataFromClient vboxrc = %d\n", vboxrc));
     350
     351                if (   RT_SUCCESS (vboxrc)
     352                    && pCtx->pClient->data.pv != NULL
     353                    && pCtx->pClient->data.cb > 0
     354                    && pCtx->pClient->data.u32Format == u32Format)
     355                {
     356                    HANDLE hMem = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, pCtx->pClient->data.cb);
     357
     358                    dprintf(("hMem %p\n", hMem));
     359
     360                    if (hMem)
     361                    {
     362                        void *pMem = GlobalLock (hMem);
     363
     364                        dprintf(("pMem %p, GlobalSize %d\n", pMem, GlobalSize (hMem)));
     365
     366                        if (pMem)
     367                        {
     368                            Log(("WM_RENDERFORMAT setting data\n"));
     369
     370                            if (pCtx->pClient->data.pv)
     371                            {
     372                                memcpy (pMem, pCtx->pClient->data.pv, pCtx->pClient->data.cb);
     373
     374                                RTMemFree (pCtx->pClient->data.pv);
     375                                pCtx->pClient->data.pv        = NULL;
     376                            }
     377
     378                            pCtx->pClient->data.cb        = 0;
     379                            pCtx->pClient->data.u32Format = 0;
     380
     381                            /* The memory must be unlocked before inserting to the Clipboard. */
     382                            GlobalUnlock (hMem);
     383
     384                            /* 'hMem' contains the host clipboard data.
     385                             * size is 'cb' and format is 'format'.
     386                             */
     387                            HANDLE hClip = SetClipboardData (format, hMem);
     388
     389                            dprintf(("vboxClipboardHostEvent hClip %p\n", hClip));
     390
     391                            if (hClip)
     392                            {
     393                                /* The hMem ownership has gone to the system. Nothing to do. */
     394                                break;
     395                            }
     396                        }
     397
     398                        GlobalFree (hMem);
     399                    }
     400                }
     401
     402                RTMemFree (pCtx->pClient->data.pv);
     403                pCtx->pClient->data.pv        = NULL;
     404                pCtx->pClient->data.cb        = 0;
     405                pCtx->pClient->data.u32Format = 0;
     406
     407                /* Something went wrong. */
     408                EmptyClipboard ();
     409            }
     410        } break;
     411
     412        case WM_RENDERALLFORMATS:
     413        {
     414            Log(("WM_RENDERALLFORMATS\n"));
     415
     416            /* Do nothing. The clipboard formats will be unavailable now, because the
     417             * windows is to be destroyed and therefore the guest side becomes inactive.
     418             */
     419            if (OpenClipboard (hwnd))
     420            {
     421                EmptyClipboard();
     422
     423                CloseClipboard();
     424            }
     425        } break;
     426
     427        case WM_USER:
     428        {
     429            if (pCtx->pClient == NULL || pCtx->pClient->fMsgFormats)
     430            {
     431                /* Host has pending formats message. Ignore the guest announcement,
     432                 * because host clipboard has more priority.
     433                 */
     434                break;
     435            }
     436
     437            /* Announce available formats. Do not insert data, they will be inserted in WM_RENDER*. */
     438            uint32_t u32Formats = (uint32_t)lParam;
     439
     440            Log(("WM_USER u32Formats = %02X\n", u32Formats));
     441
     442            if (OpenClipboard (hwnd))
     443            {
     444                EmptyClipboard();
     445
     446                Log(("WM_USER emptied clipboard\n"));
     447
     448                HANDLE hClip = NULL;
     449
     450                if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
     451                {
     452                    dprintf(("window proc WM_USER: VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT\n"));
     453
     454                    hClip = SetClipboardData (CF_UNICODETEXT, NULL);
     455                }
     456
     457                if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
     458                {
     459                    dprintf(("window proc WM_USER: VBOX_SHARED_CLIPBOARD_FMT_BITMAP\n"));
     460
     461                    hClip = SetClipboardData (CF_DIB, NULL);
     462                }
     463
     464                if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML)
     465                {
     466                    UINT format = RegisterClipboardFormat ("HTML Format");
     467                    dprintf(("window proc WM_USER: VBOX_SHARED_CLIPBOARD_FMT_HTML 0x%04X\n", format));
     468                    if (format != 0)
     469                    {
     470                        hClip = SetClipboardData (format, NULL);
     471                    }
     472                }
     473
     474                CloseClipboard();
     475
     476                dprintf(("window proc WM_USER: hClip %p, err %d\n", hClip, GetLastError ()));
     477            }
     478            else
     479            {
     480                dprintf(("window proc WM_USER: failed to open clipboard\n"));
     481            }
     482        } break;
     483
     484        default:
     485        {
     486            Log(("WM_ %p\n", msg));
     487            rc = DefWindowProc (hwnd, msg, wParam, lParam);
     488        }
     489    }
     490
     491    Log(("WM_ rc %d\n", rc));
     492    return rc;
     493}
     494
     495DECLCALLBACK(int) VBoxClipboardThread (RTTHREAD ThreadSelf, void *pInstance)
     496{
     497    /* Create a window and make it a clipboard viewer. */
     498    int rc = VINF_SUCCESS;
     499
     500    LogFlow(("VBoxClipboardThread\n"));
     501
     502    VBOXCLIPBOARDCONTEXT *pCtx = &g_ctx;
     503
     504    HINSTANCE hInstance = (HINSTANCE)GetModuleHandle (NULL);
     505
     506    /* Register the Window Class. */
     507    WNDCLASS wc;
     508
     509    wc.style         = CS_NOCLOSE;
     510    wc.lpfnWndProc   = vboxClipboardWndProc;
     511    wc.cbClsExtra    = 0;
     512    wc.cbWndExtra    = 0;
     513    wc.hInstance     = hInstance;
     514    wc.hIcon         = NULL;
     515    wc.hCursor       = NULL;
     516    wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
     517    wc.lpszMenuName  = NULL;
     518    wc.lpszClassName = gachWindowClassName;
     519
     520    ATOM atomWindowClass = RegisterClass (&wc);
     521
     522    if (atomWindowClass == 0)
     523    {
     524        Log(("Failed to register window class\n"));
     525        rc = VERR_NOT_SUPPORTED;
     526    }
     527    else
     528    {
     529        /* Create the window. */
     530        pCtx->hwnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
     531                                     gachWindowClassName, gachWindowClassName,
     532                                     WS_POPUPWINDOW,
     533                                     -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
     534
     535        if (pCtx->hwnd == NULL)
     536        {
     537            Log(("Failed to create window\n"));
     538            rc = VERR_NOT_SUPPORTED;
     539        }
     540        else
     541        {
     542            SetWindowPos(pCtx->hwnd, HWND_TOPMOST, -200, -200, 0, 0,
     543                         SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
     544
     545            addToCBChain(pCtx);
     546            pCtx->timerRefresh = SetTimer(pCtx->hwnd, 0, 10 * 1000, NULL);
     547
     548            MSG msg;
     549            while (GetMessage(&msg, NULL, 0, 0) && !pCtx->fTerminate)
     550            {
     551                TranslateMessage(&msg);
     552                DispatchMessage(&msg);
     553            }
     554        }
     555    }
     556
     557    if (pCtx->hwnd)
     558    {
     559        removeFromCBChain(pCtx);
     560        if (pCtx->timerRefresh)
     561            KillTimer(pCtx->hwnd, 0);
     562
     563        DestroyWindow (pCtx->hwnd);
     564        pCtx->hwnd = NULL;
     565    }
     566
     567    if (atomWindowClass != 0)
     568    {
     569        UnregisterClass (gachWindowClassName, hInstance);
     570        atomWindowClass = 0;
     571    }
     572
     573    return 0;
     574}
     575
     576/*
     577 * Public platform dependent functions.
     578 */
     579int vboxClipboardInit (void)
     580{
     581    int rc = VINF_SUCCESS;
     582
     583    g_ctx.hRenderEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
     584
     585    rc = RTThreadCreate (&g_ctx.thread, VBoxClipboardThread, NULL, 65536,
     586                         RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
     587
     588    if (RT_FAILURE (rc))
     589    {
     590        CloseHandle (g_ctx.hRenderEvent);
     591    }
     592
     593    return rc;
     594}
     595
     596void vboxClipboardDestroy (void)
     597{
     598    Log(("vboxClipboardDestroy\n"));
     599
     600    /* Set the termination flag and ping the window thread. */
     601    ASMAtomicWriteBool (&g_ctx.fTerminate, true);
     602
     603    if (g_ctx.hwnd)
     604    {
     605        PostMessage (g_ctx.hwnd, WM_CLOSE, 0, 0);
     606    }
     607
     608    CloseHandle (g_ctx.hRenderEvent);
     609
     610    /* Wait for the window thread to terminate. */
     611    RTThreadWait (g_ctx.thread, RT_INDEFINITE_WAIT, NULL);
     612
     613    g_ctx.thread = NIL_RTTHREAD;
     614}
     615
     616int vboxClipboardConnect (VBOXCLIPBOARDCLIENTDATA *pClient, bool)
     617{
     618    Log(("vboxClipboardConnect\n"));
     619
     620    if (g_ctx.pClient != NULL)
     621    {
     622        /* One client only. */
     623        return VERR_NOT_SUPPORTED;
     624    }
     625
     626    pClient->pCtx = &g_ctx;
     627
     628    pClient->pCtx->pClient = pClient;
     629
     630    /* Sync the host clipboard content with the client. */
     631    vboxClipboardSync (pClient);
     632
     633    return VINF_SUCCESS;
     634}
     635
     636int vboxClipboardSync (VBOXCLIPBOARDCLIENTDATA *pClient)
     637{
     638    /* Sync the host clipboard content with the client. */
     639    vboxClipboardChanged (pClient->pCtx);
     640
     641    return VINF_SUCCESS;
     642}
     643
     644void vboxClipboardDisconnect (VBOXCLIPBOARDCLIENTDATA *pClient)
     645{
     646    Log(("vboxClipboardDisconnect\n"));
     647
     648    g_ctx.pClient = NULL;
     649}
     650
     651void vboxClipboardFormatAnnounce (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Formats)
     652{
     653    /*
     654     * The guest announces formats. Forward to the window thread.
     655     */
     656    PostMessage (pClient->pCtx->hwnd, WM_USER, 0, u32Formats);
     657}
     658
     659int vboxClipboardReadData (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Format, void *pv, uint32_t cb, uint32_t *pcbActual)
     660{
     661    LogFlow(("vboxClipboardReadData: u32Format = %02X\n", u32Format));
     662
     663    HANDLE hClip = NULL;
     664
     665    /*
     666     * The guest wants to read data in the given format.
     667     */
     668    if (OpenClipboard (pClient->pCtx->hwnd))
     669    {
     670        dprintf(("Clipboard opened.\n"));
     671
     672        if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
     673        {
     674            hClip = GetClipboardData (CF_DIB);
     675
     676            if (hClip != NULL)
     677            {
     678                LPVOID lp = GlobalLock (hClip);
     679
     680                if (lp != NULL)
     681                {
     682                    dprintf(("CF_DIB\n"));
     683
     684                    vboxClipboardGetData (VBOX_SHARED_CLIPBOARD_FMT_BITMAP, lp, GlobalSize (hClip),
     685                                          pv, cb, pcbActual);
     686
     687                    GlobalUnlock(hClip);
     688                }
     689                else
     690                {
     691                    hClip = NULL;
     692                }
     693            }
     694        }
     695        else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
     696        {
     697            hClip = GetClipboardData(CF_UNICODETEXT);
     698
     699            if (hClip != NULL)
     700            {
     701                LPWSTR uniString = (LPWSTR)GlobalLock (hClip);
     702
     703                if (uniString != NULL)
     704                {
     705                    dprintf(("CF_UNICODETEXT\n"));
     706
     707                    vboxClipboardGetData (VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, uniString, (lstrlenW (uniString) + 1) * 2,
     708                                          pv, cb, pcbActual);
     709
     710                    GlobalUnlock(hClip);
     711                }
     712                else
     713                {
     714                    hClip = NULL;
     715                }
     716            }
     717        }
     718        else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_HTML)
     719        {
     720            UINT format = RegisterClipboardFormat ("HTML Format");
     721
     722            if (format != 0)
     723            {
     724                hClip = GetClipboardData (format);
     725
     726                if (hClip != NULL)
     727                {
     728                    LPVOID lp = GlobalLock (hClip);
     729
     730                    if (lp != NULL)
     731                    {
     732                        dprintf(("CF_HTML\n"));
     733
     734                        vboxClipboardGetData (VBOX_SHARED_CLIPBOARD_FMT_HTML, lp, GlobalSize (hClip),
     735                                              pv, cb, pcbActual);
     736
     737                        GlobalUnlock(hClip);
     738                    }
     739                    else
     740                    {
     741                        hClip = NULL;
     742                    }
     743                }
     744            }
     745        }
     746
     747        CloseClipboard ();
     748    }
     749    else
     750    {
     751        dprintf(("failed to open clipboard\n"));
     752    }
     753
     754    if (hClip == NULL)
     755    {
     756        /* Reply with empty data. */
     757        vboxClipboardGetData (0, NULL, 0,
     758                              pv, cb, pcbActual);
     759    }
     760
     761    return VINF_SUCCESS;
     762}
     763
     764void vboxClipboardWriteData (VBOXCLIPBOARDCLIENTDATA *pClient, void *pv, uint32_t cb, uint32_t u32Format)
     765{
     766    LogFlow(("vboxClipboardWriteData\n"));
     767
     768    /*
     769     * The guest returns data that was requested in the WM_RENDERFORMAT handler.
     770     */
     771    Assert(pClient->data.pv == NULL && pClient->data.cb == 0 && pClient->data.u32Format == 0);
     772
     773    vboxClipboardDump(pv, cb, u32Format);
     774
     775    if (cb > 0)
     776    {
     777        pClient->data.pv = RTMemAlloc (cb);
     778
     779        if (pClient->data.pv)
     780        {
     781            memcpy (pClient->data.pv, pv, cb);
     782            pClient->data.cb = cb;
     783            pClient->data.u32Format = u32Format;
     784        }
     785    }
     786
     787    SetEvent(pClient->pCtx->hRenderEvent);
     788}