VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp@ 79266

Last change on this file since 79266 was 79178, checked in by vboxsync, 6 years ago

Shared Clipboard/URI: Build fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.1 KB
Line 
1/* $Id: VBoxSharedClipboardSvc-win.cpp 79178 2019-06-17 10:52:52Z vboxsync $ */
2/** @file
3 * Shared Clipboard Service - Win32 host.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
23#include <iprt/win/windows.h>
24
25#include <VBox/HostServices/VBoxClipboardSvc.h>
26#include <VBox/GuestHost/clipboard-helper.h>
27#include <VBox/GuestHost/SharedClipboard-win.h>
28#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
29# include <VBox/GuestHost/SharedClipboard-uri.h>
30#endif
31
32#include <iprt/alloc.h>
33#include <iprt/string.h>
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/ldr.h>
37#include <iprt/semaphore.h>
38#include <iprt/thread.h>
39#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
40# include <iprt/utf16.h>
41#endif
42
43#include <process.h>
44#include <shlobj.h> /* Needed for shell objects. */
45
46#include "VBoxSharedClipboardSvc-internal.h"
47#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
48# include "VBoxSharedClipboardSvc-uri.h"
49#endif
50
51/** Static window class name. */
52static char s_szClipWndClassName[] = VBOX_CLIPBOARD_WNDCLASS_NAME;
53
54
55/*********************************************************************************************************************************
56* Internal Functions *
57*********************************************************************************************************************************/
58static int vboxClipboardWinSyncInternal(PVBOXCLIPBOARDCONTEXT pCtx);
59
60struct _VBOXCLIPBOARDCONTEXT
61{
62 /** Handle for window message handling thread. */
63 RTTHREAD hThread;
64 /** Event which gets triggered if the host clipboard needs to render its data. */
65 RTSEMEVENT hRenderEvent;
66 /** Structure for keeping and communicating with client data (from the guest). */
67 PVBOXCLIPBOARDCLIENTDATA pClientData;
68 /** Windows-specific context data. */
69 VBOXCLIPBOARDWINCTX Win;
70#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
71 /** Structure for keeping URI clipboard information around. */
72 SHAREDCLIPBOARDURICTX URI;
73#endif
74};
75
76/* Only one client is supported. There seems to be no need for more clients. */
77static VBOXCLIPBOARDCONTEXT g_ctx;
78
79
80/** @todo Someone please explain the protocol wrt overflows... */
81static void vboxClipboardGetData(uint32_t u32Format, const void *pvSrc, uint32_t cbSrc,
82 void *pvDst, uint32_t cbDst, uint32_t *pcbActualDst)
83{
84 LogFlowFunc(("cbSrc = %d, cbDst = %d\n", cbSrc, cbDst));
85
86 if ( u32Format == VBOX_SHARED_CLIPBOARD_FMT_HTML
87 && VBoxClipboardWinIsCFHTML((const char *)pvSrc))
88 {
89 /** @todo r=bird: Why the double conversion? */
90 char *pszBuf = NULL;
91 uint32_t cbBuf = 0;
92 int rc = VBoxClipboardWinConvertCFHTMLToMIME((const char *)pvSrc, cbSrc, &pszBuf, &cbBuf);
93 if (RT_SUCCESS(rc))
94 {
95 *pcbActualDst = cbBuf;
96 if (cbBuf > cbDst)
97 {
98 /* Do not copy data. The dst buffer is not enough. */
99 RTMemFree(pszBuf);
100 return;
101 }
102 memcpy(pvDst, pszBuf, cbBuf);
103 RTMemFree(pszBuf);
104 }
105 else
106 *pcbActualDst = 0;
107 }
108 else
109 {
110 *pcbActualDst = cbSrc;
111
112 if (cbSrc > cbDst)
113 {
114 /* Do not copy data. The dst buffer is not enough. */
115 return;
116 }
117
118 memcpy(pvDst, pvSrc, cbSrc);
119 }
120
121#ifdef LOG_ENABLED
122 VBoxClipboardDbgDumpData(pvDst, cbSrc, u32Format);
123#endif
124
125 return;
126}
127
128/**
129 * Reads data of a specific format by waiting for its arrival.
130 *
131 * @returns VBox status code.
132 * @param pCtx Clipboard context to use.
133 * @param fFormat Format to receive data in.
134 * @param uTimeoutMs Timeout in ms.
135 */
136static int vboxClipboardWinReadData(PVBOXCLIPBOARDCONTEXT pCtx, VBOXCLIPBOARDFORMAT fFormat,
137 RTMSINTERVAL uTimeoutMs)
138{
139 Assert(pCtx->pClientData);
140 Assert(pCtx->hRenderEvent);
141 Assert(pCtx->pClientData->State.data.pv == NULL && pCtx->pClientData->State.data.cb == 0 && pCtx->pClientData->State.data.u32Format == 0);
142
143 LogFlowFunc(("fFormat=%02X\n", fFormat));
144
145 int rc = vboxSvcClipboardReportMsg(pCtx->pClientData, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA, fFormat);
146 if (RT_SUCCESS(rc))
147 rc = RTSemEventWait(pCtx->hRenderEvent, uTimeoutMs /* Timeout in ms */);
148
149 LogFlowFuncLeaveRC(rc);
150 return rc;
151}
152
153static LRESULT CALLBACK vboxClipboardWinWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
154{
155 LRESULT lresultRc = 0;
156
157 const PVBOXCLIPBOARDCONTEXT pCtx = &g_ctx;
158 const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win;
159
160 switch (msg)
161 {
162 case WM_CLIPBOARDUPDATE:
163 {
164 const HWND hWndClipboardOwner = GetClipboardOwner();
165 if (pWinCtx->hWndClipboardOwnerUs != hWndClipboardOwner)
166 {
167 LogFunc(("WM_CLIPBOARDUPDATE: hWndOldClipboardOwner=%p, hWndNewClipboardOwner=%p\n",
168 pWinCtx->hWndClipboardOwnerUs, hWndClipboardOwner));
169
170 /* Clipboard was updated by another application, retrieve formats and report back. */
171 int rc = vboxClipboardWinSyncInternal(pCtx);
172 AssertRC(rc);
173 }
174 } break;
175
176 case WM_CHANGECBCHAIN:
177 {
178 LogFunc(("WM_CHANGECBCHAIN\n"));
179 lresultRc = VBoxClipboardWinHandleWMChangeCBChain(pWinCtx, hwnd, msg, wParam, lParam);
180 } break;
181
182 case WM_DRAWCLIPBOARD:
183 {
184 LogFunc(("WM_DRAWCLIPBOARD\n"));
185
186 if (GetClipboardOwner() != hwnd)
187 {
188 /* Clipboard was updated by another application, retrieve formats and report back. */
189 int vboxrc = vboxClipboardWinSyncInternal(pCtx);
190 AssertRC(vboxrc);
191 }
192
193 lresultRc = VBoxClipboardWinChainPassToNext(pWinCtx, msg, wParam, lParam);
194
195 } break;
196
197 case WM_TIMER:
198 {
199 int rc = VBoxClipboardWinHandleWMTimer(pWinCtx);
200 AssertRC(rc);
201 } break;
202
203 case WM_RENDERFORMAT:
204 {
205 LogFunc(("WM_RENDERFORMAT\n"));
206
207 /* Insert the requested clipboard format data into the clipboard. */
208 const UINT cfFormat = (UINT)wParam;
209
210 const VBOXCLIPBOARDFORMAT fFormat = VBoxClipboardWinClipboardFormatToVBox(cfFormat);
211
212 LogFunc(("WM_RENDERFORMAT: cfFormat=%u -> fFormat=0x%x\n", cfFormat, fFormat));
213
214 if ( fFormat == VBOX_SHARED_CLIPBOARD_FMT_NONE
215 || pCtx->pClientData == NULL)
216 {
217 /* Unsupported clipboard format is requested. */
218 LogFunc(("WM_RENDERFORMAT unsupported format requested or client is not active\n"));
219 VBoxClipboardWinClear();
220 }
221 else
222 {
223 int rc = vboxClipboardWinReadData(pCtx, fFormat, 30 * 1000 /* 30s timeout */);
224
225 LogFunc(("vboxClipboardReadDataFromClient rc = %Rrc, pv %p, cb %d, u32Format %d\n",
226 rc, pCtx->pClientData->State.data.pv, pCtx->pClientData->State.data.cb,
227 pCtx->pClientData->State.data.u32Format));
228
229 if ( RT_SUCCESS (rc)
230 && pCtx->pClientData->State.data.pv != NULL
231 && pCtx->pClientData->State.data.cb > 0
232 && pCtx->pClientData->State.data.u32Format == fFormat)
233 {
234 HANDLE hMem = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, pCtx->pClientData->State.data.cb);
235
236 LogFunc(("hMem %p\n", hMem));
237
238 if (hMem)
239 {
240 void *pMem = GlobalLock(hMem);
241
242 LogFunc(("pMem %p, GlobalSize %d\n", pMem, GlobalSize(hMem)));
243
244 if (pMem)
245 {
246 LogFunc(("WM_RENDERFORMAT setting data\n"));
247
248 if (pCtx->pClientData->State.data.pv)
249 {
250 memcpy(pMem, pCtx->pClientData->State.data.pv, pCtx->pClientData->State.data.cb);
251
252 RTMemFree(pCtx->pClientData->State.data.pv);
253 pCtx->pClientData->State.data.pv = NULL;
254 }
255
256 pCtx->pClientData->State.data.cb = 0;
257 pCtx->pClientData->State.data.u32Format = 0;
258
259 /* The memory must be unlocked before inserting to the Clipboard. */
260 GlobalUnlock(hMem);
261
262 /* 'hMem' contains the host clipboard data.
263 * size is 'cb' and format is 'format'.
264 */
265 HANDLE hClip = SetClipboardData(cfFormat, hMem);
266
267 LogFunc(("vboxClipboardHostEvent hClip %p\n", hClip));
268
269 if (hClip)
270 {
271 /* The hMem ownership has gone to the system. Nothing to do. */
272 break;
273 }
274 }
275
276 GlobalFree(hMem);
277 }
278 }
279
280 RTMemFree(pCtx->pClientData->State.data.pv);
281 pCtx->pClientData->State.data.pv = NULL;
282 pCtx->pClientData->State.data.cb = 0;
283 pCtx->pClientData->State.data.u32Format = 0;
284
285 /* Something went wrong. */
286 VBoxClipboardWinClear();
287 }
288 } break;
289
290 case WM_RENDERALLFORMATS:
291 {
292 LogFunc(("WM_RENDERALLFORMATS\n"));
293
294 int rc = VBoxClipboardWinHandleWMRenderAllFormats(pWinCtx, hwnd);
295 AssertRC(rc);
296 } break;
297
298 case VBOX_CLIPBOARD_WM_SET_FORMATS:
299 {
300 LogFunc(("VBOX_CLIPBOARD_WM_SET_FORMATS\n"));
301
302 if ( pCtx->pClientData == NULL
303 || pCtx->pClientData->State.fHostMsgFormats)
304 {
305 /* Host has pending formats message. Ignore the guest announcement,
306 * because host clipboard has more priority.
307 */
308 LogFunc(("VBOX_CLIPBOARD_WM_SET_FORMATS ignored\n"));
309 break;
310 }
311
312 /* Announce available formats. Do not insert data -- will be inserted in WM_RENDERFORMAT. */
313 VBOXCLIPBOARDFORMATS fFormats = (uint32_t)lParam;
314 if (fFormats != VBOX_SHARED_CLIPBOARD_FMT_NONE) /* Could arrive with some older GA versions. */
315 {
316 int rc = VBoxClipboardWinOpen(hwnd);
317 if (RT_SUCCESS(rc))
318 {
319 VBoxClipboardWinClear();
320
321#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
322 if (fFormats & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
323 {
324 LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_URI_LIST\n"));
325
326 SHAREDCLIPBOARDPROVIDERCREATIONCTX providerCtx;
327 RT_ZERO(providerCtx);
328 providerCtx.enmSource = SHAREDCLIPBOARDPROVIDERSOURCE_HOSTSERVICE;
329
330 SHAREDCLIPBOARDPROVIDERCALLBACKS providerCallbacks;
331 RT_ZERO(providerCallbacks);
332 providerCallbacks.pvUser = pCtx->pClientData;
333 providerCallbacks.pfnReadDataHdr = vboxClipboardSvcReadDataHdrCallback;
334
335 providerCtx.pCallbacks = &providerCallbacks;
336
337 rc = VBoxClipboardWinURIReadMain(pWinCtx, &pCtx->URI, &providerCtx, fFormats);
338
339 /* Note: VBoxClipboardWinURIReadMain() takes care of closing the clipboard. */
340 }
341 else
342 {
343#endif
344 rc = VBoxClipboardWinAnnounceFormats(pWinCtx, fFormats);
345
346 VBoxClipboardWinClose();
347#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
348 }
349#endif
350 }
351 }
352 LogFunc(("VBOX_CLIPBOARD_WM_SET_FORMATS: fFormats=0x%x, lastErr=%ld\n", fFormats, GetLastError()));
353 } break;
354
355 case WM_DESTROY:
356 {
357 LogFunc(("WM_DESTROY\n"));
358
359 int rc = VBoxClipboardWinHandleWMDestroy(pWinCtx);
360 AssertRC(rc);
361
362 PostQuitMessage(0);
363 } break;
364
365 default:
366 {
367 LogFunc(("WM_ %p\n", msg));
368 lresultRc = DefWindowProc(hwnd, msg, wParam, lParam);
369 }
370 }
371
372 LogFunc(("WM_ rc %d\n", lresultRc));
373 return lresultRc;
374}
375
376DECLCALLBACK(int) vboxClipboardWinThread(RTTHREAD hThreadSelf, void *pvUser)
377{
378 RT_NOREF(hThreadSelf, pvUser);
379
380 /* Create a window and make it a clipboard viewer. */
381 int rc = VINF_SUCCESS;
382
383 LogFlowFuncEnter();
384
385 const PVBOXCLIPBOARDCONTEXT pCtx = &g_ctx;
386 const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win;
387
388 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
389
390 /* Register the Window Class. */
391 WNDCLASS wc;
392 RT_ZERO(wc);
393
394 wc.style = CS_NOCLOSE;
395 wc.lpfnWndProc = vboxClipboardWinWndProc;
396 wc.hInstance = hInstance;
397 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
398 wc.lpszClassName = s_szClipWndClassName;
399
400 ATOM atomWindowClass = RegisterClass(&wc);
401
402 if (atomWindowClass == 0)
403 {
404 LogFunc(("Failed to register window class\n"));
405 rc = VERR_NOT_SUPPORTED;
406 }
407 else
408 {
409 /* Create the window. */
410 pWinCtx->hWnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
411 s_szClipWndClassName, s_szClipWndClassName,
412 WS_POPUPWINDOW,
413 -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
414 if (pWinCtx->hWnd == NULL)
415 {
416 LogFunc(("Failed to create window\n"));
417 rc = VERR_NOT_SUPPORTED;
418 }
419 else
420 {
421 SetWindowPos(pWinCtx->hWnd, HWND_TOPMOST, -200, -200, 0, 0,
422 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
423
424 rc = VBoxClipboardWinChainAdd(&pCtx->Win);
425 if (RT_SUCCESS(rc))
426 {
427 if (!VBoxClipboardWinIsNewAPI(&pWinCtx->newAPI))
428 pWinCtx->oldAPI.timerRefresh = SetTimer(pWinCtx->hWnd, 0, 10 * 1000, NULL);
429 }
430
431#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
432 if (RT_SUCCESS(rc))
433 {
434 HRESULT hr = OleInitialize(NULL);
435 if (FAILED(hr))
436 {
437 LogRel(("Clipboard: Initializing OLE failed (%Rhrc) -- file transfers unavailable\n"));
438 /* Not critical, the rest of the clipboard might work. */
439 }
440 else
441 LogRel(("Clipboard: Initialized OLE\n"));
442
443 int rc2 = SharedClipboardURICtxInit(&g_ctx.URI);
444 AssertRC(rc2);
445 }
446#endif
447 MSG msg;
448 BOOL msgret = 0;
449 while ((msgret = GetMessage(&msg, NULL, 0, 0)) > 0)
450 {
451 TranslateMessage(&msg);
452 DispatchMessage(&msg);
453 }
454 /*
455 * Window procedure can return error,
456 * but this is exceptional situation
457 * that should be identified in testing
458 */
459 Assert(msgret >= 0);
460 LogFunc(("Message loop finished. GetMessage returned %d, message id: %d \n", msgret, msg.message));
461
462#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
463 OleSetClipboard(NULL); /* Make sure to flush the clipboard on destruction. */
464 OleUninitialize();
465
466 SharedClipboardURICtxDestroy(&g_ctx.URI);
467#endif
468 }
469 }
470
471 pWinCtx->hWnd = NULL;
472
473 if (atomWindowClass != 0)
474 {
475 UnregisterClass(s_szClipWndClassName, hInstance);
476 atomWindowClass = 0;
477 }
478
479 LogFlowFuncLeaveRC(rc);
480 return rc;
481}
482
483/**
484 * Synchronizes the host and the guest clipboard formats by sending all supported host clipboard
485 * formats to the guest.
486 *
487 * @returns VBox status code, VINF_NO_CHANGE if no synchronization was required.
488 * @param pCtx Clipboard context to synchronize.
489 */
490static int vboxClipboardWinSyncInternal(PVBOXCLIPBOARDCONTEXT pCtx)
491{
492 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
493
494 LogFlowFuncEnter();
495
496 int rc;
497
498 if (pCtx->pClientData)
499 {
500 uint32_t uFormats;
501 rc = VBoxClipboardWinGetFormats(&pCtx->Win, &uFormats);
502 if (RT_SUCCESS(rc))
503 vboxSvcClipboardReportMsg(pCtx->pClientData, VBOX_SHARED_CLIPBOARD_HOST_MSG_REPORT_FORMATS, uFormats);
504 }
505 else /* If we don't have any client data (yet), bail out. */
506 rc = VINF_NO_CHANGE;
507
508 LogFlowFuncLeaveRC(rc);
509 return rc;
510}
511
512/*
513 * Public platform dependent functions.
514 */
515
516int VBoxClipboardSvcImplInit(void)
517{
518 RT_ZERO(g_ctx); /* Be careful not messing up non-POD types! */
519
520 /* Check that new Clipboard API is available. */
521 VBoxClipboardWinCheckAndInitNewAPI(&g_ctx.Win.newAPI);
522
523 int rc = RTSemEventCreate(&g_ctx.hRenderEvent);
524 if (RT_SUCCESS(rc))
525 {
526 rc = RTThreadCreate(&g_ctx.hThread, vboxClipboardWinThread, NULL, _64K /* Stack size */,
527 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
528 }
529
530 if (RT_FAILURE(rc))
531 RTSemEventDestroy(g_ctx.hRenderEvent);
532
533 LogFlowFuncLeaveRC(rc);
534 return rc;
535}
536
537void VBoxClipboardSvcImplDestroy(void)
538{
539 LogFlowFuncEnter();
540
541 if (g_ctx.Win.hWnd)
542 {
543 PostMessage(g_ctx.Win.hWnd, WM_CLOSE, 0, 0);
544 }
545
546 int rc = RTSemEventDestroy(g_ctx.hRenderEvent);
547 AssertRC(rc);
548
549 /* Wait for the window thread to terminate. */
550 rc = RTThreadWait(g_ctx.hThread, 30 * 1000 /* Timeout in ms */, NULL);
551 if (RT_FAILURE(rc))
552 LogRel(("Shared Clipboard: Waiting for window thread termination failed with rc=%Rrc\n", rc));
553
554 g_ctx.hThread = NIL_RTTHREAD;
555}
556
557int VBoxClipboardSvcImplConnect(PVBOXCLIPBOARDCLIENTDATA pClientData, bool fHeadless)
558{
559 RT_NOREF(fHeadless);
560
561 LogFlowFuncEnter();
562
563 if (g_ctx.pClientData != NULL)
564 {
565 /* One client only. */
566 return VERR_NOT_SUPPORTED;
567 }
568
569 pClientData->State.pCtx = &g_ctx;
570
571 pClientData->State.pCtx->pClientData = pClientData;
572
573 /* Sync the host clipboard content with the client. */
574 VBoxClipboardSvcImplSync(pClientData);
575
576 return VINF_SUCCESS;
577}
578
579int VBoxClipboardSvcImplSync(PVBOXCLIPBOARDCLIENTDATA pClientData)
580{
581 /* Sync the host clipboard content with the client. */
582 return vboxClipboardWinSyncInternal(pClientData->State.pCtx);
583}
584
585int VBoxClipboardSvcImplDisconnect(PVBOXCLIPBOARDCLIENTDATA pClientData)
586{
587 RT_NOREF(pClientData);
588
589 LogFlowFuncEnter();
590
591 g_ctx.pClientData = NULL;
592
593 return VINF_SUCCESS;
594}
595
596int VBoxClipboardSvcImplFormatAnnounce(PVBOXCLIPBOARDCLIENTDATA pClientData, uint32_t u32Formats)
597{
598 AssertPtrReturn(pClientData, VERR_INVALID_POINTER);
599 AssertPtrReturn(pClientData->State.pCtx, VERR_INVALID_POINTER);
600
601 /*
602 * The guest announces formats. Forward to the window thread.
603 */
604 PostMessage(pClientData->State.pCtx->Win.hWnd, VBOX_CLIPBOARD_WM_SET_FORMATS, 0, u32Formats);
605
606 return VINF_SUCCESS;
607}
608
609int VBoxClipboardSvcImplReadData(PVBOXCLIPBOARDCLIENTDATA pClientData, uint32_t u32Format, void *pv, uint32_t cb,
610 uint32_t *pcbActual)
611{
612 AssertPtrReturn(pClientData, VERR_INVALID_POINTER);
613 AssertPtrReturn(pClientData->State.pCtx, VERR_INVALID_POINTER);
614
615 LogFlowFunc(("u32Format=%02X\n", u32Format));
616
617 HANDLE hClip = NULL;
618
619 const PVBOXCLIPBOARDWINCTX pWinCtx = &pClientData->State.pCtx->Win;
620
621 /*
622 * The guest wants to read data in the given format.
623 */
624 int rc = VBoxClipboardWinOpen(pWinCtx->hWnd);
625 if (RT_SUCCESS(rc))
626 {
627 LogFunc(("Clipboard opened\n"));
628
629 if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
630 {
631 hClip = GetClipboardData(CF_DIB);
632 if (hClip != NULL)
633 {
634 LPVOID lp = GlobalLock(hClip);
635
636 if (lp != NULL)
637 {
638 LogFunc(("CF_DIB\n"));
639
640 vboxClipboardGetData(VBOX_SHARED_CLIPBOARD_FMT_BITMAP, lp, GlobalSize(hClip),
641 pv, cb, pcbActual);
642
643 GlobalUnlock(hClip);
644 }
645 else
646 {
647 hClip = NULL;
648 }
649 }
650 }
651 else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
652 {
653 hClip = GetClipboardData(CF_UNICODETEXT);
654 if (hClip != NULL)
655 {
656 LPWSTR uniString = (LPWSTR)GlobalLock(hClip);
657
658 if (uniString != NULL)
659 {
660 LogFunc(("CF_UNICODETEXT\n"));
661
662 vboxClipboardGetData(VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, uniString, (lstrlenW(uniString) + 1) * 2,
663 pv, cb, pcbActual);
664
665 GlobalUnlock(hClip);
666 }
667 else
668 {
669 hClip = NULL;
670 }
671 }
672 }
673 else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_HTML)
674 {
675 UINT format = RegisterClipboardFormat(VBOX_CLIPBOARD_WIN_REGFMT_HTML);
676 if (format != 0)
677 {
678 hClip = GetClipboardData(format);
679 if (hClip != NULL)
680 {
681 LPVOID lp = GlobalLock(hClip);
682 if (lp != NULL)
683 {
684 /** @todo r=andy Add data overflow handling. */
685 vboxClipboardGetData(VBOX_SHARED_CLIPBOARD_FMT_HTML, lp, GlobalSize(hClip),
686 pv, cb, pcbActual);
687#ifdef VBOX_STRICT
688 LogFlowFunc(("Raw HTML clipboard data from host:"));
689 VBoxClipboardDbgDumpHtml((char *)pv, cb);
690#endif
691 GlobalUnlock(hClip);
692 }
693 else
694 {
695 hClip = NULL;
696 }
697 }
698 }
699 }
700#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
701 else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
702 {
703 hClip = GetClipboardData(CF_HDROP);
704 if (hClip != NULL) /* Do we have data in CF_HDROP format? */
705 {
706 LPVOID lp = GlobalLock(hClip);
707 if (lp)
708 {
709 void *pvTemp;
710 size_t cbTemp;
711 rc = VBoxClipboardWinDropFilesToStringList((DROPFILES *)lp, (char **)&pvTemp, &cbTemp);
712 if (RT_SUCCESS(rc))
713 {
714 if (cbTemp > cb) /** @todo Add overflow handling! */
715 {
716 AssertMsgFailed(("More data buffer needed -- fix this\n"));
717 cbTemp = cb; /* Never copy more than the available buffer supplies. */
718 }
719
720 memcpy(pv, pvTemp, cbTemp);
721
722 RTMemFree(pvTemp);
723
724 *pcbActual = (uint32_t)cbTemp;
725 }
726
727 GlobalUnlock(hClip);
728 }
729 }
730 }
731#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
732 VBoxClipboardWinClose();
733 }
734
735 if (hClip == NULL)
736 {
737 /* Reply with empty data. */
738 vboxClipboardGetData(0, NULL, 0, pv, cb, pcbActual);
739 }
740
741 LogFlowFuncLeaveRC(rc);
742 return rc;
743}
744
745int VBoxClipboardSvcImplWriteData(PVBOXCLIPBOARDCLIENTDATA pClientData, void *pv, uint32_t cb, uint32_t u32Format)
746{
747 LogFlowFuncEnter();
748
749 /*
750 * The guest returns data that was requested in the WM_RENDERFORMAT handler.
751 */
752 Assert(pClientData->State.data.pv == NULL && pClientData->State.data.cb == 0 && pClientData->State.data.u32Format == 0);
753
754#ifdef LOG_ENABLED
755 VBoxClipboardDbgDumpData(pv, cb, u32Format);
756#endif
757
758 if (cb > 0)
759 {
760 char *pszResult = NULL;
761
762 if ( u32Format == VBOX_SHARED_CLIPBOARD_FMT_HTML
763 && !VBoxClipboardWinIsCFHTML((const char*)pv))
764 {
765 /* check that this is not already CF_HTML */
766 uint32_t cbResult;
767 int rc = VBoxClipboardWinConvertMIMEToCFHTML((const char *)pv, cb, &pszResult, &cbResult);
768 if (RT_SUCCESS(rc))
769 {
770 if (pszResult != NULL && cbResult != 0)
771 {
772 pClientData->State.data.pv = pszResult;
773 pClientData->State.data.cb = cbResult;
774 pClientData->State.data.u32Format = u32Format;
775 }
776 }
777 }
778 else
779 {
780 pClientData->State.data.pv = RTMemDup(pv, cb);
781 if (pClientData->State.data.pv)
782 {
783 pClientData->State.data.cb = cb;
784 pClientData->State.data.u32Format = u32Format;
785 }
786 }
787 }
788
789 AssertPtr(pClientData->State.pCtx);
790 int rc = RTSemEventSignal(pClientData->State.pCtx->hRenderEvent);
791 AssertRC(rc);
792
793 LogFlowFuncLeaveRC(rc);
794 return rc;
795}
796
797#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
798int VBoxClipboardSvcImplURIReadDir(PVBOXCLIPBOARDCLIENTDATA pClientData, PVBOXCLIPBOARDDIRDATA pDirData)
799{
800 RT_NOREF(pClientData, pDirData);
801 return VERR_NOT_IMPLEMENTED;
802}
803
804int VBoxClipboardSvcImplURIWriteDir(PVBOXCLIPBOARDCLIENTDATA pClientData, PVBOXCLIPBOARDDIRDATA pDirData)
805{
806 RT_NOREF(pClientData, pDirData);
807 return VERR_NOT_IMPLEMENTED;
808}
809
810int VBoxClipboardSvcImplURIReadFileHdr(PVBOXCLIPBOARDCLIENTDATA pClientData, PVBOXCLIPBOARDFILEHDR pFileHdr)
811{
812 RT_NOREF(pClientData, pFileHdr);
813 return VERR_NOT_IMPLEMENTED;
814}
815
816int VBoxClipboardSvcImplURIWriteFileHdr(PVBOXCLIPBOARDCLIENTDATA pClientData, PVBOXCLIPBOARDFILEHDR pFileHdr)
817{
818 RT_NOREF(pClientData, pFileHdr);
819 return VERR_NOT_IMPLEMENTED;
820}
821
822int VBoxClipboardSvcImplURIReadFileData(PVBOXCLIPBOARDCLIENTDATA pClientData, PVBOXCLIPBOARDFILEDATA pFileData)
823{
824 RT_NOREF(pClientData, pFileData);
825 return VERR_NOT_IMPLEMENTED;
826}
827
828int VBoxClipboardSvcImplURIWriteFileData(PVBOXCLIPBOARDCLIENTDATA pClientData, PVBOXCLIPBOARDFILEDATA pFileData)
829{
830 RT_NOREF(pClientData, pFileData);
831 return VERR_NOT_IMPLEMENTED;
832}
833#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
834
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette