VirtualBox

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

Last change on this file since 50724 was 50724, checked in by vboxsync, 11 years ago

DnD: Implemented guest->host drag'n drop for X11-based guests.

  • 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 50724 2014-03-07 10:54:59Z 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 rc = Msg.uScreenId.GetUInt32(puScreenId); AssertRC(rc);
657 }
658
659 return rc;
660}
661
662static int vbglR3DnDGHProcessDroppedMessage(uint32_t uClientId,
663 char *pszFormat,
664 uint32_t cbFormat,
665 uint32_t *pcbFormatRecv,
666 uint32_t *puAction)
667{
668 AssertPtrReturn(pszFormat, VERR_INVALID_POINTER);
669 AssertReturn(cbFormat, VERR_INVALID_PARAMETER);
670 AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
671 AssertPtrReturn(puAction, VERR_INVALID_POINTER);
672
673 DragAndDropSvc::VBOXDNDGHDROPPEDMSG Msg;
674 RT_ZERO(Msg);
675 Msg.hdr.u32ClientID = uClientId;
676 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_EVT_DROPPED;
677 Msg.hdr.cParms = 3;
678
679 Msg.pvFormat.SetPtr(pszFormat, cbFormat);
680 Msg.cFormat.SetUInt32(0);
681 Msg.uAction.SetUInt32(0);
682
683 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
684 if (RT_SUCCESS(rc))
685 {
686 rc = Msg.hdr.result;
687 if (RT_SUCCESS(rc))
688 {
689 rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
690 rc = Msg.uAction.GetUInt32(puAction); AssertRC(rc);
691
692 AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
693 }
694 }
695
696 return rc;
697}
698
699/******************************************************************************
700 * Public functions *
701 ******************************************************************************/
702
703VBGLR3DECL(int) VbglR3DnDConnect(uint32_t *pu32ClientId)
704{
705 AssertPtrReturn(pu32ClientId, VERR_INVALID_POINTER);
706
707 /* Initialize header */
708 VBoxGuestHGCMConnectInfo Info;
709 RT_ZERO(Info.Loc.u);
710 Info.result = VERR_WRONG_ORDER;
711 Info.u32ClientID = UINT32_MAX; /* try make valgrind shut up. */
712 /* Initialize parameter */
713 Info.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
714 int rc = RTStrCopy(Info.Loc.u.host.achName, sizeof(Info.Loc.u.host.achName), "VBoxDragAndDropSvc");
715 if (RT_FAILURE(rc)) return rc;
716 /* Do request */
717 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CONNECT, &Info, sizeof(Info));
718 if (RT_SUCCESS(rc))
719 {
720 rc = Info.result;
721 if (RT_SUCCESS(rc))
722 *pu32ClientId = Info.u32ClientID;
723 }
724 return rc;
725}
726
727VBGLR3DECL(int) VbglR3DnDDisconnect(uint32_t u32ClientId)
728{
729 VBoxGuestHGCMDisconnectInfo Info;
730 Info.result = VERR_WRONG_ORDER;
731 Info.u32ClientID = u32ClientId;
732
733 /* Do request */
734 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_DISCONNECT, &Info, sizeof(Info));
735 if (RT_SUCCESS(rc))
736 rc = Info.result;
737
738 return rc;
739}
740
741VBGLR3DECL(int) VbglR3DnDProcessNextMessage(uint32_t u32ClientId, CPVBGLR3DNDHGCMEVENT pEvent)
742{
743 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
744
745 uint32_t uMsg = 0;
746 uint32_t uNumParms = 0;
747 const uint32_t ccbFormats = _64K;
748 const uint32_t ccbData = _64K;
749 int rc = vbglR3DnDQueryNextHostMessageType(u32ClientId, &uMsg, &uNumParms,
750 true /* fWait */);
751 if (RT_SUCCESS(rc))
752 {
753 switch(uMsg)
754 {
755 case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
756 case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
757 case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
758 {
759 pEvent->uType = uMsg;
760 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
761 if (!pEvent->pszFormats)
762 rc = VERR_NO_MEMORY;
763
764 if (RT_SUCCESS(rc))
765 rc = vbglR3DnDHGProcessActionMessage(u32ClientId,
766 uMsg,
767 &pEvent->uScreenId,
768 &pEvent->u.a.uXpos,
769 &pEvent->u.a.uYpos,
770 &pEvent->u.a.uDefAction,
771 &pEvent->u.a.uAllActions,
772 pEvent->pszFormats,
773 ccbFormats,
774 &pEvent->cbFormats);
775 break;
776 }
777 case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE:
778 {
779 pEvent->uType = uMsg;
780 rc = vbglR3DnDHGProcessLeaveMessage(u32ClientId);
781 break;
782 }
783 case DragAndDropSvc::HOST_DND_HG_SND_DATA:
784 {
785 pEvent->uType = uMsg;
786 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
787 if (!pEvent->pszFormats)
788 rc = VERR_NO_MEMORY;
789
790 if (RT_SUCCESS(rc))
791 {
792 pEvent->u.b.pvData = RTMemAlloc(ccbData);
793 if (!pEvent->u.b.pvData)
794 {
795 RTMemFree(pEvent->pszFormats);
796 pEvent->pszFormats = NULL;
797 rc = VERR_NO_MEMORY;
798 }
799 }
800
801 if (RT_SUCCESS(rc))
802 rc = vbglR3DnDHGProcessSendDataMessage(u32ClientId,
803 &pEvent->uScreenId,
804 pEvent->pszFormats,
805 ccbFormats,
806 &pEvent->cbFormats,
807 &pEvent->u.b.pvData,
808 ccbData,
809 &pEvent->u.b.cbData);
810 break;
811 }
812 case DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA:
813 case DragAndDropSvc::HOST_DND_HG_SND_DIR:
814 case DragAndDropSvc::HOST_DND_HG_SND_FILE:
815 {
816 pEvent->uType = uMsg;
817
818 /* All messages in this case are handled internally
819 * by vbglR3DnDHGProcessSendDataMessage() and must
820 * be specified by a preceding HOST_DND_HG_SND_DATA call. */
821 rc = VERR_WRONG_ORDER;
822 break;
823 }
824 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
825 {
826 pEvent->uType = uMsg;
827 rc = vbglR3DnDHGProcessCancelMessage(u32ClientId);
828 break;
829 }
830#ifdef VBOX_WITH_DRAG_AND_DROP_GH
831 case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
832 {
833 pEvent->uType = uMsg;
834 rc = vbglR3DnDGHProcessRequestPendingMessage(u32ClientId,
835 &pEvent->uScreenId);
836 break;
837 }
838 case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
839 {
840 pEvent->uType = uMsg;
841 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
842 if (!pEvent->pszFormats)
843 rc = VERR_NO_MEMORY;
844
845 if (RT_SUCCESS(rc))
846 rc = vbglR3DnDGHProcessDroppedMessage(u32ClientId,
847 pEvent->pszFormats,
848 ccbFormats,
849 &pEvent->cbFormats,
850 &pEvent->u.a.uDefAction);
851 break;
852 }
853#endif
854 default:
855 {
856 pEvent->uType = uMsg;
857
858 rc = VERR_NOT_SUPPORTED;
859 break;
860 }
861 }
862 }
863
864 return rc;
865}
866
867VBGLR3DECL(int) VbglR3DnDHGAcknowledgeOperation(uint32_t u32ClientId, uint32_t uAction)
868{
869 DragAndDropSvc::VBOXDNDHGACKOPMSG Msg;
870 RT_ZERO(Msg);
871 Msg.hdr.result = VERR_WRONG_ORDER;
872 Msg.hdr.u32ClientID = u32ClientId;
873 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_ACK_OP;
874 Msg.hdr.cParms = 1;
875
876 Msg.uAction.SetUInt32(uAction);
877
878 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
879 if (RT_SUCCESS(rc))
880 rc = Msg.hdr.result;
881
882 return rc;
883}
884
885VBGLR3DECL(int) VbglR3DnDHGRequestData(uint32_t u32ClientId, const char* pcszFormat)
886{
887 AssertPtrReturn(pcszFormat, VERR_INVALID_PARAMETER);
888
889 DragAndDropSvc::VBOXDNDHGREQDATAMSG Msg;
890 RT_ZERO(Msg);
891 Msg.hdr.result = VERR_WRONG_ORDER;
892 Msg.hdr.u32ClientID = u32ClientId;
893 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_REQ_DATA;
894 Msg.hdr.cParms = 1;
895
896 Msg.pFormat.SetPtr((void*)pcszFormat, (uint32_t)strlen(pcszFormat) + 1);
897
898 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
899 if (RT_SUCCESS(rc))
900 rc = Msg.hdr.result;
901
902 return rc;
903}
904
905#ifdef VBOX_WITH_DRAG_AND_DROP_GH
906VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending(uint32_t u32ClientId,
907 uint32_t uDefAction, uint32_t uAllActions,
908 const char* pcszFormats)
909{
910 AssertPtrReturn(pcszFormats, VERR_INVALID_POINTER);
911
912 DragAndDropSvc::VBOXDNDGHACKPENDINGMSG Msg;
913 RT_ZERO(Msg);
914 Msg.hdr.result = VERR_WRONG_ORDER;
915 Msg.hdr.u32ClientID = u32ClientId;
916 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_ACK_PENDING;
917 Msg.hdr.cParms = 3;
918
919 Msg.uDefAction.SetUInt32(uDefAction);
920 Msg.uAllActions.SetUInt32(uAllActions);
921 Msg.pFormat.SetPtr((void*)pcszFormats, (uint32_t)strlen(pcszFormats) + 1);
922
923 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
924 if (RT_SUCCESS(rc))
925 rc = Msg.hdr.result;
926
927 return rc;
928}
929
930static int vbglR3DnDGHSendDataInternal(uint32_t u32ClientId,
931 void *pvData, uint32_t cbData,
932 uint32_t cbAdditionalData)
933{
934 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
935 AssertReturn(cbData, VERR_INVALID_PARAMETER);
936
937 DragAndDropSvc::VBOXDNDGHSENDDATAMSG Msg;
938 RT_ZERO(Msg);
939 Msg.hdr.result = VERR_WRONG_ORDER;
940 Msg.hdr.u32ClientID = u32ClientId;
941 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DATA;
942 Msg.hdr.cParms = 2;
943
944 /* Total amount of bytes to send (including this data block). */
945 Msg.cbTotalBytes.SetUInt32(cbData + cbAdditionalData);
946
947 int rc;
948
949 uint32_t cbMaxChunk = _64K; /** @todo Transfer max. 64K chunks per message. Configurable? */
950 uint32_t cbSent = 0;
951
952 while (cbSent < cbData)
953 {
954 uint32_t cbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk);
955 Msg.pvData.SetPtr(static_cast<uint8_t*>(pvData) + cbSent, cbCurChunk);
956
957 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
958 if (RT_SUCCESS(rc))
959 rc = Msg.hdr.result;
960
961 if (RT_FAILURE(rc))
962 break;
963
964 cbSent += cbCurChunk;
965 }
966
967 if (RT_SUCCESS(rc))
968 Assert(cbSent == cbData);
969
970 LogFlowFunc(("Returning rc=%Rrc, cbData=%RU32, cbAddtionalData=%RU32, cbSent=%RU32\n",
971 rc, cbData, cbAdditionalData, cbSent));
972 return rc;
973}
974
975static int vbglR3DnDGHSendDir(uint32_t u32ClientId, DnDURIObject &obj)
976{
977 AssertReturn(obj.GetType() == DnDURIObject::Directory, VERR_INVALID_PARAMETER);
978
979 DragAndDropSvc::VBOXDNDGHSENDDIRMSG Msg;
980 RT_ZERO(Msg);
981 Msg.hdr.result = VERR_WRONG_ORDER;
982 Msg.hdr.u32ClientID = u32ClientId;
983 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DIR;
984 Msg.hdr.cParms = 3;
985
986 RTCString strPath = obj.GetDestPath();
987 LogFlowFunc(("strDir=%s (%zu), fMode=0x%x\n",
988 strPath.c_str(), strPath.length(), obj.GetMode()));
989
990 Msg.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
991 Msg.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
992 Msg.fMode.SetUInt32(obj.GetMode());
993
994 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
995 if (RT_SUCCESS(rc))
996 rc = Msg.hdr.result;
997
998 LogFlowFuncLeaveRC(rc);
999 return rc;
1000}
1001
1002static int vbglR3DnDGHSendFile(uint32_t u32ClientId, DnDURIObject &obj)
1003{
1004 AssertReturn(obj.GetType() == DnDURIObject::File, VERR_INVALID_PARAMETER);
1005
1006 uint32_t cbBuf = _64K; /** @todo Make this configurable? */
1007 void *pvBuf = RTMemAlloc(cbBuf);
1008 if (!pvBuf)
1009 return VERR_NO_MEMORY;
1010
1011 DragAndDropSvc::VBOXDNDGHSENDFILEMSG Msg;
1012 RT_ZERO(Msg);
1013 Msg.hdr.result = VERR_WRONG_ORDER;
1014 Msg.hdr.u32ClientID = u32ClientId;
1015 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_FILE;
1016 Msg.hdr.cParms = 5;
1017
1018 RTCString strPath = obj.GetDestPath();
1019 LogFlowFunc(("strFile=%s (%zu), fMode=0x%x\n",
1020 strPath.c_str(), strPath.length(), obj.GetMode()));
1021
1022 Msg.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
1023 Msg.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
1024 Msg.fMode.SetUInt32(obj.GetMode());
1025
1026 int rc = VINF_SUCCESS;
1027 uint32_t cbData = obj.GetSize();
1028
1029 do
1030 {
1031 uint32_t cbToRead = RT_MIN(cbData, cbBuf);
1032 uint32_t cbRead = 0;
1033 if (cbToRead)
1034 rc = obj.Read(pvBuf, cbToRead, &cbRead);
1035 if (RT_SUCCESS(rc))
1036 {
1037 Msg.cbData.SetUInt32(cbRead);
1038 Msg.pvData.SetPtr(pvBuf, cbRead);
1039
1040 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
1041 if (RT_SUCCESS(rc))
1042 rc = Msg.hdr.result;
1043 }
1044
1045 if (RT_FAILURE(rc))
1046 break;
1047
1048 Assert(cbRead <= cbData);
1049 cbData -= cbRead;
1050
1051 } while (cbData);
1052
1053 RTMemFree(pvBuf);
1054
1055 LogFlowFuncLeaveRC(rc);
1056 return rc;
1057}
1058
1059static int vbglR3DnDGHSendURIObject(uint32_t u32ClientId, DnDURIObject &obj)
1060{
1061 int rc;
1062
1063 switch (obj.GetType())
1064 {
1065 case DnDURIObject::Directory:
1066 rc = vbglR3DnDGHSendDir(u32ClientId, obj);
1067 break;
1068
1069 case DnDURIObject::File:
1070 rc = vbglR3DnDGHSendFile(u32ClientId, obj);
1071 break;
1072
1073 default:
1074 AssertMsgFailed(("Type %ld not implemented\n",
1075 obj.GetType()));
1076 rc = VERR_NOT_IMPLEMENTED;
1077 break;
1078 }
1079
1080 return rc;
1081}
1082
1083static int vbglR3DnDGHProcessURIMessages(uint32_t u32ClientId,
1084 void *pvData, uint32_t cbData)
1085{
1086 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1087 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1088
1089 RTCList<RTCString> lstPaths =
1090 RTCString((const char *)pvData, cbData).split("\r\n");
1091
1092 DnDURIList lstURI;
1093 int rc = lstURI.AppendURIPathsFromList(lstPaths, 0 /* fFlags */);
1094 if (RT_SUCCESS(rc))
1095 {
1096 /* Send metadata; in this case it's the (non-recursive) file/directory
1097 * URI list the host needs to know to initialize the drag'n drop operation. */
1098 RTCString strRootDest = lstURI.RootToString();
1099 Assert(strRootDest.isNotEmpty());
1100
1101 void *pvToSend = (void *)strRootDest.c_str();
1102 uint32_t cbToSend = (uint32_t)strRootDest.length() + 1;
1103
1104 rc = vbglR3DnDGHSendDataInternal(u32ClientId, pvToSend, cbToSend,
1105 /* Include total bytes of all file paths,
1106 * file sizes etc. */
1107 lstURI.TotalBytes());
1108 }
1109
1110 if (RT_SUCCESS(rc))
1111 {
1112 while (!lstURI.IsEmpty())
1113 {
1114 DnDURIObject &nextObj = lstURI.First();
1115
1116 rc = vbglR3DnDGHSendURIObject(u32ClientId, nextObj);
1117 if (RT_FAILURE(rc))
1118 break;
1119
1120 lstURI.RemoveFirst();
1121 }
1122 }
1123
1124 return rc;
1125}
1126
1127VBGLR3DECL(int) VbglR3DnDGHSendData(uint32_t u32ClientId,
1128 const char *pszFormat,
1129 void *pvData, uint32_t cbData)
1130{
1131 AssertPtrReturn(pszFormat, VERR_INVALID_POINTER);
1132 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1133 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1134
1135 int rc;
1136 if (DnDMIMEHasFileURLs(pszFormat, strlen(pszFormat)))
1137 {
1138 rc = vbglR3DnDGHProcessURIMessages(u32ClientId, pvData, cbData);
1139 }
1140 else
1141 rc = vbglR3DnDGHSendDataInternal(u32ClientId, pvData, cbData,
1142 0 /* cbAdditionalData */);
1143 if (RT_FAILURE(rc))
1144 {
1145 int rc2 = VbglR3DnDGHSendError(u32ClientId, rc);
1146 AssertRC(rc2);
1147 }
1148
1149 return rc;
1150}
1151
1152VBGLR3DECL(int) VbglR3DnDGHSendError(uint32_t u32ClientId, int rcErr)
1153{
1154 DragAndDropSvc::VBOXDNDGHEVTERRORMSG Msg;
1155 RT_ZERO(Msg);
1156 Msg.hdr.result = VERR_WRONG_ORDER;
1157 Msg.hdr.u32ClientID = u32ClientId;
1158 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_EVT_ERROR;
1159 Msg.hdr.cParms = 1;
1160
1161 Msg.uRC.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
1162
1163 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
1164 if (RT_SUCCESS(rc))
1165 rc = Msg.hdr.result;
1166
1167 LogFlowFunc(("Sending error %Rrc returned with rc=%Rrc\n", rcErr, rc));
1168 return rc;
1169}
1170#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