VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp@ 16684

Last change on this file since 16684 was 13835, checked in by vboxsync, 16 years ago

s/VBOX_SUCCESS/RT_SUCCESS/g s/VBOX_FAILURE/RT_FAILURE/g - VBOX_SUCCESS and VBOX_FAILURE have *NOT* been retired (because old habbits die hard) just sligtly deprecated.

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