VirtualBox

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

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

Shared Clipboard/Win: Don't leak allocated SHCLEVENTPAYLOAD struct.

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