VirtualBox

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

Last change on this file since 79497 was 79497, checked in by vboxsync, 6 years ago

Shared Clipboard/URI: Update.

  • 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 79497 2019-07-03 13:28:33Z 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_URI_LIST
29# include <VBox/GuestHost/SharedClipboard-uri.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_URI_LIST
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_URI_LIST
48# include "VBoxSharedClipboardSvc-uri.h"
49#endif
50
51
52/*********************************************************************************************************************************
53* Internal Functions *
54*********************************************************************************************************************************/
55static int vboxClipboardSvcWinSyncInternal(PVBOXCLIPBOARDCONTEXT pCtx);
56
57struct _VBOXCLIPBOARDCONTEXT
58{
59 /** Handle for window message handling thread. */
60 RTTHREAD hThread;
61 /** Event which gets triggered if the host clipboard needs to render its data. */
62 RTSEMEVENT hRenderEvent;
63 /** Structure for keeping and communicating with client data (from the guest). */
64 PVBOXCLIPBOARDCLIENTDATA pClientData;
65 /** Windows-specific context data. */
66 VBOXCLIPBOARDWINCTX Win;
67};
68
69
70/** @todo Someone please explain the protocol wrt overflows... */
71static void vboxClipboardGetData(uint32_t u32Format, const void *pvSrc, uint32_t cbSrc,
72 void *pvDst, uint32_t cbDst, uint32_t *pcbActualDst)
73{
74 LogFlowFunc(("cbSrc = %d, cbDst = %d\n", cbSrc, cbDst));
75
76 if ( u32Format == VBOX_SHARED_CLIPBOARD_FMT_HTML
77 && VBoxClipboardWinIsCFHTML((const char *)pvSrc))
78 {
79 /** @todo r=bird: Why the double conversion? */
80 char *pszBuf = NULL;
81 uint32_t cbBuf = 0;
82 int rc = VBoxClipboardWinConvertCFHTMLToMIME((const char *)pvSrc, cbSrc, &pszBuf, &cbBuf);
83 if (RT_SUCCESS(rc))
84 {
85 *pcbActualDst = cbBuf;
86 if (cbBuf > cbDst)
87 {
88 /* Do not copy data. The dst buffer is not enough. */
89 RTMemFree(pszBuf);
90 return;
91 }
92 memcpy(pvDst, pszBuf, cbBuf);
93 RTMemFree(pszBuf);
94 }
95 else
96 *pcbActualDst = 0;
97 }
98 else
99 {
100 *pcbActualDst = cbSrc;
101
102 if (cbSrc > cbDst)
103 {
104 /* Do not copy data. The dst buffer is not enough. */
105 return;
106 }
107
108 memcpy(pvDst, pvSrc, cbSrc);
109 }
110
111#ifdef LOG_ENABLED
112 VBoxClipboardDbgDumpData(pvDst, cbSrc, u32Format);
113#endif
114
115 return;
116}
117
118/**
119 * Requests data of a specific format from the guest, optionally waiting for its arrival via VBoxClipboardSvcImplWriteData().
120 *
121 * @returns VBox status code.
122 * @param pCtx Clipboard context to use.
123 * @param fFormat Format to receive data in.
124 * @param uTimeoutMs Timeout (in ms) to wait until the render event has been triggered.
125 * Specify 0 if no waiting is required.
126 */
127static int vboxClipboardSvcWinRequestData(PVBOXCLIPBOARDCONTEXT pCtx, VBOXCLIPBOARDFORMAT fFormat,
128 RTMSINTERVAL uTimeoutMs)
129{
130 AssertPtr(pCtx->pClientData);
131 Assert(pCtx->hRenderEvent);
132 Assert(pCtx->pClientData->State.data.pv == NULL && pCtx->pClientData->State.data.cb == 0 && pCtx->pClientData->State.data.u32Format == 0);
133
134 LogFlowFunc(("fFormat=%02X, uTimeoutMs=%RU32\n", fFormat, uTimeoutMs));
135
136 int rc = vboxSvcClipboardReportMsg(pCtx->pClientData, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA, fFormat);
137 if ( RT_SUCCESS(rc)
138 && uTimeoutMs)
139 {
140 rc = RTSemEventWait(pCtx->hRenderEvent, uTimeoutMs /* Timeout in ms */);
141 }
142
143 LogFlowFuncLeaveRC(rc);
144 return rc;
145}
146
147static LRESULT CALLBACK vboxClipboardSvcWinWndProcMain(PVBOXCLIPBOARDCONTEXT pCtx,
148 HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
149{
150 AssertPtr(pCtx);
151
152 LRESULT lresultRc = 0;
153
154 const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win;
155
156 switch (uMsg)
157 {
158 case WM_CLIPBOARDUPDATE:
159 {
160 const HWND hWndClipboardOwner = GetClipboardOwner();
161 if (pWinCtx->hWndClipboardOwnerUs != hWndClipboardOwner)
162 {
163 LogFunc(("WM_CLIPBOARDUPDATE: hWndClipboardOwnerUs=%p, hWndNewClipboardOwner=%p\n",
164 pWinCtx->hWndClipboardOwnerUs, hWndClipboardOwner));
165
166 /* Clipboard was updated by another application, retrieve formats and report back. */
167 int rc = vboxClipboardSvcWinSyncInternal(pCtx);
168 AssertRC(rc);
169
170 vboxSvcClipboardSetSource(pCtx->pClientData, SHAREDCLIPBOARDSOURCE_LOCAL);
171 }
172 } break;
173
174 case WM_CHANGECBCHAIN:
175 {
176 LogFunc(("WM_CHANGECBCHAIN\n"));
177 lresultRc = VBoxClipboardWinHandleWMChangeCBChain(pWinCtx, hWnd, uMsg, wParam, lParam);
178 } break;
179
180 case WM_DRAWCLIPBOARD:
181 {
182 LogFunc(("WM_DRAWCLIPBOARD\n"));
183
184 if (GetClipboardOwner() != hWnd)
185 {
186 /* Clipboard was updated by another application, retrieve formats and report back. */
187 int rc = vboxClipboardSvcWinSyncInternal(pCtx);
188 if (RT_SUCCESS(rc))
189 vboxSvcClipboardSetSource(pCtx->pClientData, SHAREDCLIPBOARDSOURCE_LOCAL);
190 }
191
192 lresultRc = VBoxClipboardWinChainPassToNext(pWinCtx, uMsg, wParam, lParam);
193
194 } break;
195
196 case WM_TIMER:
197 {
198 int rc = VBoxClipboardWinHandleWMTimer(pWinCtx);
199 AssertRC(rc);
200 } break;
201
202 case WM_RENDERFORMAT:
203 {
204 LogFunc(("WM_RENDERFORMAT\n"));
205
206 /* Insert the requested clipboard format data into the clipboard. */
207 const UINT cfFormat = (UINT)wParam;
208
209 const VBOXCLIPBOARDFORMAT fFormat = VBoxClipboardWinClipboardFormatToVBox(cfFormat);
210
211 LogFunc(("WM_RENDERFORMAT: cfFormat=%u -> fFormat=0x%x\n", cfFormat, fFormat));
212
213 if ( fFormat == VBOX_SHARED_CLIPBOARD_FMT_NONE
214 || pCtx->pClientData == NULL)
215 {
216 /* Unsupported clipboard format is requested. */
217 LogFunc(("WM_RENDERFORMAT unsupported format requested or client is not active\n"));
218 VBoxClipboardWinClear();
219 }
220 else
221 {
222 int rc = vboxClipboardSvcWinRequestData(pCtx, fFormat, 30 * 1000 /* 30s timeout */);
223
224 LogFlowFunc(("rc=%Rrc, pv=%p, cb=%RU32, u32Format=%RU32\n",
225 rc, pCtx->pClientData->State.data.pv, pCtx->pClientData->State.data.cb,
226 pCtx->pClientData->State.data.u32Format));
227
228 if ( RT_SUCCESS (rc)
229 && pCtx->pClientData->State.data.pv != NULL
230 && pCtx->pClientData->State.data.cb > 0
231 && pCtx->pClientData->State.data.u32Format == fFormat)
232 {
233 HANDLE hMem = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, pCtx->pClientData->State.data.cb);
234
235 LogFlowFunc(("hMem=%p\n", hMem));
236
237 if (hMem)
238 {
239 void *pMem = GlobalLock(hMem);
240
241 LogFlowFunc(("pMem=%p, GlobalSize=%zu\n", pMem, GlobalSize(hMem)));
242
243 if (pMem)
244 {
245 LogFlowFunc(("WM_RENDERFORMAT: Setting data\n"));
246
247 if (pCtx->pClientData->State.data.pv)
248 {
249 memcpy(pMem, pCtx->pClientData->State.data.pv, pCtx->pClientData->State.data.cb);
250
251 RTMemFree(pCtx->pClientData->State.data.pv);
252 pCtx->pClientData->State.data.pv = NULL;
253 }
254
255 pCtx->pClientData->State.data.cb = 0;
256 pCtx->pClientData->State.data.u32Format = 0;
257
258 /* The memory must be unlocked before inserting to the Clipboard. */
259 GlobalUnlock(hMem);
260
261 /* 'hMem' contains the host clipboard data.
262 * size is 'cb' and format is 'format'.
263 */
264 HANDLE hClip = SetClipboardData(cfFormat, hMem);
265
266 LogFlowFunc(("hClip=%p\n", hClip));
267
268 if (hClip)
269 {
270 /* The hMem ownership has gone to the system. Nothing to do. */
271 break;
272 }
273 }
274
275 GlobalFree(hMem);
276 }
277 }
278
279 RTMemFree(pCtx->pClientData->State.data.pv);
280 pCtx->pClientData->State.data.pv = NULL;
281 pCtx->pClientData->State.data.cb = 0;
282 pCtx->pClientData->State.data.u32Format = 0;
283
284 /* Something went wrong. */
285 VBoxClipboardWinClear();
286 }
287 } break;
288
289 case WM_RENDERALLFORMATS:
290 {
291 LogFunc(("WM_RENDERALLFORMATS\n"));
292
293 int rc = VBoxClipboardWinHandleWMRenderAllFormats(pWinCtx, hWnd);
294 AssertRC(rc);
295 } break;
296
297 case VBOX_CLIPBOARD_WM_SET_FORMATS:
298 {
299 LogFunc(("VBOX_CLIPBOARD_WM_SET_FORMATS\n"));
300
301 if ( pCtx->pClientData == NULL
302 || pCtx->pClientData->State.fHostMsgFormats)
303 {
304 /* Host has pending formats message. Ignore the guest announcement,
305 * because host clipboard has more priority.
306 */
307 LogFunc(("VBOX_CLIPBOARD_WM_SET_FORMATS ignored; pClientData=%p\n", pCtx->pClientData));
308 break;
309 }
310
311 /* Announce available formats. Do not insert data -- will be inserted in WM_RENDERFORMAT. */
312 VBOXCLIPBOARDFORMATS fFormats = (uint32_t)lParam;
313 if (fFormats != VBOX_SHARED_CLIPBOARD_FMT_NONE) /* Could arrive with some older GA versions. */
314 {
315 int rc = VBoxClipboardWinOpen(hWnd);
316 if (RT_SUCCESS(rc))
317 {
318 VBoxClipboardWinClear();
319
320#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
321 if (fFormats & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
322 {
323 LogFunc(("VBOX_SHARED_CLIPBOARD_FMT_URI_LIST\n"));
324
325 PSHAREDCLIPBOARDURITRANSFER pTransfer = SharedClipboardURICtxGetTransfer(&pCtx->pClientData->URI,
326 0 /* uIdx */);
327 if (pTransfer)
328 {
329 rc = VBoxClipboardWinURITransferCreate(pWinCtx, pTransfer);
330
331 /* Note: The actual requesting + retrieving of data will be done in the IDataObject implementation
332 (ClipboardDataObjectImpl::GetData()). */
333 }
334 else
335 AssertFailedStmt(rc = VERR_NOT_FOUND);
336
337 /* Note: VBoxClipboardWinURITransferCreate() takes care of closing the clipboard. */
338 }
339 else
340 {
341#endif
342 rc = VBoxClipboardWinAnnounceFormats(pWinCtx, fFormats);
343
344 VBoxClipboardWinClose();
345#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
346 }
347#endif
348 }
349
350 if (RT_FAILURE(rc))
351 LogFunc(("Failed with rc=%Rrc\n", rc));
352 }
353 LogFunc(("VBOX_CLIPBOARD_WM_SET_FORMATS: fFormats=0x%x, lastErr=%ld\n", fFormats, GetLastError()));
354 } break;
355
356 case WM_DESTROY:
357 {
358 LogFunc(("WM_DESTROY\n"));
359
360 int rc = VBoxClipboardWinHandleWMDestroy(pWinCtx);
361 AssertRC(rc);
362
363 PostQuitMessage(0);
364 } break;
365
366 default:
367 break;
368 }
369
370 LogFlowFunc(("hWnd=%p, WM_ %u\n", hWnd, uMsg));
371 return DefWindowProc(hWnd, uMsg, wParam, lParam);
372}
373
374/**
375 * Static helper function for having a per-client proxy window instances.
376 */
377static LRESULT CALLBACK vboxClipboardSvcWinWndProcInstance(HWND hWnd, UINT uMsg,
378 WPARAM wParam, LPARAM lParam)
379{
380 LONG_PTR pUserData = GetWindowLongPtr(hWnd, GWLP_USERDATA);
381 AssertPtrReturn(pUserData, 0);
382
383 PVBOXCLIPBOARDCONTEXT pCtx = reinterpret_cast<PVBOXCLIPBOARDCONTEXT>(pUserData);
384 if (pCtx)
385 return vboxClipboardSvcWinWndProcMain(pCtx, hWnd, uMsg, wParam, lParam);
386
387 return 0;
388}
389
390/**
391 * Static helper function for routing Windows messages to a specific
392 * proxy window instance.
393 */
394static LRESULT CALLBACK vboxClipboardSvcWinWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
395{
396 /* Note: WM_NCCREATE is not the first ever message which arrives, but
397 * early enough for us. */
398 if (uMsg == WM_NCCREATE)
399 {
400 LogFlowFunc(("WM_NCCREATE\n"));
401
402 LPCREATESTRUCT pCS = (LPCREATESTRUCT)lParam;
403 AssertPtr(pCS);
404 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pCS->lpCreateParams);
405 SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)vboxClipboardSvcWinWndProcInstance);
406
407 return vboxClipboardSvcWinWndProcInstance(hWnd, uMsg, wParam, lParam);
408 }
409
410 /* No window associated yet. */
411 return DefWindowProc(hWnd, uMsg, wParam, lParam);
412}
413
414DECLCALLBACK(int) vboxClipboardSvcWinThread(RTTHREAD hThreadSelf, void *pvUser)
415{
416 LogFlowFuncEnter();
417
418 bool fThreadSignalled = false;
419
420 const PVBOXCLIPBOARDCONTEXT pCtx = (PVBOXCLIPBOARDCONTEXT)pvUser;
421 AssertPtr(pCtx);
422 const PVBOXCLIPBOARDWINCTX pWinCtx = &pCtx->Win;
423
424 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
425
426 /* Register the Window Class. */
427 WNDCLASS wc;
428 RT_ZERO(wc);
429
430 wc.style = CS_NOCLOSE;
431 wc.lpfnWndProc = vboxClipboardSvcWinWndProc;
432 wc.hInstance = hInstance;
433 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
434
435 /* Register an unique wnd class name. */
436 char szWndClassName[32];
437 RTStrPrintf2(szWndClassName, sizeof(szWndClassName),
438 "%s-%RU64", VBOX_CLIPBOARD_WNDCLASS_NAME, RTThreadGetNative(hThreadSelf));
439 wc.lpszClassName = szWndClassName;
440
441 int rc;
442
443 ATOM atomWindowClass = RegisterClass(&wc);
444 if (atomWindowClass == 0)
445 {
446 LogFunc(("Failed to register window class\n"));
447 rc = VERR_NOT_SUPPORTED;
448 }
449 else
450 {
451 /* Create a window and make it a clipboard viewer. */
452 pWinCtx->hWnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
453 szWndClassName, szWndClassName,
454 WS_POPUPWINDOW,
455 -200, -200, 100, 100, NULL, NULL, hInstance, pCtx /* lpParam */);
456 if (pWinCtx->hWnd == NULL)
457 {
458 LogFunc(("Failed to create window\n"));
459 rc = VERR_NOT_SUPPORTED;
460 }
461 else
462 {
463 SetWindowPos(pWinCtx->hWnd, HWND_TOPMOST, -200, -200, 0, 0,
464 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
465
466 rc = VBoxClipboardWinChainAdd(&pCtx->Win);
467 if (RT_SUCCESS(rc))
468 {
469 if (!VBoxClipboardWinIsNewAPI(&pWinCtx->newAPI))
470 pWinCtx->oldAPI.timerRefresh = SetTimer(pWinCtx->hWnd, 0, 10 * 1000, NULL);
471 }
472
473#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
474 if (RT_SUCCESS(rc))
475 {
476 HRESULT hr = OleInitialize(NULL);
477 if (FAILED(hr))
478 {
479 LogRel(("Clipboard: Initializing OLE failed (%Rhrc) -- file transfers unavailable\n"));
480 /* Not critical, the rest of the clipboard might work. */
481 }
482 else
483 LogRel(("Clipboard: Initialized OLE\n"));
484 }
485#endif
486
487 int rc2 = RTThreadUserSignal(hThreadSelf);
488 AssertRC(rc2);
489
490 fThreadSignalled = true;
491
492 MSG msg;
493 BOOL msgret = 0;
494 while ((msgret = GetMessage(&msg, NULL, 0, 0)) > 0)
495 {
496 TranslateMessage(&msg);
497 DispatchMessage(&msg);
498 }
499
500 /*
501 * Window procedure can return error, * but this is exceptional situation that should be
502 * identified in testing.
503 */
504 Assert(msgret >= 0);
505 LogFunc(("Message loop finished. GetMessage returned %d, message id: %d \n", msgret, msg.message));
506
507#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
508 OleSetClipboard(NULL); /* Make sure to flush the clipboard on destruction. */
509 OleUninitialize();
510#endif
511 }
512 }
513
514 pWinCtx->hWnd = NULL;
515
516 if (atomWindowClass != 0)
517 {
518 UnregisterClass(szWndClassName, hInstance);
519 atomWindowClass = 0;
520 }
521
522 if (!fThreadSignalled)
523 {
524 int rc2 = RTThreadUserSignal(hThreadSelf);
525 AssertRC(rc2);
526 }
527
528 LogFlowFuncLeaveRC(rc);
529 return rc;
530}
531
532/**
533 * Synchronizes the host and the guest clipboard formats by sending all supported host clipboard
534 * formats to the guest.
535 *
536 * @returns VBox status code, VINF_NO_CHANGE if no synchronization was required.
537 * @param pCtx Clipboard context to synchronize.
538 */
539static int vboxClipboardSvcWinSyncInternal(PVBOXCLIPBOARDCONTEXT pCtx)
540{
541 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
542
543 LogFlowFuncEnter();
544
545 int rc;
546
547 if (pCtx->pClientData)
548 {
549 VBOXCLIPBOARDFORMATS uFormats = VBOX_SHARED_CLIPBOARD_FMT_NONE;
550 rc = VBoxClipboardWinGetFormats(&pCtx->Win, &uFormats);
551 if ( RT_SUCCESS(rc)
552 && uFormats != VBOX_SHARED_CLIPBOARD_FMT_NONE
553#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
554 /* For URI handling we don't need to sync the format. */
555 && !(uFormats & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
556#endif
557 )
558 {
559 vboxSvcClipboardReportMsg(pCtx->pClientData, VBOX_SHARED_CLIPBOARD_HOST_MSG_REPORT_FORMATS, uFormats);
560 }
561 }
562 else /* If we don't have any client data (yet), bail out. */
563 rc = VINF_NO_CHANGE;
564
565 LogFlowFuncLeaveRC(rc);
566 return rc;
567}
568
569/*
570 * Public platform dependent functions.
571 */
572
573int VBoxClipboardSvcImplInit(void)
574{
575 /* Initialization is done in VBoxClipboardSvcImplConnect(). */
576 return VINF_SUCCESS;
577}
578
579void VBoxClipboardSvcImplDestroy(void)
580{
581 /* Destruction is done in VBoxClipboardSvcImplDisconnect(). */
582}
583
584int VBoxClipboardSvcImplConnect(PVBOXCLIPBOARDCLIENTDATA pClientData, bool fHeadless)
585{
586 RT_NOREF(fHeadless);
587
588 AssertPtrReturn(pClientData, VERR_INVALID_POINTER);
589
590 LogFlowFuncEnter();
591
592 int rc;
593
594 PVBOXCLIPBOARDCONTEXT pCtx = (PVBOXCLIPBOARDCONTEXT)RTMemAllocZ(sizeof(VBOXCLIPBOARDCONTEXT));
595 if (pCtx)
596 {
597 /* Check that new Clipboard API is available. */
598 rc = VBoxClipboardWinCheckAndInitNewAPI(&pCtx->Win.newAPI);
599 if (RT_SUCCESS(rc))
600 {
601 rc = RTSemEventCreate(&pCtx->hRenderEvent);
602 if (RT_SUCCESS(rc))
603 {
604 rc = RTThreadCreate(&pCtx->hThread, vboxClipboardSvcWinThread, pCtx /* pvUser */, _64K /* Stack size */,
605 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP");
606 if (RT_SUCCESS(rc))
607 {
608 int rc2 = RTThreadUserWait(pCtx->hThread, 30 * 1000 /* Timeout in ms */);
609 AssertRC(rc2);
610 }
611 }
612
613 if (RT_FAILURE(rc))
614 RTSemEventDestroy(pCtx->hRenderEvent);
615 }
616
617 pClientData->State.pCtx = pCtx;
618 pClientData->State.pCtx->pClientData = pClientData;
619
620 /* Sync the host clipboard content with the client. */
621 rc = VBoxClipboardSvcImplSync(pClientData);
622 }
623 else
624 rc = VERR_NO_MEMORY;
625
626 LogFlowFuncLeaveRC(rc);
627 return rc;
628}
629
630int VBoxClipboardSvcImplSync(PVBOXCLIPBOARDCLIENTDATA pClientData)
631{
632 /* Sync the host clipboard content with the client. */
633 return vboxClipboardSvcWinSyncInternal(pClientData->State.pCtx);
634}
635
636int VBoxClipboardSvcImplDisconnect(PVBOXCLIPBOARDCLIENTDATA pClientData)
637{
638 AssertPtrReturn(pClientData, VERR_INVALID_POINTER);
639
640 LogFlowFuncEnter();
641
642 int rc = VINF_SUCCESS;
643
644 PVBOXCLIPBOARDCONTEXT pCtx = pClientData->State.pCtx;
645 if (pCtx)
646 {
647 if (pCtx->Win.hWnd)
648 PostMessage(pCtx->Win.hWnd, WM_CLOSE, 0 /* wParam */, 0 /* lParam */);
649
650 rc = RTSemEventDestroy(pCtx->hRenderEvent);
651 if (RT_SUCCESS(rc))
652 {
653 if (pCtx->hThread != NIL_RTTHREAD)
654 {
655 LogFunc(("Waiting for thread to terminate ...\n"));
656
657 /* Wait for the window thread to terminate. */
658 rc = RTThreadWait(pCtx->hThread, 30 * 1000 /* Timeout in ms */, NULL);
659 if (RT_FAILURE(rc))
660 LogRel(("Shared Clipboard: Waiting for window thread termination failed with rc=%Rrc\n", rc));
661
662 pCtx->hThread = NIL_RTTHREAD;
663 }
664 }
665
666 if (RT_SUCCESS(rc))
667 {
668 RTMemFree(pCtx);
669 pCtx = NULL;
670
671 pClientData->State.pCtx = NULL;
672 }
673 }
674
675 LogFlowFuncLeaveRC(rc);
676 return rc;
677}
678
679int VBoxClipboardSvcImplFormatAnnounce(PVBOXCLIPBOARDCLIENTDATA pClientData, uint32_t u32Formats)
680{
681 AssertPtrReturn(pClientData, VERR_INVALID_POINTER);
682
683 PVBOXCLIPBOARDCONTEXT pCtx = pClientData->State.pCtx;
684 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
685
686 LogFlowFunc(("u32Formats=0x%x, hWnd=%p\n", u32Formats, pCtx->Win.hWnd));
687
688 /*
689 * The guest announced formats. Forward to the window thread.
690 */
691 PostMessage(pCtx->Win.hWnd, VBOX_CLIPBOARD_WM_SET_FORMATS,
692 0 /* wParam */, u32Formats /* lParam */);
693
694 return VINF_SUCCESS;
695}
696
697int VBoxClipboardSvcImplReadData(PVBOXCLIPBOARDCLIENTDATA pClientData, uint32_t u32Format, void *pv, uint32_t cb,
698 uint32_t *pcbActual)
699{
700 AssertPtrReturn(pClientData, VERR_INVALID_POINTER);
701 AssertPtrReturn(pClientData->State.pCtx, VERR_INVALID_POINTER);
702
703 LogFlowFunc(("u32Format=%02X\n", u32Format));
704
705 HANDLE hClip = NULL;
706
707 const PVBOXCLIPBOARDWINCTX pWinCtx = &pClientData->State.pCtx->Win;
708
709 /*
710 * The guest wants to read data in the given format.
711 */
712 int rc = VBoxClipboardWinOpen(pWinCtx->hWnd);
713 if (RT_SUCCESS(rc))
714 {
715 LogFunc(("Clipboard opened\n"));
716
717 if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
718 {
719 hClip = GetClipboardData(CF_DIB);
720 if (hClip != NULL)
721 {
722 LPVOID lp = GlobalLock(hClip);
723
724 if (lp != NULL)
725 {
726 LogFunc(("CF_DIB\n"));
727
728 vboxClipboardGetData(VBOX_SHARED_CLIPBOARD_FMT_BITMAP, lp, GlobalSize(hClip),
729 pv, cb, pcbActual);
730
731 GlobalUnlock(hClip);
732 }
733 else
734 {
735 hClip = NULL;
736 }
737 }
738 }
739 else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
740 {
741 hClip = GetClipboardData(CF_UNICODETEXT);
742 if (hClip != NULL)
743 {
744 LPWSTR uniString = (LPWSTR)GlobalLock(hClip);
745
746 if (uniString != NULL)
747 {
748 LogFunc(("CF_UNICODETEXT\n"));
749
750 vboxClipboardGetData(VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, uniString, (lstrlenW(uniString) + 1) * 2,
751 pv, cb, pcbActual);
752
753 GlobalUnlock(hClip);
754 }
755 else
756 {
757 hClip = NULL;
758 }
759 }
760 }
761 else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_HTML)
762 {
763 UINT format = RegisterClipboardFormat(VBOX_CLIPBOARD_WIN_REGFMT_HTML);
764 if (format != 0)
765 {
766 hClip = GetClipboardData(format);
767 if (hClip != NULL)
768 {
769 LPVOID lp = GlobalLock(hClip);
770 if (lp != NULL)
771 {
772 /** @todo r=andy Add data overflow handling. */
773 vboxClipboardGetData(VBOX_SHARED_CLIPBOARD_FMT_HTML, lp, GlobalSize(hClip),
774 pv, cb, pcbActual);
775#ifdef VBOX_STRICT
776 LogFlowFunc(("Raw HTML clipboard data from host:"));
777 VBoxClipboardDbgDumpHtml((char *)pv, cb);
778#endif
779 GlobalUnlock(hClip);
780 }
781 else
782 {
783 hClip = NULL;
784 }
785 }
786 }
787 }
788#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
789 else if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
790 {
791 AssertFailed(); /** @todo */
792 }
793#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
794 VBoxClipboardWinClose();
795 }
796
797 if (hClip == NULL)
798 {
799 /* Reply with empty data. */
800 vboxClipboardGetData(0, NULL, 0, pv, cb, pcbActual);
801 }
802
803 LogFlowFuncLeaveRC(rc);
804 return rc;
805}
806
807int VBoxClipboardSvcImplWriteData(PVBOXCLIPBOARDCLIENTDATA pClientData, void *pv, uint32_t cb, uint32_t u32Format)
808{
809 LogFlowFuncEnter();
810
811 /*
812 * The guest returns data that was requested in the WM_RENDERFORMAT handler.
813 */
814 Assert(pClientData->State.data.pv == NULL && pClientData->State.data.cb == 0 && pClientData->State.data.u32Format == 0);
815
816#ifdef LOG_ENABLED
817 VBoxClipboardDbgDumpData(pv, cb, u32Format);
818#endif
819
820 if (cb > 0)
821 {
822 char *pszResult = NULL;
823
824 if ( u32Format == VBOX_SHARED_CLIPBOARD_FMT_HTML
825 && !VBoxClipboardWinIsCFHTML((const char*)pv))
826 {
827 /* check that this is not already CF_HTML */
828 uint32_t cbResult;
829 int rc = VBoxClipboardWinConvertMIMEToCFHTML((const char *)pv, cb, &pszResult, &cbResult);
830 if (RT_SUCCESS(rc))
831 {
832 if (pszResult != NULL && cbResult != 0)
833 {
834 pClientData->State.data.pv = pszResult;
835 pClientData->State.data.cb = cbResult;
836 pClientData->State.data.u32Format = u32Format;
837 }
838 }
839 }
840 else
841 {
842 pClientData->State.data.pv = RTMemDup(pv, cb);
843 if (pClientData->State.data.pv)
844 {
845 pClientData->State.data.cb = cb;
846 pClientData->State.data.u32Format = u32Format;
847 }
848 }
849 }
850
851 AssertPtr(pClientData->State.pCtx);
852 int rc = RTSemEventSignal(pClientData->State.pCtx->hRenderEvent);
853 AssertRC(rc);
854
855 LogFlowFuncLeaveRC(rc);
856 return rc;
857}
858
859#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
860int VBoxClipboardSvcImplURITransferCreate(PVBOXCLIPBOARDCLIENTDATA pClientData, PSHAREDCLIPBOARDURITRANSFER pTransfer)
861{
862 RT_NOREF(pClientData, pTransfer);
863
864 LogFlowFuncEnter();
865
866 return VINF_SUCCESS;
867}
868
869int VBoxClipboardSvcImplURITransferDestroy(PVBOXCLIPBOARDCLIENTDATA pClientData, PSHAREDCLIPBOARDURITRANSFER pTransfer)
870{
871 LogFlowFuncEnter();
872
873 VBoxClipboardWinURITransferDestroy(&pClientData->State.pCtx->Win, pTransfer);
874
875 return VINF_SUCCESS;
876}
877#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
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