VirtualBox

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

Last change on this file since 93919 was 93919, checked in by vboxsync, 3 years ago

Shared Clipboard: Resolved a @todo (renamed ShClBackendFormatAnnounce -> ShClBackendReportFormats).

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