VirtualBox

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

Last change on this file since 85416 was 85121, checked in by vboxsync, 4 years ago

iprt/cdefs.h: Refactored the typedef use of DECLCALLBACK as well as DECLCALLBACKMEMBER to wrap the whole expression, similar to the DECLR?CALLBACKMEMBER macros. This allows adding a throw() at the end when compiling with the VC++ compiler to indicate that the callbacks won't throw anything, so we can stop supressing the C5039 warning about passing functions that can potential throw C++ exceptions to extern C code that can't necessarily cope with such (unwind,++). Introduced a few _EX variations that allows specifying different/no calling convention too, as that's handy when dynamically resolving host APIs. Fixed numerous places missing DECLCALLBACK and such. Left two angry @todos regarding use of CreateThread. bugref:9794

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.3 KB
Line 
1/* $Id: VBoxSharedClipboardSvc-win.cpp 85121 2020-07-08 19:33:26Z vboxsync $ */
2/** @file
3 * Shared Clipboard Service - Win32 host.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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 <iprt/win/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 uFormat, void **ppvData, uint32_t *pcbData)
170{
171 SHCLFORMAT fFormat = SharedClipboardWinClipboardFormatToVBox(uFormat);
172 LogFlowFunc(("uFormat=%u -> uFmt=0x%x\n", uFormat, fFormat));
173
174 if (fFormat == VBOX_SHCL_FMT_NONE)
175 {
176 LogRel2(("Shared Clipbaord: Windows format %u not supported, ingoring\n", uFormat));
177 return VERR_NOT_SUPPORTED;
178 }
179
180 SHCLEVENTID idEvent = 0;
181 int rc = ShClSvcDataReadRequest(pCtx->pClient, fFormat, &idEvent);
182 if (RT_SUCCESS(rc))
183 {
184 PSHCLEVENTPAYLOAD pPayload;
185 rc = ShClEventWait(&pCtx->pClient->EventSrc, idEvent, 30 * 1000, &pPayload);
186 if (RT_SUCCESS(rc))
187 {
188 *ppvData = pPayload ? pPayload->pvData : NULL;
189 *pcbData = pPayload ? pPayload->cbData : 0;
190 }
191
192 ShClEventRelease(&pCtx->pClient->EventSrc, idEvent);
193 ShClEventUnregister(&pCtx->pClient->EventSrc, idEvent);
194 }
195
196 LogFlowFuncLeaveRC(rc);
197 return rc;
198}
199
200static LRESULT CALLBACK vboxClipboardSvcWinWndProcMain(PSHCLCONTEXT pCtx,
201 HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) RT_NOTHROW_DEF
202{
203 AssertPtr(pCtx);
204
205 LRESULT lresultRc = 0;
206
207 const PSHCLWINCTX pWinCtx = &pCtx->Win;
208
209 switch (uMsg)
210 {
211 case WM_CLIPBOARDUPDATE:
212 {
213 LogFunc(("WM_CLIPBOARDUPDATE\n"));
214
215 int rc = RTCritSectEnter(&pWinCtx->CritSect);
216 if (RT_SUCCESS(rc))
217 {
218 const HWND hWndClipboardOwner = GetClipboardOwner();
219
220 LogFunc(("WM_CLIPBOARDUPDATE: hWndClipboardOwnerUs=%p, hWndNewClipboardOwner=%p\n",
221 pWinCtx->hWndClipboardOwnerUs, hWndClipboardOwner));
222
223 if (pWinCtx->hWndClipboardOwnerUs != hWndClipboardOwner)
224 {
225 int rc2 = RTCritSectLeave(&pWinCtx->CritSect);
226 AssertRC(rc2);
227
228 /* Clipboard was updated by another application, retrieve formats and report back. */
229 rc = vboxClipboardSvcWinSyncInternal(pCtx);
230 }
231 else
232 {
233 int rc2 = RTCritSectLeave(&pWinCtx->CritSect);
234 AssertRC(rc2);
235 }
236 }
237
238 if (RT_FAILURE(rc))
239 LogRel(("Shared Clipboard: WM_CLIPBOARDUPDATE failed with %Rrc\n", rc));
240
241 break;
242 }
243
244 case WM_CHANGECBCHAIN:
245 {
246 LogFunc(("WM_CHANGECBCHAIN\n"));
247 lresultRc = SharedClipboardWinHandleWMChangeCBChain(pWinCtx, hWnd, uMsg, wParam, lParam);
248 break;
249 }
250
251 case WM_DRAWCLIPBOARD:
252 {
253 LogFunc(("WM_DRAWCLIPBOARD\n"));
254
255 int rc = RTCritSectEnter(&pWinCtx->CritSect);
256 if (RT_SUCCESS(rc))
257 {
258 const HWND hWndClipboardOwner = GetClipboardOwner();
259
260 LogFunc(("WM_DRAWCLIPBOARD: hWndClipboardOwnerUs=%p, hWndNewClipboardOwner=%p\n",
261 pWinCtx->hWndClipboardOwnerUs, hWndClipboardOwner));
262
263 if (pWinCtx->hWndClipboardOwnerUs != hWndClipboardOwner)
264 {
265 int rc2 = RTCritSectLeave(&pWinCtx->CritSect);
266 AssertRC(rc2);
267
268 /* Clipboard was updated by another application, retrieve formats and report back. */
269 rc = vboxClipboardSvcWinSyncInternal(pCtx);
270 }
271 else
272 {
273 int rc2 = RTCritSectLeave(&pWinCtx->CritSect);
274 AssertRC(rc2);
275 }
276 }
277
278 lresultRc = SharedClipboardWinChainPassToNext(pWinCtx, uMsg, wParam, lParam);
279 break;
280 }
281
282 case WM_TIMER:
283 {
284 int rc = SharedClipboardWinHandleWMTimer(pWinCtx);
285 AssertRC(rc);
286
287 break;
288 }
289
290 case WM_RENDERFORMAT:
291 {
292 LogFunc(("WM_RENDERFORMAT\n"));
293
294 /* Insert the requested clipboard format data into the clipboard. */
295 const UINT uFormat = (UINT)wParam;
296 const SHCLFORMAT fFormat = SharedClipboardWinClipboardFormatToVBox(uFormat);
297 LogFunc(("WM_RENDERFORMAT: uFormat=%u -> fFormat=0x%x\n", uFormat, fFormat));
298
299 if ( fFormat == VBOX_SHCL_FMT_NONE
300 || pCtx->pClient == NULL)
301 {
302 /* Unsupported clipboard format is requested. */
303 LogFunc(("WM_RENDERFORMAT unsupported format requested or client is not active\n"));
304 SharedClipboardWinClear();
305 }
306 else
307 {
308 void *pvData = NULL;
309 uint32_t cbData = 0;
310 int rc = vboxClipboardSvcWinDataRead(pCtx, uFormat, &pvData, &cbData);
311 if ( RT_SUCCESS(rc)
312 && pvData
313 && cbData)
314 {
315 rc = vboxClipboardSvcWinDataSet(pCtx, uFormat, pvData, cbData);
316
317 RTMemFree(pvData);
318 cbData = 0;
319 }
320
321 if (RT_FAILURE(rc))
322 SharedClipboardWinClear();
323 }
324
325 break;
326 }
327
328 case WM_RENDERALLFORMATS:
329 {
330 LogFunc(("WM_RENDERALLFORMATS\n"));
331
332 int rc = SharedClipboardWinHandleWMRenderAllFormats(pWinCtx, hWnd);
333 AssertRC(rc);
334
335 break;
336 }
337
338 case SHCL_WIN_WM_REPORT_FORMATS:
339 {
340 /* Announce available formats. Do not insert data -- will be inserted in WM_RENDERFORMAT (or via IDataObject). */
341 SHCLFORMATS fFormats = (uint32_t)lParam;
342 LogFunc(("SHCL_WIN_WM_REPORT_FORMATS: fFormats=0x%x\n", fFormats));
343
344#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
345 if (fFormats & VBOX_SHCL_FMT_URI_LIST)
346 {
347 PSHCLTRANSFER pTransfer;
348 int rc = shClSvcTransferStart(pCtx->pClient,
349 SHCLTRANSFERDIR_FROM_REMOTE, SHCLSOURCE_REMOTE,
350 &pTransfer);
351 if (RT_SUCCESS(rc))
352 {
353 /* Create the IDataObject implementation the host OS needs and assign
354 * the newly created transfer to this object. */
355 rc = SharedClipboardWinTransferCreate(&pCtx->Win, pTransfer);
356
357 /* Note: The actual requesting + retrieving of data will be done in the IDataObject implementation
358 (ClipboardDataObjectImpl::GetData()). */
359 }
360 else
361 LogRel(("Shared Clipboard: Initializing read transfer failed with %Rrc\n", rc));
362 }
363 else
364 {
365#endif
366 int rc = SharedClipboardWinOpen(hWnd);
367 if (RT_SUCCESS(rc))
368 {
369 SharedClipboardWinClear();
370
371 rc = SharedClipboardWinAnnounceFormats(pWinCtx, fFormats);
372
373 SharedClipboardWinClose();
374 }
375#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
376 }
377#endif
378 LogFunc(("SHCL_WIN_WM_REPORT_FORMATS: lastErr=%ld\n", GetLastError()));
379 break;
380 }
381
382 case WM_DESTROY:
383 {
384 LogFunc(("WM_DESTROY\n"));
385
386 int rc = SharedClipboardWinHandleWMDestroy(pWinCtx);
387 AssertRC(rc);
388
389 PostQuitMessage(0);
390 break;
391 }
392
393 default:
394 break;
395 }
396
397 LogFlowFunc(("LEAVE hWnd=%p, WM_ %u\n", hWnd, uMsg));
398 return DefWindowProc(hWnd, uMsg, wParam, lParam);
399}
400
401/**
402 * Static helper function for having a per-client proxy window instances.
403 */
404static LRESULT CALLBACK vboxClipboardSvcWinWndProcInstance(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) RT_NOTHROW_DEF
405{
406 LONG_PTR pUserData = GetWindowLongPtr(hWnd, GWLP_USERDATA);
407 AssertPtrReturn(pUserData, 0);
408
409 PSHCLCONTEXT pCtx = reinterpret_cast<PSHCLCONTEXT>(pUserData);
410 if (pCtx)
411 return vboxClipboardSvcWinWndProcMain(pCtx, hWnd, uMsg, wParam, lParam);
412
413 return 0;
414}
415
416/**
417 * Static helper function for routing Windows messages to a specific
418 * proxy window instance.
419 */
420static LRESULT CALLBACK vboxClipboardSvcWinWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) RT_NOTHROW_DEF
421{
422 /* Note: WM_NCCREATE is not the first ever message which arrives, but
423 * early enough for us. */
424 if (uMsg == WM_NCCREATE)
425 {
426 LogFlowFunc(("WM_NCCREATE\n"));
427
428 LPCREATESTRUCT pCS = (LPCREATESTRUCT)lParam;
429 AssertPtr(pCS);
430 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pCS->lpCreateParams);
431 SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)vboxClipboardSvcWinWndProcInstance);
432
433 return vboxClipboardSvcWinWndProcInstance(hWnd, uMsg, wParam, lParam);
434 }
435
436 /* No window associated yet. */
437 return DefWindowProc(hWnd, uMsg, wParam, lParam);
438}
439
440DECLCALLBACK(int) vboxClipboardSvcWinThread(RTTHREAD hThreadSelf, void *pvUser)
441{
442 LogFlowFuncEnter();
443
444 bool fThreadSignalled = false;
445
446 const PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pvUser;
447 AssertPtr(pCtx);
448 const PSHCLWINCTX pWinCtx = &pCtx->Win;
449
450 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
451
452 /* Register the Window Class. */
453 WNDCLASS wc;
454 RT_ZERO(wc);
455
456 wc.style = CS_NOCLOSE;
457 wc.lpfnWndProc = vboxClipboardSvcWinWndProc;
458 wc.hInstance = hInstance;
459 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
460
461 /* Register an unique wnd class name. */
462 char szWndClassName[32];
463 RTStrPrintf2(szWndClassName, sizeof(szWndClassName),
464 "%s-%RU64", SHCL_WIN_WNDCLASS_NAME, RTThreadGetNative(hThreadSelf));
465 wc.lpszClassName = szWndClassName;
466
467 int rc;
468
469 ATOM atomWindowClass = RegisterClass(&wc);
470 if (atomWindowClass == 0)
471 {
472 LogFunc(("Failed to register window class\n"));
473 rc = VERR_NOT_SUPPORTED;
474 }
475 else
476 {
477 /* Create a window and make it a clipboard viewer. */
478 pWinCtx->hWnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
479 szWndClassName, szWndClassName,
480 WS_POPUPWINDOW,
481 -200, -200, 100, 100, NULL, NULL, hInstance, pCtx /* lpParam */);
482 if (pWinCtx->hWnd == NULL)
483 {
484 LogFunc(("Failed to create window\n"));
485 rc = VERR_NOT_SUPPORTED;
486 }
487 else
488 {
489 SetWindowPos(pWinCtx->hWnd, HWND_TOPMOST, -200, -200, 0, 0,
490 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
491
492 rc = SharedClipboardWinChainAdd(&pCtx->Win);
493 if (RT_SUCCESS(rc))
494 {
495 if (!SharedClipboardWinIsNewAPI(&pWinCtx->newAPI))
496 pWinCtx->oldAPI.timerRefresh = SetTimer(pWinCtx->hWnd, 0, 10 * 1000, NULL);
497 }
498
499#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
500 if (RT_SUCCESS(rc))
501 {
502 HRESULT hr = OleInitialize(NULL);
503 if (FAILED(hr))
504 {
505 LogRel(("Shared Clipboard: Initializing window thread OLE failed (%Rhrc) -- file transfers unavailable\n", hr));
506 /* Not critical, the rest of the clipboard might work. */
507 }
508 else
509 LogRel(("Shared Clipboard: Initialized window thread OLE\n"));
510 }
511#endif
512 int rc2 = RTThreadUserSignal(hThreadSelf);
513 AssertRC(rc2);
514
515 fThreadSignalled = true;
516
517 MSG msg;
518 BOOL msgret = 0;
519 while ((msgret = GetMessage(&msg, NULL, 0, 0)) > 0)
520 {
521 TranslateMessage(&msg);
522 DispatchMessage(&msg);
523 }
524
525 /*
526 * Window procedure can return error, * but this is exceptional situation that should be
527 * identified in testing.
528 */
529 Assert(msgret >= 0);
530 LogFunc(("Message loop finished. GetMessage returned %d, message id: %d \n", msgret, msg.message));
531
532#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
533 OleSetClipboard(NULL); /* Make sure to flush the clipboard on destruction. */
534 OleUninitialize();
535#endif
536 }
537 }
538
539 pWinCtx->hWnd = NULL;
540
541 if (atomWindowClass != 0)
542 {
543 UnregisterClass(szWndClassName, hInstance);
544 atomWindowClass = 0;
545 }
546
547 if (!fThreadSignalled)
548 {
549 int rc2 = RTThreadUserSignal(hThreadSelf);
550 AssertRC(rc2);
551 }
552
553 LogFlowFuncLeaveRC(rc);
554 return rc;
555}
556
557/**
558 * Synchronizes the host and the guest clipboard formats by sending all supported host clipboard
559 * formats to the guest.
560 *
561 * @returns VBox status code, VINF_NO_CHANGE if no synchronization was required.
562 * @param pCtx Clipboard context to synchronize.
563 */
564static int vboxClipboardSvcWinSyncInternal(PSHCLCONTEXT pCtx)
565{
566 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
567
568 LogFlowFuncEnter();
569
570 int rc;
571
572 if (pCtx->pClient)
573 {
574 SHCLFORMATS fFormats = 0;
575 rc = SharedClipboardWinGetFormats(&pCtx->Win, &fFormats);
576 if ( RT_SUCCESS(rc)
577 && fFormats != VBOX_SHCL_FMT_NONE) /** @todo r=bird: BUGBUG: revisit this. */
578 rc = ShClSvcHostReportFormats(pCtx->pClient, fFormats);
579 }
580 else /* If we don't have any client data (yet), bail out. */
581 rc = VINF_NO_CHANGE;
582
583 LogFlowFuncLeaveRC(rc);
584 return rc;
585}
586
587/*
588 * Public platform dependent functions.
589 */
590
591int ShClBackendInit(void)
592{
593#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
594 HRESULT hr = OleInitialize(NULL);
595 if (FAILED(hr))
596 {
597 LogRel(("Shared Clipboard: Initializing OLE failed (%Rhrc) -- file transfers unavailable\n", hr));
598 /* Not critical, the rest of the clipboard might work. */
599 }
600 else
601 LogRel(("Shared Clipboard: Initialized OLE\n"));
602#endif
603
604 return VINF_SUCCESS;
605}
606
607void ShClBackendDestroy(void)
608{
609#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
610 OleSetClipboard(NULL); /* Make sure to flush the clipboard on destruction. */
611 OleUninitialize();
612#endif
613}
614
615int ShClBackendConnect(PSHCLCLIENT pClient, bool fHeadless)
616{
617 RT_NOREF(fHeadless);
618
619 LogFlowFuncEnter();
620
621 int rc;
622
623 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)RTMemAllocZ(sizeof(SHCLCONTEXT));
624 if (pCtx)
625 {
626 rc = SharedClipboardWinCtxInit(&pCtx->Win);
627 if (RT_SUCCESS(rc))
628 {
629 rc = RTThreadCreate(&pCtx->hThread, vboxClipboardSvcWinThread, pCtx /* pvUser */, _64K /* Stack size */,
630 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
631 if (RT_SUCCESS(rc))
632 {
633 int rc2 = RTThreadUserWait(pCtx->hThread, 30 * 1000 /* Timeout in ms */);
634 AssertRC(rc2);
635 }
636 }
637
638 pClient->State.pCtx = pCtx;
639 pClient->State.pCtx->pClient = pClient;
640 }
641 else
642 rc = VERR_NO_MEMORY;
643
644 LogFlowFuncLeaveRC(rc);
645 return rc;
646}
647
648int ShClBackendSync(PSHCLCLIENT pClient)
649{
650 /* Sync the host clipboard content with the client. */
651 return vboxClipboardSvcWinSyncInternal(pClient->State.pCtx);
652}
653
654int ShClBackendDisconnect(PSHCLCLIENT pClient)
655{
656 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
657
658 LogFlowFuncEnter();
659
660 int rc = VINF_SUCCESS;
661
662 PSHCLCONTEXT pCtx = pClient->State.pCtx;
663 if (pCtx)
664 {
665 if (pCtx->Win.hWnd)
666 PostMessage(pCtx->Win.hWnd, WM_DESTROY, 0 /* wParam */, 0 /* lParam */);
667
668 if (pCtx->hThread != NIL_RTTHREAD)
669 {
670 LogFunc(("Waiting for thread to terminate ...\n"));
671
672 /* Wait for the window thread to terminate. */
673 rc = RTThreadWait(pCtx->hThread, 30 * 1000 /* Timeout in ms */, NULL);
674 if (RT_FAILURE(rc))
675 LogRel(("Shared Clipboard: Waiting for window thread termination failed with rc=%Rrc\n", rc));
676
677 pCtx->hThread = NIL_RTTHREAD;
678 }
679
680 SharedClipboardWinCtxDestroy(&pCtx->Win);
681
682 if (RT_SUCCESS(rc))
683 {
684 RTMemFree(pCtx);
685 pCtx = NULL;
686
687 pClient->State.pCtx = NULL;
688 }
689 }
690
691 LogFlowFuncLeaveRC(rc);
692 return rc;
693}
694
695int ShClBackendFormatAnnounce(PSHCLCLIENT pClient, SHCLFORMATS fFormats)
696{
697 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
698
699 PSHCLCONTEXT pCtx = pClient->State.pCtx;
700 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
701
702 LogFlowFunc(("fFormats=0x%x, hWnd=%p\n", fFormats, pCtx->Win.hWnd));
703
704 /*
705 * The guest announced formats. Forward to the window thread.
706 */
707 PostMessage(pCtx->Win.hWnd, SHCL_WIN_WM_REPORT_FORMATS,
708 0 /* wParam */, fFormats /* lParam */);
709
710
711 LogFlowFuncLeaveRC(VINF_SUCCESS);
712 return VINF_SUCCESS;
713}
714
715int ShClBackendReadData(PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx,
716 SHCLFORMAT uFormat, void *pvData, uint32_t cbData, uint32_t *pcbActual)
717{
718 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
719 RT_NOREF(pCmdCtx);
720 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
721 AssertPtrReturn(pClient->State.pCtx, VERR_INVALID_POINTER);
722
723 LogFlowFunc(("uFormat=%02X\n", uFormat));
724
725 HANDLE hClip = NULL;
726
727 const PSHCLWINCTX pWinCtx = &pClient->State.pCtx->Win;
728
729 /*
730 * The guest wants to read data in the given format.
731 */
732 int rc = SharedClipboardWinOpen(pWinCtx->hWnd);
733 if (RT_SUCCESS(rc))
734 {
735 LogFunc(("Clipboard opened\n"));
736
737 if (uFormat & VBOX_SHCL_FMT_BITMAP)
738 {
739 hClip = GetClipboardData(CF_DIB);
740 if (hClip != NULL)
741 {
742 LPVOID lp = GlobalLock(hClip);
743
744 if (lp != NULL)
745 {
746 LogFunc(("CF_DIB\n"));
747
748 vboxClipboardSvcWinGetData(VBOX_SHCL_FMT_BITMAP, lp, GlobalSize(hClip),
749 pvData, cbData, pcbActual);
750
751 GlobalUnlock(hClip);
752 }
753 else
754 {
755 hClip = NULL;
756 }
757 }
758 }
759 else if (uFormat & VBOX_SHCL_FMT_UNICODETEXT)
760 {
761 hClip = GetClipboardData(CF_UNICODETEXT);
762 if (hClip != NULL)
763 {
764 LPWSTR uniString = (LPWSTR)GlobalLock(hClip);
765
766 if (uniString != NULL)
767 {
768 LogFunc(("CF_UNICODETEXT\n"));
769
770 vboxClipboardSvcWinGetData(VBOX_SHCL_FMT_UNICODETEXT, uniString, (lstrlenW(uniString) + 1) * 2,
771 pvData, cbData, pcbActual);
772
773 GlobalUnlock(hClip);
774 }
775 else
776 {
777 hClip = NULL;
778 }
779 }
780 }
781 else if (uFormat & VBOX_SHCL_FMT_HTML)
782 {
783 UINT format = RegisterClipboardFormat(SHCL_WIN_REGFMT_HTML);
784 if (format != 0)
785 {
786 hClip = GetClipboardData(format);
787 if (hClip != NULL)
788 {
789 LPVOID lp = GlobalLock(hClip);
790 if (lp != NULL)
791 {
792 /** @todo r=andy Add data overflow handling. */
793 vboxClipboardSvcWinGetData(VBOX_SHCL_FMT_HTML, lp, GlobalSize(hClip),
794 pvData, cbData, pcbActual);
795#ifdef VBOX_STRICT
796 LogFlowFunc(("Raw HTML clipboard data from host:"));
797 ShClDbgDumpHtml((char *)pvData, cbData);
798#endif
799 GlobalUnlock(hClip);
800 }
801 else
802 {
803 hClip = NULL;
804 }
805 }
806 }
807 }
808#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
809 else if (uFormat & VBOX_SHCL_FMT_URI_LIST)
810 {
811 AssertFailed(); /** @todo */
812 }
813#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
814 SharedClipboardWinClose();
815 }
816
817 if (hClip == NULL)
818 {
819 /* Reply with empty data. */
820 vboxClipboardSvcWinGetData(0, NULL, 0, pvData, cbData, pcbActual);
821 }
822
823 LogFlowFuncLeaveRC(rc);
824 return rc;
825}
826
827int ShClBackendWriteData(PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx,
828 SHCLFORMAT uFormat, void *pvData, uint32_t cbData)
829{
830 LogFlowFuncEnter();
831
832 int rc = ShClSvcDataReadSignal(pClient, pCmdCtx, uFormat, pvData, cbData);
833
834 LogFlowFuncLeaveRC(rc);
835 return rc;
836}
837
838#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
839int ShClBackendTransferCreate(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
840{
841 RT_NOREF(pClient, pTransfer);
842
843 LogFlowFuncEnter();
844
845 return VINF_SUCCESS;
846}
847
848int ShClBackendTransferDestroy(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
849{
850 LogFlowFuncEnter();
851
852 SharedClipboardWinTransferDestroy(&pClient->State.pCtx->Win, pTransfer);
853
854 return VINF_SUCCESS;
855}
856
857int ShClBackendTransferGetRoots(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
858{
859 LogFlowFuncEnter();
860
861 const PSHCLWINCTX pWinCtx = &pClient->State.pCtx->Win;
862
863 int rc = SharedClipboardWinGetRoots(pWinCtx, pTransfer);
864
865 LogFlowFuncLeaveRC(rc);
866 return rc;
867}
868#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
869
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