VirtualBox

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

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

InnoTek -> innotek: all the headers and comments.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.3 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 if (cb > 0 && !VirtualLock (pv, cb))
229 {
230 dprintf (("vboxClipboardHostEventRead: VirtualLock failed\n"));
231 return VERR_NOT_SUPPORTED;
232 }
233
234 VBoxClipboardReadData parms;
235
236 VBOX_INIT_CALL(&parms, VBOX_SHARED_CLIPBOARD_FN_READ_DATA, pCtx);
237
238 VBoxHGCMParmUInt32Set (&parms.format, u32Format);
239 VBoxHGCMParmPtrSet (&parms.ptr, pv, cb);
240 VBoxHGCMParmUInt32Set (&parms.size, 0);
241
242 int rc = vboxCall (pCtx->pEnv->hDriver, &parms, sizeof (parms));
243
244 if (VBOX_SUCCESS (rc))
245 {
246 rc = parms.hdr.result;
247
248 if (VBOX_SUCCESS (rc))
249 {
250 uint32_t u32Size;
251
252 rc = VBoxHGCMParmUInt32Get (&parms.size, &u32Size);
253
254 dprintf (("vboxClipboardReadData: actual size = %d, rc = %d\n", u32Size, rc));
255
256 if (VBOX_SUCCESS (rc))
257 {
258 if (pcbActual)
259 {
260 *pcbActual = u32Size;
261 }
262 }
263 }
264 }
265
266 if (cb > 0)
267 {
268 VirtualUnlock (pv, cb);
269 }
270
271 return rc;
272}
273
274static int vboxClipboardWriteData (VBOXCLIPBOARDCONTEXT *pCtx, uint32_t u32Format,
275 void *pv, uint32_t cb)
276{
277// if (vboxClipboardIsSameAsLastSent (pCtx, u32Format, pv, cb))
278// {
279// dprintf (("vboxClipboardWriteData: The data to be sent are the same as the last sent.\n"));
280// return VINF_SUCCESS;
281// }
282
283 if (cb > 0 && !VirtualLock (pv, cb))
284 {
285 dprintf (("vboxClipboardWriteData: VirtualLock failed\n"));
286 return VERR_NOT_SUPPORTED;
287 }
288
289 VBoxClipboardWriteData parms;
290
291 VBOX_INIT_CALL(&parms, VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA, pCtx);
292
293 VBoxHGCMParmUInt32Set (&parms.format, u32Format);
294 VBoxHGCMParmPtrSet (&parms.ptr, pv, cb);
295
296 int rc = vboxCall (pCtx->pEnv->hDriver, &parms, sizeof (parms));
297
298 if (VBOX_SUCCESS (rc))
299 {
300 rc = parms.hdr.result;
301 }
302
303 if (cb > 0)
304 {
305 VirtualUnlock (pv, cb);
306 }
307
308 return rc;
309}
310
311static void vboxClipboardChanged (VBOXCLIPBOARDCONTEXT *pCtx)
312{
313 /* Query list of available formats and report to host. */
314 if (OpenClipboard (pCtx->hwnd))
315 {
316 uint32_t u32Formats = 0;
317
318 UINT format = 0;
319
320 while ((format = EnumClipboardFormats (format)) != 0)
321 {
322 dprintf (("vboxClipboardChanged: format 0x%08X\n", format));
323 switch (format)
324 {
325 case CF_UNICODETEXT:
326 case CF_TEXT:
327 u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
328 break;
329
330 case CF_DIB:
331 case CF_BITMAP:
332 u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
333 break;
334
335 default:
336 if (format >= 0xC000)
337 {
338 TCHAR szFormatName[256];
339
340 int cActual = GetClipboardFormatName(format, szFormatName, sizeof(szFormatName)/sizeof (TCHAR));
341
342 if (cActual)
343 {
344 if (strcmp (szFormatName, "HTML Format") == 0)
345 {
346 u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_HTML;
347 }
348 }
349 }
350 break;
351 }
352 }
353
354 CloseClipboard ();
355
356 vboxClipboardReportFormats (pCtx, u32Formats);
357 }
358}
359
360static LRESULT vboxClipboardProcessMsg(VBOXCLIPBOARDCONTEXT *pCtx, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
361{
362 LRESULT rc = 0;
363
364 switch (msg)
365 {
366 case WM_CHANGECBCHAIN:
367 {
368 HWND hwndRemoved = (HWND)wParam;
369 HWND hwndNext = (HWND)lParam;
370
371 dprintf (("vboxClipboardProcessMsg: WM_CHANGECBCHAIN: hwndRemoved %p, hwndNext %p, hwnd %p\n", hwndRemoved, hwndNext, pCtx->hwnd));
372
373 if (hwndRemoved == pCtx->hwndNextInChain)
374 {
375 /* The window that was next to our in the chain is being removed.
376 * Relink to the new next window.
377 */
378 pCtx->hwndNextInChain = hwndNext;
379 }
380 else
381 {
382 if (pCtx->hwndNextInChain)
383 {
384 /* Pass the message further. */
385 rc = SendMessage (pCtx->hwndNextInChain, WM_CHANGECBCHAIN, wParam, lParam);
386 }
387 }
388 } break;
389
390 case WM_DRAWCLIPBOARD:
391 {
392 dprintf (("vboxClipboardProcessMsg: WM_DRAWCLIPBOARD, hwnd %p\n", pCtx->hwnd));
393
394 if (!pCtx->fAnnouncing)
395 {
396 vboxClipboardChanged (pCtx);
397 }
398
399 /* Pass the message to next windows in the clipboard chain. */
400 rc = SendMessage (pCtx->hwndNextInChain, msg, wParam, lParam);
401 } break;
402
403 case WM_CLOSE:
404 {
405 /* Do nothing. Ignore the message. */
406 } break;
407
408 case WM_RENDERFORMAT:
409 {
410 /* Insert the requested clipboard format data into the clipboard. */
411 uint32_t u32Format = 0;
412
413 UINT format = (UINT)wParam;
414
415 switch (format)
416 {
417 case CF_UNICODETEXT:
418 u32Format |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
419 break;
420
421 case CF_DIB:
422 u32Format |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
423 break;
424
425 default:
426 if (format >= 0xC000)
427 {
428 TCHAR szFormatName[256];
429
430 int cActual = GetClipboardFormatName(format, szFormatName, sizeof(szFormatName)/sizeof (TCHAR));
431
432 if (cActual)
433 {
434 if (strcmp (szFormatName, "HTML Format") == 0)
435 {
436 u32Format |= VBOX_SHARED_CLIPBOARD_FMT_HTML;
437 }
438 }
439 }
440 break;
441 }
442
443 if (u32Format == 0)
444 {
445 /* Unsupported clipboard format is requested. */
446 EmptyClipboard ();
447 }
448 else
449 {
450 const uint32_t cbPrealloc = 4096;
451 uint32_t cb = 0;
452
453 /* Preallocate a buffer, most of small text transfers will fit into it. */
454 HANDLE hMem = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, cbPrealloc);
455 dprintf(("hMem %p\n", hMem));
456
457 if (hMem)
458 {
459 void *pMem = GlobalLock (hMem);
460 dprintf(("pMem %p, GlobalSize %d\n", pMem, GlobalSize (hMem)));
461
462 if (pMem)
463 {
464 /* Read the host data to the preallocated buffer. */
465 int vboxrc = vboxClipboardReadData (pCtx, u32Format, pMem, cbPrealloc, &cb);
466 dprintf(("vboxClipboardReadData vboxrc %d\n", vboxrc));
467
468 if (VBOX_SUCCESS (rc))
469 {
470 if (cb > cbPrealloc)
471 {
472 GlobalUnlock (hMem);
473
474 /* The preallocated buffer is too small, adjust the size. */
475 hMem = GlobalReAlloc (hMem, cb, 0);
476 dprintf(("hMem %p\n", hMem));
477
478 if (hMem)
479 {
480 pMem = GlobalLock (hMem);
481 dprintf(("pMem %p, GlobalSize %d\n", pMem, GlobalSize (hMem)));
482
483 if (pMem)
484 {
485 /* Read the host data to the preallocated buffer. */
486 uint32_t cbNew = 0;
487 vboxrc = vboxClipboardReadData (pCtx, u32Format, pMem, cb, &cbNew);
488 dprintf(("vboxClipboardReadData vboxrc %d, cb = %d, cbNew = %d\n", vboxrc, cb, cbNew));
489
490 if (VBOX_SUCCESS (vboxrc) && cbNew <= cb)
491 {
492 cb = cbNew;
493 }
494 else
495 {
496 GlobalUnlock (pMem);
497 GlobalFree (hMem);
498 hMem = NULL;
499 }
500 }
501 else
502 {
503 GlobalFree (hMem);
504 hMem = NULL;
505 }
506 }
507 }
508
509 if (hMem)
510 {
511 /* pMem is the address of the data. cb is the size of returned data. */
512 /* Verify the size of returned text. */
513 if (u32Format == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
514 {
515 cb = (lstrlenW((LPWSTR)pMem) + 1) * 2;
516 }
517
518 GlobalUnlock (hMem);
519
520 hMem = GlobalReAlloc (hMem, cb, 0);
521 dprintf(("hMem %p\n", hMem));
522
523 if (hMem)
524 {
525 /* 'hMem' contains the host clipboard data.
526 * size is 'cb' and format is 'format'.
527 */
528 HANDLE hClip = SetClipboardData (format, hMem);
529 dprintf(("WM_RENDERFORMAT hClip %p\n", hClip));
530
531 if (hClip)
532 {
533 /* The hMem ownership has gone to the system. Finish the processing. */
534 break;
535 }
536
537 /* Cleanup follows. */
538 }
539 }
540 }
541
542 if (hMem)
543 {
544 GlobalUnlock (hMem);
545 }
546 }
547
548 if (hMem)
549 {
550 GlobalFree (hMem);
551 }
552 }
553
554 /* Something went wrong. */
555 EmptyClipboard ();
556 }
557 } break;
558
559 case WM_RENDERALLFORMATS:
560 {
561 /* Do nothing. The clipboard formats will be unavailable now, because the
562 * windows is to be destroyed and therefore the guest side becomes inactive.
563 */
564 if (OpenClipboard (hwnd))
565 {
566 EmptyClipboard();
567
568 CloseClipboard();
569 }
570 } break;
571
572 case WM_USER:
573 {
574 /* Announce available formats. Do not insert data, they will be inserted in WM_RENDER*. */
575 uint32_t u32Formats = (uint32_t)lParam;
576
577 /* Prevent the WM_DRAWCLIPBOARD processing. */
578 pCtx->fAnnouncing = true;
579
580 if (OpenClipboard (hwnd))
581 {
582 EmptyClipboard();
583
584 HANDLE hClip = NULL;
585
586 if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
587 {
588 dprintf(("window proc WM_USER: VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT\n"));
589 hClip = SetClipboardData (CF_UNICODETEXT, NULL);
590 }
591
592 if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
593 {
594 dprintf(("window proc WM_USER: VBOX_SHARED_CLIPBOARD_FMT_BITMAP\n"));
595 hClip = SetClipboardData (CF_DIB, NULL);
596 }
597
598 if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML)
599 {
600 UINT format = RegisterClipboardFormat ("HTML Format");
601 dprintf(("window proc WM_USER: VBOX_SHARED_CLIPBOARD_FMT_HTML 0x%04X\n", format));
602 if (format != 0)
603 {
604 hClip = SetClipboardData (format, NULL);
605 }
606 }
607
608 CloseClipboard();
609
610 dprintf(("window proc WM_USER: hClip %p\n", hClip));
611 }
612 else
613 {
614 dprintf(("window proc WM_USER: failed to open clipboard\n"));
615 }
616
617 pCtx->fAnnouncing = false;
618 } break;
619
620 case WM_USER + 1:
621 {
622 /* Send data in the specified format to the host. */
623 uint32_t u32Formats = (uint32_t)lParam;
624
625 HANDLE hClip = NULL;
626
627 if (OpenClipboard (hwnd))
628 {
629 if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
630 {
631 hClip = GetClipboardData (CF_DIB);
632
633 if (hClip != NULL)
634 {
635 LPVOID lp = GlobalLock (hClip);
636
637 if (lp != NULL)
638 {
639 dprintf(("CF_DIB\n"));
640
641 vboxClipboardWriteData (pCtx, VBOX_SHARED_CLIPBOARD_FMT_BITMAP,
642 lp, GlobalSize (hClip));
643
644 GlobalUnlock(hClip);
645 }
646 else
647 {
648 hClip = NULL;
649 }
650 }
651 }
652 else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
653 {
654 hClip = GetClipboardData(CF_UNICODETEXT);
655
656 if (hClip != NULL)
657 {
658 LPWSTR uniString = (LPWSTR)GlobalLock (hClip);
659
660 if (uniString != NULL)
661 {
662 dprintf(("CF_UNICODETEXT\n"));
663
664 vboxClipboardWriteData (pCtx, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
665 uniString, (lstrlenW (uniString) + 1) * 2);
666
667 GlobalUnlock(hClip);
668 }
669 else
670 {
671 hClip = NULL;
672 }
673 }
674 }
675 else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML)
676 {
677 UINT format = RegisterClipboardFormat ("HTML Format");
678
679 if (format != 0)
680 {
681 hClip = GetClipboardData (format);
682
683 if (hClip != NULL)
684 {
685 LPVOID lp = GlobalLock (hClip);
686
687 if (lp != NULL)
688 {
689 dprintf(("CF_HTML\n"));
690
691 vboxClipboardWriteData (pCtx, VBOX_SHARED_CLIPBOARD_FMT_HTML,
692 lp, GlobalSize (hClip));
693
694 GlobalUnlock(hClip);
695 }
696 else
697 {
698 hClip = NULL;
699 }
700 }
701 }
702 }
703
704 CloseClipboard ();
705 }
706
707 if (hClip == NULL)
708 {
709 /* Requested clipboard format is not available, send empty data. */
710 vboxClipboardWriteData (pCtx, 0, NULL, 0);
711 }
712 } break;
713
714 default:
715 {
716 rc = DefWindowProc (hwnd, msg, wParam, lParam);
717 }
718 }
719
720 return rc;
721}
722
723static LRESULT CALLBACK vboxClipboardWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
724
725static int vboxClipboardInit (VBOXCLIPBOARDCONTEXT *pCtx)
726{
727 int rc = VINF_SUCCESS;
728
729 /* Register the Window Class. */
730 WNDCLASS wc;
731
732 wc.style = CS_NOCLOSE;
733 wc.lpfnWndProc = vboxClipboardWndProc;
734 wc.cbClsExtra = 0;
735 wc.cbWndExtra = 0;
736 wc.hInstance = pCtx->pEnv->hInstance;
737 wc.hIcon = NULL;
738 wc.hCursor = NULL;
739 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
740 wc.lpszMenuName = NULL;
741 wc.lpszClassName = gachWindowClassName;
742
743 pCtx->atomWindowClass = RegisterClass (&wc);
744
745 if (pCtx->atomWindowClass == 0)
746 {
747 rc = VERR_NOT_SUPPORTED;
748 }
749 else
750 {
751 /* Create the window. */
752 pCtx->hwnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
753 gachWindowClassName, gachWindowClassName,
754 WS_POPUPWINDOW,
755 -200, -200, 100, 100, NULL, NULL, pCtx->pEnv->hInstance, NULL);
756
757 if (pCtx->hwnd == NULL)
758 {
759 rc = VERR_NOT_SUPPORTED;
760 }
761 else
762 {
763 SetWindowPos(pCtx->hwnd, HWND_TOPMOST, -200, -200, 0, 0,
764 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
765
766 pCtx->hwndNextInChain = SetClipboardViewer (pCtx->hwnd);
767 }
768 }
769
770 return rc;
771}
772
773static void vboxClipboardDestroy (VBOXCLIPBOARDCONTEXT *pCtx)
774{
775 if (pCtx->hwnd)
776 {
777 ChangeClipboardChain (pCtx->hwnd, pCtx->hwndNextInChain);
778 pCtx->hwndNextInChain = NULL;
779
780 DestroyWindow (pCtx->hwnd);
781 pCtx->hwnd = NULL;
782 }
783
784 if (pCtx->atomWindowClass != 0)
785 {
786 UnregisterClass(gachWindowClassName, pCtx->pEnv->hInstance);
787 pCtx->atomWindowClass = 0;
788 }
789}
790
791/* Static since it is the single instance. Directly used in the windows proc. */
792static VBOXCLIPBOARDCONTEXT gCtx = { NULL };
793
794static LRESULT CALLBACK vboxClipboardWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
795{
796 /* Forward with proper context. */
797 return vboxClipboardProcessMsg (&gCtx, hwnd, msg, wParam, lParam);
798}
799
800int VBoxClipboardInit (const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread)
801{
802 int rc = VINF_SUCCESS;
803
804 dprintf (("VboxClipboardInit\n"));
805
806 if (gCtx.pEnv)
807 {
808 /* Clipboard was already initialized. 2 or more instances are not supported. */
809 return VERR_NOT_SUPPORTED;
810 }
811
812 memset (&gCtx, 0, sizeof (gCtx));
813
814 gCtx.pEnv = pEnv;
815
816 rc = vboxClipboardConnect (&gCtx);
817
818 if (VBOX_SUCCESS (rc))
819 {
820 rc = vboxClipboardInit (&gCtx);
821
822 dprintf (("vboxClipboardInit: rc = %d\n", rc));
823
824 if (VBOX_SUCCESS (rc))
825 {
826 /* Always start the thread for host messages. */
827 *pfStartThread = true;
828 }
829 }
830
831 if (VBOX_SUCCESS (rc))
832 {
833 *ppInstance = &gCtx;
834 }
835 else
836 {
837 vboxClipboardDisconnect (&gCtx);
838 }
839
840 return rc;
841}
842
843unsigned __stdcall VBoxClipboardThread (void *pInstance)
844{
845 VBOXCLIPBOARDCONTEXT *pCtx = (VBOXCLIPBOARDCONTEXT *)pInstance;
846
847 dprintf(("VBoxClipboardThread\n"));
848
849 /* Open the new driver instance to not interfere with other callers. */
850 HANDLE hDriver = CreateFile(VBOXGUEST_DEVICE_NAME,
851 GENERIC_READ | GENERIC_WRITE,
852 FILE_SHARE_READ | FILE_SHARE_WRITE,
853 NULL,
854 OPEN_EXISTING,
855 FILE_ATTRIBUTE_NORMAL,
856 NULL);
857
858 /* The thread waits for incoming messages from the host. */
859 for (;;)
860 {
861 VBoxClipboardGetHostMsg parms;
862
863 VBOX_INIT_CALL(&parms, VBOX_SHARED_CLIPBOARD_FN_GET_HOST_MSG, pCtx);
864
865 VBoxHGCMParmUInt32Set (&parms.msg, 0);
866 VBoxHGCMParmUInt32Set (&parms.formats, 0);
867
868 DWORD cbReturned;
869
870 if (!DeviceIoControl (hDriver,
871 IOCTL_VBOXGUEST_HGCM_CALL,
872 &parms, sizeof (parms),
873 &parms, sizeof (parms),
874 &cbReturned,
875 NULL))
876 {
877 dprintf(("Failed to call the driver for host message.\n"));
878
879 /* Wait a bit before retrying. */
880 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 1000) == WAIT_OBJECT_0)
881 {
882 break;
883 }
884
885 continue;
886 }
887
888 int rc = parms.hdr.result;
889
890 if (VBOX_SUCCESS (rc))
891 {
892 uint32_t u32Msg;
893 uint32_t u32Formats;
894
895 rc = VBoxHGCMParmUInt32Get (&parms.msg, &u32Msg);
896
897 if (VBOX_SUCCESS (rc))
898 {
899 rc = VBoxHGCMParmUInt32Get (&parms.formats, &u32Formats);
900
901 if (VBOX_SUCCESS (rc))
902 {
903 dprintf(("vboxClipboardHostEvent u32Msg %d, u32Formats %d\n", u32Msg, u32Formats));
904
905 switch (u32Msg)
906 {
907 case VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS:
908 {
909 /* The host has announced available clipboard formats.
910 * Forward the information to the window, so it can later
911 * respond to WM_RENDERFORMAT message.
912 */
913 ::PostMessage (pCtx->hwnd, WM_USER, 0, u32Formats);
914 } break;
915 case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA:
916 {
917 /* The host needs data in the specified format.
918 */
919 ::PostMessage (pCtx->hwnd, WM_USER + 1, 0, u32Formats);
920 } break;
921 case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT:
922 {
923 /* The host is terminating.
924 */
925 rc = VERR_INTERRUPTED;
926 } break;
927 default:
928 {
929 dprintf(("Unsupported message from host!!!"));
930 }
931 }
932 }
933 }
934 }
935
936 if (rc == VERR_INTERRUPTED)
937 {
938 /* Wait for termination event. */
939 WaitForSingleObject(pCtx->pEnv->hStopEvent, INFINITE);
940 break;
941 }
942
943 if (VBOX_FAILURE (rc))
944 {
945 /* Wait a bit before retrying. */
946 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 1000) == WAIT_OBJECT_0)
947 {
948 break;
949 }
950
951 continue;
952 }
953
954 dprintf(("processed host event rc = %d\n", rc));
955 }
956
957 CloseHandle (hDriver);
958
959 return 0;
960}
961
962void VBoxClipboardDestroy (const VBOXSERVICEENV *pEnv, void *pInstance)
963{
964 VBOXCLIPBOARDCONTEXT *pCtx = (VBOXCLIPBOARDCONTEXT *)pInstance;
965
966 if (pCtx != &gCtx)
967 {
968 dprintf(("VBoxClipboardDestroy: invalid instance %p (our %p)!!!\n", pCtx, &gCtx));
969
970 pCtx = &gCtx;
971 }
972
973 vboxClipboardDestroy (pCtx);
974
975 vboxClipboardDisconnect (pCtx);
976
977 memset (pCtx, 0, sizeof (*pCtx));
978
979 return;
980}
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