VirtualBox

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

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