VirtualBox

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

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

Shared Clipboard: More renaming + unification.

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