VirtualBox

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

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

SharedClipboardSvc,Vbgl: Reviewed and adjusted the handling of the VBOX_SHCL_GUEST_FN_REPORT_FORMATS message, paddling back the parameter changes from the 6.1 dev cycle and fixing a couple of bugs introduced. Also documented the message and renamed it to a more sensible name. Dropped the new Vbgl method, renaming the old one. bugref:9437

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