VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp@ 80968

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

Shared Clipboard/VbglR3: Fixes for legacy protocol handling.

  • Property svn:eol-style set to native
  • Property svn:keyword set to Id
  • Property svn:keywords set to Author Date Id Revision
File size: 67.2 KB
Line 
1/* $Id: VBoxGuestR3LibClipboard.cpp 80968 2019-09-24 11:40:42Z vboxsync $ */
2/** @file
3 * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, Shared Clipboard.
4 */
5
6/*
7 * Copyright (C) 2007-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 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <VBox/GuestHost/SharedClipboard.h>
32#include <VBox/GuestHost/clipboard-helper.h>
33#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
34# include <VBox/GuestHost/SharedClipboard-transfers.h>
35#endif
36#include <VBox/HostServices/VBoxClipboardSvc.h>
37#include <VBox/err.h>
38#include <iprt/assert.h>
39#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
40# include <iprt/dir.h>
41# include <iprt/file.h>
42# include <iprt/path.h>
43#endif
44#include <iprt/string.h>
45#include <iprt/cpp/ministring.h>
46
47#include "VBoxGuestR3LibInternal.h"
48
49
50/*********************************************************************************************************************************
51* Prototypes *
52*********************************************************************************************************************************/
53
54
55/**
56 * Connects to the Shared Clipboard service, legacy version, do not use anymore.
57 *
58 * @returns VBox status code
59 * @param pidClient Where to put the client id on success. The client id
60 * must be passed to all the other clipboard calls.
61 */
62VBGLR3DECL(int) VbglR3ClipboardConnect(HGCMCLIENTID *pidClient)
63{
64 int rc = VbglR3HGCMConnect("VBoxSharedClipboard", pidClient);
65 if (rc == VERR_HGCM_SERVICE_NOT_FOUND)
66 rc = VINF_PERMISSION_DENIED;
67
68 LogFlowFuncLeaveRC(rc);
69 return rc;
70}
71
72
73/**
74 * Connects to the Shared Clipboard service, extended version.
75 *
76 * @returns VBox status code.
77 * @param pCtx Shared Clipboard command context to use for the connection.
78 */
79VBGLR3DECL(int) VbglR3ClipboardConnectEx(PVBGLR3SHCLCMDCTX pCtx)
80{
81 int rc = VbglR3ClipboardConnect(&pCtx->uClientID);
82 if (RT_SUCCESS(rc))
83 {
84 VBoxShClConnect Msg;
85 RT_ZERO(Msg);
86
87 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
88 VBOX_SHCL_GUEST_FN_CONNECT, VBOX_SHCL_CPARMS_CONNECT);
89
90 VbglHGCMParmUInt32Set(&Msg.uProtocolVer, 0);
91 VbglHGCMParmUInt32Set(&Msg.uProtocolFlags, 0);
92 VbglHGCMParmUInt32Set(&Msg.cbChunkSize, 0);
93 VbglHGCMParmUInt32Set(&Msg.enmCompression, 0);
94 VbglHGCMParmUInt32Set(&Msg.enmChecksumType, 0);
95
96 rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
97 if (RT_SUCCESS(rc))
98 {
99 rc = VbglHGCMParmUInt32Get(&Msg.uProtocolVer, &pCtx->uProtocolVer);
100 if (RT_SUCCESS(rc))
101 rc = VbglHGCMParmUInt32Get(&Msg.uProtocolFlags, &pCtx->uProtocolFlags);
102 if (RT_SUCCESS(rc))
103 rc = VbglHGCMParmUInt32Get(&Msg.cbChunkSize, &pCtx->cbChunkSize);
104
105 /** @todo Add / handle checksum + compression type. */
106 }
107 else
108 {
109 /* If the above call fails, make sure to use some sane defaults for
110 * the old (legacy) protocol. */
111 pCtx->uProtocolVer = 0;
112 pCtx->uProtocolFlags = 0;
113 pCtx->cbChunkSize = _64K;
114
115 rc = VINF_SUCCESS; /* Failing above is not fatal. */
116 }
117
118 LogFlowFunc(("uProtocolVer=%RU32, cbChunkSize=%RU32\n", pCtx->uProtocolVer, pCtx->cbChunkSize));
119
120 LogRel2(("Shared Clipboard: Client %RU32 connected, using protocol v%RU32 (cbChunkSize=%RU32)\n",
121 pCtx->uClientID, pCtx->uProtocolVer, pCtx->cbChunkSize));
122
123 }
124
125 LogFlowFuncLeaveRC(rc);
126 return rc;
127}
128
129
130/**
131 * Disconnects from the Shared Clipboard service, legacy version, do not use anymore.
132 *
133 * @returns VBox status code.
134 * @param idClient The client id returned by VbglR3ClipboardConnect().
135 */
136VBGLR3DECL(int) VbglR3ClipboardDisconnect(HGCMCLIENTID idClient)
137{
138 return VbglR3HGCMDisconnect(idClient);
139}
140
141
142/**
143 * Disconnects from the Shared Clipboard service, extended version.
144 *
145 * @returns VBox status code.
146 * @param pCtx Shared Clipboard command context to use for the connection.
147 */
148VBGLR3DECL(int) VbglR3ClipboardDisconnectEx(PVBGLR3SHCLCMDCTX pCtx)
149{
150 int rc = VbglR3ClipboardDisconnect(pCtx->uClientID);
151 if (RT_SUCCESS(rc))
152 {
153 pCtx->uClientID = 0;
154 }
155
156 LogFlowFuncLeaveRC(rc);
157 return rc;
158}
159
160
161VBGLR3DECL(int) VbglR3ClipboardFormatsReportRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMATDATA pFormats)
162{
163 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
164 AssertPtrReturn(pFormats, VERR_INVALID_POINTER);
165
166 VBoxShClFormatsMsg Msg;
167 RT_ZERO(Msg);
168
169 if (pCtx->uProtocolVer >= 1)
170 {
171 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
172 VBOX_SHCL_GUEST_FN_MSG_GET, 3);
173
174 Msg.u.v1.uContext.SetUInt32(VBOX_SHCL_HOST_MSG_FORMATS_REPORT);
175 Msg.u.v1.uFormats.SetUInt32(0);
176 Msg.u.v1.fFlags.SetUInt32(0);
177 }
178
179 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
180 if (RT_SUCCESS(rc))
181 {
182 rc = Msg.u.v1.uContext.GetUInt32(&pCtx->uContextID);
183 if (RT_SUCCESS(rc))
184 rc = Msg.u.v1.uFormats.GetUInt32(&pFormats->uFormats);
185 if (RT_SUCCESS(rc))
186 rc = Msg.u.v1.fFlags.GetUInt32(&pFormats->fFlags);
187 }
188
189 LogFlowFuncLeaveRC(rc);
190 return rc;
191}
192
193
194VBGLR3DECL(int) VbglR3ClipboardReadDataRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLDATAREQ pDataReq)
195{
196 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
197 AssertPtrReturn(pDataReq, VERR_INVALID_POINTER);
198
199 VBoxShClReadDataReqMsg Msg;
200
201 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
202 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_READ_DATA);
203
204 Msg.uContext.SetUInt32(VBOX_SHCL_HOST_MSG_READ_DATA);
205 Msg.uFormat.SetUInt32(0);
206 Msg.cbSize.SetUInt32(0);
207
208 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
209 if (RT_SUCCESS(rc))
210 {
211 rc = Msg.uContext.GetUInt32(&pCtx->uContextID);
212 if (RT_SUCCESS(rc))
213 rc = Msg.uFormat.GetUInt32(&pDataReq->uFmt);
214 if (RT_SUCCESS(rc))
215 rc = Msg.cbSize.GetUInt32(&pDataReq->cbSize);
216 }
217
218 LogFlowFuncLeaveRC(rc);
219 return rc;
220}
221
222
223/**
224 * Get a host message, legacy version (protocol v0). Do not use anymore.
225 *
226 * Note: This is the old message which still is being used for the non-URI Shared Clipboard transfers,
227 * to not break compatibility with older additions / VBox versions.
228 *
229 * This will block until a message becomes available.
230 *
231 * @returns VBox status code.
232 * @param idClient The client id returned by VbglR3ClipboardConnect().
233 * @param pidMsg Where to store the message id.
234 * @param pfFormats Where to store the format(s) the message applies to.
235 */
236VBGLR3DECL(int) VbglR3ClipboardGetHostMsgOld(HGCMCLIENTID idClient, uint32_t *pidMsg, uint32_t *pfFormats)
237{
238 VBoxShClGetHostMsgOld Msg;
239
240 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient,
241 VBOX_SHCL_GUEST_FN_GET_HOST_MSG_OLD, VBOX_SHCL_CPARMS_GET_HOST_MSG_OLD);
242
243 VbglHGCMParmUInt32Set(&Msg.msg, 0);
244 VbglHGCMParmUInt32Set(&Msg.formats, 0);
245
246 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
247 if (RT_SUCCESS(rc))
248 {
249 int rc2 = VbglHGCMParmUInt32Get(&Msg.msg, pidMsg);
250 if (RT_SUCCESS(rc))
251 {
252 rc2 = VbglHGCMParmUInt32Get(&Msg.formats, pfFormats);
253 if (RT_SUCCESS(rc2))
254 return rc;
255 }
256 rc = rc2;
257 }
258 *pidMsg = UINT32_MAX - 1;
259 *pfFormats = UINT32_MAX;
260 return rc;
261}
262
263
264/**
265 * Reads data from the host clipboard.
266 *
267 * @returns VBox status code.
268 * @retval VINF_BUFFER_OVERFLOW If there is more data available than the caller provided buffer space for.
269 *
270 * @param idClient The client id returned by VbglR3ClipboardConnect().
271 * @param fFormat The format we're requesting the data in.
272 * @param pv Where to store the data.
273 * @param cb The size of the buffer pointed to by pv.
274 * @param pcb The actual size of the host clipboard data. May be larger than cb.
275 */
276VBGLR3DECL(int) VbglR3ClipboardReadData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb, uint32_t *pcb)
277{
278 VBoxShClReadDataMsg Msg;
279
280 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_DATA_READ, VBOX_SHCL_CPARMS_READ_DATA);
281 VbglHGCMParmUInt32Set(&Msg.format, fFormat);
282 VbglHGCMParmPtrSet(&Msg.ptr, pv, cb);
283 VbglHGCMParmUInt32Set(&Msg.size, 0);
284
285 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
286 if (RT_SUCCESS(rc))
287 {
288 uint32_t cbActual;
289 int rc2 = VbglHGCMParmUInt32Get(&Msg.size, &cbActual);
290 if (RT_SUCCESS(rc2))
291 {
292 *pcb = cbActual;
293 if (cbActual > cb)
294 return VINF_BUFFER_OVERFLOW;
295 return rc;
296 }
297 rc = rc2;
298 }
299 return rc;
300}
301
302/**
303 * Peeks at the next host message, waiting for one to turn up.
304 *
305 * @returns VBox status code.
306 * @retval VERR_INTERRUPTED if interrupted. Does the necessary cleanup, so
307 * caller just have to repeat this call.
308 * @retval VERR_VM_RESTORED if the VM has been restored (idRestoreCheck).
309 *
310 * @param pCtx Shared Clipboard command context to use for the connection.
311 * @param pidMsg Where to store the message id.
312 * @param pcParameters Where to store the number of parameters which will
313 * be received in a second call to the host.
314 * @param pidRestoreCheck Pointer to the VbglR3GetSessionId() variable to use
315 * for the VM restore check. Optional.
316 *
317 * @note Restore check is only performed optimally with a 6.0 host.
318 */
319int VbglR3ClipboardMsgPeekWait(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pidMsg, uint32_t *pcParameters, uint64_t *pidRestoreCheck)
320{
321 AssertPtrReturn(pidMsg, VERR_INVALID_POINTER);
322 AssertPtrReturn(pcParameters, VERR_INVALID_POINTER);
323
324 int rc;
325
326 struct
327 {
328 VBGLIOCHGCMCALL Hdr;
329 HGCMFunctionParameter idMsg; /* Doubles as restore check on input. */
330 HGCMFunctionParameter cParameters;
331 } Msg;
332 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->uClientID, VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT, 2);
333 VbglHGCMParmUInt64Set(&Msg.idMsg, pidRestoreCheck ? *pidRestoreCheck : 0);
334 VbglHGCMParmUInt32Set(&Msg.cParameters, 0);
335 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
336 LogFlowFunc(("VbglR3HGCMCall -> %Rrc\n", rc));
337 if (RT_SUCCESS(rc))
338 {
339 AssertMsgReturn( Msg.idMsg.type == VMMDevHGCMParmType_64bit
340 && Msg.cParameters.type == VMMDevHGCMParmType_32bit,
341 ("msg.type=%d num_parms.type=%d\n", Msg.idMsg.type, Msg.cParameters.type),
342 VERR_INTERNAL_ERROR_3);
343
344 *pidMsg = (uint32_t)Msg.idMsg.u.value64;
345 *pcParameters = Msg.cParameters.u.value32;
346 return rc;
347 }
348
349 /*
350 * If interrupted we must cancel the call so it doesn't prevent us from making another one.
351 */
352 if (rc == VERR_INTERRUPTED)
353 {
354 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->uClientID, VBOX_SHCL_GUEST_FN_CANCEL, 0);
355 int rc2 = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg.Hdr));
356 AssertRC(rc2);
357 }
358
359 /*
360 * If restored, update pidRestoreCheck.
361 */
362 if (rc == VERR_VM_RESTORED && pidRestoreCheck)
363 *pidRestoreCheck = Msg.idMsg.u.value64;
364
365 *pidMsg = UINT32_MAX - 1;
366 *pcParameters = UINT32_MAX - 2;
367 return rc;
368}
369
370#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
371static int vbglR3ClipboardRootListHdrRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLISTHDR pRootListHdr)
372{
373 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
374 AssertPtrReturn(pRootListHdr, VERR_INVALID_POINTER);
375
376 VBoxShClRootListHdrMsg Msg;
377 RT_ZERO(Msg);
378
379 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
380 VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ);
381
382 Msg.ReqParms.uContext.SetUInt32(pCtx->uContextID);
383 Msg.ReqParms.fRoots.SetUInt32(0);
384
385 Msg.cRoots.SetUInt32(0);
386
387 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
388 if (RT_SUCCESS(rc))
389 {
390 rc = Msg.ReqParms.fRoots.GetUInt32(&pRootListHdr->fRoots); AssertRC(rc);
391 if (RT_SUCCESS(rc))
392 rc = Msg.cRoots.GetUInt32(&pRootListHdr->cRoots); AssertRC(rc);
393 }
394
395 LogFlowFuncLeaveRC(rc);
396 return rc;
397}
398
399static int vbglR3ClipboardRootListEntryRead(PVBGLR3SHCLCMDCTX pCtx, uint32_t uIndex, PSHCLROOTLISTENTRY pRootListEntry)
400{
401 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
402 AssertPtrReturn(pRootListEntry, VERR_INVALID_POINTER);
403
404 VBoxShClRootListEntryMsg Msg;
405 RT_ZERO(Msg);
406
407 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
408 VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY);
409
410 Msg.Parms.uContext.SetUInt32(pCtx->uContextID);
411 Msg.Parms.fInfo.SetUInt32(pRootListEntry->fInfo);
412 Msg.Parms.uIndex.SetUInt32(uIndex);
413
414 Msg.szName.SetPtr(pRootListEntry->pszName, pRootListEntry->cbName);
415 Msg.cbInfo.SetUInt32(pRootListEntry->cbInfo);
416 Msg.pvInfo.SetPtr(pRootListEntry->pvInfo, pRootListEntry->cbInfo);
417
418 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
419 if (RT_SUCCESS(rc))
420 {
421 rc = Msg.Parms.fInfo.GetUInt32(&pRootListEntry->fInfo); AssertRC(rc);
422 if (RT_SUCCESS(rc))
423 {
424 uint32_t cbInfo = 0;
425 rc = Msg.cbInfo.GetUInt32(&cbInfo); AssertRC(rc);
426 if (pRootListEntry->cbInfo != cbInfo)
427 rc = VERR_INVALID_PARAMETER;
428 }
429 }
430
431 LogFlowFuncLeaveRC(rc);
432 return rc;
433}
434
435VBGLR3DECL(int) VbglR3ClipboardRootListRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLIST *ppRootList)
436{
437 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
438 AssertPtrReturn(ppRootList, VERR_INVALID_POINTER);
439
440 int rc;
441
442 PSHCLROOTLIST pRootList = SharedClipboardTransferRootListAlloc();
443 if (pRootList)
444 {
445 SHCLROOTLISTHDR srcRootListHdr;
446 rc = vbglR3ClipboardRootListHdrRead(pCtx, &srcRootListHdr);
447 if (RT_SUCCESS(rc))
448 {
449 pRootList->Hdr.cRoots = srcRootListHdr.cRoots;
450 pRootList->Hdr.fRoots = 0; /** @todo Implement this. */
451
452 if (srcRootListHdr.cRoots)
453 {
454 pRootList->paEntries =
455 (PSHCLROOTLISTENTRY)RTMemAllocZ(srcRootListHdr.cRoots * sizeof(SHCLROOTLISTENTRY));
456 if (pRootList->paEntries)
457 {
458 for (uint32_t i = 0; i < srcRootListHdr.cRoots; i++)
459 {
460 rc = vbglR3ClipboardRootListEntryRead(pCtx, i, &pRootList->paEntries[i]);
461 if (RT_FAILURE(rc))
462 break;
463 }
464 }
465 else
466 rc = VERR_NO_MEMORY;
467 }
468 }
469
470 if (RT_SUCCESS(rc))
471 {
472 *ppRootList = pRootList;
473 }
474 else
475 SharedClipboardTransferRootListFree(pRootList);
476 }
477 else
478 rc = VERR_NO_MEMORY;
479
480 LogFlowFuncLeaveRC(rc);
481 return rc;
482}
483
484VBGLR3DECL(int) VbglR3ClipboarTransferStatusRecv(PVBGLR3SHCLCMDCTX pCtx,
485 PSHCLTRANSFERDIR pEnmDir, PSHCLTRANSFERREPORT pReport)
486{
487 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
488 AssertPtrReturn(pReport, VERR_INVALID_POINTER);
489 AssertPtrReturn(pEnmDir, VERR_INVALID_POINTER);
490
491 VBoxShClTransferStatusMsg Msg;
492 RT_ZERO(Msg);
493
494 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
495 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_TRANSFER_STATUS);
496
497 Msg.uContext.SetUInt32(VBOX_SHCL_HOST_MSG_TRANSFER_STATUS);
498 Msg.enmDir.SetUInt32(0);
499 Msg.enmStatus.SetUInt32(0);
500 Msg.rc.SetUInt32(0);
501 Msg.fFlags.SetUInt32(0);
502
503 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
504 if (RT_SUCCESS(rc))
505 {
506 rc = Msg.uContext.GetUInt32(&pCtx->uContextID); AssertRC(rc);
507 if (RT_SUCCESS(rc))
508 rc = Msg.enmDir.GetUInt32((uint32_t *)pEnmDir); AssertRC(rc);
509 if (RT_SUCCESS(rc))
510 rc = Msg.enmStatus.GetUInt32(&pReport->uStatus); AssertRC(rc);
511 if (RT_SUCCESS(rc))
512 rc = Msg.rc.GetUInt32((uint32_t *)&pReport->rc); AssertRC(rc);
513 if (RT_SUCCESS(rc))
514 rc = Msg.fFlags.GetUInt32(&pReport->fFlags); AssertRC(rc);
515 }
516
517 LogFlowFuncLeaveRC(rc);
518 return rc;
519}
520
521VBGLR3DECL(int) VbglR3ClipboardTransferStatusReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFER pTransfer,
522 SHCLTRANSFERSTATUS uStatus, int rcTransfer)
523{
524 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
525 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
526
527 RT_NOREF(pTransfer);
528
529 VBoxShClReplyMsg Msg;
530 RT_ZERO(Msg);
531
532 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
533 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
534
535 Msg.uContext.SetUInt32(pCtx->uContextID);
536 Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS);
537 Msg.rc.SetUInt32((uint32_t )rcTransfer); /* int vs. uint32_t */
538 Msg.cbPayload.SetUInt32(0);
539 Msg.pvPayload.SetPtr(NULL, 0);
540
541 Msg.u.TransferStatus.enmStatus.SetUInt32((uint32_t)uStatus);
542
543 LogFlowFunc(("%s\n", VBoxShClTransferStatusToStr(uStatus)));
544
545 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
546
547 LogFlowFuncLeaveRC(rc);
548 return rc;
549}
550
551VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReq(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pfRoots)
552{
553 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
554 AssertPtrReturn(pfRoots, VERR_INVALID_POINTER);
555
556 VBoxShClRootListReadReqMsg Msg;
557 RT_ZERO(Msg);
558
559 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
560 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ);
561
562 Msg.ReqParms.uContext.SetUInt32(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ);
563 Msg.ReqParms.fRoots.SetUInt32(0);
564
565 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
566 if (RT_SUCCESS(rc))
567 {
568 rc = Msg.ReqParms.uContext.GetUInt32(&pCtx->uContextID); AssertRC(rc);
569 if (RT_SUCCESS(rc))
570 rc = Msg.ReqParms.fRoots.GetUInt32(pfRoots); AssertRC(rc);
571 }
572
573 LogFlowFuncLeaveRC(rc);
574 return rc;
575}
576
577VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLISTHDR pRootListHdr)
578{
579 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
580 AssertPtrReturn(pRootListHdr, VERR_INVALID_POINTER);
581
582 VBoxShClRootListHdrMsg Msg;
583 RT_ZERO(Msg);
584
585 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
586 VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE, VBOX_SHCL_CPARMS_ROOT_LIST_HDR);
587
588 Msg.ReqParms.uContext.SetUInt32(pCtx->uContextID);
589 Msg.ReqParms.fRoots.SetUInt32(pRootListHdr->fRoots);
590
591 Msg.cRoots.SetUInt32(pRootListHdr->cRoots);
592
593 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
594
595 LogFlowFuncLeaveRC(rc);
596 return rc;
597}
598
599VBGLR3DECL(int) VbglR3ClipboardRootListEntryReadReq(PVBGLR3SHCLCMDCTX pCtx, uint32_t *puIndex, uint32_t *pfInfo)
600{
601 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
602 AssertPtrReturn(puIndex, VERR_INVALID_POINTER);
603 AssertPtrReturn(pfInfo, VERR_INVALID_POINTER);
604
605 VBoxShClRootListEntryReadReqMsg Msg;
606 RT_ZERO(Msg);
607
608 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
609 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ);
610
611 Msg.Parms.uContext.SetUInt32(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ);
612 Msg.Parms.fInfo.SetUInt32(0);
613 Msg.Parms.uIndex.SetUInt32(0);
614
615 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
616 if (RT_SUCCESS(rc))
617 {
618 rc = Msg.Parms.uContext.GetUInt32(&pCtx->uContextID); AssertRC(rc);
619 if (RT_SUCCESS(rc))
620 rc = Msg.Parms.fInfo.GetUInt32(pfInfo); AssertRC(rc);
621 if (RT_SUCCESS(rc))
622 rc = Msg.Parms.uIndex.GetUInt32(puIndex); AssertRC(rc);
623 }
624
625 LogFlowFuncLeaveRC(rc);
626 return rc;
627}
628
629VBGLR3DECL(int) VbglR3ClipboardRootListEntryReadReply(PVBGLR3SHCLCMDCTX pCtx, uint32_t uIndex, PSHCLROOTLISTENTRY pEntry)
630{
631 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
632 AssertPtrReturn(pEntry, VERR_INVALID_POINTER);
633
634 VBoxShClRootListEntryMsg Msg;
635 RT_ZERO(Msg);
636
637 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
638 VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY);
639
640 Msg.Parms.uContext.SetUInt32(pCtx->uContextID);
641 Msg.Parms.fInfo.SetUInt32(0);
642 Msg.Parms.uIndex.SetUInt32(uIndex);
643
644 Msg.szName.SetPtr(pEntry->pszName, pEntry->cbName);
645 Msg.cbInfo.SetUInt32(pEntry->cbInfo);
646 Msg.pvInfo.SetPtr(pEntry->pvInfo, pEntry->cbInfo);
647
648 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
649
650 LogFlowFuncLeaveRC(rc);
651 return rc;
652}
653
654VBGLR3DECL(int) VbglR3ClipboardListOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
655 PSHCLLISTHANDLE phList)
656{
657 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
658 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
659 AssertPtrReturn(phList, VERR_INVALID_POINTER);
660
661 VBoxShClListOpenMsg Msg;
662 RT_ZERO(Msg);
663
664 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
665 VBOX_SHCL_GUEST_FN_LIST_OPEN, VBOX_SHCL_CPARMS_LIST_OPEN);
666
667 Msg.uContext.SetUInt32(pCtx->uContextID);
668 Msg.fList.SetUInt32(0);
669 Msg.cbFilter.SetUInt32(pOpenParms->cbFilter);
670 Msg.pvFilter.SetPtr(pOpenParms->pszFilter, pOpenParms->cbFilter);
671 Msg.cbPath.SetUInt32(pOpenParms->cbPath);
672 Msg.pvFilter.SetPtr(pOpenParms->pszPath, pOpenParms->cbPath);
673
674 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
675 if (RT_SUCCESS(rc))
676 {
677 rc = Msg.uHandle.GetUInt64(phList); AssertRC(rc);
678 }
679
680 LogFlowFuncLeaveRC(rc);
681 return rc;
682}
683
684VBGLR3DECL(int) VbglR3ClipboardListOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms)
685{
686 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
687 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
688
689 VBoxShClListOpenMsg Msg;
690 RT_ZERO(Msg);
691
692 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
693 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_OPEN);
694
695 Msg.uContext.SetUInt32(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN);
696 Msg.fList.SetUInt32(0);
697 Msg.cbPath.SetUInt32(pOpenParms->cbPath);
698 Msg.pvPath.SetPtr(pOpenParms->pszPath, pOpenParms->cbPath);
699 Msg.cbFilter.SetUInt32(pOpenParms->cbFilter);
700 Msg.pvFilter.SetPtr(pOpenParms->pszFilter, pOpenParms->cbFilter);
701 Msg.uHandle.SetUInt64(0);
702
703 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
704 if (RT_SUCCESS(rc))
705 {
706 rc = Msg.uContext.GetUInt32(&pCtx->uContextID);
707 if (RT_SUCCESS(rc))
708 rc = Msg.fList.GetUInt32(&pOpenParms->fList);
709 if (RT_SUCCESS(rc))
710 rc = Msg.cbFilter.GetUInt32(&pOpenParms->cbFilter);
711 if (RT_SUCCESS(rc))
712 rc = Msg.cbPath.GetUInt32(&pOpenParms->cbPath);
713 }
714
715 LogFlowFuncLeaveRC(rc);
716 return rc;
717}
718
719VBGLR3DECL(int) VbglR3ClipboardListOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList)
720{
721 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
722
723 VBoxShClReplyMsg Msg;
724 RT_ZERO(Msg);
725
726 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
727 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
728
729 Msg.uContext.SetUInt32(pCtx->uContextID);
730 Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN);
731 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
732 Msg.cbPayload.SetUInt32(0);
733 Msg.pvPayload.SetPtr(NULL, 0);
734
735 Msg.u.ListOpen.uHandle.SetUInt64(hList);
736
737 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
738
739 LogFlowFuncLeaveRC(rc);
740 return rc;
741}
742
743VBGLR3DECL(int) VbglR3ClipboardListCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList)
744{
745 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
746 AssertPtrReturn(phList, VERR_INVALID_POINTER);
747
748 VBoxShClListCloseMsg Msg;
749 RT_ZERO(Msg);
750
751 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
752 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_CLOSE);
753
754 Msg.uContext.SetUInt32(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE);
755 Msg.uHandle.SetUInt64(0);
756
757 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
758 if (RT_SUCCESS(rc))
759 {
760 rc = Msg.uContext.GetUInt32(&pCtx->uContextID);
761 if (RT_SUCCESS(rc))
762 rc = Msg.uHandle.GetUInt64(phList); AssertRC(rc);
763 }
764
765 LogFlowFuncLeaveRC(rc);
766 return rc;
767}
768
769VBGLR3DECL(int) VbglR3ClipboardListCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList)
770{
771 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
772
773 VBoxShClReplyMsg Msg;
774 RT_ZERO(Msg);
775
776 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
777 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
778
779 Msg.uContext.SetUInt32(pCtx->uContextID);
780 Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_LIST_CLOSE);
781 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
782 Msg.cbPayload.SetUInt32(0);
783 Msg.pvPayload.SetPtr(NULL, 0);
784
785 Msg.u.ListOpen.uHandle.SetUInt64(hList);
786
787 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
788
789 LogFlowFuncLeaveRC(rc);
790 return rc;
791}
792
793VBGLR3DECL(int) VbglR3ClipboardListCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList)
794{
795 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
796
797 VBoxShClListCloseMsg Msg;
798 RT_ZERO(Msg);
799
800 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
801 VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE, VBOX_SHCL_CPARMS_LIST_CLOSE);
802
803 Msg.uContext.SetUInt32(pCtx->uContextID);
804 Msg.uHandle.SetUInt64(hList);
805
806 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
807
808 LogFlowFuncLeaveRC(rc);
809 return rc;
810}
811
812
813VBGLR3DECL(int) VbglR3ClipboardListHdrRead(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList, uint32_t fFlags,
814 PSHCLLISTHDR pListHdr)
815{
816 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
817 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
818
819 VBoxShClListHdrMsg Msg;
820 RT_ZERO(Msg);
821
822 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
823 VBOX_SHCL_GUEST_FN_LIST_HDR_READ, VBOX_SHCL_CPARMS_LIST_HDR);
824
825 Msg.ReqParms.uContext.SetUInt32(pCtx->uContextID);
826 Msg.ReqParms.uHandle.SetUInt64(hList);
827 Msg.ReqParms.fFlags.SetUInt32(fFlags);
828
829 Msg.fFeatures.SetUInt32(0);
830 Msg.cbTotalSize.SetUInt32(0);
831 Msg.cTotalObjects.SetUInt64(0);
832 Msg.cbTotalSize.SetUInt64(0);
833
834 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
835 if (RT_SUCCESS(rc))
836 {
837 rc = Msg.fFeatures.GetUInt32(&pListHdr->fFeatures);
838 if (RT_SUCCESS(rc))
839 rc = Msg.cTotalObjects.GetUInt64(&pListHdr->cTotalObjects);
840 if (RT_SUCCESS(rc))
841 rc = Msg.cbTotalSize.GetUInt64(&pListHdr->cbTotalSize);
842 }
843
844 LogFlowFuncLeaveRC(rc);
845 return rc;
846}
847
848VBGLR3DECL(int) VbglR3ClipboardListHdrReadRecvReq(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList, uint32_t *pfFlags)
849{
850 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
851 AssertPtrReturn(phList, VERR_INVALID_POINTER);
852 AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
853
854 VBoxShClListHdrReadReqMsg Msg;
855 RT_ZERO(Msg);
856
857 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
858 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_HDR_READ_REQ);
859
860 Msg.ReqParms.uContext.SetUInt32(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ);
861 Msg.ReqParms.uHandle.SetUInt64(0);
862 Msg.ReqParms.fFlags.SetUInt32(0);
863
864 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
865 if (RT_SUCCESS(rc))
866 {
867 rc = Msg.ReqParms.uContext.GetUInt32(&pCtx->uContextID);
868 if (RT_SUCCESS(rc))
869 rc = Msg.ReqParms.uHandle.GetUInt64(phList);
870 if (RT_SUCCESS(rc))
871 rc = Msg.ReqParms.fFlags.GetUInt32(pfFlags);
872 }
873
874 LogFlowFuncLeaveRC(rc);
875 return rc;
876}
877
878VBGLR3DECL(int) VbglR3ClipboardListHdrWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
879 PSHCLLISTHDR pListHdr)
880{
881 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
882 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
883
884 VBoxShClListHdrMsg Msg;
885 RT_ZERO(Msg);
886
887 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
888 VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE, VBOX_SHCL_CPARMS_LIST_HDR);
889
890 Msg.ReqParms.uContext.SetUInt32(pCtx->uContextID);
891 Msg.ReqParms.uHandle.SetUInt64(hList);
892 Msg.ReqParms.fFlags.SetUInt32(0);
893
894 Msg.fFeatures.SetUInt32(0);
895 Msg.cbTotalSize.SetUInt32(pListHdr->fFeatures);
896 Msg.cTotalObjects.SetUInt64(pListHdr->cTotalObjects);
897 Msg.cbTotalSize.SetUInt64(pListHdr->cbTotalSize);
898
899 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
900
901 LogFlowFuncLeaveRC(rc);
902 return rc;
903}
904
905VBGLR3DECL(int) VbglR3ClipboardListEntryRead(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
906 PSHCLLISTENTRY pListEntry)
907{
908 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
909 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
910
911 VBoxShClListEntryMsg Msg;
912 RT_ZERO(Msg);
913
914 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
915 VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ, VBOX_SHCL_CPARMS_LIST_ENTRY);
916
917 Msg.ReqParms.uContext.SetUInt32(pCtx->uContextID);
918 Msg.ReqParms.uHandle.SetUInt64(hList);
919 Msg.ReqParms.fInfo.SetUInt32(0);
920
921 Msg.szName.SetPtr(pListEntry->pszName, pListEntry->cbName);
922 Msg.cbInfo.SetUInt32(pListEntry->cbInfo);
923 Msg.pvInfo.SetPtr(pListEntry->pvInfo, pListEntry->cbInfo);
924
925 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
926 if (RT_SUCCESS(rc))
927 {
928 rc = Msg.cbInfo.GetUInt32(&pListEntry->cbInfo); AssertRC(rc);
929 }
930
931 LogFlowFuncLeaveRC(rc);
932 return rc;
933}
934
935VBGLR3DECL(int) VbglR3ClipboardListEntryReadRecvReq(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList, uint32_t *pfInfo)
936{
937 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
938 AssertPtrReturn(phList, VERR_INVALID_POINTER);
939 AssertPtrReturn(pfInfo, VERR_INVALID_POINTER);
940
941 VBoxShClListEntryReadReqMsg Msg;
942 RT_ZERO(Msg);
943
944 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
945 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_ENTRY_READ);
946
947 Msg.ReqParms.uContext.SetUInt32(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ);
948 Msg.ReqParms.uHandle.SetUInt64(0);
949 Msg.ReqParms.fInfo.SetUInt32(0);
950
951 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
952 if (RT_SUCCESS(rc))
953 {
954 rc = Msg.ReqParms.uContext.GetUInt32(&pCtx->uContextID);
955 if (RT_SUCCESS(rc))
956 rc = Msg.ReqParms.uHandle.GetUInt64(phList); AssertRC(rc);
957 if (RT_SUCCESS(rc))
958 rc = Msg.ReqParms.fInfo.GetUInt32(pfInfo); AssertRC(rc);
959 }
960
961 LogFlowFuncLeaveRC(rc);
962 return rc;
963}
964
965VBGLR3DECL(int) VbglR3ClipboardListEntryWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
966 PSHCLLISTENTRY pListEntry)
967{
968 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
969 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
970
971 VBoxShClListEntryMsg Msg;
972 RT_ZERO(Msg);
973
974 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
975 VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE, VBOX_SHCL_CPARMS_LIST_ENTRY);
976
977 Msg.ReqParms.uContext.SetUInt32(pCtx->uContextID);
978 Msg.ReqParms.uHandle.SetUInt64(hList);
979 Msg.ReqParms.fInfo.SetUInt32(pListEntry->fInfo);
980
981 Msg.szName.SetPtr(pListEntry->pszName, pListEntry->cbName);
982 Msg.cbInfo.SetUInt32(pListEntry->cbInfo);
983 Msg.pvInfo.SetPtr(pListEntry->pvInfo, pListEntry->cbInfo);
984
985 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
986
987 LogFlowFuncLeaveRC(rc);
988 return rc;
989}
990
991VBGLR3DECL(int) VbglR3ClipboardObjOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms)
992{
993 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
994 AssertPtrReturn(pCreateParms, VERR_INVALID_POINTER);
995
996 VBoxShClObjOpenMsg Msg;
997 RT_ZERO(Msg);
998
999 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
1000 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_OPEN);
1001
1002 Msg.uContext.SetUInt32(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN);
1003 Msg.uHandle.SetUInt64(0);
1004 Msg.cbPath.SetUInt32(pCreateParms->cbPath);
1005 Msg.szPath.SetPtr(pCreateParms->pszPath, pCreateParms->cbPath);
1006 Msg.fCreate.SetUInt32(0);
1007
1008 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1009 if (RT_SUCCESS(rc))
1010 {
1011 rc = Msg.uContext.GetUInt32(&pCtx->uContextID);
1012 if (RT_SUCCESS(rc))
1013 rc = Msg.cbPath.GetUInt32(&pCreateParms->cbPath);
1014 if (RT_SUCCESS(rc))
1015 rc = Msg.fCreate.GetUInt32(&pCreateParms->fCreate);
1016 }
1017
1018 LogFlowFuncLeaveRC(rc);
1019 return rc;
1020}
1021
1022VBGLR3DECL(int) VbglR3ClipboardObjOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj)
1023{
1024 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1025
1026 VBoxShClReplyMsg Msg;
1027 RT_ZERO(Msg);
1028
1029 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
1030 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1031
1032 Msg.uContext.SetUInt32(pCtx->uContextID);
1033 Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN);
1034 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1035 Msg.cbPayload.SetUInt32(0);
1036 Msg.pvPayload.SetPtr(NULL, 0);
1037
1038 Msg.u.ObjOpen.uHandle.SetUInt64(hObj);
1039
1040 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1041
1042 LogFlowFuncLeaveRC(rc);
1043 return rc;
1044}
1045
1046VBGLR3DECL(int) VbglR3ClipboardObjOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms,
1047 PSHCLOBJHANDLE phObj)
1048{
1049 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1050 AssertPtrReturn(pCreateParms, VERR_INVALID_POINTER);
1051 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1052
1053 VBoxShClObjOpenMsg Msg;
1054 RT_ZERO(Msg);
1055
1056 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
1057 VBOX_SHCL_GUEST_FN_OBJ_OPEN, VBOX_SHCL_CPARMS_OBJ_OPEN);
1058
1059 Msg.uContext.SetUInt32(pCtx->uContextID);
1060 Msg.uHandle.SetUInt64(0);
1061 Msg.cbPath.SetUInt32(pCreateParms->cbPath);
1062 Msg.szPath.SetPtr((void *)pCreateParms->pszPath, pCreateParms->cbPath + 1 /* Include terminating zero */);
1063 Msg.fCreate.SetUInt32(pCreateParms->fCreate);
1064
1065 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1066 if (RT_SUCCESS(rc))
1067 {
1068 Msg.uHandle.GetUInt64(phObj);
1069 }
1070
1071 LogFlowFuncLeaveRC(rc);
1072 return rc;
1073}
1074
1075VBGLR3DECL(int) VbglR3ClipboardObjCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj)
1076{
1077 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1078 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1079
1080 VBoxShClObjCloseMsg Msg;
1081 RT_ZERO(Msg);
1082
1083 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
1084 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_CLOSE);
1085
1086 Msg.uContext.SetUInt32(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE);
1087 Msg.uHandle.SetUInt64(0);
1088
1089 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1090 if (RT_SUCCESS(rc))
1091 {
1092 rc = Msg.uContext.GetUInt32(&pCtx->uContextID);
1093 if (RT_SUCCESS(rc))
1094 rc = Msg.uHandle.GetUInt64(phObj);
1095 }
1096
1097 LogFlowFuncLeaveRC(rc);
1098 return rc;
1099}
1100
1101VBGLR3DECL(int) VbglR3ClipboardObjCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj)
1102{
1103 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1104
1105 VBoxShClReplyMsg Msg;
1106 RT_ZERO(Msg);
1107
1108 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
1109 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1110
1111 Msg.uContext.SetUInt32(pCtx->uContextID);
1112 Msg.enmType.SetUInt32(VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE);
1113 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1114 Msg.cbPayload.SetUInt32(0);
1115 Msg.pvPayload.SetPtr(NULL, 0);
1116
1117 Msg.u.ObjClose.uHandle.SetUInt64(hObj);
1118
1119 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1120
1121 LogFlowFuncLeaveRC(rc);
1122 return rc;
1123}
1124
1125VBGLR3DECL(int) VbglR3ClipboardObjCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj)
1126{
1127 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1128
1129 VBoxShClObjCloseMsg Msg;
1130 RT_ZERO(Msg);
1131
1132 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
1133 VBOX_SHCL_GUEST_FN_OBJ_CLOSE, VBOX_SHCL_CPARMS_OBJ_CLOSE);
1134
1135 Msg.uContext.SetUInt32(pCtx->uContextID);
1136 Msg.uHandle.SetUInt64(hObj);
1137
1138 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1139
1140 LogFlowFuncLeaveRC(rc);
1141 return rc;
1142}
1143
1144VBGLR3DECL(int) VbglR3ClipboardObjReadRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj, uint32_t *pcbToRead,
1145 uint32_t *pfFlags)
1146{
1147 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1148 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1149 AssertPtrReturn(pcbToRead, VERR_INVALID_POINTER);
1150 AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
1151
1152 VBoxShClObjReadReqMsg Msg;
1153 RT_ZERO(Msg);
1154
1155 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
1156 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_READ_REQ);
1157
1158 Msg.ReqParms.uContext.SetUInt32(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ);
1159 Msg.ReqParms.uHandle.SetUInt64(0);
1160 Msg.ReqParms.cbToRead.SetUInt32(0);
1161 Msg.ReqParms.fRead.SetUInt32(0);
1162
1163 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1164 if (RT_SUCCESS(rc))
1165 {
1166 rc = Msg.ReqParms.uContext.GetUInt32(&pCtx->uContextID);
1167 if (RT_SUCCESS(rc))
1168 rc = Msg.ReqParms.uHandle.GetUInt64(phObj);
1169 if (RT_SUCCESS(rc))
1170 rc = Msg.ReqParms.cbToRead.GetUInt32(pcbToRead);
1171 if (RT_SUCCESS(rc))
1172 rc = Msg.ReqParms.fRead.GetUInt32(pfFlags);
1173 }
1174
1175 LogFlowFuncLeaveRC(rc);
1176 return rc;
1177}
1178
1179VBGLR3DECL(int) VbglR3ClipboardObjRead(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj,
1180 void *pvData, uint32_t cbData, uint32_t *pcbRead)
1181{
1182 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1183 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1184 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1185 /* pcbRead is optional. */
1186
1187 VBoxShClObjReadWriteMsg Msg;
1188 RT_ZERO(Msg);
1189
1190 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
1191 VBOX_SHCL_GUEST_FN_OBJ_READ, VBOX_SHCL_CPARMS_OBJ_READ);
1192
1193 Msg.uContext.SetUInt32(pCtx->uContextID);
1194 Msg.uHandle.SetUInt64(hObj);
1195 Msg.pvData.SetPtr(pvData, cbData);
1196 Msg.cbData.SetUInt32(cbData);
1197 Msg.pvChecksum.SetPtr(NULL, 0);
1198 Msg.cbChecksum.SetUInt32(0);
1199
1200 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1201 if (RT_SUCCESS(rc))
1202 {
1203 /** @todo Add checksum support. */
1204
1205 if (pcbRead)
1206 {
1207 rc = Msg.cbData.GetUInt32(pcbRead); AssertRC(rc);
1208 AssertReturn(cbData >= *pcbRead, VERR_TOO_MUCH_DATA);
1209 }
1210 }
1211
1212 LogFlowFuncLeaveRC(rc);
1213 return rc;
1214}
1215
1216VBGLR3DECL(int) VbglR3ClipboardObjWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj,
1217 void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1218{
1219 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1220 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1221 /* cbData can be 0. */
1222 /* pcbWritten is optional. */
1223
1224 VBoxShClObjReadWriteMsg Msg;
1225 RT_ZERO(Msg);
1226
1227 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
1228 VBOX_SHCL_GUEST_FN_OBJ_WRITE, VBOX_SHCL_CPARMS_OBJ_WRITE);
1229
1230 Msg.uContext.SetUInt32(pCtx->uContextID);
1231 Msg.uHandle.SetUInt64(hObj);
1232 Msg.pvData.SetPtr(pvData, cbData);
1233 Msg.cbData.SetUInt32(cbData);
1234 Msg.pvChecksum.SetPtr(NULL, 0);
1235 Msg.cbChecksum.SetUInt32(0);
1236
1237 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1238 if (RT_SUCCESS(rc))
1239 {
1240 /** @todo Add checksum support. */
1241
1242 if (pcbWritten)
1243 *pcbWritten = cbData; /** @todo For now return all as being written. */
1244 }
1245
1246 LogFlowFuncLeaveRC(rc);
1247 return rc;
1248}
1249
1250/**
1251 * Starts a transfer on the guest side.
1252 *
1253 * @returns VBox status code.
1254 * @param pCmdCtx Command context to use.
1255 * @param pTransferCtx Transfer context to create transfer for.
1256 * @param uTransferID ID to use for transfer to start.
1257 * @param enmDir Direction of transfer to start.
1258 * @param enmSource Source of transfer to start.
1259 * @param ppTransfer Where to return the transfer object on success. Optional.
1260 */
1261static int vbglR3ClipboardTransferStart(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
1262 SHCLTRANSFERID uTransferID, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource,
1263 PSHCLTRANSFER *ppTransfer)
1264{
1265 PSHCLTRANSFER pTransfer;
1266 int rc = SharedClipboardTransferCreate(&pTransfer);
1267 if (RT_SUCCESS(rc))
1268 {
1269 SharedClipboardTransferSetCallbacks(pTransfer, &pCmdCtx->Transfers.Callbacks);
1270
1271 rc = SharedClipboardTransferCtxTransferRegisterByIndex(pTransferCtx, pTransfer, uTransferID);
1272 if (RT_SUCCESS(rc))
1273 {
1274 rc = SharedClipboardTransferInit(pTransfer, uTransferID, enmDir, enmSource);
1275 if (RT_SUCCESS(rc))
1276 {
1277 rc = SharedClipboardTransferStart(pTransfer);
1278 }
1279 else
1280 SharedClipboardTransferCtxTransferUnregister(pTransferCtx, uTransferID);
1281 }
1282 }
1283
1284 if (RT_SUCCESS(rc))
1285 {
1286 if (ppTransfer)
1287 *ppTransfer = pTransfer;
1288
1289 LogRel2(("Shared Clipboard: Transfer ID=%RU16 (%s %s) successfully started\n",
1290 uTransferID,
1291 enmDir == SHCLTRANSFERDIR_READ ? "reading from" : "writing to",
1292 enmSource == SHCLSOURCE_LOCAL ? "local" : "remote"));
1293 }
1294 else
1295 LogRel(("Shared Clipboard: Unable to start transfer ID=%RU16, rc=%Rrc\n", uTransferID, rc));
1296
1297 /* Send a reply in any case. */
1298 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
1299 RT_SUCCESS(rc)
1300 ? SHCLTRANSFERSTATUS_STARTED : SHCLTRANSFERSTATUS_ERROR, rc);
1301 AssertRC(rc2);
1302
1303 LogFlowFuncLeaveRC(rc);
1304 return rc;
1305}
1306
1307/**
1308 * Stops a transfer on the guest side.
1309 *
1310 * @returns VBox status code, or VERR_NOT_FOUND if transfer has not been found.
1311 * @param pCmdCtx Command context to use.
1312 * @param pTransferCtx Transfer context to stop transfer for.
1313 * @param uTransferID ID of transfer to stop.
1314 */
1315static int vbglR3ClipboardTransferStop(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
1316 SHCLTRANSFERID uTransferID)
1317{
1318 int rc;
1319
1320 PSHCLTRANSFER pTransfer = SharedClipboardTransferCtxGetTransfer(pTransferCtx, uTransferID);
1321 if (pTransfer)
1322 {
1323 rc = SharedClipboardTransferClose(pTransfer);
1324 if (RT_SUCCESS(rc))
1325 rc = SharedClipboardTransferCtxTransferUnregister(pTransferCtx, uTransferID);
1326
1327 if (RT_SUCCESS(rc))
1328 {
1329 LogRel2(("Shared Clipboard: Transfer ID=%RU16 successfully stopped\n", uTransferID));
1330 }
1331 else
1332 LogRel(("Shared Clipboard: Unable to stop transfer ID=%RU16, rc=%Rrc\n", uTransferID, rc));
1333
1334 /* Send a reply in any case. */
1335 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
1336 RT_SUCCESS(rc)
1337 ? SHCLTRANSFERSTATUS_STOPPED : SHCLTRANSFERSTATUS_ERROR, rc);
1338 AssertRC(rc2);
1339 }
1340 else
1341 rc = VERR_NOT_FOUND;
1342
1343 LogFlowFuncLeaveRC(rc);
1344 return rc;
1345}
1346
1347VBGLR3DECL(int) VbglR3ClipboardEventGetNextEx(uint32_t idMsg, uint32_t cParms,
1348 PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
1349 PVBGLR3CLIPBOARDEVENT pEvent)
1350{
1351 AssertPtrReturn(pCmdCtx, VERR_INVALID_POINTER);
1352 AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER);
1353 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1354
1355 LogFunc(("Handling idMsg=%RU32 (%s), cParms=%RU32\n", idMsg, VBoxShClHostMsgToStr(idMsg), cParms));
1356
1357 int rc;
1358
1359 switch (idMsg)
1360 {
1361 case VBOX_SHCL_HOST_MSG_TRANSFER_STATUS:
1362 {
1363 SHCLTRANSFERDIR enmDir;
1364 SHCLTRANSFERREPORT transferReport;
1365 rc = VbglR3ClipboarTransferStatusRecv(pCmdCtx, &enmDir, &transferReport);
1366 if (RT_SUCCESS(rc))
1367 {
1368 const SHCLTRANSFERID uTransferID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID);
1369
1370 LogFlowFunc(("[Transfer %RU16] enmDir=%RU32, status=%s\n",
1371 uTransferID, enmDir, VBoxShClTransferStatusToStr(transferReport.uStatus)));
1372
1373 switch (transferReport.uStatus)
1374 {
1375 case SHCLTRANSFERSTATUS_INITIALIZED:
1376 RT_FALL_THROUGH();
1377 case SHCLTRANSFERSTATUS_STARTED:
1378 {
1379 SHCLSOURCE enmSource = SHCLSOURCE_INVALID;
1380
1381 /* The host announces the transfer direction from its point of view, so inverse the direction here. */
1382 if (enmDir == SHCLTRANSFERDIR_WRITE)
1383 {
1384 enmDir = SHCLTRANSFERDIR_READ;
1385 enmSource = SHCLSOURCE_REMOTE;
1386 }
1387 else if (enmDir == SHCLTRANSFERDIR_READ)
1388 {
1389 enmDir = SHCLTRANSFERDIR_WRITE;
1390 enmSource = SHCLSOURCE_LOCAL;
1391 }
1392 else
1393 AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
1394
1395 rc = vbglR3ClipboardTransferStart(pCmdCtx, pTransferCtx, uTransferID,
1396 enmDir, enmSource, NULL /* ppTransfer */);
1397 break;
1398 }
1399
1400 case SHCLTRANSFERSTATUS_STOPPED:
1401 RT_FALL_THROUGH();
1402 case SHCLTRANSFERSTATUS_CANCELED:
1403 RT_FALL_THROUGH();
1404 case SHCLTRANSFERSTATUS_KILLED:
1405 RT_FALL_THROUGH();
1406 case SHCLTRANSFERSTATUS_ERROR:
1407 {
1408 rc = vbglR3ClipboardTransferStop(pCmdCtx, pTransferCtx,
1409 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
1410 break;
1411 }
1412
1413 default:
1414 rc = VERR_NOT_SUPPORTED;
1415 break;
1416 }
1417
1418 if (RT_SUCCESS(rc))
1419 {
1420 pEvent->u.TransferStatus.enmDir = enmDir;
1421 pEvent->u.TransferStatus.Report = transferReport;
1422 pEvent->u.TransferStatus.uID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID);
1423
1424 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_URI_TRANSFER_STATUS;
1425
1426 LogRel2(("Shared Clipboard: Received status %RU32 (%Rrc) for transfer ID=%RU16\n",
1427 pEvent->u.TransferStatus.Report.uStatus, pEvent->u.TransferStatus.Report.rc,
1428 pEvent->u.TransferStatus.uID));
1429 }
1430 }
1431 break;
1432 }
1433
1434 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ:
1435 {
1436 uint32_t fRoots;
1437 rc = VbglR3ClipboardRootListHdrReadReq(pCmdCtx, &fRoots);
1438
1439 /** @todo Validate / handle fRoots. */
1440
1441 if (RT_SUCCESS(rc))
1442 {
1443 PSHCLTRANSFER pTransfer = SharedClipboardTransferCtxGetTransfer(pTransferCtx,
1444 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
1445 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
1446
1447 SHCLROOTLISTHDR rootListHdr;
1448 RT_ZERO(rootListHdr);
1449
1450 rootListHdr.cRoots = SharedClipboardTransferRootsCount(pTransfer);
1451
1452 LogFlowFunc(("cRoots=%RU32\n", rootListHdr.cRoots));
1453
1454 rc = VbglR3ClipboardRootListHdrReadReply(pCmdCtx, &rootListHdr);
1455 }
1456 break;
1457 }
1458
1459 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ:
1460 {
1461 uint32_t uIndex;
1462 uint32_t fInfo;
1463 rc = VbglR3ClipboardRootListEntryReadReq(pCmdCtx, &uIndex, &fInfo);
1464 if (RT_SUCCESS(rc))
1465 {
1466 PSHCLTRANSFER pTransfer = SharedClipboardTransferCtxGetTransfer(pTransferCtx,
1467 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
1468 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
1469
1470 SHCLROOTLISTENTRY rootListEntry;
1471 rc = SharedClipboardTransferRootsEntry(pTransfer, uIndex, &rootListEntry);
1472 if (RT_SUCCESS(rc))
1473 rc = VbglR3ClipboardRootListEntryReadReply(pCmdCtx, uIndex, &rootListEntry);
1474 }
1475 break;
1476 }
1477
1478 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN:
1479 {
1480 SHCLLISTOPENPARMS openParmsList;
1481 rc = SharedClipboardTransferListOpenParmsInit(&openParmsList);
1482 if (RT_SUCCESS(rc))
1483 {
1484 rc = VbglR3ClipboardListOpenRecv(pCmdCtx, &openParmsList);
1485 if (RT_SUCCESS(rc))
1486 {
1487 PSHCLTRANSFER pTransfer = SharedClipboardTransferCtxGetTransfer(pTransferCtx,
1488 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
1489 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
1490
1491 LogFlowFunc(("pszPath=%s\n", openParmsList.pszPath));
1492
1493 SHCLLISTHANDLE hList = SHCLLISTHANDLE_INVALID;
1494 rc = SharedClipboardTransferListOpen(pTransfer, &openParmsList, &hList);
1495
1496 /* Reply in any case. */
1497 int rc2 = VbglR3ClipboardListOpenReply(pCmdCtx, rc, hList);
1498 AssertRC(rc2);
1499 }
1500
1501 SharedClipboardTransferListOpenParmsDestroy(&openParmsList);
1502 }
1503
1504 break;
1505 }
1506
1507 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE:
1508 {
1509 SHCLLISTHANDLE hList;
1510 rc = VbglR3ClipboardListCloseRecv(pCmdCtx, &hList);
1511 if (RT_SUCCESS(rc))
1512 {
1513 PSHCLTRANSFER pTransfer = SharedClipboardTransferCtxGetTransfer(pTransferCtx,
1514 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
1515 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
1516
1517 rc = SharedClipboardTransferListClose(pTransfer, hList);
1518
1519 /* Reply in any case. */
1520 int rc2 = VbglR3ClipboardListCloseReply(pCmdCtx, rc, hList);
1521 AssertRC(rc2);
1522 }
1523
1524 break;
1525 }
1526
1527 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ:
1528 {
1529 /** @todo Handle filter + list features. */
1530
1531 SHCLLISTHANDLE hList = SHCLLISTHANDLE_INVALID;
1532 uint32_t fFlags = 0;
1533 rc = VbglR3ClipboardListHdrReadRecvReq(pCmdCtx, &hList, &fFlags);
1534 if (RT_SUCCESS(rc))
1535 {
1536 PSHCLTRANSFER pTransfer = SharedClipboardTransferCtxGetTransfer(pTransferCtx,
1537 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
1538 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
1539
1540 SHCLLISTHDR hdrList;
1541 rc = SharedClipboardTransferListGetHeader(pTransfer, hList, &hdrList);
1542 if (RT_SUCCESS(rc))
1543 {
1544 rc = VbglR3ClipboardListHdrWrite(pCmdCtx, hList, &hdrList);
1545
1546 SharedClipboardTransferListHdrDestroy(&hdrList);
1547 }
1548 }
1549
1550 break;
1551 }
1552
1553 #if 0
1554 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_WRITE:
1555 {
1556 LogFlowFunc(("VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_WRITE\n"));
1557
1558 SHCLLISTHDR hdrList;
1559 rc = SharedClipboardTransferListHdrInit(&hdrList);
1560 if (RT_SUCCESS(rc))
1561 {
1562 rc = VBglR3ClipboardListHdrRecv(pCtx, )
1563 }
1564 break;
1565 }
1566 #endif
1567
1568 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ:
1569 {
1570 LogFlowFunc(("VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ\n"));
1571
1572 SHCLLISTENTRY entryList;
1573 rc = SharedClipboardTransferListEntryInit(&entryList);
1574 if (RT_SUCCESS(rc))
1575 {
1576 SHCLLISTHANDLE hList;
1577 uint32_t fInfo;
1578 rc = VbglR3ClipboardListEntryReadRecvReq(pCmdCtx, &hList, &fInfo);
1579 if (RT_SUCCESS(rc))
1580 {
1581 PSHCLTRANSFER pTransfer = SharedClipboardTransferCtxGetTransfer(pTransferCtx,
1582 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
1583 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
1584
1585 rc = SharedClipboardTransferListRead(pTransfer, hList, &entryList);
1586 if (RT_SUCCESS(rc))
1587 {
1588 PSHCLFSOBJINFO pObjInfo = (PSHCLFSOBJINFO)entryList.pvInfo;
1589 Assert(entryList.cbInfo == sizeof(SHCLFSOBJINFO));
1590
1591 RT_NOREF(pObjInfo);
1592
1593 LogFlowFunc(("\t%s (%RU64 bytes)\n", entryList.pszName, pObjInfo->cbObject));
1594
1595 rc = VbglR3ClipboardListEntryWrite(pCmdCtx, hList, &entryList);
1596 }
1597 }
1598
1599 SharedClipboardTransferListEntryDestroy(&entryList);
1600 }
1601
1602 break;
1603 }
1604
1605 #if 0
1606 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_WRITE:
1607 {
1608 LogFlowFunc(("VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_WRITE\n"));
1609 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_URI_LIST_ENTRY_WRITE;
1610 break;
1611 }
1612 #endif
1613
1614 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN:
1615 {
1616 SHCLOBJOPENCREATEPARMS openParms;
1617 rc = SharedClipboardTransferObjectOpenParmsInit(&openParms);
1618 if (RT_SUCCESS(rc))
1619 {
1620 rc = VbglR3ClipboardObjOpenRecv(pCmdCtx, &openParms);
1621 if (RT_SUCCESS(rc))
1622 {
1623 PSHCLTRANSFER pTransfer = SharedClipboardTransferCtxGetTransfer(pTransferCtx,
1624 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
1625 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
1626
1627 SHCLOBJHANDLE hObj;
1628 rc = SharedClipboardTransferObjectOpen(pTransfer, &openParms, &hObj);
1629
1630 /* Reply in any case. */
1631 int rc2 = VbglR3ClipboardObjOpenReply(pCmdCtx, rc, hObj);
1632 AssertRC(rc2);
1633 }
1634
1635 SharedClipboardTransferObjectOpenParmsDestroy(&openParms);
1636 }
1637
1638 break;
1639 }
1640
1641 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE:
1642 {
1643 SHCLOBJHANDLE hObj;
1644 rc = VbglR3ClipboardObjCloseRecv(pCmdCtx, &hObj);
1645 if (RT_SUCCESS(rc))
1646 {
1647 PSHCLTRANSFER pTransfer = SharedClipboardTransferCtxGetTransfer(pTransferCtx,
1648 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
1649 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
1650
1651 rc = SharedClipboardTransferObjectClose(pTransfer, hObj);
1652
1653 /* Reply in any case. */
1654 int rc2 = VbglR3ClipboardObjCloseReply(pCmdCtx, rc, hObj);
1655 AssertRC(rc2);
1656 }
1657
1658 break;
1659 }
1660
1661 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ:
1662 {
1663 SHCLOBJHANDLE hObj;
1664 uint32_t cbBuf;
1665 uint32_t fFlags;
1666 rc = VbglR3ClipboardObjReadRecv(pCmdCtx, &hObj, &cbBuf, &fFlags);
1667 if (RT_SUCCESS(rc))
1668 {
1669 PSHCLTRANSFER pTransfer = SharedClipboardTransferCtxGetTransfer(pTransferCtx,
1670 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->uContextID));
1671 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
1672
1673 AssertBreakStmt(pCmdCtx->cbChunkSize, rc = VERR_INVALID_PARAMETER);
1674
1675 const uint32_t cbToRead = RT_MIN(cbBuf, pCmdCtx->cbChunkSize);
1676
1677 LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, fFlags=0x%x -> cbChunkSize=%RU32, cbToRead=%RU32\n",
1678 hObj, cbBuf, fFlags, pCmdCtx->cbChunkSize, cbToRead));
1679
1680 void *pvBuf = RTMemAlloc(cbToRead);
1681 if (pvBuf)
1682 {
1683 uint32_t cbRead;
1684 rc = SharedClipboardTransferObjectRead(pTransfer, hObj, pvBuf, cbToRead, &cbRead, fFlags);
1685 if (RT_SUCCESS(rc))
1686 rc = VbglR3ClipboardObjWrite(pCmdCtx, hObj, pvBuf, cbRead, NULL /* pcbWritten */);
1687
1688 RTMemFree(pvBuf);
1689 }
1690 else
1691 rc = VERR_NO_MEMORY;
1692 }
1693
1694 break;
1695 }
1696
1697 #if 0
1698 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_WRITE:
1699 {
1700 LogFlowFunc(("VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_WRITE\n"));
1701 break;
1702 }
1703 #endif
1704
1705 default:
1706 {
1707 rc = VbglR3ClipboardEventGetNext(idMsg, cParms, pCmdCtx, pEvent);
1708 break;
1709 }
1710 }
1711
1712 LogFlowFuncLeaveRC(rc);
1713 return rc;
1714}
1715#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
1716
1717VBGLR3DECL(int) VbglR3ClipboardEventGetNext(uint32_t idMsg, uint32_t cParms,
1718 PVBGLR3SHCLCMDCTX pCtx, PVBGLR3CLIPBOARDEVENT pEvent)
1719{
1720 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1721 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1722
1723 RT_NOREF(cParms);
1724
1725 int rc;
1726
1727#ifdef LOG_ENABLED
1728 LogFunc(("Handling idMsg=%RU32 (%s), protocol v%RU32\n", idMsg, VBoxShClHostMsgToStr(idMsg), pCtx->uProtocolVer));
1729#endif
1730 switch (idMsg)
1731 {
1732 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
1733 {
1734 rc = VbglR3ClipboardFormatsReportRecv(pCtx, &pEvent->u.ReportedFormats);
1735 if (RT_SUCCESS(rc))
1736 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
1737 break;
1738 }
1739
1740 case VBOX_SHCL_HOST_MSG_READ_DATA:
1741 {
1742 rc = VbglR3ClipboardReadDataRecv(pCtx, &pEvent->u.ReadData);
1743 if (RT_SUCCESS(rc))
1744 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
1745 break;
1746 }
1747
1748 default:
1749 {
1750 rc = VERR_NOT_SUPPORTED;
1751 break;
1752 }
1753 }
1754
1755 if (RT_SUCCESS(rc))
1756 {
1757 /* Copy over our command context to the event. */
1758 pEvent->cmdCtx = *pCtx;
1759 }
1760 else
1761 {
1762 /* Report error back to the host. */
1763 int rc2 = VbglR3ClipboardWriteError(pCtx->uClientID, rc);
1764 AssertRC(rc2);
1765
1766 }
1767
1768 LogFlowFuncLeaveRC(rc);
1769 return rc;
1770}
1771
1772/**
1773 * Frees (destroys) a formerly allocated Shared Clipboard event.
1774 *
1775 * @returns IPRT status code.
1776 * @param pEvent Event to free (destroy).
1777 */
1778VBGLR3DECL(void) VbglR3ClipboardEventFree(PVBGLR3CLIPBOARDEVENT pEvent)
1779{
1780 if (!pEvent)
1781 return;
1782
1783 /* Some messages require additional cleanup. */
1784 switch (pEvent->enmType)
1785 {
1786 default:
1787 break;
1788 }
1789
1790 RTMemFree(pEvent);
1791 pEvent = NULL;
1792}
1793
1794#if 0
1795VBGLR3DECL(int) VbglR3ClipboardListHdrReadRecv(HGCMCLIENTID idClient, PSHCLLISTHANDLE phList)
1796{
1797 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1798
1799 VBoxShClListHdrReadMsg Msg;
1800 RT_ZERO(Msg);
1801
1802 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient,
1803 VBOX_SHCL_GUEST_FN_LIST_HDR_READ, VBOX_SHCL_CPARMS_LIST_HDR_READ);
1804
1805 Msg.uContext.SetUInt32(0); /** @todo Not used yet. */
1806 Msg.uHandle.SetUInt64(0);
1807
1808 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1809 if (RT_SUCCESS(rc))
1810 {
1811 Msg.uHandle.GetUInt32(phList);
1812 }
1813
1814 LogFlowFuncLeaveRC(rc);
1815 return rc;
1816}
1817
1818/**
1819 * Sends a list header to the host.
1820 *
1821 * @returns VBox status code.
1822 * @param idClient The client id returned by VbglR3ClipboardConnect().
1823 * @param hList List handle to send header for.
1824 * @param pListHdr List header to send.
1825 */
1826VBGLR3DECL(int) VbglR3ClipboardListHdrSend(HGCMCLIENTID idClient,
1827 SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
1828{
1829 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
1830
1831 VBoxShClListHdrMsg Msg;
1832 RT_ZERO(Msg);
1833
1834 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient,
1835 VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE, VBOX_SHCL_CPARMS_LIST_HDR);
1836
1837 Msg.uContext.SetUInt32(0); /** @todo Not used yet. */
1838 Msg.fFeatures.SetUInt32(pListHdr->fFeatures);
1839 Msg.cTotalObjects.SetUInt64(pListHdr->cTotalObjects);
1840 Msg.cbTotalSize.SetUInt64(pListHdr->cbTotalSize);
1841 Msg.enmCompression.SetUInt32(pListHdr->enmCompression);
1842 Msg.enmChecksumType.SetUInt32(RTDIGESTTYPE_INVALID);
1843
1844 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1845
1846 LogFlowFuncLeaveRC(rc);
1847 return rc;
1848}
1849
1850/**
1851 * Sends a list entry to the host.
1852 *
1853 * @returns IPRT status code.
1854 * @param idClient The client id returned by VbglR3ClipboardConnect()
1855 * @param hList List handle to send entry for.
1856 * @param pListEntry List entry to send.
1857 */
1858VBGLR3DECL(int) VbglR3ClipboardSendListEntryWrite(HGCMCLIENTID idClient,
1859 SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry)
1860{
1861 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
1862
1863 VBoxShClListEntryWriteMsg Msg;
1864 RT_ZERO(Msg);
1865
1866 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient,
1867 VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE, VBOX_SHCL_CPARMS_LIST_ENTRY_WRITE);
1868
1869 Msg.uContext.SetUInt32(0); /** @todo Not used yet. */
1870 Msg.uHandle.SetUInt64(hList);
1871 Msg.fInfo.SetUInt32(pListEntry->fInfo);
1872 Msg.cbInfo.SetUInt32(pListEntry->cbInfo);
1873 Msg.pvInfo.SetPtr(pListEntry->pvInfo, pListEntry->cbInfo);
1874
1875 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1876
1877 LogFlowFuncLeaveRC(rc);
1878 return rc;
1879}
1880#endif
1881
1882/**
1883 * Sends (reports) guest clipboard formats to the host.
1884 *
1885 * @returns VBox status code.
1886 * @param pCtx The command context returned by VbglR3ClipboardConnect().
1887 * @param pFormats The formats to send (report).
1888 */
1889VBGLR3DECL(int) VbglR3ClipboardFormatsSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMATDATA pFormats)
1890{
1891 VBoxShClFormatsMsg Msg;
1892
1893 int rc;
1894
1895 if (pCtx->uProtocolVer == 0)
1896 {
1897 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, VBOX_SHCL_GUEST_FN_FORMATS_REPORT, 1);
1898 Msg.u.v0.uFormats.SetUInt32(pFormats->uFormats);
1899
1900 rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg.hdr) + sizeof(Msg.u.v0));
1901 }
1902 else
1903 {
1904 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, VBOX_SHCL_GUEST_FN_FORMATS_REPORT, 3);
1905
1906 Msg.u.v1.uContext.SetUInt32(pCtx->uContextID);
1907 Msg.u.v1.uFormats.SetUInt32(pFormats->uFormats);
1908 Msg.u.v1.fFlags.SetUInt32(pFormats->fFlags);
1909
1910 rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg.hdr) + sizeof(Msg.u.v1));
1911 }
1912
1913 LogFlowFuncLeaveRC(rc);
1914 return rc;
1915}
1916
1917/**
1918 * Reports (advertises) guest clipboard formats to the host.
1919 *
1920 * Legacy function, do not use anymore.
1921 *
1922 * @returns VBox status code.
1923 * @param idClient The client id returned by VbglR3ClipboardConnect().
1924 * @param fFormats The formats to advertise.
1925 */
1926VBGLR3DECL(int) VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats)
1927{
1928 VBoxShClFormatsMsg Msg;
1929
1930 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_FORMATS_REPORT, 1);
1931 VbglHGCMParmUInt32Set(&Msg.u.v0.uFormats, fFormats);
1932
1933 return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg.hdr) + sizeof(Msg.u.v0));
1934}
1935
1936/**
1937 * Sends guest clipboard data to the host. Legacy function kept for compatibility, do not use anymore.
1938 *
1939 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
1940 * from the host.
1941 *
1942 * @returns VBox status code.
1943 * @param idClient The client id returned by VbglR3ClipboardConnect().
1944 * @param fFormat The format of the data.
1945 * @param pv The data.
1946 * @param cb The size of the data.
1947 */
1948VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
1949{
1950 VBoxShClWriteDataMsg Msg;
1951 RT_ZERO(Msg);
1952
1953 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient,
1954 VBOX_SHCL_GUEST_FN_DATA_WRITE, 2);
1955
1956 VbglHGCMParmUInt32Set(&Msg.u.v0.format, fFormat);
1957 VbglHGCMParmPtrSet(&Msg.u.v0.ptr, pv, cb);
1958
1959 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg.hdr) + sizeof(Msg.u.v0));
1960
1961 LogFlowFuncLeaveRC(rc);
1962 return rc;
1963}
1964
1965/**
1966 * Sends guest clipboard data to the host.
1967 *
1968 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
1969 * from the host.
1970 *
1971 * @returns VBox status code.
1972 * @param pCtx The command context returned by VbglR3ClipboardConnect().
1973 * @param pData Clipboard data to send.
1974 */
1975VBGLR3DECL(int) VbglR3ClipboardWriteDataEx(PVBGLR3SHCLCMDCTX pCtx, PSHCLDATABLOCK pData)
1976{
1977 int rc;
1978
1979 if (pCtx->uProtocolVer == 0)
1980 {
1981 rc = VbglR3ClipboardWriteData(pCtx->uClientID, pData->uFormat, pData->pvData, pData->cbData);
1982 }
1983 else
1984 {
1985 VBoxShClWriteDataMsg Msg;
1986 RT_ZERO(Msg);
1987
1988 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID,
1989 VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_WRITE_DATA);
1990
1991 LogFlowFunc(("CID=%RU32\n", pCtx->uContextID));
1992
1993 Msg.u.v1.uContext.SetUInt32(pCtx->uContextID);
1994 Msg.u.v1.uFormat.SetUInt32(pData->uFormat);
1995 Msg.u.v1.cbData.SetUInt32(pData->cbData);
1996 Msg.u.v1.pvData.SetPtr(pData->pvData, pData->cbData);
1997
1998 rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1999 }
2000
2001 LogFlowFuncLeaveRC(rc);
2002 return rc;
2003}
2004
2005/**
2006 * Writes an error to the host.
2007 *
2008 * @returns IPRT status code.
2009 * @param idClient The client id returned by VbglR3ClipboardConnect().
2010 * @param rcErr Error (IPRT-style) to send.
2011 */
2012VBGLR3DECL(int) VbglR3ClipboardWriteError(HGCMCLIENTID idClient, int rcErr)
2013{
2014 VBoxShClWriteErrorMsg Msg;
2015 RT_ZERO(Msg);
2016
2017 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_ERROR, VBOX_SHCL_CPARMS_ERROR);
2018
2019 /** @todo Context ID not used yet. */
2020 Msg.uContext.SetUInt32(0);
2021 Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
2022
2023 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
2024
2025 if (RT_FAILURE(rc))
2026 LogFlowFunc(("Sending error %Rrc failed with rc=%Rrc\n", rcErr, rc));
2027 if (rc == VERR_NOT_SUPPORTED)
2028 rc = VINF_SUCCESS;
2029
2030 if (RT_FAILURE(rc))
2031 LogRel(("Shared Clipboard: Reporting error %Rrc to the host failed with %Rrc\n", rcErr, rc));
2032
2033 LogFlowFuncLeaveRC(rc);
2034 return rc;
2035}
2036
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