VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxService/VBoxClipboard.cpp@ 3109

Last change on this file since 3109 was 3091, checked in by vboxsync, 18 years ago

User buffers are now locked in the VBoxGuest driver.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.9 KB
Line 
1/** @file
2 *
3 * VBoxClipboard - Shared clipboard
4 *
5 * Copyright (C) 2006-2007 innotek GmbH
6 *
7 * This file is part of VirtualBox Open Source Edition (OSE), as
8 * available from http://www.virtualbox.org. This file is free software;
9 * you can redistribute it and/or modify it under the terms of the GNU
10 * General Public License as published by the Free Software Foundation,
11 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
12 * distribution. VirtualBox OSE is distributed in the hope that it will
13 * be useful, but WITHOUT ANY WARRANTY of any kind.
14 *
15 * If you received this file as part of a commercial VirtualBox
16 * distribution, then only the terms of your commercial VirtualBox
17 * license agreement apply instead of the previous paragraph.
18 *
19 */
20
21#include "VBoxService.h"
22#include <VBox/HostServices/VBoxClipboardSvc.h>
23
24// #include <iprt/crc64.h>
25
26// #define LOG_ENABLED
27
28#ifdef LOG_ENABLED
29#include <stdio.h>
30
31static void _dprintf(LPSTR String, ...)
32{
33 va_list va;
34
35 va_start(va, String);
36
37 CHAR Buffer[1024];
38 if (strlen(String) < 1000)
39 {
40 _vsntprintf (Buffer, sizeof(Buffer), String, va);
41
42 FILE *f = fopen ("c:\\inst\\clip.log", "ab");
43 if (f)
44 {
45 fprintf (f, "%s", Buffer);
46 fclose (f);
47 }
48 }
49
50 va_end (va);
51}
52#define dprintf(a) _dprintf a
53#else
54#define dprintf(a) do {} while (0)
55#endif /* LOG_ENABLED */
56
57
58typedef struct _VBOXCLIPBOARDCONTEXT
59{
60 const VBOXSERVICEENV *pEnv;
61
62 uint32_t u32ClientID;
63
64 ATOM atomWindowClass;
65
66 HWND hwnd;
67
68 HWND hwndNextInChain;
69
70// bool fOperational;
71
72// uint32_t u32LastSentFormat;
73// uint64_t u64LastSentCRC64;
74
75 bool fAnnouncing;
76
77} VBOXCLIPBOARDCONTEXT;
78
79
80static char gachWindowClassName[] = "VBoxSharedClipboardClass";
81
82
83#define VBOX_INIT_CALL(__a, __b, __c) do { \
84 (__a)->hdr.result = VINF_SUCCESS; \
85 (__a)->hdr.u32ClientID = (__c)->u32ClientID; \
86 (__a)->hdr.u32Function = (__b); \
87 (__a)->hdr.cParms = (sizeof (*(__a)) - sizeof ((__a)->hdr)) / sizeof (HGCMFunctionParameter); \
88} while (0)
89
90
91//static bool vboxClipboardIsSameAsLastSent (VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Format,
92// void *pv, uint32_t cb)
93//{
94// uint64_t u64CRC = RTCrc64 (pv, cb);
95//
96// if ( pCtx->u32LastSentFormat == u32Format
97// && pCtx->u64LastSentCRC64 == u64CRC)
98// {
99// return true;
100// }
101//
102// pCtx->u64LastSentCRC64 = u64CRC;
103// pCtx->u32LastSentFormat = u32Format;
104//
105// return false;
106//}
107
108static int vboxClipboardConnect (VBOXCLIPBOARDCONTEXT *pCtx)
109{
110 VBoxGuestHGCMConnectInfo info;
111
112 memset (&info, 0, sizeof (info));
113
114 info.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
115
116 strcpy (info.Loc.u.host.achName, "VBoxSharedClipboard");
117
118 DWORD cbReturned;
119
120 if (DeviceIoControl (pCtx->pEnv->hDriver,
121 IOCTL_VBOXGUEST_HGCM_CONNECT,
122 &info, sizeof (info),
123 &info, sizeof (info),
124 &cbReturned,
125 NULL))
126 {
127 if (info.result == VINF_SUCCESS)
128 {
129 pCtx->u32ClientID = info.u32ClientID;
130 }
131 }
132 else
133 {
134 info.result = VERR_NOT_SUPPORTED;
135 }
136
137 return info.result;
138}
139
140static void vboxClipboardDisconnect (VBOXCLIPBOARDCONTEXT *pCtx)
141{
142 if (pCtx->u32ClientID == 0)
143 {
144 return;
145 }
146
147 VBoxGuestHGCMDisconnectInfo info;
148
149 memset (&info, 0, sizeof (info));
150
151 info.u32ClientID = pCtx->u32ClientID;
152
153 DWORD cbReturned;
154
155 DeviceIoControl (pCtx->pEnv->hDriver,
156 IOCTL_VBOXGUEST_HGCM_DISCONNECT,
157 &info, sizeof (info),
158 &info, sizeof (info),
159 &cbReturned,
160 NULL);
161
162 return;
163}
164
165
166static void VBoxHGCMParmUInt32Set (HGCMFunctionParameter *pParm, uint32_t u32)
167{
168 pParm->type = VMMDevHGCMParmType_32bit;
169 pParm->u.value32 = u32;
170}
171
172static int VBoxHGCMParmUInt32Get (HGCMFunctionParameter *pParm, uint32_t *pu32)
173{
174 if (pParm->type == VMMDevHGCMParmType_32bit)
175 {
176 *pu32 = pParm->u.value32;
177 return VINF_SUCCESS;
178 }
179
180 return VERR_INVALID_PARAMETER;
181}
182
183static void VBoxHGCMParmPtrSet (HGCMFunctionParameter *pParm, void *pv, uint32_t cb)
184{
185 pParm->type = VMMDevHGCMParmType_LinAddr;
186 pParm->u.Pointer.size = cb;
187 pParm->u.Pointer.u.linearAddr = (VBOXGCPTR)pv;
188}
189
190
191static int vboxCall (HANDLE hDriver, void *pvData, unsigned cbData)
192{
193 DWORD cbReturned;
194
195 if (DeviceIoControl (hDriver,
196 IOCTL_VBOXGUEST_HGCM_CALL,
197 pvData, cbData,
198 pvData, cbData,
199 &cbReturned,
200 NULL))
201 {
202 return VINF_SUCCESS;
203 }
204
205 return VERR_NOT_SUPPORTED;
206}
207
208static int vboxClipboardReportFormats (VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Formats)
209{
210 VBoxClipboardFormats parms;
211
212 VBOX_INIT_CALL(&parms, VBOX_SHARED_CLIPBOARD_FN_FORMATS, pCtx);
213
214 VBoxHGCMParmUInt32Set (&parms.formats, u32Formats);
215
216 int rc = vboxCall (pCtx->pEnv->hDriver, &parms, sizeof (parms));
217
218 if (VBOX_SUCCESS (rc))
219 {
220 rc = parms.hdr.result;
221 }
222
223 return rc;
224}
225
226static int vboxClipboardReadData (VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Format, void *pv, uint32_t cb, uint32_t *pcbActual)
227{
228 VBoxClipboardReadData parms;
229
230 VBOX_INIT_CALL(&parms, VBOX_SHARED_CLIPBOARD_FN_READ_DATA, pCtx);
231
232 VBoxHGCMParmUInt32Set (&parms.format, u32Format);
233 VBoxHGCMParmPtrSet (&parms.ptr, pv, cb);
234 VBoxHGCMParmUInt32Set (&parms.size, 0);
235
236 int rc = vboxCall (pCtx->pEnv->hDriver, &parms, sizeof (parms));
237
238 if (VBOX_SUCCESS (rc))
239 {
240 rc = parms.hdr.result;
241
242 if (VBOX_SUCCESS (rc))
243 {
244 uint32_t u32Size;
245
246 rc = VBoxHGCMParmUInt32Get (&parms.size, &u32Size);
247
248 dprintf (("vboxClipboardReadData: actual size = %d, rc = %d\n", u32Size, rc));
249
250 if (VBOX_SUCCESS (rc))
251 {
252 if (pcbActual)
253 {
254 *pcbActual = u32Size;
255 }
256 }
257 }
258 }
259
260 return rc;
261}
262
263static int vboxClipboardWriteData (VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Format,
264 void *pv, uint32_t cb)
265{
266// if (vboxClipboardIsSameAsLastSent (pCtx, u32Format, pv, cb))
267// {
268// dprintf (("vboxClipboardWriteData: The data to be sent are the same as the last sent.\n"));
269// return VINF_SUCCESS;
270// }
271
272 VBoxClipboardWriteData parms;
273
274 VBOX_INIT_CALL(&parms, VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA, pCtx);
275
276 VBoxHGCMParmUInt32Set (&parms.format, u32Format);
277 VBoxHGCMParmPtrSet (&parms.ptr, pv, cb);
278
279 int rc = vboxCall (pCtx->pEnv->hDriver, &parms, sizeof (parms));
280
281 if (VBOX_SUCCESS (rc))
282 {
283 rc = parms.hdr.result;
284 }
285
286 return rc;
287}
288
289static void vboxClipboardChanged (VBOXCLIPBOARDCONTEXT *pCtx)
290{
291 /* Query list of available formats and report to host. */
292 if (OpenClipboard (pCtx->hwnd))
293 {
294 uint32_t u32Formats = 0;
295
296 UINT format = 0;
297
298 while ((format = EnumClipboardFormats (format)) != 0)
299 {
300 dprintf (("vboxClipboardChanged: format 0x%08X\n", format));
301 switch (format)
302 {
303 case CF_UNICODETEXT:
304 case CF_TEXT:
305 u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
306 break;
307
308 case CF_DIB:
309 case CF_BITMAP:
310 u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
311 break;
312
313 default:
314 if (format >= 0xC000)
315 {
316 TCHAR szFormatName[256];
317
318 int cActual = GetClipboardFormatName(format, szFormatName, sizeof(szFormatName)/sizeof (TCHAR));
319
320 if (cActual)
321 {
322 if (strcmp (szFormatName, "HTML Format") == 0)
323 {
324 u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_HTML;
325 }
326 }
327 }
328 break;
329 }
330 }
331
332 CloseClipboard ();
333
334 vboxClipboardReportFormats (pCtx, u32Formats);
335 }
336}
337
338static LRESULT vboxClipboardProcessMsg(VBOXCLIPBOARDCONTEXT *pCtx, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
339{
340 LRESULT rc = 0;
341
342 switch (msg)
343 {
344 case WM_CHANGECBCHAIN:
345 {
346 HWND hwndRemoved = (HWND)wParam;
347 HWND hwndNext = (HWND)lParam;
348
349 dprintf (("vboxClipboardProcessMsg: WM_CHANGECBCHAIN: hwndRemoved %p, hwndNext %p, hwnd %p\n", hwndRemoved, hwndNext, pCtx->hwnd));
350
351 if (hwndRemoved == pCtx->hwndNextInChain)
352 {
353 /* The window that was next to our in the chain is being removed.
354 * Relink to the new next window.
355 */
356 pCtx->hwndNextInChain = hwndNext;
357 }
358 else
359 {
360 if (pCtx->hwndNextInChain)
361 {
362 /* Pass the message further. */
363 rc = SendMessage (pCtx->hwndNextInChain, WM_CHANGECBCHAIN, wParam, lParam);
364 }
365 }
366 } break;
367
368 case WM_DRAWCLIPBOARD:
369 {
370 dprintf (("vboxClipboardProcessMsg: WM_DRAWCLIPBOARD, hwnd %p\n", pCtx->hwnd));
371
372 if (!pCtx->fAnnouncing)
373 {
374 vboxClipboardChanged (pCtx);
375 }
376
377 /* Pass the message to next windows in the clipboard chain. */
378 rc = SendMessage (pCtx->hwndNextInChain, msg, wParam, lParam);
379 } break;
380
381 case WM_CLOSE:
382 {
383 /* Do nothing. Ignore the message. */
384 } break;
385
386 case WM_RENDERFORMAT:
387 {
388 /* Insert the requested clipboard format data into the clipboard. */
389 uint32_t u32Format = 0;
390
391 UINT format = (UINT)wParam;
392
393 switch (format)
394 {
395 case CF_UNICODETEXT:
396 u32Format |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
397 break;
398
399 case CF_DIB:
400 u32Format |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
401 break;
402
403 default:
404 if (format >= 0xC000)
405 {
406 TCHAR szFormatName[256];
407
408 int cActual = GetClipboardFormatName(format, szFormatName, sizeof(szFormatName)/sizeof (TCHAR));
409
410 if (cActual)
411 {
412 if (strcmp (szFormatName, "HTML Format") == 0)
413 {
414 u32Format |= VBOX_SHARED_CLIPBOARD_FMT_HTML;
415 }
416 }
417 }
418 break;
419 }
420
421 if (u32Format == 0)
422 {
423 /* Unsupported clipboard format is requested. */
424 EmptyClipboard ();
425 }
426 else
427 {
428 const uint32_t cbPrealloc = 4096;
429 uint32_t cb = 0;
430
431 /* Preallocate a buffer, most of small text transfers will fit into it. */
432 HANDLE hMem = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, cbPrealloc);
433 dprintf(("hMem %p\n", hMem));
434
435 if (hMem)
436 {
437 void *pMem = GlobalLock (hMem);
438 dprintf(("pMem %p, GlobalSize %d\n", pMem, GlobalSize (hMem)));
439
440 if (pMem)
441 {
442 /* Read the host data to the preallocated buffer. */
443 int vboxrc = vboxClipboardReadData (pCtx, u32Format, pMem, cbPrealloc, &cb);
444 dprintf(("vboxClipboardReadData vboxrc %d\n", vboxrc));
445
446 if (VBOX_SUCCESS (rc))
447 {
448 if (cb > cbPrealloc)
449 {
450 GlobalUnlock (hMem);
451
452 /* The preallocated buffer is too small, adjust the size. */
453 hMem = GlobalReAlloc (hMem, cb, 0);
454 dprintf(("hMem %p\n", hMem));
455
456 if (hMem)
457 {
458 pMem = GlobalLock (hMem);
459 dprintf(("pMem %p, GlobalSize %d\n", pMem, GlobalSize (hMem)));
460
461 if (pMem)
462 {
463 /* Read the host data to the preallocated buffer. */
464 uint32_t cbNew = 0;
465 vboxrc = vboxClipboardReadData (pCtx, u32Format, pMem, cb, &cbNew);
466 dprintf(("vboxClipboardReadData vboxrc %d, cb = %d, cbNew = %d\n", vboxrc, cb, cbNew));
467
468 if (VBOX_SUCCESS (vboxrc) && cbNew <= cb)
469 {
470 cb = cbNew;
471 }
472 else
473 {
474 GlobalUnlock (pMem);
475 GlobalFree (hMem);
476 hMem = NULL;
477 }
478 }
479 else
480 {
481 GlobalFree (hMem);
482 hMem = NULL;
483 }
484 }
485 }
486
487 if (hMem)
488 {
489 /* pMem is the address of the data. cb is the size of returned data. */
490 /* Verify the size of returned text. */
491 if (u32Format == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
492 {
493 cb = (lstrlenW((LPWSTR)pMem) + 1) * 2;
494 }
495
496 GlobalUnlock (hMem);
497
498 hMem = GlobalReAlloc (hMem, cb, 0);
499 dprintf(("hMem %p\n", hMem));
500
501 if (hMem)
502 {
503 /* 'hMem' contains the host clipboard data.
504 * size is 'cb' and format is 'format'.
505 */
506 HANDLE hClip = SetClipboardData (format, hMem);
507 dprintf(("WM_RENDERFORMAT hClip %p\n", hClip));
508
509 if (hClip)
510 {
511 /* The hMem ownership has gone to the system. Finish the processing. */
512 break;
513 }
514
515 /* Cleanup follows. */
516 }
517 }
518 }
519
520 if (hMem)
521 {
522 GlobalUnlock (hMem);
523 }
524 }
525
526 if (hMem)
527 {
528 GlobalFree (hMem);
529 }
530 }
531
532 /* Something went wrong. */
533 EmptyClipboard ();
534 }
535 } break;
536
537 case WM_RENDERALLFORMATS:
538 {
539 /* Do nothing. The clipboard formats will be unavailable now, because the
540 * windows is to be destroyed and therefore the guest side becomes inactive.
541 */
542 if (OpenClipboard (hwnd))
543 {
544 EmptyClipboard();
545
546 CloseClipboard();
547 }
548 } break;
549
550 case WM_USER:
551 {
552 /* Announce available formats. Do not insert data, they will be inserted in WM_RENDER*. */
553 uint32_t u32Formats = (uint32_t)lParam;
554
555 /* Prevent the WM_DRAWCLIPBOARD processing. */
556 pCtx->fAnnouncing = true;
557
558 if (OpenClipboard (hwnd))
559 {
560 EmptyClipboard();
561
562 HANDLE hClip = NULL;
563
564 if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
565 {
566 dprintf(("window proc WM_USER: VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT\n"));
567 hClip = SetClipboardData (CF_UNICODETEXT, NULL);
568 }
569
570 if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
571 {
572 dprintf(("window proc WM_USER: VBOX_SHARED_CLIPBOARD_FMT_BITMAP\n"));
573 hClip = SetClipboardData (CF_DIB, NULL);
574 }
575
576 if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML)
577 {
578 UINT format = RegisterClipboardFormat ("HTML Format");
579 dprintf(("window proc WM_USER: VBOX_SHARED_CLIPBOARD_FMT_HTML 0x%04X\n", format));
580 if (format != 0)
581 {
582 hClip = SetClipboardData (format, NULL);
583 }
584 }
585
586 CloseClipboard();
587
588 dprintf(("window proc WM_USER: hClip %p\n", hClip));
589 }
590 else
591 {
592 dprintf(("window proc WM_USER: failed to open clipboard\n"));
593 }
594
595 pCtx->fAnnouncing = false;
596 } break;
597
598 case WM_USER + 1:
599 {
600 /* Send data in the specified format to the host. */
601 uint32_t u32Formats = (uint32_t)lParam;
602
603 HANDLE hClip = NULL;
604
605 if (OpenClipboard (hwnd))
606 {
607 if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
608 {
609 hClip = GetClipboardData (CF_DIB);
610
611 if (hClip != NULL)
612 {
613 LPVOID lp = GlobalLock (hClip);
614
615 if (lp != NULL)
616 {
617 dprintf(("CF_DIB\n"));
618
619 vboxClipboardWriteData (pCtx, VBOX_SHARED_CLIPBOARD_FMT_BITMAP,
620 lp, GlobalSize (hClip));
621
622 GlobalUnlock(hClip);
623 }
624 else
625 {
626 hClip = NULL;
627 }
628 }
629 }
630 else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
631 {
632 hClip = GetClipboardData(CF_UNICODETEXT);
633
634 if (hClip != NULL)
635 {
636 LPWSTR uniString = (LPWSTR)GlobalLock (hClip);
637
638 if (uniString != NULL)
639 {
640 dprintf(("CF_UNICODETEXT\n"));
641
642 vboxClipboardWriteData (pCtx, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
643 uniString, (lstrlenW (uniString) + 1) * 2);
644
645 GlobalUnlock(hClip);
646 }
647 else
648 {
649 hClip = NULL;
650 }
651 }
652 }
653 else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML)
654 {
655 UINT format = RegisterClipboardFormat ("HTML Format");
656
657 if (format != 0)
658 {
659 hClip = GetClipboardData (format);
660
661 if (hClip != NULL)
662 {
663 LPVOID lp = GlobalLock (hClip);
664
665 if (lp != NULL)
666 {
667 dprintf(("CF_HTML\n"));
668
669 vboxClipboardWriteData (pCtx, VBOX_SHARED_CLIPBOARD_FMT_HTML,
670 lp, GlobalSize (hClip));
671
672 GlobalUnlock(hClip);
673 }
674 else
675 {
676 hClip = NULL;
677 }
678 }
679 }
680 }
681
682 CloseClipboard ();
683 }
684
685 if (hClip == NULL)
686 {
687 /* Requested clipboard format is not available, send empty data. */
688 vboxClipboardWriteData (pCtx, 0, NULL, 0);
689 }
690 } break;
691
692 default:
693 {
694 rc = DefWindowProc (hwnd, msg, wParam, lParam);
695 }
696 }
697
698 return rc;
699}
700
701static LRESULT CALLBACK vboxClipboardWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
702
703static int vboxClipboardInit (VBOXCLIPBOARDCONTEXT *pCtx)
704{
705 int rc = VINF_SUCCESS;
706
707 /* Register the Window Class. */
708 WNDCLASS wc;
709
710 wc.style = CS_NOCLOSE;
711 wc.lpfnWndProc = vboxClipboardWndProc;
712 wc.cbClsExtra = 0;
713 wc.cbWndExtra = 0;
714 wc.hInstance = pCtx->pEnv->hInstance;
715 wc.hIcon = NULL;
716 wc.hCursor = NULL;
717 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
718 wc.lpszMenuName = NULL;
719 wc.lpszClassName = gachWindowClassName;
720
721 pCtx->atomWindowClass = RegisterClass (&wc);
722
723 if (pCtx->atomWindowClass == 0)
724 {
725 rc = VERR_NOT_SUPPORTED;
726 }
727 else
728 {
729 /* Create the window. */
730 pCtx->hwnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
731 gachWindowClassName, gachWindowClassName,
732 WS_POPUPWINDOW,
733 -200, -200, 100, 100, NULL, NULL, pCtx->pEnv->hInstance, NULL);
734
735 if (pCtx->hwnd == NULL)
736 {
737 rc = VERR_NOT_SUPPORTED;
738 }
739 else
740 {
741 SetWindowPos(pCtx->hwnd, HWND_TOPMOST, -200, -200, 0, 0,
742 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
743
744 pCtx->hwndNextInChain = SetClipboardViewer (pCtx->hwnd);
745 }
746 }
747
748 return rc;
749}
750
751static void vboxClipboardDestroy (VBOXCLIPBOARDCONTEXT *pCtx)
752{
753 if (pCtx->hwnd)
754 {
755 ChangeClipboardChain (pCtx->hwnd, pCtx->hwndNextInChain);
756 pCtx->hwndNextInChain = NULL;
757
758 DestroyWindow (pCtx->hwnd);
759 pCtx->hwnd = NULL;
760 }
761
762 if (pCtx->atomWindowClass != 0)
763 {
764 UnregisterClass(gachWindowClassName, pCtx->pEnv->hInstance);
765 pCtx->atomWindowClass = 0;
766 }
767}
768
769/* Static since it is the single instance. Directly used in the windows proc. */
770static VBOXCLIPBOARDCONTEXT gCtx = { NULL };
771
772static LRESULT CALLBACK vboxClipboardWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
773{
774 /* Forward with proper context. */
775 return vboxClipboardProcessMsg (&gCtx, hwnd, msg, wParam, lParam);
776}
777
778int VBoxClipboardInit (const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread)
779{
780 int rc = VINF_SUCCESS;
781
782 dprintf (("VboxClipboardInit\n"));
783
784 if (gCtx.pEnv)
785 {
786 /* Clipboard was already initialized. 2 or more instances are not supported. */
787 return VERR_NOT_SUPPORTED;
788 }
789
790 memset (&gCtx, 0, sizeof (gCtx));
791
792 gCtx.pEnv = pEnv;
793
794 rc = vboxClipboardConnect (&gCtx);
795
796 if (VBOX_SUCCESS (rc))
797 {
798 rc = vboxClipboardInit (&gCtx);
799
800 dprintf (("vboxClipboardInit: rc = %d\n", rc));
801
802 if (VBOX_SUCCESS (rc))
803 {
804 /* Always start the thread for host messages. */
805 *pfStartThread = true;
806 }
807 }
808
809 if (VBOX_SUCCESS (rc))
810 {
811 *ppInstance = &gCtx;
812 }
813 else
814 {
815 vboxClipboardDisconnect (&gCtx);
816 }
817
818 return rc;
819}
820
821unsigned __stdcall VBoxClipboardThread (void *pInstance)
822{
823 VBOXCLIPBOARDCONTEXT *pCtx = (VBOXCLIPBOARDCONTEXT *)pInstance;
824
825 dprintf(("VBoxClipboardThread\n"));
826
827 /* Open the new driver instance to not interfere with other callers. */
828 HANDLE hDriver = CreateFile(VBOXGUEST_DEVICE_NAME,
829 GENERIC_READ | GENERIC_WRITE,
830 FILE_SHARE_READ | FILE_SHARE_WRITE,
831 NULL,
832 OPEN_EXISTING,
833 FILE_ATTRIBUTE_NORMAL,
834 NULL);
835
836 /* The thread waits for incoming messages from the host. */
837 for (;;)
838 {
839 VBoxClipboardGetHostMsg parms;
840
841 VBOX_INIT_CALL(&parms, VBOX_SHARED_CLIPBOARD_FN_GET_HOST_MSG, pCtx);
842
843 VBoxHGCMParmUInt32Set (&parms.msg, 0);
844 VBoxHGCMParmUInt32Set (&parms.formats, 0);
845
846 DWORD cbReturned;
847
848 if (!DeviceIoControl (hDriver,
849 IOCTL_VBOXGUEST_HGCM_CALL,
850 &parms, sizeof (parms),
851 &parms, sizeof (parms),
852 &cbReturned,
853 NULL))
854 {
855 dprintf(("Failed to call the driver for host message.\n"));
856
857 /* Wait a bit before retrying. */
858 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 1000) == WAIT_OBJECT_0)
859 {
860 break;
861 }
862
863 continue;
864 }
865
866 int rc = parms.hdr.result;
867
868 if (VBOX_SUCCESS (rc))
869 {
870 uint32_t u32Msg;
871 uint32_t u32Formats;
872
873 rc = VBoxHGCMParmUInt32Get (&parms.msg, &u32Msg);
874
875 if (VBOX_SUCCESS (rc))
876 {
877 rc = VBoxHGCMParmUInt32Get (&parms.formats, &u32Formats);
878
879 if (VBOX_SUCCESS (rc))
880 {
881 dprintf(("vboxClipboardHostEvent u32Msg %d, u32Formats %d\n", u32Msg, u32Formats));
882
883 switch (u32Msg)
884 {
885 case VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS:
886 {
887 /* The host has announced available clipboard formats.
888 * Forward the information to the window, so it can later
889 * respond to WM_RENDERFORMAT message.
890 */
891 ::PostMessage (pCtx->hwnd, WM_USER, 0, u32Formats);
892 } break;
893 case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA:
894 {
895 /* The host needs data in the specified format.
896 */
897 ::PostMessage (pCtx->hwnd, WM_USER + 1, 0, u32Formats);
898 } break;
899 case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT:
900 {
901 /* The host is terminating.
902 */
903 rc = VERR_INTERRUPTED;
904 } break;
905 default:
906 {
907 dprintf(("Unsupported message from host!!!"));
908 }
909 }
910 }
911 }
912 }
913
914 if (rc == VERR_INTERRUPTED)
915 {
916 /* Wait for termination event. */
917 WaitForSingleObject(pCtx->pEnv->hStopEvent, INFINITE);
918 break;
919 }
920
921 if (VBOX_FAILURE (rc))
922 {
923 /* Wait a bit before retrying. */
924 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 1000) == WAIT_OBJECT_0)
925 {
926 break;
927 }
928
929 continue;
930 }
931
932 dprintf(("processed host event rc = %d\n", rc));
933 }
934
935 CloseHandle (hDriver);
936
937 return 0;
938}
939
940void VBoxClipboardDestroy (const VBOXSERVICEENV *pEnv, void *pInstance)
941{
942 VBOXCLIPBOARDCONTEXT *pCtx = (VBOXCLIPBOARDCONTEXT *)pInstance;
943
944 if (pCtx != &gCtx)
945 {
946 dprintf(("VBoxClipboardDestroy: invalid instance %p (our %p)!!!\n", pCtx, &gCtx));
947
948 pCtx = &gCtx;
949 }
950
951 vboxClipboardDestroy (pCtx);
952
953 vboxClipboardDisconnect (pCtx);
954
955 memset (pCtx, 0, sizeof (*pCtx));
956
957 return;
958}
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