VirtualBox

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

Last change on this file since 6670 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

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