VirtualBox

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

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

Shared Clipboard: Renaming (SHAREDCLIPBOARD -> SHCL and VBOXCLIPBOARD -> SHCL).

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