VirtualBox

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

Last change on this file since 80849 was 80849, checked in by vboxsync, 5 years ago

Shared Clipboard/URI: Renamed VBOX_WITH_SHARED_CLIPBOARD_URI_LIST -> VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 47.6 KB
Line 
1/* $Id: VBoxClipboard.cpp 80849 2019-09-17 09:46:51Z 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/errcore.h>
30#include <iprt/mem.h>
31#include <iprt/ldr.h>
32
33
34#include <VBox/GuestHost/SharedClipboard.h>
35#include <VBox/GuestHost/SharedClipboard-win.h>
36#include <VBox/GuestHost/clipboard-helper.h>
37#include <VBox/HostServices/VBoxClipboardSvc.h> /* Temp, remove. */
38#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
39# include <VBox/GuestHost/SharedClipboard-uri.h>
40#endif
41
42#include <strsafe.h>
43
44#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
45# include <iprt/win/shlobj.h>
46# include <iprt/win/shlwapi.h>
47#endif
48
49
50/*********************************************************************************************************************************
51* Structures and Typedefs *
52*********************************************************************************************************************************/
53
54typedef struct _SHCLCONTEXT
55{
56 /** Pointer to the VBoxClient service environment. */
57 const VBOXSERVICEENV *pEnv;
58 /** Command context. */
59 VBGLR3SHCLCMDCTX CmdCtx;
60 /** Windows-specific context data. */
61 SHCLWINCTX Win;
62#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
63 /** Associated transfer data. */
64 SHCLURICTX URI;
65#endif
66} SHCLCONTEXT, *PSHCLCONTEXT;
67
68#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
69typedef struct _SHCLURIREADTHREADCTX
70{
71 PSHCLCONTEXT pClipboardCtx;
72 PSHCLURITRANSFER pTransfer;
73} SHCLURIREADTHREADCTX, *PSHCLURIREADTHREADCTX;
74
75typedef struct _SHCLURIWRITETHREADCTX
76{
77 PSHCLCONTEXT pClipboardCtx;
78 PSHCLURITRANSFER pTransfer;
79} SHCLURIWRITETHREADCTX, *PSHCLURIWRITETHREADCTX;
80#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
81
82
83/*********************************************************************************************************************************
84* Static variables *
85*********************************************************************************************************************************/
86/** Static clipboard context (since it is the single instance). Directly used in the windows proc. */
87static SHCLCONTEXT g_Ctx = { NULL };
88/** Static window class name. */
89static char s_szClipWndClassName[] = SHCL_WIN_WNDCLASS_NAME;
90
91
92/*********************************************************************************************************************************
93* Prototypes *
94*********************************************************************************************************************************/
95#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
96static DECLCALLBACK(void) vboxClipboardURITransferCompleteCallback(PSHCLURITRANSFERCALLBACKDATA pData, int rc);
97static DECLCALLBACK(void) vboxClipboardURITransferErrorCallback(PSHCLURITRANSFERCALLBACKDATA pData, int rc);
98#endif
99
100
101#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
102#if 0
103static DECLCALLBACK(int) vboxClipboardURIWriteThread(RTTHREAD ThreadSelf, void *pvUser)
104{
105 RT_NOREF(ThreadSelf);
106
107 LogFlowFuncEnter();
108
109 PSHCLURIWRITETHREADCTX pCtx = (PSHCLURIWRITETHREADCTX)pvUser;
110 AssertPtr(pCtx);
111
112 PSHCLURITRANSFER pTransfer = pCtx->pTransfer;
113 AssertPtr(pTransfer);
114
115 pTransfer->Thread.fStarted = true;
116
117 RTThreadUserSignal(RTThreadSelf());
118
119 VBGLR3SHCLCMDCTX cmdCtx;
120 int rc = VbglR3ClipboardConnectEx(&cmdCtx);
121 if (RT_SUCCESS(rc))
122 {
123 rc = VbglR3ClipboardTransferSendStatus(&cmdCtx, pTransfer, SHCLURITRANSFERSTATUS_RUNNING);
124 if (RT_SUCCESS(rc))
125 {
126 bool fTerminate = false;
127 unsigned cErrors = 0;
128
129 for (;;)
130 {
131 PVBGLR3CLIPBOARDEVENT pEvent = NULL;
132 rc = VbglR3ClipboardEventGetNext(&cmdCtx, &pEvent);
133 if (RT_SUCCESS(rc))
134 {
135 /* Nothing to do in here right now. */
136
137 VbglR3ClipboardEventFree(pEvent);
138 }
139
140 if (fTerminate)
141 break;
142
143 if (RT_FAILURE(rc))
144 {
145 if (cErrors++ >= 3)
146 break;
147 RTThreadSleep(1000);
148 }
149 }
150 }
151
152 VbglR3ClipboardDisconnectEx(&cmdCtx);
153 }
154
155 RTMemFree(pCtx);
156
157 LogFlowFuncLeaveRC(rc);
158 return rc;
159}
160#endif
161
162static void vboxClipboardURITransferCallbackCleanup(PSHCLURITRANSFERCALLBACKDATA pData)
163{
164 PSHCLURICTX pCtx = (PSHCLURICTX)pData->pvUser;
165 AssertPtr(pCtx);
166
167 PSHCLURITRANSFER pTransfer = pData->pTransfer;
168 AssertPtr(pTransfer);
169
170 if (pTransfer->pvUser) /* SharedClipboardWinURITransferCtx */
171 {
172 delete pTransfer->pvUser;
173 pTransfer->pvUser = NULL;
174 }
175
176 int rc2 = SharedClipboardURICtxTransferUnregister(pCtx, pTransfer->State.uID);
177 AssertRC(rc2);
178
179 SharedClipboardURITransferDestroy(pTransfer);
180
181 RTMemFree(pTransfer);
182 pTransfer = NULL;
183}
184
185static DECLCALLBACK(void) vboxClipboardURITransferCompleteCallback(PSHCLURITRANSFERCALLBACKDATA pData, int rc)
186{
187 RT_NOREF(rc);
188
189 LogFlowFunc(("pData=%p, rc=%Rrc\n", pData, rc));
190
191 LogRel2(("Shared Clipboard: Transfer to destination complete\n"));
192
193 vboxClipboardURITransferCallbackCleanup(pData);
194}
195
196static DECLCALLBACK(void) vboxClipboardURITransferErrorCallback(PSHCLURITRANSFERCALLBACKDATA pData, int rc)
197{
198 RT_NOREF(rc);
199
200 LogFlowFunc(("pData=%p, rc=%Rrc\n", pData, rc));
201
202 LogRel(("Shared Clipboard: Transfer to destination failed with %Rrc\n", rc));
203
204 vboxClipboardURITransferCallbackCleanup(pData);
205}
206
207static int vboxClipboardURITransferOpen(PSHCLPROVIDERCTX pCtx)
208{
209 RT_NOREF(pCtx);
210
211 LogFlowFuncLeave();
212 return VINF_SUCCESS;
213}
214
215static int vboxClipboardURITransferClose(PSHCLPROVIDERCTX pCtx)
216{
217 RT_NOREF(pCtx);
218
219 LogFlowFuncLeave();
220 return VINF_SUCCESS;
221}
222
223static int vboxClipboardURIListOpen(PSHCLPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
224 PSHCLLISTHANDLE phList)
225{
226 RT_NOREF(pCtx, pOpenParms, phList);
227
228 LogFlowFuncEnter();
229
230 PSHCLCONTEXT pThisCtx = (PSHCLCONTEXT)pCtx->pvUser;
231 AssertPtr(pThisCtx);
232
233 RT_NOREF(pThisCtx);
234
235 int rc = 0; // VbglR3ClipboardRecvListOpen(pThisCtx->u32ClientID, pListHdr, phList);
236
237 LogFlowFuncLeaveRC(rc);
238 return rc;
239}
240
241static int vboxClipboardURIListClose(PSHCLPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
242{
243 RT_NOREF(pCtx, hList);
244
245 LogFlowFuncEnter();
246
247 PSHCLCONTEXT pThisCtx = (PSHCLCONTEXT)pCtx->pvUser;
248 AssertPtr(pThisCtx);
249
250 RT_NOREF(pThisCtx);
251
252 int rc = 0; // VbglR3ClipboardRecvListOpen(pThisCtx->u32ClientID, pListHdr, phList);
253
254 LogFlowFuncLeaveRC(rc);
255 return rc;
256}
257
258static int vboxClipboardURIGetRoots(PSHCLPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList)
259{
260 LogFlowFuncEnter();
261
262 PSHCLCONTEXT pThisCtx = (PSHCLCONTEXT)pCtx->pvUser;
263 AssertPtr(pThisCtx);
264
265 int rc = VbglR3ClipboardRootListRead(&pThisCtx->CmdCtx, ppRootList);
266
267 LogFlowFuncLeaveRC(rc);
268 return rc;
269}
270
271static int vboxClipboardURIListHdrRead(PSHCLPROVIDERCTX pCtx, SHCLLISTHANDLE hList,
272 PSHCLLISTHDR pListHdr)
273{
274 RT_NOREF(hList);
275
276 LogFlowFuncEnter();
277
278 PSHCLCONTEXT pThisCtx = (PSHCLCONTEXT)pCtx->pvUser;
279 AssertPtr(pThisCtx);
280
281 RT_NOREF(pThisCtx);
282
283 int rc = SharedClipboardURIListHdrInit(pListHdr);
284 if (RT_SUCCESS(rc))
285 {
286 if (RT_SUCCESS(rc))
287 {
288 //rc = VbglR3ClipboardListHdrReadRecv(pThisCtx->u32ClientID, hList, pListHdr);
289 }
290 else
291 SharedClipboardURIListHdrDestroy(pListHdr);
292 }
293
294 LogFlowFuncLeaveRC(rc);
295 return rc;
296}
297
298/*
299static int vboxClipboardURIListHdrWrite(PSHCLPROVIDERCTX pCtx, SHCLLISTHANDLE hList,
300 PSHCLLISTHDR pListHdr)
301{
302 LogFlowFuncEnter();
303
304 PSHCLCONTEXT pThisCtx = (PSHCLCONTEXT)pCtx->pvUser;
305 AssertPtr(pThisCtx);
306
307 int rc = VbglR3ClipboardListHdrWrite(pThisCtx->u32ClientID, hList, pListHdr);
308
309 LogFlowFuncLeaveRC(rc);
310 return rc;
311}*/
312
313static int vboxClipboardURIListEntryRead(PSHCLPROVIDERCTX pCtx, SHCLLISTHANDLE hList,
314 PSHCLLISTENTRY pListEntry)
315{
316 RT_NOREF(hList);
317
318 LogFlowFuncEnter();
319
320 PSHCLCONTEXT pThisCtx = (PSHCLCONTEXT)pCtx->pvUser;
321 AssertPtr(pThisCtx);
322
323 RT_NOREF(pThisCtx);
324
325 RT_NOREF(pListEntry);
326 int rc = 0; // VbglR3ClipboardListEntryRead(pThisCtx->u32ClientID, pListEntry);
327
328 LogFlowFuncLeaveRC(rc);
329 return rc;
330}
331
332/*
333static int vboxClipboardURIListEntryWrite(PSHCLPROVIDERCTX pCtx, SHCLLISTHANDLE hList,
334 PSHCLLISTENTRY pListEntry)
335{
336 LogFlowFuncEnter();
337
338 PSHCLCONTEXT pThisCtx = (PSHCLCONTEXT)pCtx->pvUser;
339 AssertPtr(pThisCtx);
340
341 int rc = VbglR3ClipboardListEntryWrite(pThisCtx->u32ClientID, hList, pListEntry);
342
343 LogFlowFuncLeaveRC(rc);
344 return rc;
345}
346*/
347
348static int vboxClipboardURIObjOpen(PSHCLPROVIDERCTX pCtx,
349 PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)
350{
351 LogFlowFuncEnter();
352
353 PSHCLCONTEXT pThisCtx = (PSHCLCONTEXT)pCtx->pvUser;
354 AssertPtr(pThisCtx);
355
356 int rc = VbglR3ClipboardObjOpenSend(&pThisCtx->CmdCtx, pCreateParms, phObj);
357
358 LogFlowFuncLeaveRC(rc);
359 return rc;
360}
361
362static int vboxClipboardURIObjClose(PSHCLPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
363{
364 LogFlowFuncEnter();
365
366 PSHCLCONTEXT pThisCtx = (PSHCLCONTEXT)pCtx->pvUser;
367 AssertPtr(pThisCtx);
368
369 int rc = VbglR3ClipboardObjCloseSend(&pThisCtx->CmdCtx, hObj);
370
371 LogFlowFuncLeaveRC(rc);
372 return rc;
373}
374
375static int vboxClipboardURIObjRead(PSHCLPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
376 void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbRead)
377{
378 RT_NOREF(fFlags);
379
380 LogFlowFuncEnter();
381
382 PSHCLCONTEXT pThisCtx = (PSHCLCONTEXT)pCtx->pvUser;
383 AssertPtr(pThisCtx);
384
385 int rc = VbglR3ClipboardObjRead(&pThisCtx->CmdCtx, hObj, pvData, cbData, pcbRead);
386
387 LogFlowFuncLeaveRC(rc);
388 return rc;
389}
390
391static int vboxClipboardURIObjWrite(PSHCLPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
392 void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbWritten)
393{
394 RT_NOREF(fFlags);
395
396 LogFlowFuncEnter();
397
398 PSHCLCONTEXT pThisCtx = (PSHCLCONTEXT)pCtx->pvUser;
399 AssertPtr(pThisCtx);
400
401 int rc = VbglR3ClipboardObjWrite(&pThisCtx->CmdCtx, hObj, pvData, cbData, pcbWritten);
402
403 LogFlowFuncLeaveRC(rc);
404 return rc;
405}
406#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
407
408static LRESULT vboxClipboardWinProcessMsg(PSHCLCONTEXT pCtx, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
409{
410 AssertPtr(pCtx);
411
412 const PSHCLWINCTX pWinCtx = &pCtx->Win;
413
414 LRESULT lresultRc = 0;
415
416 switch (msg)
417 {
418 case WM_CLIPBOARDUPDATE:
419 {
420 const HWND hWndClipboardOwner = GetClipboardOwner();
421 if (pWinCtx->hWndClipboardOwnerUs != hWndClipboardOwner)
422 {
423 LogFunc(("WM_CLIPBOARDUPDATE: hWndOldClipboardOwner=%p, hWndNewClipboardOwner=%p\n",
424 pWinCtx->hWndClipboardOwnerUs, hWndClipboardOwner));
425
426 /* Clipboard was updated by another application.
427 * Report available formats to the host. */
428 SHCLFORMATDATA Formats;
429 int rc = SharedClipboardWinGetFormats(&pCtx->Win, &Formats);
430 if (RT_SUCCESS(rc))
431 {
432 LogFunc(("WM_CLIPBOARDUPDATE: Reporting formats 0x%x\n", Formats.uFormats));
433 rc = VbglR3ClipboardFormatsSend(&pCtx->CmdCtx, &Formats);
434 }
435 }
436
437 break;
438 }
439
440 case WM_CHANGECBCHAIN:
441 {
442 LogFunc(("WM_CHANGECBCHAIN\n"));
443 lresultRc = SharedClipboardWinHandleWMChangeCBChain(pWinCtx, hwnd, msg, wParam, lParam);
444 break;
445 }
446
447 case WM_DRAWCLIPBOARD:
448 {
449 LogFlowFunc(("WM_DRAWCLIPBOARD, hwnd %p\n", pWinCtx->hWnd));
450
451 if (GetClipboardOwner() != hwnd)
452 {
453 /* Clipboard was updated by another application. */
454 /* WM_DRAWCLIPBOARD always expects a return code of 0, so don't change "rc" here. */
455 SHCLFORMATDATA Formats;
456 int rc = SharedClipboardWinGetFormats(pWinCtx, &Formats);
457 if (RT_SUCCESS(rc))
458 rc = VbglR3ClipboardFormatsSend(&pCtx->CmdCtx, &Formats);
459 }
460
461 lresultRc = SharedClipboardWinChainPassToNext(pWinCtx, msg, wParam, lParam);
462 break;
463 }
464
465 case WM_TIMER:
466 {
467 int rc = SharedClipboardWinHandleWMTimer(pWinCtx);
468 AssertRC(rc);
469
470 break;
471 }
472
473 case WM_CLOSE:
474 {
475 /* Do nothing. Ignore the message. */
476 break;
477 }
478
479 case WM_RENDERFORMAT:
480 {
481 LogFunc(("WM_RENDERFORMAT\n"));
482
483 /* Insert the requested clipboard format data into the clipboard. */
484 const UINT cfFormat = (UINT)wParam;
485
486 const SHCLFORMAT fFormat = SharedClipboardWinClipboardFormatToVBox(cfFormat);
487
488 LogFunc(("WM_RENDERFORMAT: cfFormat=%u -> fFormat=0x%x\n", cfFormat, fFormat));
489
490 if (fFormat == VBOX_SHCL_FMT_NONE)
491 {
492 LogFunc(("WM_RENDERFORMAT: Unsupported format requested\n"));
493 SharedClipboardWinClear();
494 }
495 else
496 {
497 const uint32_t cbPrealloc = _4K;
498 uint32_t cb = 0;
499
500 /* Preallocate a buffer, most of small text transfers will fit into it. */
501 HANDLE hMem = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cbPrealloc);
502 LogFlowFunc(("Preallocated handle hMem = %p\n", hMem));
503
504 if (hMem)
505 {
506 void *pMem = GlobalLock(hMem);
507 LogFlowFunc(("Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem)));
508
509 if (pMem)
510 {
511 /* Read the host data to the preallocated buffer. */
512 int rc = VbglR3ClipboardReadData(pCtx->CmdCtx.uClientID, fFormat, pMem, cbPrealloc, &cb);
513 LogFlowFunc(("VbglR3ClipboardReadData returned with rc = %Rrc\n", rc));
514
515 if (RT_SUCCESS(rc))
516 {
517 if (cb == 0)
518 {
519 /* 0 bytes returned means the clipboard is empty.
520 * Deallocate the memory and set hMem to NULL to get to
521 * the clipboard empty code path. */
522 GlobalUnlock(hMem);
523 GlobalFree(hMem);
524 hMem = NULL;
525 }
526 else if (cb > cbPrealloc)
527 {
528 GlobalUnlock(hMem);
529
530 /* The preallocated buffer is too small, adjust the size. */
531 hMem = GlobalReAlloc(hMem, cb, 0);
532 LogFlowFunc(("Reallocated hMem = %p\n", hMem));
533
534 if (hMem)
535 {
536 pMem = GlobalLock(hMem);
537 LogFlowFunc(("Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem)));
538
539 if (pMem)
540 {
541 /* Read the host data to the preallocated buffer. */
542 uint32_t cbNew = 0;
543 rc = VbglR3ClipboardReadData(pCtx->CmdCtx.uClientID, fFormat, pMem, cb, &cbNew);
544 LogFlowFunc(("VbglR3ClipboardReadData returned with rc = %Rrc, cb = %d, cbNew = %d\n",
545 rc, cb, cbNew));
546
547 if (RT_SUCCESS(rc)
548 && cbNew <= cb)
549 {
550 cb = cbNew;
551 }
552 else
553 {
554 GlobalUnlock(hMem);
555 GlobalFree(hMem);
556 hMem = NULL;
557 }
558 }
559 else
560 {
561 GlobalFree(hMem);
562 hMem = NULL;
563 }
564 }
565 }
566
567 if (hMem)
568 {
569 /* pMem is the address of the data. cb is the size of returned data. */
570 /* Verify the size of returned text, the memory block for clipboard
571 * must have the exact string size.
572 */
573 if (fFormat == VBOX_SHCL_FMT_UNICODETEXT)
574 {
575 size_t cbActual = 0;
576 HRESULT hrc = StringCbLengthW((LPWSTR)pMem, cb, &cbActual);
577 if (FAILED(hrc))
578 {
579 /* Discard invalid data. */
580 GlobalUnlock(hMem);
581 GlobalFree(hMem);
582 hMem = NULL;
583 }
584 else
585 {
586 /* cbActual is the number of bytes, excluding those used
587 * for the terminating null character.
588 */
589 cb = (uint32_t)(cbActual + 2);
590 }
591 }
592 }
593
594 if (hMem)
595 {
596 GlobalUnlock(hMem);
597
598 hMem = GlobalReAlloc(hMem, cb, 0);
599 LogFlowFunc(("Reallocated hMem = %p\n", hMem));
600
601 if (hMem)
602 {
603 /* 'hMem' contains the host clipboard data.
604 * size is 'cb' and format is 'format'. */
605 HANDLE hClip = SetClipboardData(cfFormat, hMem);
606 LogFlowFunc(("WM_RENDERFORMAT hClip = %p\n", hClip));
607
608 if (hClip)
609 {
610 /* The hMem ownership has gone to the system. Finish the processing. */
611 break;
612 }
613
614 /* Cleanup follows. */
615 }
616 }
617 }
618 if (hMem)
619 GlobalUnlock(hMem);
620 }
621 if (hMem)
622 GlobalFree(hMem);
623 }
624 }
625
626 break;
627 }
628
629 case WM_RENDERALLFORMATS:
630 {
631 LogFunc(("WM_RENDERALLFORMATS\n"));
632
633 int rc = SharedClipboardWinHandleWMRenderAllFormats(pWinCtx, hwnd);
634 AssertRC(rc);
635
636 break;
637 }
638
639 case SHCL_WIN_WM_REPORT_FORMATS:
640 {
641 LogFunc(("SHCL_WIN_WM_REPORT_FORMATS\n"));
642
643 /* Announce available formats. Do not insert data -- will be inserted in WM_RENDERFORMAT. */
644 PVBGLR3CLIPBOARDEVENT pEvent = (PVBGLR3CLIPBOARDEVENT)lParam;
645 AssertPtr(pEvent);
646 Assert(pEvent->enmType == VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS);
647
648 const SHCLFORMATS fFormats = pEvent->u.ReportedFormats.uFormats;
649
650 if (fFormats != VBOX_SHCL_FMT_NONE) /* Could arrive with some older GA versions. */
651 {
652 int rc = SharedClipboardWinOpen(hwnd);
653 if (RT_SUCCESS(rc))
654 {
655 SharedClipboardWinClear();
656
657#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
658 if (fFormats & VBOX_SHCL_FMT_URI_LIST)
659 {
660 LogFunc(("VBOX_SHCL_FMT_URI_LIST\n"));
661
662 PSHCLURITRANSFER pTransfer = SharedClipboardURICtxGetTransfer(&pCtx->URI, 0); /** @todo FIX !!! */
663 if (pTransfer)
664 {
665 rc = SharedClipboardWinURITransferCreate(pWinCtx, pTransfer);
666
667 /* Note: The actual requesting + retrieving of data will be done in the IDataObject implementation
668 (ClipboardDataObjectImpl::GetData()). */
669 }
670 else
671 AssertFailedStmt(rc = VERR_NOT_FOUND);
672
673 /* Note: SharedClipboardWinURITransferCreate() takes care of closing the clipboard. */
674 }
675 else
676 {
677#endif
678 rc = SharedClipboardWinAnnounceFormats(pWinCtx, fFormats);
679
680 SharedClipboardWinClose();
681#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
682 }
683#endif
684 }
685 }
686
687 LogFunc(("SHCL_WIN_WM_REPORT_FORMATS: fFormats=0x%x, lastErr=%ld\n", fFormats, GetLastError()));
688 break;
689 }
690
691 case SHCL_WIN_WM_READ_DATA:
692 {
693 /* Send data in the specified format to the host. */
694 PVBGLR3CLIPBOARDEVENT pEvent = (PVBGLR3CLIPBOARDEVENT)lParam;
695 AssertPtr(pEvent);
696 Assert(pEvent->enmType == VBGLR3CLIPBOARDEVENTTYPE_READ_DATA);
697
698 const SHCLFORMAT uFormat = (uint32_t)pEvent->u.ReadData.uFmt;
699
700 HANDLE hClip = NULL;
701
702 LogFlowFunc(("SHCL_WIN_WM_READ_DATA: uFormat=0x%x\n", uFormat));
703
704 int rc = SharedClipboardWinOpen(hwnd);
705 if (RT_SUCCESS(rc))
706 {
707 if (uFormat == VBOX_SHCL_FMT_BITMAP)
708 {
709 hClip = GetClipboardData(CF_DIB);
710 if (hClip != NULL)
711 {
712 LPVOID lp = GlobalLock(hClip);
713 if (lp != NULL)
714 {
715 SHCLDATABLOCK dataBlock = { uFormat, lp, (uint32_t)GlobalSize(hClip) };
716
717 rc = VbglR3ClipboardWriteDataEx(&pEvent->cmdCtx, &dataBlock);
718
719 GlobalUnlock(hClip);
720 }
721 else
722 {
723 hClip = NULL;
724 }
725 }
726 }
727 else if (uFormat == VBOX_SHCL_FMT_UNICODETEXT)
728 {
729 hClip = GetClipboardData(CF_UNICODETEXT);
730 if (hClip != NULL)
731 {
732 LPWSTR uniString = (LPWSTR)GlobalLock(hClip);
733 if (uniString != NULL)
734 {
735 SHCLDATABLOCK dataBlock = { uFormat, uniString, ((uint32_t)lstrlenW(uniString) + 1) * 2 };
736
737 rc = VbglR3ClipboardWriteDataEx(&pEvent->cmdCtx, &dataBlock);
738
739 GlobalUnlock(hClip);
740 }
741 else
742 {
743 hClip = NULL;
744 }
745 }
746 }
747 else if (uFormat == VBOX_SHCL_FMT_HTML)
748 {
749 UINT format = RegisterClipboardFormat(SHCL_WIN_REGFMT_HTML);
750 if (format != 0)
751 {
752 hClip = GetClipboardData(format);
753 if (hClip != NULL)
754 {
755 LPVOID lp = GlobalLock(hClip);
756
757 if (lp != NULL)
758 {
759 SHCLDATABLOCK dataBlock = { uFormat, lp, (uint32_t)GlobalSize(hClip) };
760
761 rc = VbglR3ClipboardWriteDataEx(&pEvent->cmdCtx, &dataBlock);
762
763 GlobalUnlock(hClip);
764 }
765 else
766 {
767 hClip = NULL;
768 }
769 }
770 }
771 }
772#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
773 else if (uFormat == VBOX_SHCL_FMT_URI_LIST)
774 {
775 LogFunc(("cTransfersRunning=%RU32\n", SharedClipboardURICtxGetRunningTransfers(&pCtx->URI)));
776
777 int rc = SharedClipboardWinOpen(hwnd);
778 if (RT_SUCCESS(rc))
779 {
780 PSHCLURITRANSFER pTransfer;
781 rc = SharedClipboardURITransferCreate(&pTransfer);
782 if (RT_SUCCESS(rc))
783 rc = SharedClipboardURITransferInit(pTransfer, 0 /* uID */,
784 SHCLURITRANSFERDIR_WRITE, SHCLSOURCE_LOCAL);
785 if (RT_SUCCESS(rc))
786 {
787 /* The data data in CF_HDROP format, as the files are locally present and don't need to be
788 * presented as a IDataObject or IStream. */
789 HANDLE hClip = hClip = GetClipboardData(CF_HDROP);
790 if (hClip)
791 {
792 HDROP hDrop = (HDROP)GlobalLock(hClip);
793 if (hDrop)
794 {
795 char *papszList;
796 uint32_t cbList;
797 rc = SharedClipboardWinDropFilesToStringList((DROPFILES *)hDrop, &papszList, &cbList);
798
799 GlobalUnlock(hClip);
800
801 if (RT_SUCCESS(rc))
802 {
803 rc = SharedClipboardURILTransferSetRoots(pTransfer,
804 papszList, cbList + 1 /* Include termination */);
805 if (RT_SUCCESS(rc))
806 {
807 PSHCLURIWRITETHREADCTX pThreadCtx
808 = (PSHCLURIWRITETHREADCTX)RTMemAllocZ(sizeof(SHCLURIWRITETHREADCTX));
809 if (pThreadCtx)
810 {
811 pThreadCtx->pClipboardCtx = pCtx;
812 pThreadCtx->pTransfer = pTransfer;
813
814 rc = SharedClipboardURITransferPrepare(pTransfer);
815 if (RT_SUCCESS(rc))
816 {
817 rc = SharedClipboardURICtxTransferRegister(&pCtx->URI, pTransfer,
818 NULL /* puTransferID */);
819 #if 0
820 if (RT_SUCCESS(rc))
821 {
822 rc = SharedClipboardURITransferRun(pTransfer, vboxClipboardURIWriteThread,
823 pThreadCtx /* pvUser */);
824 /* pThreadCtx now is owned by vboxClipboardURIWriteThread(). */
825 }
826 #endif
827 }
828 }
829 else
830 rc = VERR_NO_MEMORY;
831 }
832
833 if (papszList)
834 RTStrFree(papszList);
835 }
836 }
837 else
838 {
839 hClip = NULL;
840 }
841 }
842 }
843
844 SharedClipboardWinClose();
845 }
846
847 if (RT_FAILURE(rc))
848 LogFunc(("SHCL_WIN_WM_READ_DATA: Failed with rc=%Rrc\n", rc));
849 }
850#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
851
852 if (hClip == NULL)
853 {
854 LogFunc(("SHCL_WIN_WM_READ_DATA: hClip=NULL, lastError=%ld\n", GetLastError()));
855
856 /* Requested clipboard format is not available, send empty data. */
857 VbglR3ClipboardWriteData(pCtx->CmdCtx.uClientID, VBOX_SHCL_FMT_NONE, NULL, 0);
858#ifdef DEBUG_andy
859 AssertFailed();
860#endif
861 }
862
863 SharedClipboardWinClose();
864 }
865 break;
866 }
867
868#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
869 case SHCL_WIN_WM_URI_TRANSFER_STATUS:
870 {
871 LogFunc(("SHCL_WIN_WM_URI_TRANSFER_STATUS\n"));
872
873 break;
874 }
875#endif
876
877#if 0
878 /* The host wants to read URI data. */
879 case VBOX_CLIPBOARD_WM_URI_START_READ:
880 {
881 LogFunc(("VBOX_CLIPBOARD_WM_URI_START_READ: cTransfersRunning=%RU32\n",
882 SharedClipboardURICtxGetRunningTransfers(&pCtx->URI)));
883
884 int rc = SharedClipboardWinOpen(hwnd);
885 if (RT_SUCCESS(rc))
886 {
887 PSHCLURITRANSFER pTransfer;
888 rc = SharedClipboardURITransferCreate(SHCLURITRANSFERDIR_WRITE,
889 SHCLSOURCE_LOCAL,
890 &pTransfer);
891 if (RT_SUCCESS(rc))
892 {
893 rc = SharedClipboardURICtxTransferAdd(&pCtx->URI, pTransfer);
894 if (RT_SUCCESS(rc))
895 {
896 /* The data data in CF_HDROP format, as the files are locally present and don't need to be
897 * presented as a IDataObject or IStream. */
898 HANDLE hClip = hClip = GetClipboardData(CF_HDROP);
899 if (hClip)
900 {
901 HDROP hDrop = (HDROP)GlobalLock(hClip);
902 if (hDrop)
903 {
904 char *papszList;
905 uint32_t cbList;
906 rc = SharedClipboardWinDropFilesToStringList((DROPFILES *)hDrop, &papszList, &cbList);
907
908 GlobalUnlock(hClip);
909
910 if (RT_SUCCESS(rc))
911 {
912 rc = SharedClipboardURILTransferSetRoots(pTransfer,
913 papszList, cbList + 1 /* Include termination */);
914 if (RT_SUCCESS(rc))
915 {
916 PSHCLURIWRITETHREADCTX pThreadCtx
917 = (PSHCLURIWRITETHREADCTX)RTMemAllocZ(sizeof(SHCLURIWRITETHREADCTX));
918 if (pThreadCtx)
919 {
920 pThreadCtx->pClipboardCtx = pCtx;
921 pThreadCtx->pTransfer = pTransfer;
922
923 rc = SharedClipboardURITransferPrepare(pTransfer);
924 if (RT_SUCCESS(rc))
925 {
926 rc = SharedClipboardURITransferRun(pTransfer, vboxClipboardURIWriteThread,
927 pThreadCtx /* pvUser */);
928 /* pThreadCtx now is owned by vboxClipboardURIWriteThread(). */
929 }
930 }
931 else
932 rc = VERR_NO_MEMORY;
933 }
934
935 if (papszList)
936 RTStrFree(papszList);
937 }
938 }
939 else
940 {
941 hClip = NULL;
942 }
943 }
944 }
945 }
946
947 SharedClipboardWinClose();
948 }
949
950 if (RT_FAILURE(rc))
951 LogFunc(("VBOX_CLIPBOARD_WM_URI_START_READ: Failed with rc=%Rrc\n", rc));
952 break;
953 }
954
955 /* The host wants to write URI data. */
956 case VBOX_CLIPBOARD_WM_URI_START_WRITE:
957 {
958 LogFunc(("VBOX_CLIPBOARD_WM_URI_START_WRITE: cTransfersRunning=%RU32\n",
959 SharedClipboardURICtxGetRunningTransfers(&pCtx->URI)));
960
961 PSHCLURITRANSFER pTransfer;
962 int rc = SharedClipboardURITransferCreate(SHCLURITRANSFERDIR_READ,
963 SHCLSOURCE_LOCAL,
964 &pTransfer);
965 if (RT_SUCCESS(rc))
966 {
967 SHCLURITRANSFERCALLBACKS TransferCallbacks;
968 RT_ZERO(TransferCallbacks);
969
970 TransferCallbacks.pvUser = &pCtx->URI;
971 TransferCallbacks.pfnTransferComplete = vboxClipboardURITransferCompleteCallback;
972 TransferCallbacks.pfnTransferError = vboxClipboardURITransferErrorCallback;
973
974 SharedClipboardURITransferSetCallbacks(pTransfer, &TransferCallbacks);
975
976 SHCLPROVIDERCREATIONCTX creationCtx;
977 RT_ZERO(creationCtx);
978
979 creationCtx.enmSource = SHCLSOURCE_REMOTE;
980
981 creationCtx.Interface.pfnGetRoots = vboxClipboardURIGetRoots;
982 creationCtx.Interface.pfnListOpen = vboxClipboardURIListOpen;
983 creationCtx.Interface.pfnListClose = vboxClipboardURIListClose;
984 creationCtx.Interface.pfnListHdrRead = vboxClipboardURIListHdrRead;
985 creationCtx.Interface.pfnListEntryRead = vboxClipboardURIListEntryRead;
986 creationCtx.Interface.pfnObjOpen = vboxClipboardURIObjOpen;
987 creationCtx.Interface.pfnObjClose = vboxClipboardURIObjClose;
988 creationCtx.Interface.pfnObjRead = vboxClipboardURIObjRead;
989
990 creationCtx.pvUser = pCtx;
991
992 rc = SharedClipboardURITransferSetInterface(pTransfer, &creationCtx);
993 if (RT_SUCCESS(rc))
994 {
995 rc = SharedClipboardURICtxTransferAdd(&pCtx->URI, pTransfer);
996 if (RT_SUCCESS(rc))
997 {
998 rc = SharedClipboardURITransferPrepare(pTransfer);
999 if (RT_SUCCESS(rc))
1000 {
1001 rc = SharedClipboardWinURITransferCreate(pWinCtx, pTransfer);
1002 }
1003 }
1004 }
1005 }
1006
1007 break;
1008 }
1009#endif /* 0 */
1010
1011 case WM_DESTROY:
1012 {
1013 LogFunc(("WM_DESTROY\n"));
1014
1015 int rc = SharedClipboardWinHandleWMDestroy(pWinCtx);
1016 AssertRC(rc);
1017
1018 /*
1019 * Don't need to call PostQuitMessage cause
1020 * the VBoxTray already finished a message loop.
1021 */
1022
1023 break;
1024 }
1025
1026 default:
1027 {
1028 LogFunc(("WM_ %p\n", msg));
1029 lresultRc = DefWindowProc(hwnd, msg, wParam, lParam);
1030 break;
1031 }
1032 }
1033
1034 LogFunc(("WM_ rc %d\n", lresultRc));
1035 return lresultRc;
1036}
1037
1038static LRESULT CALLBACK vboxClipboardWinWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
1039
1040static int vboxClipboardCreateWindow(PSHCLCONTEXT pCtx)
1041{
1042 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1043
1044 int rc = VINF_SUCCESS;
1045
1046 AssertPtr(pCtx->pEnv);
1047 HINSTANCE hInstance = pCtx->pEnv->hInstance;
1048 Assert(hInstance != 0);
1049
1050 /* Register the Window Class. */
1051 WNDCLASSEX wc = { 0 };
1052 wc.cbSize = sizeof(WNDCLASSEX);
1053
1054 if (!GetClassInfoEx(hInstance, s_szClipWndClassName, &wc))
1055 {
1056 wc.style = CS_NOCLOSE;
1057 wc.lpfnWndProc = vboxClipboardWinWndProc;
1058 wc.hInstance = pCtx->pEnv->hInstance;
1059 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
1060 wc.lpszClassName = s_szClipWndClassName;
1061
1062 ATOM wndClass = RegisterClassEx(&wc);
1063 if (wndClass == 0)
1064 rc = RTErrConvertFromWin32(GetLastError());
1065 }
1066
1067 if (RT_SUCCESS(rc))
1068 {
1069 const PSHCLWINCTX pWinCtx = &pCtx->Win;
1070
1071 /* Create the window. */
1072 pWinCtx->hWnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
1073 s_szClipWndClassName, s_szClipWndClassName,
1074 WS_POPUPWINDOW,
1075 -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
1076 if (pWinCtx->hWnd == NULL)
1077 {
1078 rc = VERR_NOT_SUPPORTED;
1079 }
1080 else
1081 {
1082 SetWindowPos(pWinCtx->hWnd, HWND_TOPMOST, -200, -200, 0, 0,
1083 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
1084
1085 SharedClipboardWinChainAdd(pWinCtx);
1086 if (!SharedClipboardWinIsNewAPI(&pWinCtx->newAPI))
1087 pWinCtx->oldAPI.timerRefresh = SetTimer(pWinCtx->hWnd, 0, 10 * 1000 /* 10s */, NULL);
1088 }
1089 }
1090
1091 LogFlowFuncLeaveRC(rc);
1092 return rc;
1093}
1094
1095static void vboxClipboardDestroy(PSHCLCONTEXT pCtx)
1096{
1097 AssertPtrReturnVoid(pCtx);
1098
1099 const PSHCLWINCTX pWinCtx = &pCtx->Win;
1100
1101 if (pWinCtx->hWnd)
1102 {
1103 DestroyWindow(pWinCtx->hWnd);
1104 pWinCtx->hWnd = NULL;
1105 }
1106
1107 UnregisterClass(s_szClipWndClassName, pCtx->pEnv->hInstance);
1108
1109 SharedClipboardWinCtxDestroy(&pCtx->Win);
1110}
1111
1112static LRESULT CALLBACK vboxClipboardWinWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1113{
1114 PSHCLCONTEXT pCtx = &g_Ctx; /** @todo r=andy Make pCtx available through SetWindowLongPtr() / GWL_USERDATA. */
1115 AssertPtr(pCtx);
1116
1117 /* Forward with proper context. */
1118 return vboxClipboardWinProcessMsg(pCtx, hWnd, uMsg, wParam, lParam);
1119}
1120
1121DECLCALLBACK(int) VBoxShClInit(const PVBOXSERVICEENV pEnv, void **ppInstance)
1122{
1123 LogFlowFuncEnter();
1124
1125 PSHCLCONTEXT pCtx = &g_Ctx; /* Only one instance for now. */
1126 AssertPtr(pCtx);
1127
1128 if (pCtx->pEnv)
1129 {
1130 /* Clipboard was already initialized. 2 or more instances are not supported. */
1131 return VERR_NOT_SUPPORTED;
1132 }
1133
1134 if (VbglR3AutoLogonIsRemoteSession())
1135 {
1136 /* Do not use clipboard for remote sessions. */
1137 LogRel(("Shared Clipboard: Clipboard has been disabled for a remote session\n"));
1138 return VERR_NOT_SUPPORTED;
1139 }
1140
1141 pCtx->pEnv = pEnv;
1142
1143 int rc = VINF_SUCCESS;
1144
1145#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
1146 HRESULT hr = OleInitialize(NULL);
1147 if (FAILED(hr))
1148 {
1149 LogRel(("Shared Clipboard: Initializing OLE failed (%Rhrc) -- file transfers unavailable\n"));
1150 /* Not critical, the rest of the clipboard might work. */
1151 }
1152 else
1153 LogRel(("Shared Clipboard: Initialized OLE\n"));
1154#endif
1155
1156 if (RT_SUCCESS(rc))
1157 {
1158 /* Check if new Clipboard API is available. */
1159 rc = SharedClipboardWinCtxInit(&pCtx->Win);
1160 if (RT_SUCCESS(rc))
1161 rc = VbglR3ClipboardConnectEx(&pCtx->CmdCtx);
1162 if (RT_SUCCESS(rc))
1163 {
1164 rc = vboxClipboardCreateWindow(pCtx);
1165 if (RT_SUCCESS(rc))
1166 {
1167#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
1168 rc = SharedClipboardURICtxInit(&pCtx->URI);
1169 if (RT_SUCCESS(rc))
1170#endif
1171 *ppInstance = pCtx;
1172 }
1173 else
1174 {
1175 VbglR3ClipboardDisconnectEx(&pCtx->CmdCtx);
1176 }
1177 }
1178 }
1179
1180 LogFlowFuncLeaveRC(rc);
1181 return rc;
1182}
1183
1184DECLCALLBACK(int) VBoxShClWorker(void *pInstance, bool volatile *pfShutdown)
1185{
1186 AssertPtr(pInstance);
1187 LogFlowFunc(("pInstance=%p\n", pInstance));
1188
1189 /*
1190 * Tell the control thread that it can continue
1191 * spawning services.
1192 */
1193 RTThreadUserSignal(RTThreadSelf());
1194
1195 const PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pInstance;
1196 AssertPtr(pCtx);
1197
1198 const PSHCLWINCTX pWinCtx = &pCtx->Win;
1199
1200 int rc;
1201
1202 LogFlowFunc(("Using protocol %RU32\n", pCtx->CmdCtx.uProtocolVer));
1203
1204 uint32_t uMsg;
1205 uint32_t uFormats;
1206
1207 /* The thread waits for incoming messages from the host. */
1208 for (;;)
1209 {
1210 PVBGLR3CLIPBOARDEVENT pEvent = NULL;
1211
1212 LogFlowFunc(("Waiting for host message (protocol v%RU32) ...\n", pCtx->CmdCtx.uProtocolVer));
1213
1214 if (pCtx->CmdCtx.uProtocolVer == 0) /* Legacy protocol */
1215 {
1216 rc = VbglR3ClipboardGetHostMsgOld(pCtx->CmdCtx.uClientID, &uMsg, &uFormats);
1217 if (RT_FAILURE(rc))
1218 {
1219 if (rc == VERR_INTERRUPTED)
1220 break;
1221
1222 LogFunc(("Error getting host message, rc=%Rrc\n", rc));
1223 }
1224 else
1225 {
1226 pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT));
1227 AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY);
1228
1229 switch (uMsg)
1230 {
1231 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
1232 {
1233 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
1234 pEvent->u.ReportedFormats.uFormats = uFormats;
1235 break;
1236 }
1237
1238 case VBOX_SHCL_HOST_MSG_READ_DATA:
1239 {
1240 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
1241 pEvent->u.ReadData.uFmt = uFormats;
1242 break;
1243 }
1244
1245 default:
1246 rc = VERR_NOT_SUPPORTED;
1247 break;
1248 }
1249 }
1250 }
1251 else /* Protocol >= v1. */
1252 {
1253 pEvent = (PVBGLR3CLIPBOARDEVENT)RTMemAllocZ(sizeof(VBGLR3CLIPBOARDEVENT));
1254 AssertPtrBreakStmt(pEvent, rc = VERR_NO_MEMORY);
1255
1256 uint32_t uMsg = 0;
1257 uint32_t cParms = 0;
1258 rc = VbglR3ClipboardMsgPeekWait(&pCtx->CmdCtx, &uMsg, &cParms, NULL /* pidRestoreCheck */);
1259 if (RT_SUCCESS(rc))
1260 {
1261#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
1262 rc = VbglR3ClipboardEventGetNextEx(uMsg, cParms, &pCtx->CmdCtx, &pCtx->URI, pEvent);
1263#else
1264 rc = VbglR3ClipboardEventGetNext(uMsg, cParms, &pCtx->CmdCtx, pEvent);
1265#endif
1266 }
1267 }
1268
1269 if (RT_FAILURE(rc))
1270 {
1271 VbglR3ClipboardEventFree(pEvent);
1272 pEvent = NULL;
1273
1274 if (*pfShutdown)
1275 break;
1276
1277 /* Wait a bit before retrying. */
1278 RTThreadSleep(1000);
1279 continue;
1280 }
1281 else
1282 {
1283 AssertPtr(pEvent);
1284 LogFlowFunc(("Event uType=%RU32\n", pEvent->enmType));
1285
1286 switch (pEvent->enmType)
1287 {
1288 case VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS:
1289 {
1290 /* The host has announced available clipboard formats.
1291 * Forward the information to the window, so it can later
1292 * respond to WM_RENDERFORMAT message. */
1293 ::PostMessage(pWinCtx->hWnd, SHCL_WIN_WM_REPORT_FORMATS,
1294 0 /* wParam */, (LPARAM)pEvent /* lParam */);
1295 break;
1296 }
1297
1298 case VBGLR3CLIPBOARDEVENTTYPE_READ_DATA:
1299 {
1300 /* The host needs data in the specified format. */
1301 ::PostMessage(pWinCtx->hWnd, SHCL_WIN_WM_READ_DATA,
1302 0 /* wParam */, (LPARAM)pEvent /* lParam */);
1303 break;
1304 }
1305
1306#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
1307 case VBGLR3CLIPBOARDEVENTTYPE_URI_TRANSFER_STATUS:
1308 {
1309 ::PostMessage(pWinCtx->hWnd, SHCL_WIN_WM_URI_TRANSFER_STATUS,
1310 0 /* wParm */, (LPARAM)pEvent /* lParm */);
1311 break;
1312 }
1313#endif
1314 case VBGLR3CLIPBOARDEVENTTYPE_QUIT:
1315 {
1316 /* The host is terminating. */
1317 LogRel(("Shared Clipboard: Terminating ...\n"));
1318 ASMAtomicXchgBool(pfShutdown, true);
1319 break;
1320 }
1321
1322 default:
1323 {
1324 /* Wait a bit before retrying. */
1325 RTThreadSleep(1000);
1326 break;
1327 }
1328 }
1329
1330 if (RT_FAILURE(rc))
1331 VbglR3ClipboardEventFree(pEvent);
1332 }
1333
1334 if (*pfShutdown)
1335 break;
1336 }
1337
1338 LogFlowFuncLeaveRC(rc);
1339 return rc;
1340}
1341
1342DECLCALLBACK(int) VBoxShClStop(void *pInstance)
1343{
1344 AssertPtrReturn(pInstance, VERR_INVALID_POINTER);
1345
1346 LogFunc(("Stopping pInstance=%p\n", pInstance));
1347
1348 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pInstance;
1349 AssertPtr(pCtx);
1350
1351 VbglR3ClipboardDisconnect(pCtx->CmdCtx.uClientID);
1352 pCtx->CmdCtx.uClientID = 0;
1353
1354 LogFlowFuncLeaveRC(VINF_SUCCESS);
1355 return VINF_SUCCESS;
1356}
1357
1358DECLCALLBACK(void) VBoxShClDestroy(void *pInstance)
1359{
1360 AssertPtrReturnVoid(pInstance);
1361
1362 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pInstance;
1363 AssertPtr(pCtx);
1364
1365 /* Make sure that we are disconnected. */
1366 Assert(pCtx->CmdCtx.uClientID == 0);
1367
1368 vboxClipboardDestroy(pCtx);
1369
1370#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
1371 OleSetClipboard(NULL); /* Make sure to flush the clipboard on destruction. */
1372 OleUninitialize();
1373
1374 SharedClipboardURICtxDestroy(&pCtx->URI);
1375#endif
1376
1377 return;
1378}
1379
1380/**
1381 * The service description.
1382 */
1383VBOXSERVICEDESC g_SvcDescClipboard =
1384{
1385 /* pszName. */
1386 "clipboard",
1387 /* pszDescription. */
1388 "Shared Clipboard",
1389 /* methods */
1390 VBoxShClInit,
1391 VBoxShClWorker,
1392 VBoxShClStop,
1393 VBoxShClDestroy
1394};
1395
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