VirtualBox

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

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

Shared Clipboard: SCM fix.

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