VirtualBox

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

Last change on this file since 78151 was 78151, checked in by vboxsync, 6 years ago

Shared Clipboard: Got rid of a lot of duplicated code between Windows hosts / guests, plus a lot of renaming / cleanup, some more documentation.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.6 KB
Line 
1/* $Id: VBoxClipboard.cpp 78151 2019-04-17 12:03:42Z vboxsync $ */
2/** @file
3 * VBoxClipboard - Shared clipboard, Windows Guest Implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22# define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
23#include "VBoxTray.h"
24#include "VBoxHelpers.h"
25
26#include <iprt/asm.h>
27#include <iprt/ldr.h>
28
29#include <VBox/GuestHost/SharedClipboard.h>
30#include <VBox/GuestHost/SharedClipboard-win.h>
31#include <strsafe.h>
32
33#include <VBox/log.h>
34
35
36/*********************************************************************************************************************************
37* Structures and Typedefs *
38*********************************************************************************************************************************/
39
40struct _VBOXCLIPBOARDCONTEXT
41{
42 /** Pointer to the VBoxClient service environment. */
43 const VBOXSERVICEENV *pEnv;
44 /** Client ID the service is connected to the HGCM service with. */
45 uint32_t u32ClientID;
46 /** Windows-specific context data. */
47 VBOXCLIPBOARDWINCTX Win;
48};
49
50/*********************************************************************************************************************************
51* Static variables *
52*********************************************************************************************************************************/
53/** Static clipboard context (since it is the single instance). Directly used in the windows proc. */
54static VBOXCLIPBOARDCONTEXT g_Ctx = { NULL };
55/** Static window class name. */
56static char s_szClipWndClassName[] = VBOX_CLIPBOARD_WNDCLASS_NAME;
57
58
59static LRESULT vboxClipboardProcessMsg(PVBOXCLIPBOARDCONTEXT pCtx, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
60{
61 AssertPtr(pCtx);
62
63 const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win;
64
65 LRESULT rc = 0;
66
67 switch (msg)
68 {
69 case WM_CLIPBOARDUPDATE:
70 {
71 Log(("WM_CLIPBOARDUPDATE\n"));
72
73 if (GetClipboardOwner() != hwnd)
74 {
75 /* Clipboard was updated by another application. */
76 uint32_t uFormats;
77 int vboxrc = VBoxClipboardWinGetFormats(&pCtx->Win, &uFormats);
78 if (RT_SUCCESS(vboxrc))
79 vboxrc = VbglR3ClipboardReportFormats(pCtx->u32ClientID, uFormats);
80 }
81 } break;
82
83 case WM_CHANGECBCHAIN:
84 {
85 if (VBoxClipboardWinIsNewAPI(&pWinCtx->newAPI))
86 {
87 rc = DefWindowProc(hwnd, msg, wParam, lParam);
88 break;
89 }
90
91 HWND hWndRemoved = (HWND)wParam;
92 HWND hWndNext = (HWND)lParam;
93
94 LogFlowFunc(("WM_CHANGECBCHAIN: hWndRemoved=%p, hWndNext=%p, hWnd=%p\n", hWndRemoved, hWndNext, pWinCtx->hWnd));
95
96 if (hWndRemoved == pWinCtx->hWndNextInChain)
97 {
98 /* The window that was next to our in the chain is being removed.
99 * Relink to the new next window. */
100 pWinCtx->hWndNextInChain = hWndNext;
101 }
102 else
103 {
104 if (pWinCtx->hWndNextInChain)
105 {
106 /* Pass the message further. */
107 DWORD_PTR dwResult;
108 rc = SendMessageTimeout(pWinCtx->hWndNextInChain, WM_CHANGECBCHAIN, wParam, lParam, 0,
109 VBOX_CLIPBOARD_CBCHAIN_TIMEOUT_MS, &dwResult);
110 if (!rc)
111 rc = (LRESULT) dwResult;
112 }
113 }
114 } break;
115
116 case WM_DRAWCLIPBOARD:
117 {
118 LogFlowFunc(("WM_DRAWCLIPBOARD, hwnd %p\n", pWinCtx->hWnd));
119
120 if (GetClipboardOwner() != hwnd)
121 {
122 /* Clipboard was updated by another application. */
123 /* WM_DRAWCLIPBOARD always expects a return code of 0, so don't change "rc" here. */
124 uint32_t uFormats;
125 int vboxrc = VBoxClipboardWinGetFormats(pWinCtx, &uFormats);
126 if (RT_SUCCESS(vboxrc))
127 vboxrc = VbglR3ClipboardReportFormats(pCtx->u32ClientID, uFormats);
128 }
129
130 if (pWinCtx->hWndNextInChain)
131 {
132 /* Pass the message to next windows in the clipboard chain. */
133 SendMessageTimeout(pWinCtx->hWndNextInChain, msg, wParam, lParam, 0, VBOX_CLIPBOARD_CBCHAIN_TIMEOUT_MS, NULL);
134 }
135 } break;
136
137 case WM_TIMER:
138 {
139 if (VBoxClipboardWinIsNewAPI(&pWinCtx->newAPI))
140 break;
141
142 HWND hViewer = GetClipboardViewer();
143
144 /* Re-register ourselves in the clipboard chain if our last ping
145 * timed out or there seems to be no valid chain. */
146 if (!hViewer || pWinCtx->oldAPI.fCBChainPingInProcess)
147 {
148 VBoxClipboardWinRemoveFromCBChain(pWinCtx);
149 VBoxClipboardWinAddToCBChain(pWinCtx);
150 }
151
152 /* Start a new ping by passing a dummy WM_CHANGECBCHAIN to be
153 * processed by ourselves to the chain. */
154 pWinCtx->oldAPI.fCBChainPingInProcess = TRUE;
155
156 hViewer = GetClipboardViewer();
157 if (hViewer)
158 SendMessageCallback(hViewer, WM_CHANGECBCHAIN, (WPARAM)pWinCtx->hWndNextInChain, (LPARAM)pWinCtx->hWndNextInChain,
159 VBoxClipboardWinChainPingProc, (ULONG_PTR)pWinCtx);
160 } break;
161
162 case WM_CLOSE:
163 {
164 /* Do nothing. Ignore the message. */
165 } break;
166
167 case WM_RENDERFORMAT:
168 {
169 /* Insert the requested clipboard format data into the clipboard. */
170 uint32_t u32Format = 0;
171 UINT format = (UINT)wParam;
172
173 LogFlowFunc(("WM_RENDERFORMAT, format = %x\n", format));
174 switch (format)
175 {
176 case CF_UNICODETEXT:
177 u32Format |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
178 break;
179
180 case CF_DIB:
181 u32Format |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
182 break;
183
184 default:
185 if (format >= 0xC000)
186 {
187 TCHAR szFormatName[256];
188
189 int cActual = GetClipboardFormatName(format, szFormatName, sizeof(szFormatName)/sizeof (TCHAR));
190 if (cActual)
191 {
192 if (strcmp (szFormatName, "HTML Format") == 0)
193 {
194 u32Format |= VBOX_SHARED_CLIPBOARD_FMT_HTML;
195 }
196 }
197 }
198 break;
199 }
200
201 if (u32Format == 0)
202 {
203 /* Unsupported clipboard format is requested. */
204 LogFlowFunc(("Unsupported clipboard format requested: %ld\n", u32Format));
205 VBoxClipboardWinClear();
206 }
207 else
208 {
209 const uint32_t cbPrealloc = 4096; /** @todo r=andy Make it dynamic for supporting larger text buffers! */
210 uint32_t cb = 0;
211
212 /* Preallocate a buffer, most of small text transfers will fit into it. */
213 HANDLE hMem = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cbPrealloc);
214 LogFlowFunc(("Preallocated handle hMem = %p\n", hMem));
215
216 if (hMem)
217 {
218 void *pMem = GlobalLock(hMem);
219 LogFlowFunc(("Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem)));
220
221 if (pMem)
222 {
223 /* Read the host data to the preallocated buffer. */
224 int vboxrc = VbglR3ClipboardReadData(pCtx->u32ClientID, u32Format, pMem, cbPrealloc, &cb);
225 LogFlowFunc(("VbglR3ClipboardReadData returned with rc = %Rrc\n", vboxrc));
226
227 if (RT_SUCCESS(vboxrc))
228 {
229 if (cb == 0)
230 {
231 /* 0 bytes returned means the clipboard is empty.
232 * Deallocate the memory and set hMem to NULL to get to
233 * the clipboard empty code path. */
234 GlobalUnlock(hMem);
235 GlobalFree(hMem);
236 hMem = NULL;
237 }
238 else if (cb > cbPrealloc)
239 {
240 GlobalUnlock(hMem);
241
242 /* The preallocated buffer is too small, adjust the size. */
243 hMem = GlobalReAlloc(hMem, cb, 0);
244 LogFlowFunc(("Reallocated hMem = %p\n", hMem));
245
246 if (hMem)
247 {
248 pMem = GlobalLock(hMem);
249 LogFlowFunc(("Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem)));
250
251 if (pMem)
252 {
253 /* Read the host data to the preallocated buffer. */
254 uint32_t cbNew = 0;
255 vboxrc = VbglR3ClipboardReadData(pCtx->u32ClientID, u32Format, pMem, cb, &cbNew);
256 LogFlowFunc(("VbglR3ClipboardReadData returned with rc = %Rrc, cb = %d, cbNew = %d\n", vboxrc, cb, cbNew));
257
258 if (RT_SUCCESS (vboxrc) && cbNew <= cb)
259 {
260 cb = cbNew;
261 }
262 else
263 {
264 GlobalUnlock(hMem);
265 GlobalFree(hMem);
266 hMem = NULL;
267 }
268 }
269 else
270 {
271 GlobalFree(hMem);
272 hMem = NULL;
273 }
274 }
275 }
276
277 if (hMem)
278 {
279 /* pMem is the address of the data. cb is the size of returned data. */
280 /* Verify the size of returned text, the memory block for clipboard
281 * must have the exact string size.
282 */
283 if (u32Format == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
284 {
285 size_t cbActual = 0;
286 HRESULT hrc = StringCbLengthW((LPWSTR)pMem, cb, &cbActual);
287 if (FAILED (hrc))
288 {
289 /* Discard invalid data. */
290 GlobalUnlock(hMem);
291 GlobalFree(hMem);
292 hMem = NULL;
293 }
294 else
295 {
296 /* cbActual is the number of bytes, excluding those used
297 * for the terminating null character.
298 */
299 cb = (uint32_t)(cbActual + 2);
300 }
301 }
302 }
303
304 if (hMem)
305 {
306 GlobalUnlock(hMem);
307
308 hMem = GlobalReAlloc(hMem, cb, 0);
309 LogFlowFunc(("Reallocated hMem = %p\n", hMem));
310
311 if (hMem)
312 {
313 /* 'hMem' contains the host clipboard data.
314 * size is 'cb' and format is 'format'. */
315 HANDLE hClip = SetClipboardData(format, hMem);
316 LogFlowFunc(("WM_RENDERFORMAT hClip = %p\n", hClip));
317
318 if (hClip)
319 {
320 /* The hMem ownership has gone to the system. Finish the processing. */
321 break;
322 }
323
324 /* Cleanup follows. */
325 }
326 }
327 }
328 if (hMem)
329 GlobalUnlock(hMem);
330 }
331 if (hMem)
332 GlobalFree(hMem);
333 }
334
335 /* Something went wrong. */
336 VBoxClipboardWinClear();
337 }
338 } break;
339
340 case WM_RENDERALLFORMATS:
341 {
342 /* Do nothing. The clipboard formats will be unavailable now, because the
343 * windows is to be destroyed and therefore the guest side becomes inactive.
344 */
345 int vboxrc = VBoxClipboardWinOpen(hwnd);
346 if (RT_SUCCESS(vboxrc))
347 {
348 VBoxClipboardWinClear();
349 VBoxClipboardWinClose();
350 }
351 } break;
352
353 case VBOX_CLIPBOARD_WM_SET_FORMATS:
354 {
355 /* Announce available formats. Do not insert data, they will be inserted in WM_RENDER*. */
356 uint32_t u32Formats = (uint32_t)lParam;
357
358 LogFlowFunc(("VBOX_WM_SHCLPB_SET_FORMATS: u32Formats=0x%x\n", u32Formats));
359
360 int vboxrc = VBoxClipboardWinOpen(hwnd);
361 if (RT_SUCCESS(vboxrc))
362 {
363 VBoxClipboardWinClear();
364
365 HANDLE hClip = NULL;
366
367 if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
368 hClip = SetClipboardData(CF_UNICODETEXT, NULL);
369
370 if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
371 hClip = SetClipboardData(CF_DIB, NULL);
372
373 if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML)
374 {
375 UINT format = RegisterClipboardFormat ("HTML Format");
376 if (format != 0)
377 hClip = SetClipboardData(format, NULL);
378 }
379
380 VBoxClipboardWinClose();
381
382 LogFlowFunc(("VBOX_WM_SHCLPB_SET_FORMATS: hClip=%p, lastErr=%ld\n", hClip, GetLastError()));
383 }
384 } break;
385
386 case VBOX_CLIPBOARD_WM_READ_DATA:
387 {
388 /* Send data in the specified format to the host. */
389 uint32_t u32Formats = (uint32_t)lParam;
390 HANDLE hClip = NULL;
391
392 LogFlowFunc(("VBOX_WM_SHCLPB_READ_DATA: u32Formats=0x%x\n", u32Formats));
393
394 int vboxrc = VBoxClipboardWinOpen(hwnd);
395 if (RT_SUCCESS(vboxrc))
396 {
397 if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
398 {
399 hClip = GetClipboardData(CF_DIB);
400
401 if (hClip != NULL)
402 {
403 LPVOID lp = GlobalLock(hClip);
404 if (lp != NULL)
405 {
406 vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_BITMAP,
407 lp, GlobalSize(hClip));
408 GlobalUnlock(hClip);
409 }
410 else
411 {
412 hClip = NULL;
413 }
414 }
415 }
416 else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
417 {
418 hClip = GetClipboardData(CF_UNICODETEXT);
419
420 if (hClip != NULL)
421 {
422 LPWSTR uniString = (LPWSTR)GlobalLock(hClip);
423
424 if (uniString != NULL)
425 {
426 vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
427 uniString, (lstrlenW(uniString) + 1) * 2);
428 GlobalUnlock(hClip);
429 }
430 else
431 {
432 hClip = NULL;
433 }
434 }
435 }
436 else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML)
437 {
438 UINT format = RegisterClipboardFormat ("HTML Format");
439 if (format != 0)
440 {
441 hClip = GetClipboardData(format);
442 if (hClip != NULL)
443 {
444 LPVOID lp = GlobalLock(hClip);
445
446 if (lp != NULL)
447 {
448 vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_HTML,
449 lp, GlobalSize(hClip));
450 GlobalUnlock(hClip);
451 }
452 else
453 {
454 hClip = NULL;
455 }
456 }
457 }
458 }
459
460 VBoxClipboardWinClose();
461 }
462
463 if (hClip == NULL)
464 {
465 /* Requested clipboard format is not available, send empty data. */
466 VbglR3ClipboardWriteData(pCtx->u32ClientID, 0, NULL, 0);
467 }
468 } break;
469
470 case WM_DESTROY:
471 {
472 VBoxClipboardWinRemoveFromCBChain(pWinCtx);
473 if (pWinCtx->oldAPI.timerRefresh)
474 KillTimer(pWinCtx->hWnd, 0);
475 /*
476 * don't need to call PostQuitMessage cause
477 * the VBoxTray already finished a message loop
478 */
479 } break;
480
481 default:
482 {
483 rc = DefWindowProc(hwnd, msg, wParam, lParam);
484 }
485 }
486
487#ifndef DEBUG_andy
488 LogFlowFunc(("vboxClipboardProcessMsg returned with rc = %ld\n", rc));
489#endif
490 return rc;
491}
492
493static LRESULT CALLBACK vboxClipboardWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
494
495static int vboxClipboardCreateWindow(PVBOXCLIPBOARDCONTEXT pCtx)
496{
497 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
498
499 int rc = VINF_SUCCESS;
500
501 AssertPtr(pCtx->pEnv);
502 HINSTANCE hInstance = pCtx->pEnv->hInstance;
503 Assert(hInstance != 0);
504
505 /* Register the Window Class. */
506 WNDCLASSEX wc = { 0 };
507 wc.cbSize = sizeof(WNDCLASSEX);
508
509 if (!GetClassInfoEx(hInstance, s_szClipWndClassName, &wc))
510 {
511 wc.style = CS_NOCLOSE;
512 wc.lpfnWndProc = vboxClipboardWndProc;
513 wc.hInstance = pCtx->pEnv->hInstance;
514 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
515 wc.lpszClassName = s_szClipWndClassName;
516
517 ATOM wndClass = RegisterClassEx(&wc);
518 if (wndClass == 0)
519 rc = RTErrConvertFromWin32(GetLastError());
520 }
521
522 if (RT_SUCCESS(rc))
523 {
524 const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win;
525
526 /* Create the window. */
527 pWinCtx->hWnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
528 s_szClipWndClassName, s_szClipWndClassName,
529 WS_POPUPWINDOW,
530 -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
531 if (pWinCtx->hWnd == NULL)
532 {
533 rc = VERR_NOT_SUPPORTED;
534 }
535 else
536 {
537 SetWindowPos(pWinCtx->hWnd, HWND_TOPMOST, -200, -200, 0, 0,
538 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
539
540 VBoxClipboardWinAddToCBChain(pWinCtx);
541 if (!VBoxClipboardWinIsNewAPI(&pWinCtx->newAPI))
542 pWinCtx->oldAPI.timerRefresh = SetTimer(pWinCtx->hWnd, 0, 10 * 1000 /* 10s */, NULL);
543 }
544 }
545
546 LogFlowFuncLeaveRC(rc);
547 return rc;
548}
549
550static void vboxClipboardDestroy(PVBOXCLIPBOARDCONTEXT pCtx)
551{
552 AssertPtrReturnVoid(pCtx);
553
554 const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win;
555
556 if (pWinCtx->hWnd)
557 {
558 DestroyWindow(pWinCtx->hWnd);
559 pWinCtx->hWnd = NULL;
560 }
561
562 UnregisterClass(s_szClipWndClassName, pCtx->pEnv->hInstance);
563}
564
565static LRESULT CALLBACK vboxClipboardWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
566{
567 PVBOXCLIPBOARDCONTEXT pCtx = &g_Ctx; /** @todo r=andy Make pCtx available through SetWindowLongPtr() / GWL_USERDATA. */
568 AssertPtr(pCtx);
569
570 /* Forward with proper context. */
571 return vboxClipboardProcessMsg(pCtx, hWnd, uMsg, wParam, lParam);
572}
573
574DECLCALLBACK(int) VBoxClipboardInit(const PVBOXSERVICEENV pEnv, void **ppInstance)
575{
576 LogFlowFuncEnter();
577
578 PVBOXCLIPBOARDCONTEXT pCtx = &g_Ctx; /* Only one instance for now. */
579 AssertPtr(pCtx);
580
581 if (pCtx->pEnv)
582 {
583 /* Clipboard was already initialized. 2 or more instances are not supported. */
584 return VERR_NOT_SUPPORTED;
585 }
586
587 if (VbglR3AutoLogonIsRemoteSession())
588 {
589 /* Do not use clipboard for remote sessions. */
590 LogRel(("Clipboard: Clipboard has been disabled for a remote session\n"));
591 return VERR_NOT_SUPPORTED;
592 }
593
594 RT_BZERO(pCtx, sizeof(VBOXCLIPBOARDCONTEXT));
595
596 pCtx->pEnv = pEnv;
597
598 /* Check that new Clipboard API is available */
599 VBoxClipboardWinCheckAndInitNewAPI(&pCtx->Win.newAPI);
600
601 int rc = VbglR3ClipboardConnect(&pCtx->u32ClientID);
602 if (RT_SUCCESS(rc))
603 {
604 rc = vboxClipboardCreateWindow(pCtx);
605 if (RT_SUCCESS(rc))
606 {
607 *ppInstance = pCtx;
608 }
609 else
610 {
611 VbglR3ClipboardDisconnect(pCtx->u32ClientID);
612 }
613 }
614
615 LogFlowFuncLeaveRC(rc);
616 return rc;
617}
618
619DECLCALLBACK(int) VBoxClipboardWorker(void *pInstance, bool volatile *pfShutdown)
620{
621 AssertPtr(pInstance);
622 LogFlowFunc(("pInstance=%p\n", pInstance));
623
624 /*
625 * Tell the control thread that it can continue
626 * spawning services.
627 */
628 RTThreadUserSignal(RTThreadSelf());
629
630 const PVBOXCLIPBOARDCONTEXT pCtx = (PVBOXCLIPBOARDCONTEXT)pInstance;
631 AssertPtr(pCtx);
632
633 const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win;
634
635 int rc;
636
637 /* The thread waits for incoming messages from the host. */
638 for (;;)
639 {
640 uint32_t u32Msg;
641 uint32_t u32Formats;
642 rc = VbglR3ClipboardGetHostMsg(pCtx->u32ClientID, &u32Msg, &u32Formats);
643 if (RT_FAILURE(rc))
644 {
645 if (rc == VERR_INTERRUPTED)
646 break;
647
648 LogFlowFunc(("Error getting host message, rc=%Rrc\n", rc));
649
650 if (*pfShutdown)
651 break;
652
653 /* Wait a bit before retrying. */
654 RTThreadSleep(1000);
655 continue;
656 }
657 else
658 {
659 LogFlowFunc(("u32Msg=%RU32, u32Formats=0x%x\n", u32Msg, u32Formats));
660 switch (u32Msg)
661 {
662 case VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS:
663 {
664 /* The host has announced available clipboard formats.
665 * Forward the information to the window, so it can later
666 * respond to WM_RENDERFORMAT message. */
667 ::PostMessage(pWinCtx->hWnd, VBOX_CLIPBOARD_WM_SET_FORMATS, 0, u32Formats);
668 } break;
669
670 case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA:
671 {
672 /* The host needs data in the specified format. */
673 ::PostMessage(pWinCtx->hWnd, VBOX_CLIPBOARD_WM_READ_DATA, 0, u32Formats);
674 } break;
675
676 case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT:
677 {
678 /* The host is terminating. */
679 LogRel(("Clipboard: Terminating ...\n"));
680 ASMAtomicXchgBool(pfShutdown, true);
681 } break;
682
683 default:
684 {
685 LogFlowFunc(("Unsupported message from host, message=%RU32\n", u32Msg));
686
687 /* Wait a bit before retrying. */
688 RTThreadSleep(1000);
689 } break;
690 }
691 }
692
693 if (*pfShutdown)
694 break;
695 }
696
697 LogFlowFuncLeaveRC(rc);
698 return rc;
699}
700
701DECLCALLBACK(int) VBoxClipboardStop(void *pInstance)
702{
703 AssertPtrReturn(pInstance, VERR_INVALID_POINTER);
704
705 LogFunc(("Stopping pInstance=%p\n", pInstance));
706
707 PVBOXCLIPBOARDCONTEXT pCtx = (PVBOXCLIPBOARDCONTEXT)pInstance;
708 AssertPtr(pCtx);
709
710 VbglR3ClipboardDisconnect(pCtx->u32ClientID);
711 pCtx->u32ClientID = 0;
712
713 LogFlowFuncLeaveRC(VINF_SUCCESS);
714 return VINF_SUCCESS;
715}
716
717DECLCALLBACK(void) VBoxClipboardDestroy(void *pInstance)
718{
719 AssertPtrReturnVoid(pInstance);
720
721 PVBOXCLIPBOARDCONTEXT pCtx = (PVBOXCLIPBOARDCONTEXT)pInstance;
722 AssertPtr(pCtx);
723
724 /* Make sure that we are disconnected. */
725 Assert(pCtx->u32ClientID == 0);
726
727 vboxClipboardDestroy(pCtx);
728 RT_BZERO(pCtx, sizeof(VBOXCLIPBOARDCONTEXT));
729
730 return;
731}
732
733/**
734 * The service description.
735 */
736VBOXSERVICEDESC g_SvcDescClipboard =
737{
738 /* pszName. */
739 "clipboard",
740 /* pszDescription. */
741 "Shared Clipboard",
742 /* methods */
743 VBoxClipboardInit,
744 VBoxClipboardWorker,
745 VBoxClipboardStop,
746 VBoxClipboardDestroy
747};
748
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