VirtualBox

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

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

Shared Clipboard/URI: Update.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.5 KB
Line 
1/* $Id: VBoxClipboard.cpp 79299 2019-06-24 10:18:19Z 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 <VBox/log.h>
24
25#include "VBoxTray.h"
26#include "VBoxHelpers.h"
27
28#include <iprt/asm.h>
29#include <iprt/ldr.h>
30
31#include <iprt/errcore.h>
32
33#include <VBox/GuestHost/SharedClipboard.h>
34#include <VBox/GuestHost/SharedClipboard-win.h>
35#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
36# include <VBox/GuestHost/SharedClipboard-uri.h>
37#endif
38
39#include <strsafe.h>
40
41#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
42/** !!! HACK ALERT !!! Dynamically resolve functions! */
43# ifdef _WIN32_IE
44# undef _WIN32_IE
45# define _WIN32_IE 0x0501
46# endif
47# include <iprt/win/shlobj.h>
48# include <iprt/win/shlwapi.h>
49#endif
50
51
52/*********************************************************************************************************************************
53* Structures and Typedefs *
54*********************************************************************************************************************************/
55
56struct _VBOXCLIPBOARDCONTEXT
57{
58 /** Pointer to the VBoxClient service environment. */
59 const VBOXSERVICEENV *pEnv;
60 /** Client ID the service is connected to the HGCM service with. */
61 uint32_t u32ClientID;
62 /** Windows-specific context data. */
63 VBOXCLIPBOARDWINCTX Win;
64#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
65 /** URI transfer data. */
66 SHAREDCLIPBOARDURICTX URI;
67#endif
68};
69
70
71/*********************************************************************************************************************************
72* Static variables *
73*********************************************************************************************************************************/
74/** Static clipboard context (since it is the single instance). Directly used in the windows proc. */
75static VBOXCLIPBOARDCONTEXT g_Ctx = { NULL };
76/** Static window class name. */
77static char s_szClipWndClassName[] = VBOX_CLIPBOARD_WNDCLASS_NAME;
78
79
80/*********************************************************************************************************************************
81* Prototypes *
82*********************************************************************************************************************************/
83#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
84static DECLCALLBACK(void) vboxClipboardOnURITransferComplete(PSHAREDCLIPBOARDURITRANSFERCALLBACKDATA pData, int rc);
85static DECLCALLBACK(void) vboxClipboardOnURITransferError(PSHAREDCLIPBOARDURITRANSFERCALLBACKDATA pData, int rc);
86#endif
87
88
89static LRESULT vboxClipboardWinProcessMsg(PVBOXCLIPBOARDCONTEXT pCtx, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
90{
91 AssertPtr(pCtx);
92
93 const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win;
94
95 LRESULT lresultRc = 0;
96
97 switch (msg)
98 {
99 case WM_CLIPBOARDUPDATE:
100 {
101 const HWND hWndClipboardOwner = GetClipboardOwner();
102 if (pWinCtx->hWndClipboardOwnerUs != hWndClipboardOwner)
103 {
104 LogFunc(("WM_CLIPBOARDUPDATE: hWndOldClipboardOwner=%p, hWndNewClipboardOwner=%p\n",
105 pWinCtx->hWndClipboardOwnerUs, hWndClipboardOwner));
106
107 /* Clipboard was updated by another application.
108 * Report available formats to the host. */
109 VBOXCLIPBOARDFORMATS fFormats;
110 int rc = VBoxClipboardWinGetFormats(&pCtx->Win, &fFormats);
111 if (RT_SUCCESS(rc))
112 {
113 LogFunc(("WM_CLIPBOARDUPDATE: Reporting formats 0x%x\n", fFormats));
114 rc = VbglR3ClipboardReportFormats(pCtx->u32ClientID, fFormats);
115 }
116 }
117 }
118 break;
119
120 case WM_CHANGECBCHAIN:
121 {
122 LogFunc(("WM_CHANGECBCHAIN\n"));
123 lresultRc = VBoxClipboardWinHandleWMChangeCBChain(pWinCtx, hwnd, msg, wParam, lParam);
124 }
125 break;
126
127 case WM_DRAWCLIPBOARD:
128 {
129 LogFlowFunc(("WM_DRAWCLIPBOARD, hwnd %p\n", pWinCtx->hWnd));
130
131 if (GetClipboardOwner() != hwnd)
132 {
133 /* Clipboard was updated by another application. */
134 /* WM_DRAWCLIPBOARD always expects a return code of 0, so don't change "rc" here. */
135 VBOXCLIPBOARDFORMATS fFormats;
136 int rc = VBoxClipboardWinGetFormats(pWinCtx, &fFormats);
137 if (RT_SUCCESS(rc))
138 rc = VbglR3ClipboardReportFormats(pCtx->u32ClientID, fFormats);
139 }
140
141 lresultRc = VBoxClipboardWinChainPassToNext(pWinCtx, msg, wParam, lParam);
142 }
143 break;
144
145 case WM_TIMER:
146 {
147 int rc = VBoxClipboardWinHandleWMTimer(pWinCtx);
148 AssertRC(rc);
149 }
150 break;
151
152 case WM_CLOSE:
153 {
154 /* Do nothing. Ignore the message. */
155 }
156 break;
157
158 case WM_RENDERFORMAT:
159 {
160 LogFunc(("WM_RENDERFORMAT\n"));
161
162 /* Insert the requested clipboard format data into the clipboard. */
163 const UINT cfFormat = (UINT)wParam;
164
165 const VBOXCLIPBOARDFORMAT fFormat = VBoxClipboardWinClipboardFormatToVBox(cfFormat);
166
167 LogFunc(("WM_RENDERFORMAT: cfFormat=%u -> fFormat=0x%x\n", cfFormat, fFormat));
168
169 if (fFormat == VBOX_SHARED_CLIPBOARD_FMT_NONE)
170 {
171 LogFunc(("WM_RENDERFORMAT: Unsupported format requested\n"));
172 VBoxClipboardWinClear();
173 }
174 else
175 {
176 const uint32_t cbPrealloc = _4K;
177 uint32_t cb = 0;
178
179 /* Preallocate a buffer, most of small text transfers will fit into it. */
180 HANDLE hMem = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cbPrealloc);
181 LogFlowFunc(("Preallocated handle hMem = %p\n", hMem));
182
183 if (hMem)
184 {
185 void *pMem = GlobalLock(hMem);
186 LogFlowFunc(("Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem)));
187
188 if (pMem)
189 {
190 /* Read the host data to the preallocated buffer. */
191 int rc = VbglR3ClipboardReadData(pCtx->u32ClientID, fFormat, pMem, cbPrealloc, &cb);
192 LogFlowFunc(("VbglR3ClipboardReadData returned with rc = %Rrc\n", rc));
193
194 if (RT_SUCCESS(rc))
195 {
196 if (cb == 0)
197 {
198 /* 0 bytes returned means the clipboard is empty.
199 * Deallocate the memory and set hMem to NULL to get to
200 * the clipboard empty code path. */
201 GlobalUnlock(hMem);
202 GlobalFree(hMem);
203 hMem = NULL;
204 }
205 else if (cb > cbPrealloc)
206 {
207 GlobalUnlock(hMem);
208
209 /* The preallocated buffer is too small, adjust the size. */
210 hMem = GlobalReAlloc(hMem, cb, 0);
211 LogFlowFunc(("Reallocated hMem = %p\n", hMem));
212
213 if (hMem)
214 {
215 pMem = GlobalLock(hMem);
216 LogFlowFunc(("Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem)));
217
218 if (pMem)
219 {
220 /* Read the host data to the preallocated buffer. */
221 uint32_t cbNew = 0;
222 rc = VbglR3ClipboardReadData(pCtx->u32ClientID, fFormat, pMem, cb, &cbNew);
223 LogFlowFunc(("VbglR3ClipboardReadData returned with rc = %Rrc, cb = %d, cbNew = %d\n",
224 rc, cb, cbNew));
225
226 if (RT_SUCCESS(rc)
227 && cbNew <= cb)
228 {
229 cb = cbNew;
230 }
231 else
232 {
233 GlobalUnlock(hMem);
234 GlobalFree(hMem);
235 hMem = NULL;
236 }
237 }
238 else
239 {
240 GlobalFree(hMem);
241 hMem = NULL;
242 }
243 }
244 }
245
246 if (hMem)
247 {
248 /* pMem is the address of the data. cb is the size of returned data. */
249 /* Verify the size of returned text, the memory block for clipboard
250 * must have the exact string size.
251 */
252 if (fFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
253 {
254 size_t cbActual = 0;
255 HRESULT hrc = StringCbLengthW((LPWSTR)pMem, cb, &cbActual);
256 if (FAILED(hrc))
257 {
258 /* Discard invalid data. */
259 GlobalUnlock(hMem);
260 GlobalFree(hMem);
261 hMem = NULL;
262 }
263 else
264 {
265 /* cbActual is the number of bytes, excluding those used
266 * for the terminating null character.
267 */
268 cb = (uint32_t)(cbActual + 2);
269 }
270 }
271 }
272
273 if (hMem)
274 {
275 GlobalUnlock(hMem);
276
277 hMem = GlobalReAlloc(hMem, cb, 0);
278 LogFlowFunc(("Reallocated hMem = %p\n", hMem));
279
280 if (hMem)
281 {
282 /* 'hMem' contains the host clipboard data.
283 * size is 'cb' and format is 'format'. */
284 HANDLE hClip = SetClipboardData(cfFormat, hMem);
285 LogFlowFunc(("WM_RENDERFORMAT hClip = %p\n", hClip));
286
287 if (hClip)
288 {
289 /* The hMem ownership has gone to the system. Finish the processing. */
290 break;
291 }
292
293 /* Cleanup follows. */
294 }
295 }
296 }
297 if (hMem)
298 GlobalUnlock(hMem);
299 }
300 if (hMem)
301 GlobalFree(hMem);
302 }
303 }
304 }
305 break;
306
307 case WM_RENDERALLFORMATS:
308 {
309 LogFunc(("WM_RENDERALLFORMATS\n"));
310
311 int rc = VBoxClipboardWinHandleWMRenderAllFormats(pWinCtx, hwnd);
312 AssertRC(rc);
313 }
314 break;
315
316 case VBOX_CLIPBOARD_WM_SET_FORMATS:
317 {
318 LogFunc(("VBOX_CLIPBOARD_WM_SET_FORMATS\n"));
319
320 /* Announce available formats. Do not insert data -- will be inserted in WM_RENDERFORMAT. */
321 VBOXCLIPBOARDFORMATS fFormats = (uint32_t)lParam;
322 if (fFormats != VBOX_SHARED_CLIPBOARD_FMT_NONE) /* Could arrive with some older GA versions. */
323 {
324 int rc = VBoxClipboardWinOpen(hwnd);
325 if (RT_SUCCESS(rc))
326 {
327 VBoxClipboardWinClear();
328
329#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
330 if (fFormats & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
331 {
332 LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_URI_LIST\n"));
333
334 PSHAREDCLIPBOARDURITRANSFER pTransfer;
335 rc = SharedClipboardURITransferCreate(SHAREDCLIPBOARDURITRANSFERDIR_READ, &pTransfer);
336 if (RT_SUCCESS(rc))
337 {
338 SHAREDCLIPBOARDURITRANSFERCALLBACKS TransferCallbacks;
339 RT_ZERO(TransferCallbacks);
340
341 TransferCallbacks.pvUser = &pCtx->URI;
342 TransferCallbacks.pfnTransferComplete = vboxClipboardOnURITransferComplete;
343 TransferCallbacks.pfnTransferError = vboxClipboardOnURITransferError;
344
345 SharedClipboardURITransferSetCallbacks(pTransfer, &TransferCallbacks);
346
347 SHAREDCLIPBOARDPROVIDERCREATIONCTX creationCtx;
348 RT_ZERO(creationCtx);
349 creationCtx.enmSource = SHAREDCLIPBOARDURIPROVIDERSOURCE_VBGLR3;
350 creationCtx.enmDir = SHAREDCLIPBOARDURITRANSFERDIR_READ;
351 creationCtx.u.VbglR3.uClientID = pCtx->u32ClientID;
352
353 rc = SharedClipboardURITransferProviderCreate(pTransfer, &creationCtx);
354 if (RT_SUCCESS(rc))
355 {
356 rc = SharedClipboardURICtxTransferAdd(&pCtx->URI, pTransfer);
357 if (RT_SUCCESS(rc))
358 rc = VBoxClipboardWinURIAnnounce(pWinCtx, &pCtx->URI, pTransfer);
359 }
360
361 /* Note: VBoxClipboardWinURIAnnounce() takes care of closing the clipboard. */
362
363 LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_URI_LIST: rc=%Rrc\n", rc));
364 }
365 }
366 else
367 {
368#endif
369 rc = VBoxClipboardWinAnnounceFormats(pWinCtx, fFormats);
370
371 VBoxClipboardWinClose();
372#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
373 }
374#endif
375 }
376 }
377 LogFunc(("VBOX_CLIPBOARD_WM_SET_FORMATS: fFormats=0x%x, lastErr=%ld\n", fFormats, GetLastError()));
378 }
379 break;
380
381 case VBOX_CLIPBOARD_WM_READ_DATA:
382 {
383 /* Send data in the specified format to the host. */
384 VBOXCLIPBOARDFORMAT uFormat = (uint32_t)lParam;
385 HANDLE hClip = NULL;
386
387 LogFlowFunc(("VBOX_WM_SHCLPB_READ_DATA: uFormat=0x%x\n", uFormat));
388
389 int rc = VBoxClipboardWinOpen(hwnd);
390 if (RT_SUCCESS(rc))
391 {
392 if (uFormat == VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
393 {
394 hClip = GetClipboardData(CF_DIB);
395 if (hClip != NULL)
396 {
397 LPVOID lp = GlobalLock(hClip);
398 if (lp != NULL)
399 {
400 rc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_BITMAP,
401 lp, GlobalSize(hClip));
402 GlobalUnlock(hClip);
403 }
404 else
405 {
406 hClip = NULL;
407 }
408 }
409 }
410 else if (uFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
411 {
412 hClip = GetClipboardData(CF_UNICODETEXT);
413 if (hClip != NULL)
414 {
415 LPWSTR uniString = (LPWSTR)GlobalLock(hClip);
416 if (uniString != NULL)
417 {
418 rc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
419 uniString, (lstrlenW(uniString) + 1) * 2);
420 GlobalUnlock(hClip);
421 }
422 else
423 {
424 hClip = NULL;
425 }
426 }
427 }
428 else if (uFormat == VBOX_SHARED_CLIPBOARD_FMT_HTML)
429 {
430 UINT format = RegisterClipboardFormat(VBOX_CLIPBOARD_WIN_REGFMT_HTML);
431 if (format != 0)
432 {
433 hClip = GetClipboardData(format);
434 if (hClip != NULL)
435 {
436 LPVOID lp = GlobalLock(hClip);
437
438 if (lp != NULL)
439 {
440 rc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_HTML,
441 lp, GlobalSize(hClip));
442 GlobalUnlock(hClip);
443 }
444 else
445 {
446 hClip = NULL;
447 }
448 }
449 }
450 }
451#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
452 else if (uFormat == VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
453 {
454 LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_URI_LIST cTransfers=%RU32\n",
455 SharedClipboardURICtxGetActiveTransfers(&pCtx->URI)));
456
457 PSHAREDCLIPBOARDURITRANSFER pTransfer;
458 rc = SharedClipboardURITransferCreate(SHAREDCLIPBOARDURITRANSFERDIR_WRITE, &pTransfer);
459 if (RT_SUCCESS(rc))
460 {
461 SHAREDCLIPBOARDURITRANSFERCALLBACKS TransferCallbacks;
462 RT_ZERO(TransferCallbacks);
463
464 TransferCallbacks.pvUser = &pCtx->URI;
465 TransferCallbacks.pfnTransferComplete = vboxClipboardOnURITransferComplete;
466 TransferCallbacks.pfnTransferError = vboxClipboardOnURITransferError;
467
468 SharedClipboardURITransferSetCallbacks(pTransfer, &TransferCallbacks);
469
470 SHAREDCLIPBOARDPROVIDERCREATIONCTX creationCtx;
471 RT_ZERO(creationCtx);
472 creationCtx.enmSource = SHAREDCLIPBOARDURIPROVIDERSOURCE_VBGLR3;
473 creationCtx.enmDir = SHAREDCLIPBOARDURITRANSFERDIR_WRITE;
474 creationCtx.u.VbglR3.uClientID = pCtx->u32ClientID;
475
476 rc = SharedClipboardURITransferProviderCreate(pTransfer, &creationCtx);
477 if (RT_SUCCESS(rc))
478 {
479 rc = SharedClipboardURICtxTransferAdd(&pCtx->URI, pTransfer);
480 if (RT_SUCCESS(rc))
481 {
482 /* The data data in CF_HDROP format, as the files are locally present and don't need to be
483 * presented as a IDataObject or IStream. */
484 hClip = GetClipboardData(CF_HDROP);
485 if (hClip)
486 {
487 HDROP hDrop = (HDROP)GlobalLock(hClip);
488 if (hDrop)
489 {
490 rc = VBoxClipboardWinDropFilesToTransfer((DROPFILES *)hDrop, pTransfer);
491
492 GlobalUnlock(hClip);
493
494 if (RT_SUCCESS(rc))
495 {
496 rc = SharedClipboardURITransferPrepare(pTransfer);
497 if (RT_SUCCESS(rc))
498 rc = SharedClipboardURITransferRun(pTransfer, true /* fAsync */);
499 }
500 }
501 else
502 {
503 hClip = NULL;
504 }
505 }
506 }
507 }
508 }
509
510 if (RT_FAILURE(rc))
511 LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_URI_LIST failed with rc=%Rrc\n", rc));
512 }
513#endif
514 if (hClip == NULL)
515 {
516 LogFunc(("VBOX_WM_SHCLPB_READ_DATA: hClip=NULL, lastError=%ld\n", GetLastError()));
517
518 /* Requested clipboard format is not available, send empty data. */
519 VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_NONE, NULL, 0);
520#ifdef DEBUG_andy
521 AssertFailed();
522#endif
523 }
524
525 VBoxClipboardWinClose();
526 }
527 }
528 break;
529
530 case WM_DESTROY:
531 {
532 LogFunc(("WM_DESTROY\n"));
533
534 int rc = VBoxClipboardWinHandleWMDestroy(pWinCtx);
535 AssertRC(rc);
536
537 /*
538 * Don't need to call PostQuitMessage cause
539 * the VBoxTray already finished a message loop.
540 */
541 }
542 break;
543
544 default:
545 {
546 LogFunc(("WM_ %p\n", msg));
547 lresultRc = DefWindowProc(hwnd, msg, wParam, lParam);
548 }
549 break;
550 }
551
552 LogFunc(("WM_ rc %d\n", lresultRc));
553 return lresultRc;
554}
555
556static LRESULT CALLBACK vboxClipboardWinWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
557
558static int vboxClipboardCreateWindow(PVBOXCLIPBOARDCONTEXT pCtx)
559{
560 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
561
562 int rc = VINF_SUCCESS;
563
564 AssertPtr(pCtx->pEnv);
565 HINSTANCE hInstance = pCtx->pEnv->hInstance;
566 Assert(hInstance != 0);
567
568 /* Register the Window Class. */
569 WNDCLASSEX wc = { 0 };
570 wc.cbSize = sizeof(WNDCLASSEX);
571
572 if (!GetClassInfoEx(hInstance, s_szClipWndClassName, &wc))
573 {
574 wc.style = CS_NOCLOSE;
575 wc.lpfnWndProc = vboxClipboardWinWndProc;
576 wc.hInstance = pCtx->pEnv->hInstance;
577 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
578 wc.lpszClassName = s_szClipWndClassName;
579
580 ATOM wndClass = RegisterClassEx(&wc);
581 if (wndClass == 0)
582 rc = RTErrConvertFromWin32(GetLastError());
583 }
584
585 if (RT_SUCCESS(rc))
586 {
587 const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win;
588
589 /* Create the window. */
590 pWinCtx->hWnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
591 s_szClipWndClassName, s_szClipWndClassName,
592 WS_POPUPWINDOW,
593 -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
594 if (pWinCtx->hWnd == NULL)
595 {
596 rc = VERR_NOT_SUPPORTED;
597 }
598 else
599 {
600 SetWindowPos(pWinCtx->hWnd, HWND_TOPMOST, -200, -200, 0, 0,
601 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
602
603 VBoxClipboardWinChainAdd(pWinCtx);
604 if (!VBoxClipboardWinIsNewAPI(&pWinCtx->newAPI))
605 pWinCtx->oldAPI.timerRefresh = SetTimer(pWinCtx->hWnd, 0, 10 * 1000 /* 10s */, NULL);
606 }
607 }
608
609 LogFlowFuncLeaveRC(rc);
610 return rc;
611}
612
613#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
614static DECLCALLBACK(void) vboxClipboardOnURITransferComplete(PSHAREDCLIPBOARDURITRANSFERCALLBACKDATA pData, int rc)
615{
616 RT_NOREF(rc);
617
618 LogFlowFunc(("pData=%p, rc=%Rrc\n", pData, rc));
619
620 LogRel2(("Shared Clipboard: Transfer to destination complete\n"));
621
622 PSHAREDCLIPBOARDURICTX pCtx = (PSHAREDCLIPBOARDURICTX)pData->pvUser;
623 AssertPtr(pCtx);
624
625 PSHAREDCLIPBOARDURITRANSFER pTransfer = pData->pTransfer;
626 AssertPtr(pTransfer);
627
628 if (pTransfer->pvUser) /* SharedClipboardWinURITransferCtx */
629 {
630 delete pTransfer->pvUser;
631 pTransfer->pvUser = NULL;
632 }
633
634 int rc2 = SharedClipboardURICtxTransferRemove(pCtx, pTransfer);
635 AssertRC(rc2);
636}
637
638static DECLCALLBACK(void) vboxClipboardOnURITransferError(PSHAREDCLIPBOARDURITRANSFERCALLBACKDATA pData, int rc)
639{
640 RT_NOREF(rc);
641
642 LogFlowFunc(("pData=%p, rc=%Rrc\n", pData, rc));
643
644 LogRel(("Shared Clipboard: Transfer to destination failed with %Rrc\n", rc));
645
646 PSHAREDCLIPBOARDURICTX pCtx = (PSHAREDCLIPBOARDURICTX)pData->pvUser;
647 AssertPtr(pCtx);
648
649 PSHAREDCLIPBOARDURITRANSFER pTransfer = pData->pTransfer;
650 AssertPtr(pTransfer);
651
652 if (pTransfer->pvUser) /* SharedClipboardWinURITransferCtx */
653 {
654 delete pTransfer->pvUser;
655 pTransfer->pvUser = NULL;
656 }
657
658 int rc2 = SharedClipboardURICtxTransferRemove(pCtx, pTransfer);
659 AssertRC(rc2);
660}
661#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
662
663static void vboxClipboardDestroy(PVBOXCLIPBOARDCONTEXT pCtx)
664{
665 AssertPtrReturnVoid(pCtx);
666
667 const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win;
668
669 if (pWinCtx->hWnd)
670 {
671 DestroyWindow(pWinCtx->hWnd);
672 pWinCtx->hWnd = NULL;
673 }
674
675 UnregisterClass(s_szClipWndClassName, pCtx->pEnv->hInstance);
676}
677
678static LRESULT CALLBACK vboxClipboardWinWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
679{
680 PVBOXCLIPBOARDCONTEXT pCtx = &g_Ctx; /** @todo r=andy Make pCtx available through SetWindowLongPtr() / GWL_USERDATA. */
681 AssertPtr(pCtx);
682
683 /* Forward with proper context. */
684 return vboxClipboardWinProcessMsg(pCtx, hWnd, uMsg, wParam, lParam);
685}
686
687DECLCALLBACK(int) VBoxClipboardInit(const PVBOXSERVICEENV pEnv, void **ppInstance)
688{
689 LogFlowFuncEnter();
690
691 PVBOXCLIPBOARDCONTEXT pCtx = &g_Ctx; /* Only one instance for now. */
692 AssertPtr(pCtx);
693
694 if (pCtx->pEnv)
695 {
696 /* Clipboard was already initialized. 2 or more instances are not supported. */
697 return VERR_NOT_SUPPORTED;
698 }
699
700 if (VbglR3AutoLogonIsRemoteSession())
701 {
702 /* Do not use clipboard for remote sessions. */
703 LogRel(("Clipboard: Clipboard has been disabled for a remote session\n"));
704 return VERR_NOT_SUPPORTED;
705 }
706
707 pCtx->pEnv = pEnv;
708
709 int rc = VINF_SUCCESS;
710
711#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
712 HRESULT hr = OleInitialize(NULL);
713 if (FAILED(hr))
714 {
715 LogRel(("Clipboard: Initializing OLE failed (%Rhrc) -- file transfers unavailable\n"));
716 /* Not critical, the rest of the clipboard might work. */
717 }
718 else
719 LogRel(("Clipboard: Initialized OLE\n"));
720#endif
721
722 if (RT_SUCCESS(rc))
723 {
724 /* Check if new Clipboard API is available. */
725 /* ignore rc */ VBoxClipboardWinCheckAndInitNewAPI(&pCtx->Win.newAPI);
726
727 rc = VbglR3ClipboardConnect(&pCtx->u32ClientID);
728 if (RT_SUCCESS(rc))
729 {
730 rc = vboxClipboardCreateWindow(pCtx);
731 if (RT_SUCCESS(rc))
732 {
733#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
734 rc = SharedClipboardURICtxInit(&pCtx->URI);
735 if (RT_SUCCESS(rc))
736#endif
737 *ppInstance = pCtx;
738 }
739 else
740 {
741 VbglR3ClipboardDisconnect(pCtx->u32ClientID);
742 }
743 }
744 }
745
746 LogFlowFuncLeaveRC(rc);
747 return rc;
748}
749
750DECLCALLBACK(int) VBoxClipboardWorker(void *pInstance, bool volatile *pfShutdown)
751{
752 AssertPtr(pInstance);
753 LogFlowFunc(("pInstance=%p\n", pInstance));
754
755 /*
756 * Tell the control thread that it can continue
757 * spawning services.
758 */
759 RTThreadUserSignal(RTThreadSelf());
760
761 const PVBOXCLIPBOARDCONTEXT pCtx = (PVBOXCLIPBOARDCONTEXT)pInstance;
762 AssertPtr(pCtx);
763
764 const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win;
765
766 int rc;
767
768 /* The thread waits for incoming messages from the host. */
769 for (;;)
770 {
771 LogFlowFunc(("Waiting for host message ...\n"));
772
773 uint32_t u32Msg;
774 uint32_t u32Formats;
775 rc = VbglR3ClipboardGetHostMsg(pCtx->u32ClientID, &u32Msg, &u32Formats);
776 if (RT_FAILURE(rc))
777 {
778 if (rc == VERR_INTERRUPTED)
779 break;
780
781 LogFunc(("Error getting host message, rc=%Rrc\n", rc));
782
783 if (*pfShutdown)
784 break;
785
786 /* Wait a bit before retrying. */
787 RTThreadSleep(1000);
788 continue;
789 }
790 else
791 {
792 LogFlowFunc(("u32Msg=%RU32, u32Formats=0x%x\n", u32Msg, u32Formats));
793 switch (u32Msg)
794 {
795 case VBOX_SHARED_CLIPBOARD_HOST_MSG_REPORT_FORMATS:
796 {
797 LogFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_REPORT_FORMATS\n"));
798
799 /* The host has announced available clipboard formats.
800 * Forward the information to the window, so it can later
801 * respond to WM_RENDERFORMAT message. */
802 ::PostMessage(pWinCtx->hWnd, VBOX_CLIPBOARD_WM_SET_FORMATS, 0, u32Formats);
803 break;
804 }
805
806 case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA:
807 {
808 LogFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA\n"));
809
810 /* The host needs data in the specified format. */
811 ::PostMessage(pWinCtx->hWnd, VBOX_CLIPBOARD_WM_READ_DATA, 0, u32Formats);
812 break;
813 }
814
815 case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT:
816 {
817 LogFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT\n"));
818
819 /* The host is terminating. */
820 LogRel(("Clipboard: Terminating ...\n"));
821 ASMAtomicXchgBool(pfShutdown, true);
822 break;
823 }
824
825 default:
826 {
827 LogFlowFunc(("Unsupported message from host, message=%RU32\n", u32Msg));
828
829 /* Wait a bit before retrying. */
830 RTThreadSleep(1000);
831 break;
832 }
833 }
834 }
835
836 if (*pfShutdown)
837 break;
838 }
839
840 LogFlowFuncLeaveRC(rc);
841 return rc;
842}
843
844DECLCALLBACK(int) VBoxClipboardStop(void *pInstance)
845{
846 AssertPtrReturn(pInstance, VERR_INVALID_POINTER);
847
848 LogFunc(("Stopping pInstance=%p\n", pInstance));
849
850 PVBOXCLIPBOARDCONTEXT pCtx = (PVBOXCLIPBOARDCONTEXT)pInstance;
851 AssertPtr(pCtx);
852
853 VbglR3ClipboardDisconnect(pCtx->u32ClientID);
854 pCtx->u32ClientID = 0;
855
856 LogFlowFuncLeaveRC(VINF_SUCCESS);
857 return VINF_SUCCESS;
858}
859
860DECLCALLBACK(void) VBoxClipboardDestroy(void *pInstance)
861{
862 AssertPtrReturnVoid(pInstance);
863
864 PVBOXCLIPBOARDCONTEXT pCtx = (PVBOXCLIPBOARDCONTEXT)pInstance;
865 AssertPtr(pCtx);
866
867 /* Make sure that we are disconnected. */
868 Assert(pCtx->u32ClientID == 0);
869
870 vboxClipboardDestroy(pCtx);
871
872#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
873 OleSetClipboard(NULL); /* Make sure to flush the clipboard on destruction. */
874 OleUninitialize();
875
876 SharedClipboardURICtxDestroy(&pCtx->URI);
877#endif
878
879 return;
880}
881
882/**
883 * The service description.
884 */
885VBOXSERVICEDESC g_SvcDescClipboard =
886{
887 /* pszName. */
888 "clipboard",
889 /* pszDescription. */
890 "Shared Clipboard",
891 /* methods */
892 VBoxClipboardInit,
893 VBoxClipboardWorker,
894 VBoxClipboardStop,
895 VBoxClipboardDestroy
896};
897
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette