VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedClipboard/VBoxClipboard-win.cpp@ 33045

Last change on this file since 33045 was 32333, checked in by vboxsync, 14 years ago

HostServices/SharedClipboard: try to spot and fix a broken clipboard chain on Windows hosts

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