VirtualBox

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

Last change on this file since 4027 was 3739, checked in by vboxsync, 18 years ago

cleaned up logging

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

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