VirtualBox

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

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

Shared Clipboard/Transfers: Update.

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