VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp@ 52800

Last change on this file since 52800 was 52800, checked in by vboxsync, 10 years ago

Additions/VBoxGuestLib: minor typo, thanks PVS

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.5 KB
Line 
1/* $Id: VBoxGuestR3LibDragAndDrop.cpp 52800 2014-09-22 07:01:51Z vboxsync $ */
2/** @file
3 * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, Drag & Drop.
4 */
5
6/*
7 * Copyright (C) 2011-2013 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 <iprt/path.h>
32#include <iprt/dir.h>
33#include <iprt/file.h>
34#include <iprt/uri.h>
35#include <iprt/thread.h>
36
37#include <iprt/cpp/list.h>
38#include <iprt/cpp/ministring.h>
39
40#ifdef LOG_GROUP
41 #undef LOG_GROUP
42#endif
43#define LOG_GROUP LOG_GROUP_GUEST_DND
44#include <VBox/log.h>
45
46#include <VBox/GuestHost/DragAndDrop.h>
47#include <VBox/HostServices/DragAndDropSvc.h>
48
49#include "VBGLR3Internal.h"
50
51/* Here all the communication with the host over HGCM is handled platform
52 * neutral. Also the receiving of URIs content (directory trees and files) is
53 * done here. So the platform code of the guests, should not take care of that.
54 *
55 * Todo:
56 * - Sending dirs/files in the G->H case
57 * - Maybe the EOL converting of text MIME types (not fully sure, eventually
58 * better done on the host side)
59 */
60
61/******************************************************************************
62 * Private internal functions *
63 ******************************************************************************/
64
65static int vbglR3DnDQueryNextHostMessageType(uint32_t uClientId, uint32_t *puMsg, uint32_t *pcParms, bool fWait)
66{
67 AssertPtrReturn(puMsg, VERR_INVALID_POINTER);
68 AssertPtrReturn(pcParms, VERR_INVALID_POINTER);
69
70 DragAndDropSvc::VBOXDNDNEXTMSGMSG Msg;
71 RT_ZERO(Msg);
72 Msg.hdr.result = VERR_WRONG_ORDER;
73 Msg.hdr.u32ClientID = uClientId;
74 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG;
75 Msg.hdr.cParms = 3;
76
77 Msg.msg.SetUInt32(0);
78 Msg.num_parms.SetUInt32(0);
79 Msg.block.SetUInt32(fWait);
80
81 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
82 if (RT_SUCCESS(rc))
83 {
84 rc = Msg.hdr.result;
85 if (RT_SUCCESS(rc))
86 {
87 rc = Msg.msg.GetUInt32(puMsg); AssertRC(rc);
88 rc = Msg.num_parms.GetUInt32(pcParms); AssertRC(rc);
89 }
90 }
91
92 return rc;
93}
94
95static int vbglR3DnDHGProcessActionMessage(uint32_t uClientId,
96 uint32_t uMsg,
97 uint32_t *puScreenId,
98 uint32_t *puX,
99 uint32_t *puY,
100 uint32_t *puDefAction,
101 uint32_t *puAllActions,
102 char *pszFormats,
103 uint32_t cbFormats,
104 uint32_t *pcbFormatsRecv)
105{
106 AssertPtrReturn(puScreenId, VERR_INVALID_POINTER);
107 AssertPtrReturn(puX, VERR_INVALID_POINTER);
108 AssertPtrReturn(puY, VERR_INVALID_POINTER);
109 AssertPtrReturn(puDefAction, VERR_INVALID_POINTER);
110 AssertPtrReturn(puAllActions, VERR_INVALID_POINTER);
111 AssertPtrReturn(pszFormats, VERR_INVALID_POINTER);
112 AssertReturn(cbFormats, VERR_INVALID_PARAMETER);
113 AssertPtrReturn(pcbFormatsRecv, VERR_INVALID_POINTER);
114
115 DragAndDropSvc::VBOXDNDHGACTIONMSG Msg;
116 RT_ZERO(Msg);
117 Msg.hdr.u32ClientID = uClientId;
118 Msg.hdr.u32Function = uMsg;
119 Msg.hdr.cParms = 7;
120
121 Msg.uScreenId.SetUInt32(0);
122 Msg.uX.SetUInt32(0);
123 Msg.uY.SetUInt32(0);
124 Msg.uDefAction.SetUInt32(0);
125 Msg.uAllActions.SetUInt32(0);
126 Msg.pvFormats.SetPtr(pszFormats, cbFormats);
127 Msg.cFormats.SetUInt32(0);
128
129 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
130 if (RT_SUCCESS(rc))
131 {
132 rc = Msg.hdr.result;
133 if (RT_SUCCESS(rc))
134 {
135 rc = Msg.uScreenId.GetUInt32(puScreenId); AssertRC(rc);
136 rc = Msg.uX.GetUInt32(puX); AssertRC(rc);
137 rc = Msg.uY.GetUInt32(puY); AssertRC(rc);
138 rc = Msg.uDefAction.GetUInt32(puDefAction); AssertRC(rc);
139 rc = Msg.uAllActions.GetUInt32(puAllActions); AssertRC(rc);
140 rc = Msg.cFormats.GetUInt32(pcbFormatsRecv); AssertRC(rc);
141
142 AssertReturn(cbFormats >= *pcbFormatsRecv, VERR_TOO_MUCH_DATA);
143 }
144 }
145
146 return rc;
147}
148
149static int vbglR3DnDHGProcessLeaveMessage(uint32_t uClientId)
150{
151 DragAndDropSvc::VBOXDNDHGLEAVEMSG Msg;
152 RT_ZERO(Msg);
153 Msg.hdr.u32ClientID = uClientId;
154 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_LEAVE;
155 Msg.hdr.cParms = 0;
156
157 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
158 if (RT_SUCCESS(rc))
159 rc = Msg.hdr.result;
160
161 return rc;
162}
163
164static int vbglR3DnDHGProcessCancelMessage(uint32_t uClientId)
165{
166 DragAndDropSvc::VBOXDNDHGCANCELMSG Msg;
167 RT_ZERO(Msg);
168 Msg.hdr.u32ClientID = uClientId;
169 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_CANCEL;
170 Msg.hdr.cParms = 0;
171
172 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
173 if (RT_SUCCESS(rc))
174 rc = Msg.hdr.result;
175
176 return rc;
177}
178
179static int vbglR3DnDHGProcessSendDirMessage(uint32_t uClientId,
180 char *pszDirname,
181 uint32_t cbDirname,
182 uint32_t *pcbDirnameRecv,
183 uint32_t *pfMode)
184{
185 AssertPtrReturn(pszDirname, VERR_INVALID_POINTER);
186 AssertReturn(cbDirname, VERR_INVALID_PARAMETER);
187 AssertPtrReturn(pcbDirnameRecv, VERR_INVALID_POINTER);
188 AssertPtrReturn(pfMode, VERR_INVALID_POINTER);
189
190 DragAndDropSvc::VBOXDNDHGSENDDIRMSG Msg;
191 RT_ZERO(Msg);
192 Msg.hdr.u32ClientID = uClientId;
193 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_DIR;
194 Msg.hdr.cParms = 3;
195
196 Msg.pvName.SetPtr(pszDirname, cbDirname);
197 Msg.cbName.SetUInt32(0);
198 Msg.fMode.SetUInt32(0);
199
200 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
201 if (RT_SUCCESS(rc))
202 {
203 rc = Msg.hdr.result;
204 if (RT_SUCCESS(Msg.hdr.result))
205 {
206 rc = Msg.cbName.GetUInt32(pcbDirnameRecv); AssertRC(rc);
207 rc = Msg.fMode.GetUInt32(pfMode); AssertRC(rc);
208
209 AssertReturn(cbDirname >= *pcbDirnameRecv, VERR_TOO_MUCH_DATA);
210 }
211 }
212
213 return rc;
214}
215
216static int vbglR3DnDHGProcessSendFileMessage(uint32_t uClientId,
217 char *pszFilename,
218 uint32_t cbFilename,
219 uint32_t *pcbFilenameRecv,
220 void *pvData,
221 uint32_t cbData,
222 uint32_t *pcbDataRecv,
223 uint32_t *pfMode)
224{
225 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
226 AssertReturn(cbFilename, VERR_INVALID_PARAMETER);
227 AssertPtrReturn(pcbFilenameRecv, VERR_INVALID_POINTER);
228 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
229 AssertReturn(cbData, VERR_INVALID_PARAMETER);
230 AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
231 AssertPtrReturn(pfMode, VERR_INVALID_POINTER);
232
233 DragAndDropSvc::VBOXDNDHGSENDFILEMSG Msg;
234 RT_ZERO(Msg);
235 Msg.hdr.u32ClientID = uClientId;
236 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_FILE;
237 Msg.hdr.cParms = 5;
238
239 Msg.pvName.SetPtr(pszFilename, cbFilename);
240 Msg.cbName.SetUInt32(0);
241 Msg.pvData.SetPtr(pvData, cbData);
242 Msg.cbData.SetUInt32(0);
243 Msg.fMode.SetUInt32(0);
244
245 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
246 if (RT_SUCCESS(rc))
247 {
248 rc = Msg.hdr.result;
249 if (RT_SUCCESS(rc))
250 {
251 rc = Msg.cbName.GetUInt32(pcbFilenameRecv); AssertRC(rc);
252 rc = Msg.cbData.GetUInt32(pcbDataRecv); AssertRC(rc);
253 rc = Msg.fMode.GetUInt32(pfMode); AssertRC(rc);
254
255 AssertReturn(cbFilename >= *pcbFilenameRecv, VERR_TOO_MUCH_DATA);
256 AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA);
257 }
258 }
259
260 return rc;
261}
262
263static int vbglR3DnDHGProcessURIMessages(uint32_t uClientId,
264 uint32_t *puScreenId,
265 char *pszFormat,
266 uint32_t cbFormat,
267 uint32_t *pcbFormatRecv,
268 void **ppvData,
269 uint32_t cbData,
270 size_t *pcbDataRecv)
271{
272 AssertPtrReturn(ppvData, VERR_INVALID_POINTER);
273 AssertPtrReturn(cbData, VERR_INVALID_PARAMETER);
274 AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
275
276 if (!*pcbDataRecv)
277 return VERR_INVALID_PARAMETER;
278
279 /* Allocate temp buffer. */
280 uint32_t cbTmpData = _64K; /** @todo Make this configurable? */
281 void *pvTmpData = RTMemAlloc(cbTmpData);
282 if (!pvTmpData)
283 return VERR_NO_MEMORY;
284
285 /* Create and query the (unique) drop target directory. */
286 char pszDropDir[RTPATH_MAX];
287 int rc = DnDDirCreateDroppedFiles(pszDropDir, sizeof(pszDropDir));
288 if (RT_FAILURE(rc))
289 {
290 RTMemFree(pvTmpData);
291 return rc;
292 }
293
294 /* Patch the old drop data with the new drop directory, so the drop target
295 * can find the files. */
296 DnDURIList lstURI;
297 rc = lstURI.RootFromURIData(*ppvData, *pcbDataRecv,
298 0 /* fFlags */);
299 if (RT_SUCCESS(rc))
300 {
301 /* Cleanup the old data and write the new data back to the event. */
302 RTMemFree(*ppvData);
303
304 RTCString strData = lstURI.RootToString(pszDropDir);
305 *ppvData = RTStrDupN(strData.c_str(), strData.length());
306 *pcbDataRecv = strData.length() + 1;
307 }
308
309 /* Lists for holding created files & directories
310 * in the case of a rollback. */
311 RTCList<RTCString> guestDirList;
312 RTCList<RTCString> guestFileList;
313
314 char szPathName[RTPATH_MAX];
315 uint32_t cbPathName = 0;
316
317 bool fLoop = RT_SUCCESS(rc); /* No error occurred yet? */
318 while (fLoop)
319 {
320 uint32_t uNextMsg;
321 uint32_t cNextParms;
322 rc = vbglR3DnDQueryNextHostMessageType(uClientId, &uNextMsg, &cNextParms, false /* fWait */);
323 if (RT_SUCCESS(rc))
324 {
325 switch (uNextMsg)
326 {
327 case DragAndDropSvc::HOST_DND_HG_SND_DIR:
328 {
329 uint32_t fMode = 0;
330 rc = vbglR3DnDHGProcessSendDirMessage(uClientId,
331 szPathName,
332 sizeof(szPathName),
333 &cbPathName,
334 &fMode);
335#ifdef DEBUG_andy
336 LogFlowFunc(("HOST_DND_HG_SND_DIR pszPathName=%s, cbPathName=%RU32, fMode=0x%x, rc=%Rrc\n",
337 szPathName, cbPathName, fMode, rc));
338#endif
339 if (RT_SUCCESS(rc))
340 rc = DnDPathSanitize(szPathName, sizeof(szPathName));
341 if (RT_SUCCESS(rc))
342 {
343 char *pszNewDir = RTPathJoinA(pszDropDir, szPathName);
344 if (pszNewDir)
345 {
346 rc = RTDirCreate(pszNewDir, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRWXU, 0);
347 if (!guestDirList.contains(pszNewDir))
348 guestDirList.append(pszNewDir);
349
350 RTStrFree(pszNewDir);
351 }
352 else
353 rc = VERR_NO_MEMORY;
354 }
355 break;
356 }
357 case DragAndDropSvc::HOST_DND_HG_SND_FILE:
358 {
359 uint32_t cbDataRecv;
360 uint32_t fMode = 0;
361 rc = vbglR3DnDHGProcessSendFileMessage(uClientId,
362 szPathName,
363 sizeof(szPathName),
364 &cbPathName,
365 pvTmpData,
366 cbTmpData,
367 &cbDataRecv,
368 &fMode);
369#ifdef DEBUG_andy
370 LogFlowFunc(("HOST_DND_HG_SND_FILE pszPathName=%s, cbPathName=%RU32, pvData=0x%p, cbDataRecv=%RU32, fMode=0x%x, rc=%Rrc\n",
371 szPathName, cbPathName, pvTmpData, cbDataRecv, fMode, rc));
372#endif
373 if (RT_SUCCESS(rc))
374 rc = DnDPathSanitize(szPathName, sizeof(szPathName));
375 if (RT_SUCCESS(rc))
376 {
377 char *pszPathAbs = RTPathJoinA(pszDropDir, szPathName);
378 if (pszPathAbs)
379 {
380 RTFILE hFile;
381 /** @todo r=andy Keep the file open and locked during the actual file transfer. Otherwise this will
382 * create all sorts of funny races because we don't know if the guest has
383 * modified the file in between the file data send calls. */
384 rc = RTFileOpen(&hFile, pszPathAbs,
385 RTFILE_O_WRITE | RTFILE_O_APPEND | RTFILE_O_DENY_ALL | RTFILE_O_OPEN_CREATE);
386 if (RT_SUCCESS(rc))
387 {
388 /** @todo r=andy Not very safe to assume that we were last appending to the current file. */
389 rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, NULL);
390 if (RT_SUCCESS(rc))
391 {
392 rc = RTFileWrite(hFile, pvTmpData, cbDataRecv, 0);
393 /* Valid UNIX mode? */
394 if ( RT_SUCCESS(rc)
395 && (fMode & RTFS_UNIX_MASK))
396 rc = RTFileSetMode(hFile, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR);
397 }
398
399 RTFileClose(hFile);
400
401 if (!guestFileList.contains(pszPathAbs))
402 guestFileList.append(pszPathAbs);
403 }
404#ifdef DEBUG
405 else
406 LogFlowFunc(("Opening file failed with rc=%Rrc\n", rc));
407#endif
408 RTStrFree(pszPathAbs);
409 }
410 else
411 rc = VERR_NO_MEMORY;
412 }
413 break;
414 }
415 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
416 {
417 rc = vbglR3DnDHGProcessCancelMessage(uClientId);
418 if (RT_SUCCESS(rc))
419 rc = VERR_CANCELLED;
420 /* Break out of the loop. */
421 }
422 default:
423 fLoop = false;
424 break;
425 }
426 }
427 else
428 {
429 if (rc == VERR_NO_DATA)
430 rc = VINF_SUCCESS;
431 break;
432 }
433
434 if (RT_FAILURE(rc))
435 break;
436
437 } /* while */
438
439 if (pvTmpData)
440 RTMemFree(pvTmpData);
441
442 /* Cleanup on failure or if the user has canceled. */
443 if (RT_FAILURE(rc))
444 {
445 /* Remove any stuff created. */
446 for (size_t i = 0; i < guestFileList.size(); ++i)
447 RTFileDelete(guestFileList.at(i).c_str());
448 for (size_t i = 0; i < guestDirList.size(); ++i)
449 RTDirRemove(guestDirList.at(i).c_str());
450 RTDirRemove(pszDropDir);
451
452 LogFlowFunc(("Failed with rc=%Rrc\n", rc));
453 }
454
455 return rc;
456}
457
458static int vbglR3DnDHGProcessDataMessageInternal(uint32_t uClientId,
459 uint32_t *puScreenId,
460 char *pszFormat,
461 uint32_t cbFormat,
462 uint32_t *pcbFormatRecv,
463 void *pvData,
464 uint32_t cbData,
465 uint32_t *pcbDataTotal)
466{
467 AssertPtrReturn(puScreenId, VERR_INVALID_POINTER);
468 AssertPtrReturn(pszFormat, VERR_INVALID_POINTER);
469 AssertReturn(cbFormat, VERR_INVALID_PARAMETER);
470 AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
471 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
472 AssertReturn(cbData, VERR_INVALID_PARAMETER);
473 AssertPtrReturn(pcbDataTotal, VERR_INVALID_POINTER);
474
475 DragAndDropSvc::VBOXDNDHGSENDDATAMSG Msg;
476 RT_ZERO(Msg);
477 Msg.hdr.u32ClientID = uClientId;
478 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_DATA;
479 Msg.hdr.cParms = 5;
480
481 Msg.uScreenId.SetUInt32(0);
482 Msg.pvFormat.SetPtr(pszFormat, cbFormat);
483 Msg.cFormat.SetUInt32(0);
484 Msg.pvData.SetPtr(pvData, cbData);
485 Msg.cbData.SetUInt32(0);
486
487 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
488 if (RT_SUCCESS(rc))
489 {
490 rc = Msg.hdr.result;
491 if ( RT_SUCCESS(rc)
492 || rc == VERR_BUFFER_OVERFLOW)
493 {
494 rc = Msg.uScreenId.GetUInt32(puScreenId); AssertRC(rc);
495 rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
496 rc = Msg.cbData.GetUInt32(pcbDataTotal); AssertRC(rc);
497
498 AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
499 AssertReturn(cbData >= *pcbDataTotal, VERR_TOO_MUCH_DATA);
500 }
501 }
502
503 return rc;
504}
505
506static int vbglR3DnDHGProcessMoreDataMessageInternal(uint32_t uClientId,
507 void *pvData,
508 uint32_t cbData,
509 uint32_t *pcbDataRecv)
510{
511 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
512 AssertReturn(cbData, VERR_INVALID_PARAMETER);
513 AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
514
515 DragAndDropSvc::VBOXDNDHGSENDMOREDATAMSG Msg;
516 RT_ZERO(Msg);
517 Msg.hdr.u32ClientID = uClientId;
518 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA;
519 Msg.hdr.cParms = 2;
520
521 Msg.pvData.SetPtr(pvData, cbData);
522 Msg.cbData.SetUInt32(0);
523
524 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
525 if (RT_SUCCESS(rc))
526 {
527 rc = Msg.hdr.result;
528 if ( RT_SUCCESS(rc)
529 || rc == VERR_BUFFER_OVERFLOW)
530 {
531 rc = Msg.cbData.GetUInt32(pcbDataRecv); AssertRC(rc);
532 AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA);
533 }
534 }
535 return rc;
536}
537
538static int vbglR3DnDHGProcessSendDataMessageLoop(uint32_t uClientId,
539 uint32_t *puScreenId,
540 char *pszFormat,
541 uint32_t cbFormat,
542 uint32_t *pcbFormatRecv,
543 void **ppvData,
544 uint32_t cbData,
545 size_t *pcbDataRecv)
546{
547 uint32_t cbDataRecv = 0;
548 int rc = vbglR3DnDHGProcessDataMessageInternal(uClientId,
549 puScreenId,
550 pszFormat,
551 cbFormat,
552 pcbFormatRecv,
553 *ppvData,
554 cbData,
555 &cbDataRecv);
556 uint32_t cbAllDataRecv = cbDataRecv;
557 while (rc == VERR_BUFFER_OVERFLOW)
558 {
559 uint32_t uNextMsg;
560 uint32_t cNextParms;
561 rc = vbglR3DnDQueryNextHostMessageType(uClientId, &uNextMsg, &cNextParms, false);
562 if (RT_SUCCESS(rc))
563 {
564 switch(uNextMsg)
565 {
566 case DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA:
567 {
568 *ppvData = RTMemRealloc(*ppvData, cbAllDataRecv + cbData);
569 if (!*ppvData)
570 {
571 rc = VERR_NO_MEMORY;
572 break;
573 }
574 rc = vbglR3DnDHGProcessMoreDataMessageInternal(uClientId,
575 &((char*)*ppvData)[cbAllDataRecv],
576 cbData,
577 &cbDataRecv);
578 cbAllDataRecv += cbDataRecv;
579 break;
580 }
581 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
582 default:
583 {
584 rc = vbglR3DnDHGProcessCancelMessage(uClientId);
585 if (RT_SUCCESS(rc))
586 rc = VERR_CANCELLED;
587 break;
588 }
589 }
590 }
591 }
592 if (RT_SUCCESS(rc))
593 *pcbDataRecv = cbAllDataRecv;
594
595 return rc;
596}
597
598static int vbglR3DnDHGProcessSendDataMessage(uint32_t uClientId,
599 uint32_t *puScreenId,
600 char *pszFormat,
601 uint32_t cbFormat,
602 uint32_t *pcbFormatRecv,
603 void **ppvData,
604 uint32_t cbData,
605 size_t *pcbDataRecv)
606{
607 int rc = vbglR3DnDHGProcessSendDataMessageLoop(uClientId,
608 puScreenId,
609 pszFormat,
610 cbFormat,
611 pcbFormatRecv,
612 ppvData,
613 cbData,
614 pcbDataRecv);
615 if (RT_SUCCESS(rc))
616 {
617 /* Check if this is an URI event. If so, let VbglR3 do all the actual
618 * data transfer + file/directory creation internally without letting
619 * the caller know.
620 *
621 * This keeps the actual (guest OS-)dependent client (like VBoxClient /
622 * VBoxTray) small by not having too much redundant code. */
623 AssertPtr(pcbFormatRecv);
624 if (DnDMIMEHasFileURLs(pszFormat, *pcbFormatRecv))
625 rc = vbglR3DnDHGProcessURIMessages(uClientId,
626 puScreenId,
627 pszFormat,
628 cbFormat,
629 pcbFormatRecv,
630 ppvData,
631 cbData,
632 pcbDataRecv);
633 }
634
635 return rc;
636}
637
638static int vbglR3DnDGHProcessRequestPendingMessage(uint32_t uClientId,
639 uint32_t *puScreenId)
640{
641 AssertPtrReturn(puScreenId, VERR_INVALID_POINTER);
642
643 DragAndDropSvc::VBOXDNDGHREQPENDINGMSG Msg;
644 RT_ZERO(Msg);
645 Msg.hdr.u32ClientID = uClientId;
646 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_REQ_PENDING;
647 Msg.hdr.cParms = 1;
648
649 Msg.uScreenId.SetUInt32(0);
650
651 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
652 if (RT_SUCCESS(rc))
653 {
654 rc = Msg.hdr.result;
655 if (RT_SUCCESS(rc))
656 {
657 rc = Msg.uScreenId.GetUInt32(puScreenId); AssertRC(rc);
658 }
659 }
660
661 return rc;
662}
663
664static int vbglR3DnDGHProcessDroppedMessage(uint32_t uClientId,
665 char *pszFormat,
666 uint32_t cbFormat,
667 uint32_t *pcbFormatRecv,
668 uint32_t *puAction)
669{
670 AssertPtrReturn(pszFormat, VERR_INVALID_POINTER);
671 AssertReturn(cbFormat, VERR_INVALID_PARAMETER);
672 AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
673 AssertPtrReturn(puAction, VERR_INVALID_POINTER);
674
675 DragAndDropSvc::VBOXDNDGHDROPPEDMSG Msg;
676 RT_ZERO(Msg);
677 Msg.hdr.u32ClientID = uClientId;
678 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_EVT_DROPPED;
679 Msg.hdr.cParms = 3;
680
681 Msg.pvFormat.SetPtr(pszFormat, cbFormat);
682 Msg.cFormat.SetUInt32(0);
683 Msg.uAction.SetUInt32(0);
684
685 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
686 if (RT_SUCCESS(rc))
687 {
688 rc = Msg.hdr.result;
689 if (RT_SUCCESS(rc))
690 {
691 rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
692 rc = Msg.uAction.GetUInt32(puAction); AssertRC(rc);
693
694 AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
695 }
696 }
697
698 return rc;
699}
700
701/******************************************************************************
702 * Public functions *
703 ******************************************************************************/
704
705VBGLR3DECL(int) VbglR3DnDConnect(uint32_t *pu32ClientId)
706{
707 AssertPtrReturn(pu32ClientId, VERR_INVALID_POINTER);
708
709 /* Initialize header */
710 VBoxGuestHGCMConnectInfo Info;
711 RT_ZERO(Info.Loc.u);
712 Info.result = VERR_WRONG_ORDER;
713 Info.u32ClientID = UINT32_MAX; /* try make valgrind shut up. */
714 /* Initialize parameter */
715 Info.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
716 int rc = RTStrCopy(Info.Loc.u.host.achName, sizeof(Info.Loc.u.host.achName), "VBoxDragAndDropSvc");
717 if (RT_FAILURE(rc)) return rc;
718 /* Do request */
719 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CONNECT, &Info, sizeof(Info));
720 if (RT_SUCCESS(rc))
721 {
722 rc = Info.result;
723 if (RT_SUCCESS(rc))
724 *pu32ClientId = Info.u32ClientID;
725 }
726 return rc;
727}
728
729VBGLR3DECL(int) VbglR3DnDDisconnect(uint32_t u32ClientId)
730{
731 VBoxGuestHGCMDisconnectInfo Info;
732 Info.result = VERR_WRONG_ORDER;
733 Info.u32ClientID = u32ClientId;
734
735 /* Do request */
736 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_DISCONNECT, &Info, sizeof(Info));
737 if (RT_SUCCESS(rc))
738 rc = Info.result;
739
740 return rc;
741}
742
743VBGLR3DECL(int) VbglR3DnDProcessNextMessage(uint32_t u32ClientId, CPVBGLR3DNDHGCMEVENT pEvent)
744{
745 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
746
747 uint32_t uMsg = 0;
748 uint32_t uNumParms = 0;
749 const uint32_t ccbFormats = _64K;
750 const uint32_t ccbData = _64K;
751 int rc = vbglR3DnDQueryNextHostMessageType(u32ClientId, &uMsg, &uNumParms,
752 true /* fWait */);
753 if (RT_SUCCESS(rc))
754 {
755 switch(uMsg)
756 {
757 case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
758 case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
759 case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
760 {
761 pEvent->uType = uMsg;
762 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
763 if (!pEvent->pszFormats)
764 rc = VERR_NO_MEMORY;
765
766 if (RT_SUCCESS(rc))
767 rc = vbglR3DnDHGProcessActionMessage(u32ClientId,
768 uMsg,
769 &pEvent->uScreenId,
770 &pEvent->u.a.uXpos,
771 &pEvent->u.a.uYpos,
772 &pEvent->u.a.uDefAction,
773 &pEvent->u.a.uAllActions,
774 pEvent->pszFormats,
775 ccbFormats,
776 &pEvent->cbFormats);
777 break;
778 }
779 case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE:
780 {
781 pEvent->uType = uMsg;
782 rc = vbglR3DnDHGProcessLeaveMessage(u32ClientId);
783 break;
784 }
785 case DragAndDropSvc::HOST_DND_HG_SND_DATA:
786 {
787 pEvent->uType = uMsg;
788 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
789 if (!pEvent->pszFormats)
790 rc = VERR_NO_MEMORY;
791
792 if (RT_SUCCESS(rc))
793 {
794 pEvent->u.b.pvData = RTMemAlloc(ccbData);
795 if (!pEvent->u.b.pvData)
796 {
797 RTMemFree(pEvent->pszFormats);
798 pEvent->pszFormats = NULL;
799 rc = VERR_NO_MEMORY;
800 }
801 }
802
803 if (RT_SUCCESS(rc))
804 rc = vbglR3DnDHGProcessSendDataMessage(u32ClientId,
805 &pEvent->uScreenId,
806 pEvent->pszFormats,
807 ccbFormats,
808 &pEvent->cbFormats,
809 &pEvent->u.b.pvData,
810 ccbData,
811 &pEvent->u.b.cbData);
812 break;
813 }
814 case DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA:
815 case DragAndDropSvc::HOST_DND_HG_SND_DIR:
816 case DragAndDropSvc::HOST_DND_HG_SND_FILE:
817 {
818 pEvent->uType = uMsg;
819
820 /* All messages in this case are handled internally
821 * by vbglR3DnDHGProcessSendDataMessage() and must
822 * be specified by a preceding HOST_DND_HG_SND_DATA call. */
823 rc = VERR_WRONG_ORDER;
824 break;
825 }
826 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
827 {
828 pEvent->uType = uMsg;
829 rc = vbglR3DnDHGProcessCancelMessage(u32ClientId);
830 break;
831 }
832#ifdef VBOX_WITH_DRAG_AND_DROP_GH
833 case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
834 {
835 pEvent->uType = uMsg;
836 rc = vbglR3DnDGHProcessRequestPendingMessage(u32ClientId,
837 &pEvent->uScreenId);
838 break;
839 }
840 case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
841 {
842 pEvent->uType = uMsg;
843 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
844 if (!pEvent->pszFormats)
845 rc = VERR_NO_MEMORY;
846
847 if (RT_SUCCESS(rc))
848 rc = vbglR3DnDGHProcessDroppedMessage(u32ClientId,
849 pEvent->pszFormats,
850 ccbFormats,
851 &pEvent->cbFormats,
852 &pEvent->u.a.uDefAction);
853 break;
854 }
855#endif
856 default:
857 {
858 pEvent->uType = uMsg;
859
860 rc = VERR_NOT_SUPPORTED;
861 break;
862 }
863 }
864 }
865
866 return rc;
867}
868
869VBGLR3DECL(int) VbglR3DnDHGAcknowledgeOperation(uint32_t u32ClientId, uint32_t uAction)
870{
871 DragAndDropSvc::VBOXDNDHGACKOPMSG Msg;
872 RT_ZERO(Msg);
873 Msg.hdr.result = VERR_WRONG_ORDER;
874 Msg.hdr.u32ClientID = u32ClientId;
875 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_ACK_OP;
876 Msg.hdr.cParms = 1;
877
878 Msg.uAction.SetUInt32(uAction);
879
880 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
881 if (RT_SUCCESS(rc))
882 rc = Msg.hdr.result;
883
884 return rc;
885}
886
887VBGLR3DECL(int) VbglR3DnDHGRequestData(uint32_t u32ClientId, const char* pcszFormat)
888{
889 AssertPtrReturn(pcszFormat, VERR_INVALID_PARAMETER);
890
891 DragAndDropSvc::VBOXDNDHGREQDATAMSG Msg;
892 RT_ZERO(Msg);
893 Msg.hdr.result = VERR_WRONG_ORDER;
894 Msg.hdr.u32ClientID = u32ClientId;
895 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_REQ_DATA;
896 Msg.hdr.cParms = 1;
897
898 Msg.pFormat.SetPtr((void*)pcszFormat, (uint32_t)strlen(pcszFormat) + 1);
899
900 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
901 if (RT_SUCCESS(rc))
902 rc = Msg.hdr.result;
903
904 return rc;
905}
906
907#ifdef VBOX_WITH_DRAG_AND_DROP_GH
908VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending(uint32_t u32ClientId,
909 uint32_t uDefAction, uint32_t uAllActions,
910 const char* pcszFormats)
911{
912 AssertPtrReturn(pcszFormats, VERR_INVALID_POINTER);
913
914 DragAndDropSvc::VBOXDNDGHACKPENDINGMSG Msg;
915 RT_ZERO(Msg);
916 Msg.hdr.result = VERR_WRONG_ORDER;
917 Msg.hdr.u32ClientID = u32ClientId;
918 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_ACK_PENDING;
919 Msg.hdr.cParms = 3;
920
921 Msg.uDefAction.SetUInt32(uDefAction);
922 Msg.uAllActions.SetUInt32(uAllActions);
923 Msg.pFormat.SetPtr((void*)pcszFormats, (uint32_t)strlen(pcszFormats) + 1);
924
925 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
926 if (RT_SUCCESS(rc))
927 rc = Msg.hdr.result;
928
929 return rc;
930}
931
932static int vbglR3DnDGHSendDataInternal(uint32_t u32ClientId,
933 void *pvData, uint32_t cbData,
934 uint32_t cbAdditionalData)
935{
936 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
937 AssertReturn(cbData, VERR_INVALID_PARAMETER);
938
939 DragAndDropSvc::VBOXDNDGHSENDDATAMSG Msg;
940 RT_ZERO(Msg);
941 Msg.hdr.result = VERR_WRONG_ORDER;
942 Msg.hdr.u32ClientID = u32ClientId;
943 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DATA;
944 Msg.hdr.cParms = 2;
945
946 /* Total amount of bytes to send (including this data block). */
947 Msg.cbTotalBytes.SetUInt32(cbData + cbAdditionalData);
948
949 int rc;
950
951 uint32_t cbMaxChunk = _64K; /** @todo Transfer max. 64K chunks per message. Configurable? */
952 uint32_t cbSent = 0;
953
954 while (cbSent < cbData)
955 {
956 uint32_t cbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk);
957 Msg.pvData.SetPtr(static_cast<uint8_t*>(pvData) + cbSent, cbCurChunk);
958
959 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
960 if (RT_SUCCESS(rc))
961 rc = Msg.hdr.result;
962
963 if (RT_FAILURE(rc))
964 break;
965
966 cbSent += cbCurChunk;
967 }
968
969 if (RT_SUCCESS(rc))
970 Assert(cbSent == cbData);
971
972 LogFlowFunc(("Returning rc=%Rrc, cbData=%RU32, cbAddtionalData=%RU32, cbSent=%RU32\n",
973 rc, cbData, cbAdditionalData, cbSent));
974 return rc;
975}
976
977static int vbglR3DnDGHSendDir(uint32_t u32ClientId, DnDURIObject &obj)
978{
979 AssertReturn(obj.GetType() == DnDURIObject::Directory, VERR_INVALID_PARAMETER);
980
981 DragAndDropSvc::VBOXDNDGHSENDDIRMSG Msg;
982 RT_ZERO(Msg);
983 Msg.hdr.result = VERR_WRONG_ORDER;
984 Msg.hdr.u32ClientID = u32ClientId;
985 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DIR;
986 Msg.hdr.cParms = 3;
987
988 RTCString strPath = obj.GetDestPath();
989 LogFlowFunc(("strDir=%s (%zu), fMode=0x%x\n",
990 strPath.c_str(), strPath.length(), obj.GetMode()));
991
992 Msg.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
993 Msg.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
994 Msg.fMode.SetUInt32(obj.GetMode());
995
996 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
997 if (RT_SUCCESS(rc))
998 rc = Msg.hdr.result;
999
1000 LogFlowFuncLeaveRC(rc);
1001 return rc;
1002}
1003
1004static int vbglR3DnDGHSendFile(uint32_t u32ClientId, DnDURIObject &obj)
1005{
1006 AssertReturn(obj.GetType() == DnDURIObject::File, VERR_INVALID_PARAMETER);
1007
1008 uint32_t cbBuf = _64K; /** @todo Make this configurable? */
1009 void *pvBuf = RTMemAlloc(cbBuf);
1010 if (!pvBuf)
1011 return VERR_NO_MEMORY;
1012
1013 DragAndDropSvc::VBOXDNDGHSENDFILEMSG Msg;
1014 RT_ZERO(Msg);
1015 Msg.hdr.result = VERR_WRONG_ORDER;
1016 Msg.hdr.u32ClientID = u32ClientId;
1017 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_FILE;
1018 Msg.hdr.cParms = 5;
1019
1020 RTCString strPath = obj.GetDestPath();
1021 LogFlowFunc(("strFile=%s (%zu), fMode=0x%x\n",
1022 strPath.c_str(), strPath.length(), obj.GetMode()));
1023
1024 Msg.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
1025 Msg.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
1026 Msg.fMode.SetUInt32(obj.GetMode());
1027
1028 int rc = VINF_SUCCESS;
1029 uint32_t cbData = obj.GetSize();
1030
1031 do
1032 {
1033 uint32_t cbToRead = RT_MIN(cbData, cbBuf);
1034 uint32_t cbRead = 0;
1035 if (cbToRead)
1036 rc = obj.Read(pvBuf, cbToRead, &cbRead);
1037 if (RT_SUCCESS(rc))
1038 {
1039 Msg.cbData.SetUInt32(cbRead);
1040 Msg.pvData.SetPtr(pvBuf, cbRead);
1041
1042 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
1043 if (RT_SUCCESS(rc))
1044 rc = Msg.hdr.result;
1045 }
1046
1047 if (RT_FAILURE(rc))
1048 break;
1049
1050 Assert(cbRead <= cbData);
1051 cbData -= cbRead;
1052
1053 } while (cbData);
1054
1055 RTMemFree(pvBuf);
1056
1057 LogFlowFuncLeaveRC(rc);
1058 return rc;
1059}
1060
1061static int vbglR3DnDGHSendURIObject(uint32_t u32ClientId, DnDURIObject &obj)
1062{
1063 int rc;
1064
1065 switch (obj.GetType())
1066 {
1067 case DnDURIObject::Directory:
1068 rc = vbglR3DnDGHSendDir(u32ClientId, obj);
1069 break;
1070
1071 case DnDURIObject::File:
1072 rc = vbglR3DnDGHSendFile(u32ClientId, obj);
1073 break;
1074
1075 default:
1076 AssertMsgFailed(("Type %ld not implemented\n",
1077 obj.GetType()));
1078 rc = VERR_NOT_IMPLEMENTED;
1079 break;
1080 }
1081
1082 return rc;
1083}
1084
1085static int vbglR3DnDGHProcessURIMessages(uint32_t u32ClientId,
1086 const void *pvData, uint32_t cbData)
1087{
1088 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1089 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1090
1091 RTCList<RTCString> lstPaths =
1092 RTCString((const char *)pvData, cbData).split("\r\n");
1093
1094 DnDURIList lstURI;
1095 int rc = lstURI.AppendURIPathsFromList(lstPaths, 0 /* fFlags */);
1096 if (RT_SUCCESS(rc))
1097 {
1098 /* Send metadata; in this case it's the (non-recursive) file/directory
1099 * URI list the host needs to know to initialize the drag'n drop operation. */
1100 RTCString strRootDest = lstURI.RootToString();
1101 Assert(strRootDest.isNotEmpty());
1102
1103 void *pvToSend = (void *)strRootDest.c_str();
1104 uint32_t cbToSend = (uint32_t)strRootDest.length() + 1;
1105
1106 rc = vbglR3DnDGHSendDataInternal(u32ClientId, pvToSend, cbToSend,
1107 /* Include total bytes of all file paths,
1108 * file sizes etc. */
1109 lstURI.TotalBytes());
1110 }
1111
1112 if (RT_SUCCESS(rc))
1113 {
1114 while (!lstURI.IsEmpty())
1115 {
1116 DnDURIObject &nextObj = lstURI.First();
1117
1118 rc = vbglR3DnDGHSendURIObject(u32ClientId, nextObj);
1119 if (RT_FAILURE(rc))
1120 break;
1121
1122 lstURI.RemoveFirst();
1123 }
1124 }
1125
1126 return rc;
1127}
1128
1129VBGLR3DECL(int) VbglR3DnDGHSendData(uint32_t u32ClientId,
1130 const char *pszFormat,
1131 void *pvData, uint32_t cbData)
1132{
1133 AssertPtrReturn(pszFormat, VERR_INVALID_POINTER);
1134 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1135 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1136
1137 int rc;
1138 if (DnDMIMEHasFileURLs(pszFormat, strlen(pszFormat)))
1139 {
1140 rc = vbglR3DnDGHProcessURIMessages(u32ClientId, pvData, cbData);
1141 }
1142 else
1143 rc = vbglR3DnDGHSendDataInternal(u32ClientId, pvData, cbData,
1144 0 /* cbAdditionalData */);
1145 if (RT_FAILURE(rc))
1146 {
1147 int rc2 = VbglR3DnDGHSendError(u32ClientId, rc);
1148 AssertRC(rc2);
1149 }
1150
1151 return rc;
1152}
1153
1154VBGLR3DECL(int) VbglR3DnDGHSendError(uint32_t u32ClientId, int rcErr)
1155{
1156 DragAndDropSvc::VBOXDNDGHEVTERRORMSG Msg;
1157 RT_ZERO(Msg);
1158 Msg.hdr.result = VERR_WRONG_ORDER;
1159 Msg.hdr.u32ClientID = u32ClientId;
1160 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_EVT_ERROR;
1161 Msg.hdr.cParms = 1;
1162
1163 Msg.uRC.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
1164
1165 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
1166 if (RT_SUCCESS(rc))
1167 rc = Msg.hdr.result;
1168
1169 LogFlowFunc(("Sending error %Rrc returned with rc=%Rrc\n", rcErr, rc));
1170 return rc;
1171}
1172#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
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