VirtualBox

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

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

Shared Clipboard/URI: Renaming (VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS -> VBOX_SHARED_CLIPBOARD_HOST_MSG_REPORT_FORMATS).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.4 KB
Line 
1/* $Id: VBoxClipboard.cpp 78317 2019-04-26 09:44:48Z 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#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
389 if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
390 hClip = SetClipboardData(CF_HDROP, NULL);
391#endif
392 VBoxClipboardWinClose();
393
394 LogFlowFunc(("VBOX_WM_SHCLPB_SET_FORMATS: hClip=%p, lastErr=%ld\n", hClip, GetLastError()));
395 }
396 }
397 break;
398
399 case VBOX_CLIPBOARD_WM_READ_DATA:
400 {
401 /* Send data in the specified format to the host. */
402 uint32_t u32Formats = (uint32_t)lParam;
403 HANDLE hClip = NULL;
404
405 LogFlowFunc(("VBOX_WM_SHCLPB_READ_DATA: u32Formats=0x%x\n", u32Formats));
406
407 int vboxrc = VBoxClipboardWinOpen(hwnd);
408 if (RT_SUCCESS(vboxrc))
409 {
410 if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
411 {
412 hClip = GetClipboardData(CF_DIB);
413
414 if (hClip != NULL)
415 {
416 LPVOID lp = GlobalLock(hClip);
417 if (lp != NULL)
418 {
419 vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_BITMAP,
420 lp, GlobalSize(hClip));
421 GlobalUnlock(hClip);
422 }
423 else
424 {
425 hClip = NULL;
426 }
427 }
428 }
429 else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
430 {
431 hClip = GetClipboardData(CF_UNICODETEXT);
432
433 if (hClip != NULL)
434 {
435 LPWSTR uniString = (LPWSTR)GlobalLock(hClip);
436
437 if (uniString != NULL)
438 {
439 vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
440 uniString, (lstrlenW(uniString) + 1) * 2);
441 GlobalUnlock(hClip);
442 }
443 else
444 {
445 hClip = NULL;
446 }
447 }
448 }
449 else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML)
450 {
451 UINT format = RegisterClipboardFormat("HTML Format");
452 if (format != 0)
453 {
454 hClip = GetClipboardData(format);
455 if (hClip != NULL)
456 {
457 LPVOID lp = GlobalLock(hClip);
458
459 if (lp != NULL)
460 {
461 vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_HTML,
462 lp, GlobalSize(hClip));
463 GlobalUnlock(hClip);
464 }
465 else
466 {
467 hClip = NULL;
468 }
469 }
470 }
471 }
472#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
473 else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
474 {
475 hClip = GetClipboardData(CF_HDROP);
476 if (hClip)
477 {
478 HDROP hDrop = (HDROP)GlobalLock(hClip);
479 if (hDrop)
480 {
481 vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_URI_LIST,
482 );
483 GlobalUnlock(hClip);
484 }
485 else
486 {
487 hClip = NULL;
488 }
489 }
490 }
491#endif
492 VBoxClipboardWinClose();
493 }
494
495 if (hClip == NULL)
496 {
497 /* Requested clipboard format is not available, send empty data. */
498 VbglR3ClipboardWriteData(pCtx->u32ClientID, 0, NULL, 0);
499 }
500 }
501 break;
502
503 case WM_DESTROY:
504 {
505 VBoxClipboardWinRemoveFromCBChain(pWinCtx);
506 if (pWinCtx->oldAPI.timerRefresh)
507 KillTimer(pWinCtx->hWnd, 0);
508 /*
509 * don't need to call PostQuitMessage cause
510 * the VBoxTray already finished a message loop
511 */
512 }
513 break;
514
515 default:
516 {
517 rc = DefWindowProc(hwnd, msg, wParam, lParam);
518 }
519 break;
520 }
521
522#ifndef DEBUG_andy
523 LogFlowFunc(("vboxClipboardProcessMsg returned with rc = %ld\n", rc));
524#endif
525 return rc;
526}
527
528static LRESULT CALLBACK vboxClipboardWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
529
530static int vboxClipboardCreateWindow(PVBOXCLIPBOARDCONTEXT pCtx)
531{
532 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
533
534 int rc = VINF_SUCCESS;
535
536 AssertPtr(pCtx->pEnv);
537 HINSTANCE hInstance = pCtx->pEnv->hInstance;
538 Assert(hInstance != 0);
539
540 /* Register the Window Class. */
541 WNDCLASSEX wc = { 0 };
542 wc.cbSize = sizeof(WNDCLASSEX);
543
544 if (!GetClassInfoEx(hInstance, s_szClipWndClassName, &wc))
545 {
546 wc.style = CS_NOCLOSE;
547 wc.lpfnWndProc = vboxClipboardWndProc;
548 wc.hInstance = pCtx->pEnv->hInstance;
549 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
550 wc.lpszClassName = s_szClipWndClassName;
551
552 ATOM wndClass = RegisterClassEx(&wc);
553 if (wndClass == 0)
554 rc = RTErrConvertFromWin32(GetLastError());
555 }
556
557 if (RT_SUCCESS(rc))
558 {
559 const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win;
560
561 /* Create the window. */
562 pWinCtx->hWnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
563 s_szClipWndClassName, s_szClipWndClassName,
564 WS_POPUPWINDOW,
565 -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
566 if (pWinCtx->hWnd == NULL)
567 {
568 rc = VERR_NOT_SUPPORTED;
569 }
570 else
571 {
572 SetWindowPos(pWinCtx->hWnd, HWND_TOPMOST, -200, -200, 0, 0,
573 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
574
575 VBoxClipboardWinAddToCBChain(pWinCtx);
576 if (!VBoxClipboardWinIsNewAPI(&pWinCtx->newAPI))
577 pWinCtx->oldAPI.timerRefresh = SetTimer(pWinCtx->hWnd, 0, 10 * 1000 /* 10s */, NULL);
578 }
579 }
580
581 LogFlowFuncLeaveRC(rc);
582 return rc;
583}
584
585static void vboxClipboardDestroy(PVBOXCLIPBOARDCONTEXT pCtx)
586{
587 AssertPtrReturnVoid(pCtx);
588
589 const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win;
590
591 if (pWinCtx->hWnd)
592 {
593 DestroyWindow(pWinCtx->hWnd);
594 pWinCtx->hWnd = NULL;
595 }
596
597 UnregisterClass(s_szClipWndClassName, pCtx->pEnv->hInstance);
598}
599
600static LRESULT CALLBACK vboxClipboardWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
601{
602 PVBOXCLIPBOARDCONTEXT pCtx = &g_Ctx; /** @todo r=andy Make pCtx available through SetWindowLongPtr() / GWL_USERDATA. */
603 AssertPtr(pCtx);
604
605 /* Forward with proper context. */
606 return vboxClipboardProcessMsg(pCtx, hWnd, uMsg, wParam, lParam);
607}
608
609DECLCALLBACK(int) VBoxClipboardInit(const PVBOXSERVICEENV pEnv, void **ppInstance)
610{
611 LogFlowFuncEnter();
612
613 PVBOXCLIPBOARDCONTEXT pCtx = &g_Ctx; /* Only one instance for now. */
614 AssertPtr(pCtx);
615
616 if (pCtx->pEnv)
617 {
618 /* Clipboard was already initialized. 2 or more instances are not supported. */
619 return VERR_NOT_SUPPORTED;
620 }
621
622 if (VbglR3AutoLogonIsRemoteSession())
623 {
624 /* Do not use clipboard for remote sessions. */
625 LogRel(("Clipboard: Clipboard has been disabled for a remote session\n"));
626 return VERR_NOT_SUPPORTED;
627 }
628
629 RT_BZERO(pCtx, sizeof(VBOXCLIPBOARDCONTEXT));
630
631 pCtx->pEnv = pEnv;
632
633 /* Check that new Clipboard API is available */
634 VBoxClipboardWinCheckAndInitNewAPI(&pCtx->Win.newAPI);
635
636 int rc = VbglR3ClipboardConnect(&pCtx->u32ClientID);
637 if (RT_SUCCESS(rc))
638 {
639 rc = vboxClipboardCreateWindow(pCtx);
640 if (RT_SUCCESS(rc))
641 {
642 *ppInstance = pCtx;
643 }
644 else
645 {
646 VbglR3ClipboardDisconnect(pCtx->u32ClientID);
647 }
648 }
649
650 LogFlowFuncLeaveRC(rc);
651 return rc;
652}
653
654DECLCALLBACK(int) VBoxClipboardWorker(void *pInstance, bool volatile *pfShutdown)
655{
656 AssertPtr(pInstance);
657 LogFlowFunc(("pInstance=%p\n", pInstance));
658
659 /*
660 * Tell the control thread that it can continue
661 * spawning services.
662 */
663 RTThreadUserSignal(RTThreadSelf());
664
665 const PVBOXCLIPBOARDCONTEXT pCtx = (PVBOXCLIPBOARDCONTEXT)pInstance;
666 AssertPtr(pCtx);
667
668 const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win;
669
670 int rc;
671
672 /* The thread waits for incoming messages from the host. */
673 for (;;)
674 {
675 uint32_t u32Msg;
676 uint32_t u32Formats;
677 rc = VbglR3ClipboardGetHostMsg(pCtx->u32ClientID, &u32Msg, &u32Formats);
678 if (RT_FAILURE(rc))
679 {
680 if (rc == VERR_INTERRUPTED)
681 break;
682
683 LogFlowFunc(("Error getting host message, rc=%Rrc\n", rc));
684
685 if (*pfShutdown)
686 break;
687
688 /* Wait a bit before retrying. */
689 RTThreadSleep(1000);
690 continue;
691 }
692 else
693 {
694 LogFlowFunc(("u32Msg=%RU32, u32Formats=0x%x\n", u32Msg, u32Formats));
695 switch (u32Msg)
696 {
697 case VBOX_SHARED_CLIPBOARD_HOST_MSG_REPORT_FORMATS:
698 {
699 /* The host has announced available clipboard formats.
700 * Forward the information to the window, so it can later
701 * respond to WM_RENDERFORMAT message. */
702 ::PostMessage(pWinCtx->hWnd, VBOX_CLIPBOARD_WM_SET_FORMATS, 0, u32Formats);
703 }
704 break;
705
706 case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA:
707 {
708 /* The host needs data in the specified format. */
709 ::PostMessage(pWinCtx->hWnd, VBOX_CLIPBOARD_WM_READ_DATA, 0, u32Formats);
710 }
711 break;
712
713 case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT:
714 {
715 /* The host is terminating. */
716 LogRel(("Clipboard: Terminating ...\n"));
717 ASMAtomicXchgBool(pfShutdown, true);
718 }
719 break;
720
721 default:
722 {
723 LogFlowFunc(("Unsupported message from host, message=%RU32\n", u32Msg));
724
725 /* Wait a bit before retrying. */
726 RTThreadSleep(1000);
727 }
728 break;
729 }
730 }
731
732 if (*pfShutdown)
733 break;
734 }
735
736 LogFlowFuncLeaveRC(rc);
737 return rc;
738}
739
740DECLCALLBACK(int) VBoxClipboardStop(void *pInstance)
741{
742 AssertPtrReturn(pInstance, VERR_INVALID_POINTER);
743
744 LogFunc(("Stopping pInstance=%p\n", pInstance));
745
746 PVBOXCLIPBOARDCONTEXT pCtx = (PVBOXCLIPBOARDCONTEXT)pInstance;
747 AssertPtr(pCtx);
748
749 VbglR3ClipboardDisconnect(pCtx->u32ClientID);
750 pCtx->u32ClientID = 0;
751
752 LogFlowFuncLeaveRC(VINF_SUCCESS);
753 return VINF_SUCCESS;
754}
755
756DECLCALLBACK(void) VBoxClipboardDestroy(void *pInstance)
757{
758 AssertPtrReturnVoid(pInstance);
759
760 PVBOXCLIPBOARDCONTEXT pCtx = (PVBOXCLIPBOARDCONTEXT)pInstance;
761 AssertPtr(pCtx);
762
763 /* Make sure that we are disconnected. */
764 Assert(pCtx->u32ClientID == 0);
765
766 vboxClipboardDestroy(pCtx);
767 RT_BZERO(pCtx, sizeof(VBOXCLIPBOARDCONTEXT));
768
769 return;
770}
771
772/**
773 * The service description.
774 */
775VBOXSERVICEDESC g_SvcDescClipboard =
776{
777 /* pszName. */
778 "clipboard",
779 /* pszDescription. */
780 "Shared Clipboard",
781 /* methods */
782 VBoxClipboardInit,
783 VBoxClipboardWorker,
784 VBoxClipboardStop,
785 VBoxClipboardDestroy
786};
787
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