VirtualBox

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

Last change on this file since 79267 was 79267, checked in by vboxsync, 5 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.3 KB
Line 
1/* $Id: VBoxClipboard.cpp 79267 2019-06-21 10:11:59Z 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 <VBox/err.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 = SHAREDCLIPBOARDPROVIDERSOURCE_VBGLR3;
350 creationCtx.u.VbglR3.uClientID = pCtx->u32ClientID;
351
352 rc = SharedClipboardURITransferProviderCreate(pTransfer, &creationCtx);
353 if (RT_SUCCESS(rc))
354 {
355 rc = SharedClipboardURICtxTransferAdd(&pCtx->URI, pTransfer);
356 if (RT_SUCCESS(rc))
357 rc = VBoxClipboardWinURIAnnounce(pWinCtx, &pCtx->URI, pTransfer);
358 }
359
360 /* Note: VBoxClipboardWinURIAnnounce() takes care of closing the clipboard. */
361
362 LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_URI_LIST: rc=%Rrc\n", rc));
363 }
364 }
365 else
366 {
367#endif
368 rc = VBoxClipboardWinAnnounceFormats(pWinCtx, fFormats);
369
370 VBoxClipboardWinClose();
371#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
372 }
373#endif
374 }
375 }
376 LogFunc(("VBOX_CLIPBOARD_WM_SET_FORMATS: fFormats=0x%x, lastErr=%ld\n", fFormats, GetLastError()));
377 }
378 break;
379
380 case VBOX_CLIPBOARD_WM_READ_DATA:
381 {
382 /* Send data in the specified format to the host. */
383 VBOXCLIPBOARDFORMAT uFormat = (uint32_t)lParam;
384 HANDLE hClip = NULL;
385
386 LogFlowFunc(("VBOX_WM_SHCLPB_READ_DATA: uFormat=0x%x\n", uFormat));
387
388 int rc = VBoxClipboardWinOpen(hwnd);
389 if (RT_SUCCESS(rc))
390 {
391 if (uFormat == VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
392 {
393 hClip = GetClipboardData(CF_DIB);
394 if (hClip != NULL)
395 {
396 LPVOID lp = GlobalLock(hClip);
397 if (lp != NULL)
398 {
399 rc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_BITMAP,
400 lp, GlobalSize(hClip));
401 GlobalUnlock(hClip);
402 }
403 else
404 {
405 hClip = NULL;
406 }
407 }
408 }
409 else if (uFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
410 {
411 hClip = GetClipboardData(CF_UNICODETEXT);
412 if (hClip != NULL)
413 {
414 LPWSTR uniString = (LPWSTR)GlobalLock(hClip);
415 if (uniString != NULL)
416 {
417 rc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
418 uniString, (lstrlenW(uniString) + 1) * 2);
419 GlobalUnlock(hClip);
420 }
421 else
422 {
423 hClip = NULL;
424 }
425 }
426 }
427 else if (uFormat == VBOX_SHARED_CLIPBOARD_FMT_HTML)
428 {
429 UINT format = RegisterClipboardFormat(VBOX_CLIPBOARD_WIN_REGFMT_HTML);
430 if (format != 0)
431 {
432 hClip = GetClipboardData(format);
433 if (hClip != NULL)
434 {
435 LPVOID lp = GlobalLock(hClip);
436
437 if (lp != NULL)
438 {
439 rc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_HTML,
440 lp, GlobalSize(hClip));
441 GlobalUnlock(hClip);
442 }
443 else
444 {
445 hClip = NULL;
446 }
447 }
448 }
449 }
450#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
451 else if (uFormat == VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
452 {
453 LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_URI_LIST cTransfers=%RU32\n",
454 SharedClipboardURICtxGetActiveTransfers(&pCtx->URI)));
455
456 PSHAREDCLIPBOARDURITRANSFER pTransfer;
457 rc = SharedClipboardURITransferCreate(SHAREDCLIPBOARDURITRANSFERDIR_WRITE, &pTransfer);
458 if (RT_SUCCESS(rc))
459 {
460 SHAREDCLIPBOARDURITRANSFERCALLBACKS TransferCallbacks;
461 RT_ZERO(TransferCallbacks);
462
463 TransferCallbacks.pvUser = &pCtx->URI;
464 TransferCallbacks.pfnTransferComplete = vboxClipboardOnURITransferComplete;
465 TransferCallbacks.pfnTransferError = vboxClipboardOnURITransferError;
466
467 SharedClipboardURITransferSetCallbacks(pTransfer, &TransferCallbacks);
468
469 SHAREDCLIPBOARDPROVIDERCREATIONCTX creationCtx;
470 RT_ZERO(creationCtx);
471 creationCtx.enmSource = SHAREDCLIPBOARDPROVIDERSOURCE_VBGLR3;
472 creationCtx.u.VbglR3.uClientID = pCtx->u32ClientID;
473
474 rc = SharedClipboardURITransferProviderCreate(pTransfer, &creationCtx);
475 if (RT_SUCCESS(rc))
476 {
477 rc = SharedClipboardURICtxTransferAdd(&pCtx->URI, pTransfer);
478 if (RT_SUCCESS(rc))
479 {
480 /* The data data in CF_HDROP format, as the files are locally present and don't need to be
481 * presented as a IDataObject or IStream. */
482 hClip = GetClipboardData(CF_HDROP);
483 if (hClip)
484 {
485 HDROP hDrop = (HDROP)GlobalLock(hClip);
486 if (hDrop)
487 {
488 rc = VBoxClipboardWinDropFilesToTransfer((DROPFILES *)hDrop, pTransfer);
489
490 GlobalUnlock(hClip);
491
492 if (RT_SUCCESS(rc))
493 {
494 rc = SharedClipboardURITransferPrepare(pTransfer);
495 if (RT_SUCCESS(rc))
496 rc = SharedClipboardURITransferRun(pTransfer, true /* fAsync */);
497 }
498 }
499 else
500 {
501 hClip = NULL;
502 }
503 }
504 }
505 }
506 }
507
508 if (RT_FAILURE(rc))
509 LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_URI_LIST failed with rc=%Rrc\n", rc));
510 }
511#endif
512 if (hClip == NULL)
513 {
514 LogFunc(("VBOX_WM_SHCLPB_READ_DATA: hClip=NULL, lastError=%ld\n", GetLastError()));
515
516 /* Requested clipboard format is not available, send empty data. */
517 VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_NONE, NULL, 0);
518#ifdef DEBUG_andy
519 AssertFailed();
520#endif
521 }
522
523 VBoxClipboardWinClose();
524 }
525 }
526 break;
527
528 case WM_DESTROY:
529 {
530 LogFunc(("WM_DESTROY\n"));
531
532 int rc = VBoxClipboardWinHandleWMDestroy(pWinCtx);
533 AssertRC(rc);
534
535 /*
536 * Don't need to call PostQuitMessage cause
537 * the VBoxTray already finished a message loop.
538 */
539 }
540 break;
541
542 default:
543 {
544 LogFunc(("WM_ %p\n", msg));
545 lresultRc = DefWindowProc(hwnd, msg, wParam, lParam);
546 }
547 break;
548 }
549
550 LogFunc(("WM_ rc %d\n", lresultRc));
551 return lresultRc;
552}
553
554static LRESULT CALLBACK vboxClipboardWinWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
555
556static int vboxClipboardCreateWindow(PVBOXCLIPBOARDCONTEXT pCtx)
557{
558 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
559
560 int rc = VINF_SUCCESS;
561
562 AssertPtr(pCtx->pEnv);
563 HINSTANCE hInstance = pCtx->pEnv->hInstance;
564 Assert(hInstance != 0);
565
566 /* Register the Window Class. */
567 WNDCLASSEX wc = { 0 };
568 wc.cbSize = sizeof(WNDCLASSEX);
569
570 if (!GetClassInfoEx(hInstance, s_szClipWndClassName, &wc))
571 {
572 wc.style = CS_NOCLOSE;
573 wc.lpfnWndProc = vboxClipboardWinWndProc;
574 wc.hInstance = pCtx->pEnv->hInstance;
575 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
576 wc.lpszClassName = s_szClipWndClassName;
577
578 ATOM wndClass = RegisterClassEx(&wc);
579 if (wndClass == 0)
580 rc = RTErrConvertFromWin32(GetLastError());
581 }
582
583 if (RT_SUCCESS(rc))
584 {
585 const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win;
586
587 /* Create the window. */
588 pWinCtx->hWnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
589 s_szClipWndClassName, s_szClipWndClassName,
590 WS_POPUPWINDOW,
591 -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
592 if (pWinCtx->hWnd == NULL)
593 {
594 rc = VERR_NOT_SUPPORTED;
595 }
596 else
597 {
598 SetWindowPos(pWinCtx->hWnd, HWND_TOPMOST, -200, -200, 0, 0,
599 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
600
601 VBoxClipboardWinChainAdd(pWinCtx);
602 if (!VBoxClipboardWinIsNewAPI(&pWinCtx->newAPI))
603 pWinCtx->oldAPI.timerRefresh = SetTimer(pWinCtx->hWnd, 0, 10 * 1000 /* 10s */, NULL);
604 }
605 }
606
607 LogFlowFuncLeaveRC(rc);
608 return rc;
609}
610
611#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
612static DECLCALLBACK(void) vboxClipboardOnURITransferComplete(PSHAREDCLIPBOARDURITRANSFERCALLBACKDATA pData, int rc)
613{
614 RT_NOREF(rc);
615
616 LogFlowFunc(("pData=%p, rc=%Rrc\n", pData, rc));
617
618 LogRel2(("Shared Clipboard: Transfer to destination complete\n"));
619
620 PSHAREDCLIPBOARDURICTX pCtx = (PSHAREDCLIPBOARDURICTX)pData->pvUser;
621 AssertPtr(pCtx);
622
623 PSHAREDCLIPBOARDURITRANSFER pTransfer = pData->pTransfer;
624 AssertPtr(pTransfer);
625
626 if (pTransfer->pvUser) /* SharedClipboardWinURITransferCtx */
627 {
628 delete pTransfer->pvUser;
629 pTransfer->pvUser = NULL;
630 }
631
632 int rc2 = SharedClipboardURICtxTransferRemove(pCtx, pTransfer);
633 AssertRC(rc2);
634}
635
636static DECLCALLBACK(void) vboxClipboardOnURITransferError(PSHAREDCLIPBOARDURITRANSFERCALLBACKDATA pData, int rc)
637{
638 RT_NOREF(rc);
639
640 LogFlowFunc(("pData=%p, rc=%Rrc\n", pData, rc));
641
642 LogRel(("Shared Clipboard: Transfer to destination failed with %Rrc\n", rc));
643
644 PSHAREDCLIPBOARDURICTX pCtx = (PSHAREDCLIPBOARDURICTX)pData->pvUser;
645 AssertPtr(pCtx);
646
647 PSHAREDCLIPBOARDURITRANSFER pTransfer = pData->pTransfer;
648 AssertPtr(pTransfer);
649
650 if (pTransfer->pvUser) /* SharedClipboardWinURITransferCtx */
651 {
652 delete pTransfer->pvUser;
653 pTransfer->pvUser = NULL;
654 }
655
656 int rc2 = SharedClipboardURICtxTransferRemove(pCtx, pTransfer);
657 AssertRC(rc2);
658}
659#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
660
661static void vboxClipboardDestroy(PVBOXCLIPBOARDCONTEXT pCtx)
662{
663 AssertPtrReturnVoid(pCtx);
664
665 const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win;
666
667 if (pWinCtx->hWnd)
668 {
669 DestroyWindow(pWinCtx->hWnd);
670 pWinCtx->hWnd = NULL;
671 }
672
673 UnregisterClass(s_szClipWndClassName, pCtx->pEnv->hInstance);
674}
675
676static LRESULT CALLBACK vboxClipboardWinWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
677{
678 PVBOXCLIPBOARDCONTEXT pCtx = &g_Ctx; /** @todo r=andy Make pCtx available through SetWindowLongPtr() / GWL_USERDATA. */
679 AssertPtr(pCtx);
680
681 /* Forward with proper context. */
682 return vboxClipboardWinProcessMsg(pCtx, hWnd, uMsg, wParam, lParam);
683}
684
685DECLCALLBACK(int) VBoxClipboardInit(const PVBOXSERVICEENV pEnv, void **ppInstance)
686{
687 LogFlowFuncEnter();
688
689 PVBOXCLIPBOARDCONTEXT pCtx = &g_Ctx; /* Only one instance for now. */
690 AssertPtr(pCtx);
691
692 if (pCtx->pEnv)
693 {
694 /* Clipboard was already initialized. 2 or more instances are not supported. */
695 return VERR_NOT_SUPPORTED;
696 }
697
698 if (VbglR3AutoLogonIsRemoteSession())
699 {
700 /* Do not use clipboard for remote sessions. */
701 LogRel(("Clipboard: Clipboard has been disabled for a remote session\n"));
702 return VERR_NOT_SUPPORTED;
703 }
704
705 pCtx->pEnv = pEnv;
706
707 int rc = VINF_SUCCESS;
708
709#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
710 HRESULT hr = OleInitialize(NULL);
711 if (FAILED(hr))
712 {
713 LogRel(("Clipboard: Initializing OLE failed (%Rhrc) -- file transfers unavailable\n"));
714 /* Not critical, the rest of the clipboard might work. */
715 }
716 else
717 LogRel(("Clipboard: Initialized OLE\n"));
718#endif
719
720 if (RT_SUCCESS(rc))
721 {
722 /* Check if new Clipboard API is available. */
723 /* ignore rc */ VBoxClipboardWinCheckAndInitNewAPI(&pCtx->Win.newAPI);
724
725 rc = VbglR3ClipboardConnect(&pCtx->u32ClientID);
726 if (RT_SUCCESS(rc))
727 {
728 rc = vboxClipboardCreateWindow(pCtx);
729 if (RT_SUCCESS(rc))
730 {
731#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
732 rc = SharedClipboardURICtxInit(&pCtx->URI);
733 if (RT_SUCCESS(rc))
734#endif
735 *ppInstance = pCtx;
736 }
737 else
738 {
739 VbglR3ClipboardDisconnect(pCtx->u32ClientID);
740 }
741 }
742 }
743
744 LogFlowFuncLeaveRC(rc);
745 return rc;
746}
747
748DECLCALLBACK(int) VBoxClipboardWorker(void *pInstance, bool volatile *pfShutdown)
749{
750 AssertPtr(pInstance);
751 LogFlowFunc(("pInstance=%p\n", pInstance));
752
753 /*
754 * Tell the control thread that it can continue
755 * spawning services.
756 */
757 RTThreadUserSignal(RTThreadSelf());
758
759 const PVBOXCLIPBOARDCONTEXT pCtx = (PVBOXCLIPBOARDCONTEXT)pInstance;
760 AssertPtr(pCtx);
761
762 const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win;
763
764 int rc;
765
766 /* The thread waits for incoming messages from the host. */
767 for (;;)
768 {
769 LogFlowFunc(("Waiting for host message ...\n"));
770
771 uint32_t u32Msg;
772 uint32_t u32Formats;
773 rc = VbglR3ClipboardGetHostMsg(pCtx->u32ClientID, &u32Msg, &u32Formats);
774 if (RT_FAILURE(rc))
775 {
776 if (rc == VERR_INTERRUPTED)
777 break;
778
779 LogFunc(("Error getting host message, rc=%Rrc\n", rc));
780
781 if (*pfShutdown)
782 break;
783
784 /* Wait a bit before retrying. */
785 RTThreadSleep(1000);
786 continue;
787 }
788 else
789 {
790 LogFlowFunc(("u32Msg=%RU32, u32Formats=0x%x\n", u32Msg, u32Formats));
791 switch (u32Msg)
792 {
793 case VBOX_SHARED_CLIPBOARD_HOST_MSG_REPORT_FORMATS:
794 {
795 LogFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_REPORT_FORMATS\n"));
796
797 /* The host has announced available clipboard formats.
798 * Forward the information to the window, so it can later
799 * respond to WM_RENDERFORMAT message. */
800 ::PostMessage(pWinCtx->hWnd, VBOX_CLIPBOARD_WM_SET_FORMATS, 0, u32Formats);
801 break;
802 }
803
804 case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA:
805 {
806 LogFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA\n"));
807
808 /* The host needs data in the specified format. */
809 ::PostMessage(pWinCtx->hWnd, VBOX_CLIPBOARD_WM_READ_DATA, 0, u32Formats);
810 break;
811 }
812
813 case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT:
814 {
815 LogFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT\n"));
816
817 /* The host is terminating. */
818 LogRel(("Clipboard: Terminating ...\n"));
819 ASMAtomicXchgBool(pfShutdown, true);
820 break;
821 }
822
823 default:
824 {
825 LogFlowFunc(("Unsupported message from host, message=%RU32\n", u32Msg));
826
827 /* Wait a bit before retrying. */
828 RTThreadSleep(1000);
829 break;
830 }
831 }
832 }
833
834 if (*pfShutdown)
835 break;
836 }
837
838 LogFlowFuncLeaveRC(rc);
839 return rc;
840}
841
842DECLCALLBACK(int) VBoxClipboardStop(void *pInstance)
843{
844 AssertPtrReturn(pInstance, VERR_INVALID_POINTER);
845
846 LogFunc(("Stopping pInstance=%p\n", pInstance));
847
848 PVBOXCLIPBOARDCONTEXT pCtx = (PVBOXCLIPBOARDCONTEXT)pInstance;
849 AssertPtr(pCtx);
850
851 VbglR3ClipboardDisconnect(pCtx->u32ClientID);
852 pCtx->u32ClientID = 0;
853
854 LogFlowFuncLeaveRC(VINF_SUCCESS);
855 return VINF_SUCCESS;
856}
857
858DECLCALLBACK(void) VBoxClipboardDestroy(void *pInstance)
859{
860 AssertPtrReturnVoid(pInstance);
861
862 PVBOXCLIPBOARDCONTEXT pCtx = (PVBOXCLIPBOARDCONTEXT)pInstance;
863 AssertPtr(pCtx);
864
865 /* Make sure that we are disconnected. */
866 Assert(pCtx->u32ClientID == 0);
867
868 vboxClipboardDestroy(pCtx);
869
870#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
871 OleSetClipboard(NULL); /* Make sure to flush the clipboard on destruction. */
872 OleUninitialize();
873
874 SharedClipboardURICtxDestroy(&pCtx->URI);
875#endif
876
877 return;
878}
879
880/**
881 * The service description.
882 */
883VBOXSERVICEDESC g_SvcDescClipboard =
884{
885 /* pszName. */
886 "clipboard",
887 /* pszDescription. */
888 "Shared Clipboard",
889 /* methods */
890 VBoxClipboardInit,
891 VBoxClipboardWorker,
892 VBoxClipboardStop,
893 VBoxClipboardDestroy
894};
895
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