VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp@ 81790

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

Shared Clipboard: Update.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.5 KB
Line 
1/* $Id: VBoxSharedClipboardSvc-win.cpp 81768 2019-11-11 16:36:41Z vboxsync $ */
2/** @file
3 * Shared Clipboard Service - Win32 host.
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 <iprt/win/windows.h>
24
25#include <VBox/HostServices/VBoxClipboardSvc.h>
26#include <VBox/GuestHost/clipboard-helper.h>
27#include <VBox/GuestHost/SharedClipboard-win.h>
28#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
29# include <VBox/GuestHost/SharedClipboard-transfers.h>
30#endif
31
32#include <iprt/alloc.h>
33#include <iprt/string.h>
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/ldr.h>
37#include <iprt/semaphore.h>
38#include <iprt/thread.h>
39#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
40# include <iprt/utf16.h>
41#endif
42
43#include <process.h>
44#include <shlobj.h> /* Needed for shell objects. */
45
46#include "VBoxSharedClipboardSvc-internal.h"
47#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
48# include "VBoxSharedClipboardSvc-transfers.h"
49#endif
50
51
52/*********************************************************************************************************************************
53* Internal Functions *
54*********************************************************************************************************************************/
55static int vboxClipboardSvcWinSyncInternal(PSHCLCONTEXT pCtx);
56
57struct _SHCLCONTEXT
58{
59 /** Handle for window message handling thread. */
60 RTTHREAD hThread;
61 /** Structure for keeping and communicating with service client. */
62 PSHCLCLIENT pClient;
63 /** Windows-specific context data. */
64 SHCLWINCTX Win;
65};
66
67
68/** @todo Someone please explain the protocol wrt overflows... */
69static void vboxClipboardSvcWinGetData(uint32_t u32Format, const void *pvSrc, uint32_t cbSrc,
70 void *pvDst, uint32_t cbDst, uint32_t *pcbActualDst)
71{
72 LogFlowFunc(("cbSrc = %d, cbDst = %d\n", cbSrc, cbDst));
73
74 if ( u32Format == VBOX_SHCL_FMT_HTML
75 && SharedClipboardWinIsCFHTML((const char *)pvSrc))
76 {
77 /** @todo r=bird: Why the double conversion? */
78 char *pszBuf = NULL;
79 uint32_t cbBuf = 0;
80 int rc = SharedClipboardWinConvertCFHTMLToMIME((const char *)pvSrc, cbSrc, &pszBuf, &cbBuf);
81 if (RT_SUCCESS(rc))
82 {
83 *pcbActualDst = cbBuf;
84 if (cbBuf > cbDst)
85 {
86 /* Do not copy data. The dst buffer is not enough. */
87 RTMemFree(pszBuf);
88 return;
89 }
90 memcpy(pvDst, pszBuf, cbBuf);
91 RTMemFree(pszBuf);
92 }
93 else
94 *pcbActualDst = 0;
95 }
96 else
97 {
98 *pcbActualDst = cbSrc;
99
100 if (cbSrc > cbDst)
101 {
102 /* Do not copy data. The dst buffer is not enough. */
103 return;
104 }
105
106 memcpy(pvDst, pvSrc, cbSrc);
107 }
108
109#ifdef LOG_ENABLED
110 ShClDbgDumpData(pvDst, cbSrc, u32Format);
111#endif
112
113 return;
114}
115
116static int vboxClipboardSvcWinDataSet(PSHCLCONTEXT pCtx, UINT cfFormat, void *pvData, uint32_t cbData)
117{
118 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
119 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
120 AssertReturn (cbData, VERR_INVALID_PARAMETER);
121
122 int rc = VINF_SUCCESS;
123
124 HANDLE hMem = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cbData);
125
126 LogFlowFunc(("hMem=%p\n", hMem));
127
128 if (hMem)
129 {
130 void *pMem = GlobalLock(hMem);
131
132 LogFlowFunc(("pMem=%p, GlobalSize=%zu\n", pMem, GlobalSize(hMem)));
133
134 if (pMem)
135 {
136 LogFlowFunc(("Setting data\n"));
137
138 memcpy(pMem, pvData, cbData);
139
140 /* The memory must be unlocked before inserting to the Clipboard. */
141 GlobalUnlock(hMem);
142
143 /* 'hMem' contains the host clipboard data.
144 * size is 'cb' and format is 'format'.
145 */
146 HANDLE hClip = SetClipboardData(cfFormat, hMem);
147
148 LogFlowFunc(("hClip=%p\n", hClip));
149
150 if (hClip)
151 {
152 /* The hMem ownership has gone to the system. Nothing to do. */
153 }
154 else
155 rc = RTErrConvertFromWin32(GetLastError());
156 }
157 else
158 rc = VERR_ACCESS_DENIED;
159
160 GlobalFree(hMem);
161 }
162 else
163 rc = RTErrConvertFromWin32(GetLastError());
164
165 LogFlowFuncLeaveRC(rc);
166 return rc;
167}
168
169static int vboxClipboardSvcWinDataRead(PSHCLCONTEXT pCtx, UINT cfFormat,
170 void **ppvData, uint32_t *pcbData)
171{
172 SHCLDATAREQ dataReq;
173 RT_ZERO(dataReq);
174
175 dataReq.uFmt = SharedClipboardWinClipboardFormatToVBox(cfFormat);
176 dataReq.cbSize = _64K; /** @todo Make this more dynamic. */
177
178 LogFlowFunc(("cfFormat=%u -> uFmt=0x%x\n", cfFormat, dataReq.uFmt));
179
180 if (dataReq.uFmt == VBOX_SHCL_FMT_NONE)
181 {
182 LogRel2(("Shared Clipbaord: Windows format %u not supported, ingoring\n", cfFormat));
183 return VERR_NOT_SUPPORTED;
184 }
185
186 SHCLEVENTID uEvent = 0;
187 int rc = ShClSvcDataReadRequest(pCtx->pClient, &dataReq, &uEvent);
188 if (RT_SUCCESS(rc))
189 {
190 PSHCLEVENTPAYLOAD pPayload;
191 rc = ShClEventWait(&pCtx->pClient->Events, uEvent, 30 * 1000, &pPayload);
192 if (RT_SUCCESS(rc))
193 {
194 *ppvData = pPayload->pvData;
195 *pcbData = pPayload->cbData;
196
197 /* Detach the payload, as the caller then will own the data. */
198 ShClEventPayloadDetach(&pCtx->pClient->Events, uEvent);
199 }
200
201 ShClEventUnregister(&pCtx->pClient->Events, uEvent);
202 }
203
204 LogFlowFuncLeaveRC(rc);
205 return rc;
206}
207
208static LRESULT CALLBACK vboxClipboardSvcWinWndProcMain(PSHCLCONTEXT pCtx,
209 HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
210{
211 AssertPtr(pCtx);
212
213 LRESULT lresultRc = 0;
214
215 const PSHCLWINCTX pWinCtx = &pCtx->Win;
216
217 switch (uMsg)
218 {
219 case WM_CLIPBOARDUPDATE:
220 {
221 LogFunc(("WM_CLIPBOARDUPDATE\n"));
222
223 int rc = RTCritSectEnter(&pWinCtx->CritSect);
224 if (RT_SUCCESS(rc))
225 {
226 const HWND hWndClipboardOwner = GetClipboardOwner();
227
228 LogFunc(("WM_CLIPBOARDUPDATE: hWndClipboardOwnerUs=%p, hWndNewClipboardOwner=%p\n",
229 pWinCtx->hWndClipboardOwnerUs, hWndClipboardOwner));
230
231 if (pWinCtx->hWndClipboardOwnerUs != hWndClipboardOwner)
232 {
233 int rc2 = RTCritSectLeave(&pWinCtx->CritSect);
234 AssertRC(rc2);
235
236 /* Clipboard was updated by another application, retrieve formats and report back. */
237 rc = vboxClipboardSvcWinSyncInternal(pCtx);
238 if (RT_SUCCESS(rc))
239 rc = shClSvcSetSource(pCtx->pClient, SHCLSOURCE_LOCAL);
240 }
241 else
242 {
243 int rc2 = RTCritSectLeave(&pWinCtx->CritSect);
244 AssertRC(rc2);
245 }
246 }
247
248 if (RT_FAILURE(rc))
249 LogRel(("Shared Clipboard: WM_CLIPBOARDUPDATE failed with %Rrc\n", rc));
250
251 break;
252 }
253
254 case WM_CHANGECBCHAIN:
255 {
256 LogFunc(("WM_CHANGECBCHAIN\n"));
257 lresultRc = SharedClipboardWinHandleWMChangeCBChain(pWinCtx, hWnd, uMsg, wParam, lParam);
258 break;
259 }
260
261 case WM_DRAWCLIPBOARD:
262 {
263 LogFunc(("WM_DRAWCLIPBOARD\n"));
264
265 int rc = RTCritSectEnter(&pWinCtx->CritSect);
266 if (RT_SUCCESS(rc))
267 {
268 const HWND hWndClipboardOwner = GetClipboardOwner();
269
270 LogFunc(("WM_DRAWCLIPBOARD: hWndClipboardOwnerUs=%p, hWndNewClipboardOwner=%p\n",
271 pWinCtx->hWndClipboardOwnerUs, hWndClipboardOwner));
272
273 if (pWinCtx->hWndClipboardOwnerUs != hWndClipboardOwner)
274 {
275 int rc2 = RTCritSectLeave(&pWinCtx->CritSect);
276 AssertRC(rc2);
277
278 /* Clipboard was updated by another application, retrieve formats and report back. */
279 rc = vboxClipboardSvcWinSyncInternal(pCtx);
280 if (RT_SUCCESS(rc))
281 shClSvcSetSource(pCtx->pClient, SHCLSOURCE_LOCAL);
282 }
283 else
284 {
285 int rc2 = RTCritSectLeave(&pWinCtx->CritSect);
286 AssertRC(rc2);
287 }
288 }
289
290 lresultRc = SharedClipboardWinChainPassToNext(pWinCtx, uMsg, wParam, lParam);
291 break;
292 }
293
294 case WM_TIMER:
295 {
296 int rc = SharedClipboardWinHandleWMTimer(pWinCtx);
297 AssertRC(rc);
298
299 break;
300 }
301
302 case WM_RENDERFORMAT:
303 {
304 LogFunc(("WM_RENDERFORMAT\n"));
305
306 /* Insert the requested clipboard format data into the clipboard. */
307 const UINT cfFormat = (UINT)wParam;
308
309 const SHCLFORMAT fFormat = SharedClipboardWinClipboardFormatToVBox(cfFormat);
310
311 LogFunc(("WM_RENDERFORMAT: cfFormat=%u -> fFormat=0x%x\n", cfFormat, fFormat));
312
313 if ( fFormat == VBOX_SHCL_FMT_NONE
314 || pCtx->pClient == NULL)
315 {
316 /* Unsupported clipboard format is requested. */
317 LogFunc(("WM_RENDERFORMAT unsupported format requested or client is not active\n"));
318 SharedClipboardWinClear();
319 }
320 else
321 {
322 void *pvData = NULL;
323 uint32_t cbData = 0;
324 int rc = vboxClipboardSvcWinDataRead(pCtx, cfFormat, &pvData, &cbData);
325 if ( RT_SUCCESS(rc)
326 && pvData
327 && cbData)
328 {
329 rc = vboxClipboardSvcWinDataSet(pCtx, cfFormat, pvData, cbData);
330
331 RTMemFree(pvData);
332 cbData = 0;
333 }
334
335 if (RT_FAILURE(rc))
336 SharedClipboardWinClear();
337 }
338
339 break;
340 }
341
342 case WM_RENDERALLFORMATS:
343 {
344 LogFunc(("WM_RENDERALLFORMATS\n"));
345
346 int rc = SharedClipboardWinHandleWMRenderAllFormats(pWinCtx, hWnd);
347 AssertRC(rc);
348
349 break;
350 }
351
352 case SHCL_WIN_WM_REPORT_FORMATS:
353 {
354 /* Announce available formats. Do not insert data -- will be inserted in WM_RENDERFORMAT (or via IDataObject). */
355 SHCLFORMATS fFormats = (uint32_t)lParam;
356 LogFunc(("SHCL_WIN_WM_REPORT_FORMATS: fFormats=0x%x\n", fFormats));
357
358 if (fFormats == VBOX_SHCL_FMT_NONE) /* Could arrive with some older GA versions. */
359 break;
360
361#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
362 if (fFormats & VBOX_SHCL_FMT_URI_LIST)
363 {
364 PSHCLTRANSFER pTransfer;
365 int rc = shClSvcTransferStart(pCtx->pClient,
366 SHCLTRANSFERDIR_READ, SHCLSOURCE_REMOTE,
367 &pTransfer);
368 if (RT_SUCCESS(rc))
369 {
370 /* Create the IDataObject implementation the host OS needs and assign
371 * the newly created transfer to this object. */
372 rc = SharedClipboardWinTransferCreate(&pCtx->Win, pTransfer);
373
374 /* Note: The actual requesting + retrieving of data will be done in the IDataObject implementation
375 (ClipboardDataObjectImpl::GetData()). */
376 }
377 else
378 LogRel(("Shared Clipboard: Initializing read transfer failed with %Rrc\n", rc));
379 }
380 else
381 {
382#endif
383 int rc = SharedClipboardWinOpen(hWnd);
384 if (RT_SUCCESS(rc))
385 {
386 SharedClipboardWinClear();
387
388 rc = SharedClipboardWinAnnounceFormats(pWinCtx, fFormats);
389
390 SharedClipboardWinClose();
391 }
392#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
393 }
394#endif
395 LogFunc(("SHCL_WIN_WM_REPORT_FORMATS: lastErr=%ld\n", GetLastError()));
396 break;
397 }
398
399 case WM_DESTROY:
400 {
401 LogFunc(("WM_DESTROY\n"));
402
403 int rc = SharedClipboardWinHandleWMDestroy(pWinCtx);
404 AssertRC(rc);
405
406 PostQuitMessage(0);
407 break;
408 }
409
410 default:
411 break;
412 }
413
414 LogFlowFunc(("LEAVE hWnd=%p, WM_ %u\n", hWnd, uMsg));
415 return DefWindowProc(hWnd, uMsg, wParam, lParam);
416}
417
418/**
419 * Static helper function for having a per-client proxy window instances.
420 */
421static LRESULT CALLBACK vboxClipboardSvcWinWndProcInstance(HWND hWnd, UINT uMsg,
422 WPARAM wParam, LPARAM lParam)
423{
424 LONG_PTR pUserData = GetWindowLongPtr(hWnd, GWLP_USERDATA);
425 AssertPtrReturn(pUserData, 0);
426
427 PSHCLCONTEXT pCtx = reinterpret_cast<PSHCLCONTEXT>(pUserData);
428 if (pCtx)
429 return vboxClipboardSvcWinWndProcMain(pCtx, hWnd, uMsg, wParam, lParam);
430
431 return 0;
432}
433
434/**
435 * Static helper function for routing Windows messages to a specific
436 * proxy window instance.
437 */
438static LRESULT CALLBACK vboxClipboardSvcWinWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
439{
440 /* Note: WM_NCCREATE is not the first ever message which arrives, but
441 * early enough for us. */
442 if (uMsg == WM_NCCREATE)
443 {
444 LogFlowFunc(("WM_NCCREATE\n"));
445
446 LPCREATESTRUCT pCS = (LPCREATESTRUCT)lParam;
447 AssertPtr(pCS);
448 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pCS->lpCreateParams);
449 SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)vboxClipboardSvcWinWndProcInstance);
450
451 return vboxClipboardSvcWinWndProcInstance(hWnd, uMsg, wParam, lParam);
452 }
453
454 /* No window associated yet. */
455 return DefWindowProc(hWnd, uMsg, wParam, lParam);
456}
457
458DECLCALLBACK(int) vboxClipboardSvcWinThread(RTTHREAD hThreadSelf, void *pvUser)
459{
460 LogFlowFuncEnter();
461
462 bool fThreadSignalled = false;
463
464 const PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pvUser;
465 AssertPtr(pCtx);
466 const PSHCLWINCTX pWinCtx = &pCtx->Win;
467
468 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
469
470 /* Register the Window Class. */
471 WNDCLASS wc;
472 RT_ZERO(wc);
473
474 wc.style = CS_NOCLOSE;
475 wc.lpfnWndProc = vboxClipboardSvcWinWndProc;
476 wc.hInstance = hInstance;
477 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
478
479 /* Register an unique wnd class name. */
480 char szWndClassName[32];
481 RTStrPrintf2(szWndClassName, sizeof(szWndClassName),
482 "%s-%RU64", SHCL_WIN_WNDCLASS_NAME, RTThreadGetNative(hThreadSelf));
483 wc.lpszClassName = szWndClassName;
484
485 int rc;
486
487 ATOM atomWindowClass = RegisterClass(&wc);
488 if (atomWindowClass == 0)
489 {
490 LogFunc(("Failed to register window class\n"));
491 rc = VERR_NOT_SUPPORTED;
492 }
493 else
494 {
495 /* Create a window and make it a clipboard viewer. */
496 pWinCtx->hWnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
497 szWndClassName, szWndClassName,
498 WS_POPUPWINDOW,
499 -200, -200, 100, 100, NULL, NULL, hInstance, pCtx /* lpParam */);
500 if (pWinCtx->hWnd == NULL)
501 {
502 LogFunc(("Failed to create window\n"));
503 rc = VERR_NOT_SUPPORTED;
504 }
505 else
506 {
507 SetWindowPos(pWinCtx->hWnd, HWND_TOPMOST, -200, -200, 0, 0,
508 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
509
510 rc = SharedClipboardWinChainAdd(&pCtx->Win);
511 if (RT_SUCCESS(rc))
512 {
513 if (!SharedClipboardWinIsNewAPI(&pWinCtx->newAPI))
514 pWinCtx->oldAPI.timerRefresh = SetTimer(pWinCtx->hWnd, 0, 10 * 1000, NULL);
515 }
516
517#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
518 if (RT_SUCCESS(rc))
519 {
520 HRESULT hr = OleInitialize(NULL);
521 if (FAILED(hr))
522 {
523 LogRel(("Shared Clipboard: Initializing window thread OLE failed (%Rhrc) -- file transfers unavailable\n", hr));
524 /* Not critical, the rest of the clipboard might work. */
525 }
526 else
527 LogRel(("Shared Clipboard: Initialized window thread OLE\n"));
528 }
529#endif
530 int rc2 = RTThreadUserSignal(hThreadSelf);
531 AssertRC(rc2);
532
533 fThreadSignalled = true;
534
535 MSG msg;
536 BOOL msgret = 0;
537 while ((msgret = GetMessage(&msg, NULL, 0, 0)) > 0)
538 {
539 TranslateMessage(&msg);
540 DispatchMessage(&msg);
541 }
542
543 /*
544 * Window procedure can return error, * but this is exceptional situation that should be
545 * identified in testing.
546 */
547 Assert(msgret >= 0);
548 LogFunc(("Message loop finished. GetMessage returned %d, message id: %d \n", msgret, msg.message));
549
550#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
551 OleSetClipboard(NULL); /* Make sure to flush the clipboard on destruction. */
552 OleUninitialize();
553#endif
554 }
555 }
556
557 pWinCtx->hWnd = NULL;
558
559 if (atomWindowClass != 0)
560 {
561 UnregisterClass(szWndClassName, hInstance);
562 atomWindowClass = 0;
563 }
564
565 if (!fThreadSignalled)
566 {
567 int rc2 = RTThreadUserSignal(hThreadSelf);
568 AssertRC(rc2);
569 }
570
571 LogFlowFuncLeaveRC(rc);
572 return rc;
573}
574
575/**
576 * Synchronizes the host and the guest clipboard formats by sending all supported host clipboard
577 * formats to the guest.
578 *
579 * @returns VBox status code, VINF_NO_CHANGE if no synchronization was required.
580 * @param pCtx Clipboard context to synchronize.
581 */
582static int vboxClipboardSvcWinSyncInternal(PSHCLCONTEXT pCtx)
583{
584 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
585
586 LogFlowFuncEnter();
587
588 int rc;
589
590 if (pCtx->pClient)
591 {
592 SHCLFORMATDATA Formats;
593 RT_ZERO(Formats);
594
595 rc = SharedClipboardWinGetFormats(&pCtx->Win, &Formats);
596 if ( RT_SUCCESS(rc)
597 && Formats.uFormats != VBOX_SHCL_FMT_NONE)
598 {
599 rc = ShClSvcFormatsReport(pCtx->pClient, &Formats);
600 }
601 }
602 else /* If we don't have any client data (yet), bail out. */
603 rc = VINF_NO_CHANGE;
604
605 LogFlowFuncLeaveRC(rc);
606 return rc;
607}
608
609/*
610 * Public platform dependent functions.
611 */
612
613int ShClSvcImplInit(void)
614{
615#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
616 HRESULT hr = OleInitialize(NULL);
617 if (FAILED(hr))
618 {
619 LogRel(("Shared Clipboard: Initializing OLE failed (%Rhrc) -- file transfers unavailable\n", hr));
620 /* Not critical, the rest of the clipboard might work. */
621 }
622 else
623 LogRel(("Shared Clipboard: Initialized OLE\n"));
624#endif
625
626 return VINF_SUCCESS;
627}
628
629void ShClSvcImplDestroy(void)
630{
631#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
632 OleSetClipboard(NULL); /* Make sure to flush the clipboard on destruction. */
633 OleUninitialize();
634#endif
635}
636
637int ShClSvcImplConnect(PSHCLCLIENT pClient, bool fHeadless)
638{
639 RT_NOREF(fHeadless);
640
641 LogFlowFuncEnter();
642
643 int rc;
644
645 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)RTMemAllocZ(sizeof(SHCLCONTEXT));
646 if (pCtx)
647 {
648 rc = SharedClipboardWinCtxInit(&pCtx->Win);
649 if (RT_SUCCESS(rc))
650 {
651 rc = RTThreadCreate(&pCtx->hThread, vboxClipboardSvcWinThread, pCtx /* pvUser */, _64K /* Stack size */,
652 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
653 if (RT_SUCCESS(rc))
654 {
655 int rc2 = RTThreadUserWait(pCtx->hThread, 30 * 1000 /* Timeout in ms */);
656 AssertRC(rc2);
657 }
658 }
659
660 pClient->State.pCtx = pCtx;
661 pClient->State.pCtx->pClient = pClient;
662
663 /* Sync the host clipboard content with the client. */
664 rc = ShClSvcImplSync(pClient);
665 if (rc == VINF_NO_CHANGE)
666 {
667 /*
668 * The sync could return VINF_NO_CHANGE if nothing has changed on the host, but older
669 * Guest Additions rely on the fact that only VINF_SUCCESS indicates a successful connect
670 * to the host service (instead of using RT_SUCCESS()).
671 *
672 * So implicitly set VINF_SUCCESS here to not break older Guest Additions.
673 */
674 rc = VINF_SUCCESS;
675 }
676 }
677 else
678 rc = VERR_NO_MEMORY;
679
680 LogFlowFuncLeaveRC(rc);
681 return rc;
682}
683
684int ShClSvcImplSync(PSHCLCLIENT pClient)
685{
686 /* Sync the host clipboard content with the client. */
687 return vboxClipboardSvcWinSyncInternal(pClient->State.pCtx);
688}
689
690int ShClSvcImplDisconnect(PSHCLCLIENT pClient)
691{
692 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
693
694 LogFlowFuncEnter();
695
696 int rc = VINF_SUCCESS;
697
698 PSHCLCONTEXT pCtx = pClient->State.pCtx;
699 if (pCtx)
700 {
701 if (pCtx->Win.hWnd)
702 PostMessage(pCtx->Win.hWnd, WM_DESTROY, 0 /* wParam */, 0 /* lParam */);
703
704 if (pCtx->hThread != NIL_RTTHREAD)
705 {
706 LogFunc(("Waiting for thread to terminate ...\n"));
707
708 /* Wait for the window thread to terminate. */
709 rc = RTThreadWait(pCtx->hThread, 30 * 1000 /* Timeout in ms */, NULL);
710 if (RT_FAILURE(rc))
711 LogRel(("Shared Clipboard: Waiting for window thread termination failed with rc=%Rrc\n", rc));
712
713 pCtx->hThread = NIL_RTTHREAD;
714 }
715
716 SharedClipboardWinCtxDestroy(&pCtx->Win);
717
718 if (RT_SUCCESS(rc))
719 {
720 RTMemFree(pCtx);
721 pCtx = NULL;
722
723 pClient->State.pCtx = NULL;
724 }
725 }
726
727 LogFlowFuncLeaveRC(rc);
728 return rc;
729}
730
731int ShClSvcImplFormatAnnounce(PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx,
732 PSHCLFORMATDATA pFormats)
733{
734 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
735 RT_NOREF(pCmdCtx);
736
737 int rc;
738
739 PSHCLCONTEXT pCtx = pClient->State.pCtx;
740 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
741
742 LogFlowFunc(("uFormats=0x%x, hWnd=%p\n", pFormats->uFormats, pCtx->Win.hWnd));
743
744 /*
745 * The guest announced formats. Forward to the window thread.
746 */
747 PostMessage(pCtx->Win.hWnd, SHCL_WIN_WM_REPORT_FORMATS,
748 0 /* wParam */, pFormats->uFormats /* lParam */);
749
750 rc = VINF_SUCCESS;
751
752 LogFlowFuncLeaveRC(rc);
753 return rc;
754}
755
756int ShClSvcImplReadData(PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx,
757 PSHCLDATABLOCK pData, uint32_t *pcbActual)
758{
759 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
760 RT_NOREF(pCmdCtx);
761 AssertPtrReturn(pClient->State.pCtx, VERR_INVALID_POINTER);
762
763 LogFlowFunc(("uFormat=%02X\n", pData->uFormat));
764
765 HANDLE hClip = NULL;
766
767 const PSHCLWINCTX pWinCtx = &pClient->State.pCtx->Win;
768
769 /*
770 * The guest wants to read data in the given format.
771 */
772 int rc = SharedClipboardWinOpen(pWinCtx->hWnd);
773 if (RT_SUCCESS(rc))
774 {
775 LogFunc(("Clipboard opened\n"));
776
777 if (pData->uFormat & VBOX_SHCL_FMT_BITMAP)
778 {
779 hClip = GetClipboardData(CF_DIB);
780 if (hClip != NULL)
781 {
782 LPVOID lp = GlobalLock(hClip);
783
784 if (lp != NULL)
785 {
786 LogFunc(("CF_DIB\n"));
787
788 vboxClipboardSvcWinGetData(VBOX_SHCL_FMT_BITMAP, lp, GlobalSize(hClip),
789 pData->pvData, pData->cbData, pcbActual);
790
791 GlobalUnlock(hClip);
792 }
793 else
794 {
795 hClip = NULL;
796 }
797 }
798 }
799 else if (pData->uFormat & VBOX_SHCL_FMT_UNICODETEXT)
800 {
801 hClip = GetClipboardData(CF_UNICODETEXT);
802 if (hClip != NULL)
803 {
804 LPWSTR uniString = (LPWSTR)GlobalLock(hClip);
805
806 if (uniString != NULL)
807 {
808 LogFunc(("CF_UNICODETEXT\n"));
809
810 vboxClipboardSvcWinGetData(VBOX_SHCL_FMT_UNICODETEXT, uniString, (lstrlenW(uniString) + 1) * 2,
811 pData->pvData, pData->cbData, pcbActual);
812
813 GlobalUnlock(hClip);
814 }
815 else
816 {
817 hClip = NULL;
818 }
819 }
820 }
821 else if (pData->uFormat & VBOX_SHCL_FMT_HTML)
822 {
823 UINT format = RegisterClipboardFormat(SHCL_WIN_REGFMT_HTML);
824 if (format != 0)
825 {
826 hClip = GetClipboardData(format);
827 if (hClip != NULL)
828 {
829 LPVOID lp = GlobalLock(hClip);
830 if (lp != NULL)
831 {
832 /** @todo r=andy Add data overflow handling. */
833 vboxClipboardSvcWinGetData(VBOX_SHCL_FMT_HTML, lp, GlobalSize(hClip),
834 pData->pvData, pData->cbData, pcbActual);
835#ifdef VBOX_STRICT
836 LogFlowFunc(("Raw HTML clipboard data from host:"));
837 ShClDbgDumpHtml((char *)pData->pvData, pData->cbData);
838#endif
839 GlobalUnlock(hClip);
840 }
841 else
842 {
843 hClip = NULL;
844 }
845 }
846 }
847 }
848#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
849 else if (pData->uFormat & VBOX_SHCL_FMT_URI_LIST)
850 {
851 AssertFailed(); /** @todo */
852 }
853#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
854 SharedClipboardWinClose();
855 }
856
857 if (hClip == NULL)
858 {
859 /* Reply with empty data. */
860 vboxClipboardSvcWinGetData(0, NULL, 0, pData->pvData, pData->cbData, pcbActual);
861 }
862
863 LogFlowFuncLeaveRC(rc);
864 return rc;
865}
866
867int ShClSvcImplWriteData(PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx,
868 PSHCLDATABLOCK pData)
869{
870 LogFlowFuncEnter();
871
872 int rc = ShClSvcDataReadSignal(pClient, pCmdCtx, pData);
873
874 LogFlowFuncLeaveRC(rc);
875 return rc;
876}
877
878#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
879int ShClSvcImplTransferCreate(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
880{
881 RT_NOREF(pClient, pTransfer);
882
883 LogFlowFuncEnter();
884
885 return VINF_SUCCESS;
886}
887
888int ShClSvcImplTransferDestroy(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
889{
890 LogFlowFuncEnter();
891
892 SharedClipboardWinTransferDestroy(&pClient->State.pCtx->Win, pTransfer);
893
894 return VINF_SUCCESS;
895}
896
897int ShClSvcImplTransferGetRoots(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
898{
899 LogFlowFuncEnter();
900
901 const PSHCLWINCTX pWinCtx = &pClient->State.pCtx->Win;
902
903 int rc = SharedClipboardWinGetRoots(pWinCtx, pTransfer);
904
905 LogFlowFuncLeaveRC(rc);
906 return rc;
907}
908#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
909
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