VirtualBox

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

Last change on this file since 44558 was 42261, checked in by vboxsync, 12 years ago

enabled shared clipboard support for Linux hosts (guest=>host only)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.4 KB
Line 
1/* $Id: VBoxGuestR3LibDragAndDrop.cpp 42261 2012-07-20 13:27:47Z vboxsync $ */
2/** @file
3 * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, Drag & Drop.
4 */
5
6/*
7 * Copyright (C) 2011-2012 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#include "VBGLR3Internal.h"
41#include "VBox/HostServices/DragAndDropSvc.h"
42
43#define VERBOSE 1
44
45#if defined(VERBOSE) && defined(DEBUG_poetzsch)
46# include <iprt/stream.h>
47# define DO(s) RTPrintf s
48#else
49# define DO(s) do {} while(0)
50//# define DO(s) Log s
51#endif
52
53/* Here all the communication with the host over HGCM is handled platform
54 * neutral. Also the receiving of URIs content (directory trees and files) is
55 * done here. So the platform code of the guests, should not take care of that.
56 *
57 * Todo:
58 * - Sending dirs/files in the G->H case
59 * - Maybe the EOL converting of text mime-types (not fully sure, eventually
60 * better done on the host side)
61 */
62
63/* Not really used at the moment (only one client is possible): */
64uint32_t g_clientId = 0;
65
66/******************************************************************************
67 * Private internal functions *
68 ******************************************************************************/
69
70static int vbglR3DnDCreateDropDir(char* pszDropDir, size_t cbSize)
71{
72 /* Validate input */
73 AssertPtrReturn(pszDropDir, VERR_INVALID_POINTER);
74 AssertReturn(cbSize, VERR_INVALID_PARAMETER);
75
76 /* Get the users document directory (usually $HOME/Documents). */
77 int rc = RTPathUserDocuments(pszDropDir, cbSize);
78 if (RT_FAILURE(rc))
79 return rc;
80 /* Append our base drop directory. */
81 rc = RTPathAppend(pszDropDir, cbSize, "VirtualBox Dropped Files");
82 if (RT_FAILURE(rc))
83 return rc;
84 /* Create it when necessary. */
85 if (!RTDirExists(pszDropDir))
86 {
87 rc = RTDirCreateFullPath(pszDropDir, RTFS_UNIX_IRWXU);
88 if (RT_FAILURE(rc))
89 return rc;
90 }
91 /* The actually drop directory consist of the current time stamp and a
92 * unique number when necessary. */
93 char pszTime[64];
94 RTTIMESPEC time;
95 if (!RTTimeSpecToString(RTTimeNow(&time), pszTime, sizeof(pszTime)))
96 return VERR_BUFFER_OVERFLOW;
97 rc = RTPathAppend(pszDropDir, cbSize, pszTime);
98 if (RT_FAILURE(rc))
99 return rc;
100
101 /* Create it (only accessible by the current user) */
102 return RTDirCreateUniqueNumbered(pszDropDir, cbSize, RTFS_UNIX_IRWXU, 3, '-');
103}
104
105static int vbglR3DnDQueryNextHostMessageType(uint32_t uClientId, uint32_t *puMsg, uint32_t *pcParms, bool fWait)
106{
107 /* Validate input */
108 AssertPtrReturn(puMsg, VERR_INVALID_POINTER);
109 AssertPtrReturn(pcParms, VERR_INVALID_POINTER);
110
111 /* Initialize header */
112 DragAndDropSvc::VBOXDNDNEXTMSGMSG Msg;
113 RT_ZERO(Msg);
114 Msg.hdr.result = VERR_WRONG_ORDER;
115 Msg.hdr.u32ClientID = uClientId;
116 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG;
117 Msg.hdr.cParms = 3;
118 /* Initialize parameter */
119 Msg.msg.SetUInt32(0);
120 Msg.num_parms.SetUInt32(0);
121 Msg.block.SetUInt32(fWait);
122 /* Do request */
123 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
124 if (RT_SUCCESS(rc))
125 {
126 rc = Msg.hdr.result;
127 if (RT_SUCCESS(rc))
128 {
129 /* Fetch results */
130 rc = Msg.msg.GetUInt32(puMsg); AssertRC(rc);
131 rc = Msg.num_parms.GetUInt32(pcParms); AssertRC(rc);
132 }
133 }
134 return rc;
135}
136
137static int vbglR3DnDHGProcessActionMessage(uint32_t uClientId,
138 uint32_t uMsg,
139 uint32_t *puScreenId,
140 uint32_t *puX,
141 uint32_t *puY,
142 uint32_t *puDefAction,
143 uint32_t *puAllActions,
144 char *pszFormats,
145 uint32_t cbFormats,
146 uint32_t *pcbFormatsRecv)
147{
148 /* Validate input */
149 AssertPtrReturn(puScreenId, VERR_INVALID_POINTER);
150 AssertPtrReturn(puX, VERR_INVALID_POINTER);
151 AssertPtrReturn(puY, VERR_INVALID_POINTER);
152 AssertPtrReturn(puDefAction, VERR_INVALID_POINTER);
153 AssertPtrReturn(puAllActions, VERR_INVALID_POINTER);
154 AssertPtrReturn(pszFormats, VERR_INVALID_POINTER);
155 AssertReturn(cbFormats, VERR_INVALID_PARAMETER);
156 AssertPtrReturn(pcbFormatsRecv, VERR_INVALID_POINTER);
157
158 /* Initialize header */
159 DragAndDropSvc::VBOXDNDHGACTIONMSG Msg;
160 RT_ZERO(Msg);
161 Msg.hdr.u32ClientID = uClientId;
162 Msg.hdr.u32Function = uMsg;
163 Msg.hdr.cParms = 7;
164 /* Initialize parameter */
165 Msg.uScreenId.SetUInt32(0);
166 Msg.uX.SetUInt32(0);
167 Msg.uY.SetUInt32(0);
168 Msg.uDefAction.SetUInt32(0);
169 Msg.uAllActions.SetUInt32(0);
170 Msg.pvFormats.SetPtr(pszFormats, cbFormats);
171 Msg.cFormats.SetUInt32(0);
172 /* Do request */
173 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
174 if (RT_SUCCESS(rc))
175 {
176 rc = Msg.hdr.result;
177 if (RT_SUCCESS(rc))
178 {
179 /* Fetch results */
180 rc = Msg.uScreenId.GetUInt32(puScreenId); AssertRC(rc);
181 rc = Msg.uX.GetUInt32(puX); AssertRC(rc);
182 rc = Msg.uY.GetUInt32(puY); AssertRC(rc);
183 rc = Msg.uDefAction.GetUInt32(puDefAction); AssertRC(rc);
184 rc = Msg.uAllActions.GetUInt32(puAllActions); AssertRC(rc);
185 rc = Msg.cFormats.GetUInt32(pcbFormatsRecv); AssertRC(rc);
186 /* A little bit paranoia */
187 AssertReturn(cbFormats >= *pcbFormatsRecv, VERR_TOO_MUCH_DATA);
188 }
189 }
190 return rc;
191}
192
193static int vbglR3DnDHGProcessLeaveMessage(uint32_t uClientId)
194{
195 /* Initialize header */
196 DragAndDropSvc::VBOXDNDHGLEAVEMSG Msg;
197 RT_ZERO(Msg);
198 Msg.hdr.u32ClientID = uClientId;
199 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_LEAVE;
200 Msg.hdr.cParms = 0;
201 /* Do request */
202 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
203 if (RT_SUCCESS(rc))
204 rc = Msg.hdr.result;
205 return rc;
206}
207
208static int vbglR3DnDHGProcessCancelMessage(uint32_t uClientId)
209{
210 /* Initialize header */
211 DragAndDropSvc::VBOXDNDHGCANCELMSG Msg;
212 RT_ZERO(Msg);
213 Msg.hdr.u32ClientID = uClientId;
214 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_CANCEL;
215 Msg.hdr.cParms = 0;
216 /* Do request */
217 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
218 if (RT_SUCCESS(rc))
219 rc = Msg.hdr.result;
220 return rc;
221}
222
223static int vbglR3DnDHGProcessSendDirMessage(uint32_t uClientId,
224 char *pszDirname,
225 uint32_t cbDirname,
226 uint32_t *pcbDirnameRecv,
227 uint32_t *pfMode)
228{
229 /* Validate input */
230 AssertPtrReturn(pszDirname, VERR_INVALID_POINTER);
231 AssertReturn(cbDirname, VERR_INVALID_PARAMETER);
232 AssertPtrReturn(pcbDirnameRecv, VERR_INVALID_POINTER);
233 AssertPtrReturn(pfMode, VERR_INVALID_POINTER);
234
235 /* Initialize header */
236 DragAndDropSvc::VBOXDNDHGSENDDIRMSG Msg;
237 RT_ZERO(Msg);
238 Msg.hdr.u32ClientID = uClientId;
239 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_DIR;
240 Msg.hdr.cParms = 3;
241 /* Initialize parameter */
242 Msg.pvName.SetPtr(pszDirname, cbDirname);
243 Msg.cName.SetUInt32(0);
244 Msg.fMode.SetUInt32(0);
245 /* Do request */
246 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
247 if (RT_SUCCESS(rc))
248 {
249 rc = Msg.hdr.result;
250 if (RT_SUCCESS(Msg.hdr.result))
251 {
252 /* Fetch results */
253 rc = Msg.cName.GetUInt32(pcbDirnameRecv); AssertRC(rc);
254 rc = Msg.fMode.GetUInt32(pfMode); AssertRC(rc);
255 /* A little bit paranoia */
256 AssertReturn(cbDirname >= *pcbDirnameRecv, VERR_TOO_MUCH_DATA);
257 }
258 }
259 return rc;
260}
261
262static int vbglR3DnDHGProcessSendFileMessage(uint32_t uClientId,
263 char *pszFilename,
264 uint32_t cbFilename,
265 uint32_t *pcbFilenameRecv,
266 void *pvData,
267 uint32_t cbData,
268 uint32_t *pcbDataRecv,
269 uint32_t *pfMode)
270{
271 /* Validate input */
272 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
273 AssertReturn(cbFilename, VERR_INVALID_PARAMETER);
274 AssertPtrReturn(pcbFilenameRecv, VERR_INVALID_POINTER);
275 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
276 AssertReturn(cbData, VERR_INVALID_PARAMETER);
277 AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
278 AssertPtrReturn(pfMode, VERR_INVALID_POINTER);
279
280 /* Initialize header */
281 DragAndDropSvc::VBOXDNDHGSENDFILEMSG Msg;
282 RT_ZERO(Msg);
283 Msg.hdr.u32ClientID = uClientId;
284 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_FILE;
285 Msg.hdr.cParms = 5;
286 /* Initialize parameter */
287 Msg.pvName.SetPtr(pszFilename, cbFilename);
288 Msg.cName.SetUInt32(0);
289 Msg.pvData.SetPtr(pvData, cbData);
290 Msg.cData.SetUInt32(0);
291 Msg.fMode.SetUInt32(0);
292 /* Do request */
293 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
294 if (RT_SUCCESS(rc))
295 {
296 rc = Msg.hdr.result;
297 if (RT_SUCCESS(rc))
298 {
299 /* Fetch results */
300 rc = Msg.cName.GetUInt32(pcbFilenameRecv); AssertRC(rc);
301 rc = Msg.cData.GetUInt32(pcbDataRecv); AssertRC(rc);
302 rc = Msg.fMode.GetUInt32(pfMode); AssertRC(rc);
303 /* A little bit paranoia */
304 AssertReturn(cbFilename >= *pcbFilenameRecv, VERR_TOO_MUCH_DATA);
305 AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA);
306 }
307 }
308 return rc;
309}
310
311static int vbglR3DnDHGProcessURIMessages(uint32_t uClientId,
312 uint32_t *puScreenId,
313 char *pszFormat,
314 uint32_t cbFormat,
315 uint32_t *pcbFormatRecv,
316 void **ppvData,
317 uint32_t cbData,
318 size_t *pcbDataRecv)
319{
320 /* Make a string list out of the uri data. */
321 RTCList<RTCString> uriList = RTCString(static_cast<char*>(*ppvData), *pcbDataRecv - 1).split("\r\n");
322 if (uriList.isEmpty())
323 return VINF_SUCCESS;
324
325 uint32_t cbTmpData = _1M * 10;
326 void *pvTmpData = RTMemAlloc(cbTmpData);
327 if (!pvTmpData)
328 return VERR_NO_MEMORY;
329
330 /* Create and query the drop target directory. */
331 char pszDropDir[RTPATH_MAX];
332 int rc = vbglR3DnDCreateDropDir(pszDropDir, sizeof(pszDropDir));
333 if (RT_FAILURE(rc))
334 {
335 RTMemFree(pvTmpData);
336 return rc;
337 }
338
339 /* Patch the old drop data with the new drop directory, so the drop target
340 * can find the files. */
341 RTCList<RTCString> guestUriList;
342 for (size_t i = 0; i < uriList.size(); ++i)
343 {
344 const RTCString &strUri = uriList.at(i);
345 /* Query the path component of a file URI. If this hasn't a
346 * file scheme, null is returned. */
347 if (char *pszFilePath = RTUriFilePath(strUri.c_str(), URI_FILE_FORMAT_AUTO))
348 {
349 RTCString strFullPath = RTCString().printf("%s%c%s", pszDropDir, RTPATH_SLASH, pszFilePath);
350 char *pszNewUri = RTUriFileCreate(strFullPath.c_str());
351 if (pszNewUri)
352 {
353 guestUriList.append(pszNewUri);
354 RTStrFree(pszNewUri);
355 }
356 }
357 else
358 guestUriList.append(strUri);
359 }
360
361 /* Cleanup the old data and write the new data back to the event. */
362 RTMemFree(*ppvData);
363 RTCString newData = RTCString::join(guestUriList, "\r\n") + "\r\n";
364 *ppvData = RTStrDupN(newData.c_str(), newData.length());
365 *pcbDataRecv = newData.length() + 1;
366
367 /* Lists for holding created files & directories in the case of a
368 * rollback. */
369 RTCList<RTCString> guestDirList;
370 RTCList<RTCString> guestFileList;
371 char pszPathname[RTPATH_MAX];
372 uint32_t cbPathname = 0;
373 bool fLoop = true;
374 do
375 {
376 uint32_t uNextMsg;
377 uint32_t cNextParms;
378 rc = vbglR3DnDQueryNextHostMessageType(uClientId, &uNextMsg, &cNextParms, false);
379 DO(("%Rrc - %d\n", rc , uNextMsg));
380 if (RT_SUCCESS(rc))
381 {
382 switch(uNextMsg)
383 {
384 case DragAndDropSvc::HOST_DND_HG_SND_DIR:
385 {
386 uint32_t fMode = 0;
387 rc = vbglR3DnDHGProcessSendDirMessage(uClientId,
388 pszPathname,
389 sizeof(pszPathname),
390 &cbPathname,
391 &fMode);
392 if (RT_SUCCESS(rc))
393 {
394 DO(("Got drop dir: %s - %o - %Rrc\n", pszPathname, fMode, rc));
395 char *pszNewDir = RTPathJoinA(pszDropDir, pszPathname);
396 rc = RTDirCreate(pszNewDir, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRWXU, 0);
397 if (!guestDirList.contains(pszNewDir))
398 guestDirList.append(pszNewDir);
399 }
400 break;
401 }
402 case DragAndDropSvc::HOST_DND_HG_SND_FILE:
403 {
404 uint32_t cbDataRecv;
405 uint32_t fMode = 0;
406 rc = vbglR3DnDHGProcessSendFileMessage(uClientId,
407 pszPathname,
408 sizeof(pszPathname),
409 &cbPathname,
410 pvTmpData,
411 cbTmpData,
412 &cbDataRecv,
413 &fMode);
414 if (RT_SUCCESS(rc))
415 {
416 char *pszNewFile = RTPathJoinA(pszDropDir, pszPathname);
417 DO(("Got drop file: %s - %d - %o - %Rrc\n", pszPathname, cbDataRecv, fMode, rc));
418 RTFILE hFile;
419 rc = RTFileOpen(&hFile, pszNewFile, RTFILE_O_WRITE | RTFILE_O_APPEND | RTFILE_O_DENY_ALL | RTFILE_O_OPEN_CREATE);
420 if (RT_SUCCESS(rc))
421 {
422 rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, NULL);
423 if (RT_SUCCESS(rc))
424 {
425 rc = RTFileWrite(hFile, pvTmpData, cbDataRecv, 0);
426 /* Valid UNIX mode? */
427 if ( RT_SUCCESS(rc)
428 && (fMode & RTFS_UNIX_MASK))
429 rc = RTFileSetMode(hFile, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR);
430 }
431 RTFileClose(hFile);
432 if (!guestFileList.contains(pszNewFile))
433 guestFileList.append(pszNewFile);
434 }
435 }
436 break;
437 }
438 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
439 {
440 rc = vbglR3DnDHGProcessCancelMessage(uClientId);
441 if (RT_SUCCESS(rc))
442 rc = VERR_CANCELLED;
443 /* Break out of the loop. */
444 }
445 default: fLoop = false; break;
446 }
447 } else
448 {
449 if (rc == VERR_NO_DATA)
450 rc = VINF_SUCCESS;
451 break;
452 }
453 }while(fLoop);
454
455 RTMemFree(pvTmpData);
456 /* Cleanup on failure or if the user has canceled. */
457 if (RT_FAILURE(rc))
458 {
459 /* Remove any stuff created. */
460 for (size_t i = 0; i < guestFileList.size(); ++i)
461 RTFileDelete(guestFileList.at(i).c_str());
462 for (size_t i = 0; i < guestDirList.size(); ++i)
463 RTDirRemove(guestDirList.at(i).c_str());
464 RTDirRemove(pszDropDir);
465 }
466
467 return rc;
468}
469
470static int vbglR3DnDHGProcessDataMessageInternal(uint32_t uClientId,
471 uint32_t *puScreenId,
472 char *pszFormat,
473 uint32_t cbFormat,
474 uint32_t *pcbFormatRecv,
475 void *pvData,
476 uint32_t cbData,
477 uint32_t *pcbDataRecv)
478{
479 /* Validate input */
480 AssertPtrReturn(puScreenId, VERR_INVALID_POINTER);
481 AssertPtrReturn(pszFormat, VERR_INVALID_POINTER);
482 AssertReturn(cbFormat, VERR_INVALID_PARAMETER);
483 AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
484 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
485 AssertReturn(cbData, VERR_INVALID_PARAMETER);
486 AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
487
488 /* Initialize header */
489 DragAndDropSvc::VBOXDNDHGSENDDATAMSG Msg;
490 RT_ZERO(Msg);
491 Msg.hdr.u32ClientID = uClientId;
492 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_DATA;
493 Msg.hdr.cParms = 5;
494 /* Initialize parameter */
495 Msg.uScreenId.SetUInt32(0);
496 Msg.pvFormat.SetPtr(pszFormat, cbFormat);
497 Msg.cFormat.SetUInt32(0);
498 Msg.pvData.SetPtr(pvData, cbData);
499 Msg.cData.SetUInt32(0);
500 /* Do request */
501 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
502 if (RT_SUCCESS(rc))
503 {
504 rc = Msg.hdr.result;
505 if ( RT_SUCCESS(rc)
506 || rc == VERR_BUFFER_OVERFLOW)
507 {
508 /* Fetch results */
509 rc = Msg.uScreenId.GetUInt32(puScreenId); AssertRC(rc);
510 rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
511 rc = Msg.cData.GetUInt32(pcbDataRecv); AssertRC(rc);
512 /* A little bit paranoia */
513 AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
514 AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA);
515 }
516 }
517 return rc;
518}
519
520static int vbglR3DnDHGProcessMoreDataMessageInternal(uint32_t uClientId,
521 void *pvData,
522 uint32_t cbData,
523 uint32_t *pcbDataRecv)
524{
525 /* Validate input */
526 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
527 AssertReturn(cbData, VERR_INVALID_PARAMETER);
528 AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
529
530 /* Initialize header */
531 DragAndDropSvc::VBOXDNDHGSENDMOREDATAMSG Msg;
532 RT_ZERO(Msg);
533 Msg.hdr.u32ClientID = g_clientId;
534 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA;
535 Msg.hdr.cParms = 2;
536 /* Initialize parameter */
537 Msg.pvData.SetPtr(pvData, cbData);
538 Msg.cData.SetUInt32(0);
539 /* Do request */
540 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
541 if (RT_SUCCESS(rc))
542 {
543 rc = Msg.hdr.result;
544 if ( RT_SUCCESS(rc)
545 || rc == VERR_BUFFER_OVERFLOW)
546 {
547 /* Fetch results */
548 rc = Msg.cData.GetUInt32(pcbDataRecv); AssertRC(rc);
549 /* A little bit paranoia */
550 AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA);
551 }
552 }
553 return rc;
554}
555
556static int vbglR3DnDHGProcessSendDataMessages(uint32_t uClientId,
557 uint32_t *puScreenId,
558 char *pszFormat,
559 uint32_t cbFormat,
560 uint32_t *pcbFormatRecv,
561 void **ppvData,
562 uint32_t cbData,
563 size_t *pcbDataRecv)
564{
565 uint32_t cbDataRecv = 0;
566 int rc = vbglR3DnDHGProcessDataMessageInternal(uClientId,
567 puScreenId,
568 pszFormat,
569 cbFormat,
570 pcbFormatRecv,
571 *ppvData,
572 cbData,
573 &cbDataRecv);
574
575 size_t cbAllDataRecv = cbDataRecv;
576 while (rc == VERR_BUFFER_OVERFLOW)
577 {
578 uint32_t uNextMsg;
579 uint32_t cNextParms;
580 rc = vbglR3DnDQueryNextHostMessageType(uClientId, &uNextMsg, &cNextParms, false);
581 if (RT_SUCCESS(rc))
582 {
583 switch(uNextMsg)
584 {
585 case DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA:
586 {
587 *ppvData = RTMemRealloc(*ppvData, cbAllDataRecv + cbData);
588 if (!*ppvData)
589 {
590 rc = VERR_NO_MEMORY;
591 break;
592 }
593 rc = vbglR3DnDHGProcessMoreDataMessageInternal(uClientId,
594 &((char*)*ppvData)[cbAllDataRecv],
595 cbData,
596 &cbDataRecv);
597 cbAllDataRecv += cbDataRecv;
598 break;
599 }
600 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
601 default:
602 {
603 rc = vbglR3DnDHGProcessCancelMessage(uClientId);
604 if (RT_SUCCESS(rc))
605 rc = VERR_CANCELLED;
606 break;
607 }
608 }
609 }
610 }
611 if (RT_SUCCESS(rc))
612 *pcbDataRecv = cbAllDataRecv;
613
614 return rc;
615}
616
617static int vbglR3DnDHGProcessSendDataMessage(uint32_t uClientId,
618 uint32_t *puScreenId,
619 char *pszFormat,
620 uint32_t cbFormat,
621 uint32_t *pcbFormatRecv,
622 void **ppvData,
623 uint32_t cbData,
624 size_t *pcbDataRecv)
625{
626 int rc = vbglR3DnDHGProcessSendDataMessages(uClientId,
627 puScreenId,
628 pszFormat,
629 cbFormat,
630 pcbFormatRecv,
631 ppvData,
632 cbData,
633 pcbDataRecv);
634 if (RT_SUCCESS(rc))
635 {
636 /* Check if this is a uri-event */
637 if (RTStrNICmp(pszFormat, "text/uri-list", *pcbFormatRecv) == 0)
638 rc = vbglR3DnDHGProcessURIMessages(uClientId,
639 puScreenId,
640 pszFormat,
641 cbFormat,
642 pcbFormatRecv,
643 ppvData,
644 cbData,
645 pcbDataRecv);
646 }
647 return rc;
648}
649
650static int vbglR3DnDGHProcessRequestPendingMessage(uint32_t uClientId,
651 uint32_t *puScreenId)
652{
653 /* Validate input */
654 AssertPtrReturn(puScreenId, VERR_INVALID_POINTER);
655
656 /* Initialize header */
657 DragAndDropSvc::VBOXDNDGHREQPENDINGMSG Msg;
658 RT_ZERO(Msg);
659 Msg.hdr.u32ClientID = uClientId;
660 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_REQ_PENDING;
661 Msg.hdr.cParms = 1;
662 /* Initialize parameter */
663 Msg.uScreenId.SetUInt32(0);
664 /* Do request */
665 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
666 if (RT_SUCCESS(rc))
667 {
668 rc = Msg.hdr.result;
669 if (RT_SUCCESS(rc))
670 {
671 /* Fetch results */
672 rc = Msg.uScreenId.GetUInt32(puScreenId); AssertRC(rc);
673 }
674 }
675 return rc;
676}
677
678static int vbglR3DnDGHProcessDroppedMessage(uint32_t uClientId,
679 char *pszFormat,
680 uint32_t cbFormat,
681 uint32_t *pcbFormatRecv,
682 uint32_t *puAction)
683{
684 /* Validate input */
685 AssertPtrReturn(pszFormat, VERR_INVALID_POINTER);
686 AssertReturn(cbFormat, VERR_INVALID_PARAMETER);
687 AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
688 AssertPtrReturn(puAction, VERR_INVALID_POINTER);
689
690 /* Initialize header */
691 DragAndDropSvc::VBOXDNDGHDROPPEDMSG Msg;
692 RT_ZERO(Msg);
693 Msg.hdr.u32ClientID = uClientId;
694 Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_EVT_DROPPED;
695 Msg.hdr.cParms = 3;
696 /* Initialize parameter */
697 Msg.pvFormat.SetPtr(pszFormat, cbFormat);
698 Msg.cFormat.SetUInt32(0);
699 Msg.uAction.SetUInt32(0);
700 /* Do request */
701 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
702 if (RT_SUCCESS(rc))
703 {
704 rc = Msg.hdr.result;
705 if (RT_SUCCESS(rc))
706 {
707 /* Fetch results */
708 rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
709 rc = Msg.uAction.GetUInt32(puAction); AssertRC(rc);
710 /* A little bit paranoia */
711 AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
712 }
713 }
714 return rc;
715}
716
717/******************************************************************************
718 * Public functions *
719 ******************************************************************************/
720
721/**
722 * Initialize Drag & Drop.
723 *
724 * This will enable the Drag & Drop events.
725 *
726 * @returns VBox status code.
727 */
728VBGLR3DECL(int) VbglR3DnDInit(void)
729{
730 return VbglR3DnDConnect(&g_clientId);
731}
732
733/**
734 * Terminate Drag and Drop.
735 *
736 * This will Drag and Drop events.
737 *
738 * @returns VBox status.
739 */
740VBGLR3DECL(int) VbglR3DnDTerm(void)
741{
742 return VbglR3DnDDisconnect(g_clientId);
743}
744
745VBGLR3DECL(int) VbglR3DnDConnect(uint32_t *pu32ClientId)
746{
747 /* Validate input */
748 AssertPtrReturn(pu32ClientId, VERR_INVALID_POINTER);
749
750 /* Initialize header */
751 VBoxGuestHGCMConnectInfo Info;
752 RT_ZERO(Info.Loc.u);
753 Info.result = VERR_WRONG_ORDER;
754 Info.u32ClientID = UINT32_MAX; /* try make valgrind shut up. */
755 /* Initialize parameter */
756 Info.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
757 int rc = RTStrCopy(Info.Loc.u.host.achName, sizeof(Info.Loc.u.host.achName), "VBoxDragAndDropSvc");
758 if (RT_FAILURE(rc)) return rc;
759 /* Do request */
760 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CONNECT, &Info, sizeof(Info));
761 if (RT_SUCCESS(rc))
762 {
763 rc = Info.result;
764 if (RT_SUCCESS(rc))
765 *pu32ClientId = Info.u32ClientID;
766 }
767 return rc;
768}
769
770VBGLR3DECL(int) VbglR3DnDDisconnect(uint32_t u32ClientId)
771{
772 /* Initialize header */
773 VBoxGuestHGCMDisconnectInfo Info;
774 Info.result = VERR_WRONG_ORDER;
775 Info.u32ClientID = u32ClientId;
776 /* Do request */
777 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_DISCONNECT, &Info, sizeof(Info));
778 if (RT_SUCCESS(rc))
779 rc = Info.result;
780 return rc;
781}
782
783VBGLR3DECL(int) VbglR3DnDProcessNextMessage(CPVBGLR3DNDHGCMEVENT pEvent)
784{
785 /* Validate input */
786 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
787
788 uint32_t uMsg = 0;
789 uint32_t uNumParms = 0;
790 const uint32_t ccbFormats = _64K;
791 const uint32_t ccbData = _1M;
792 int rc = vbglR3DnDQueryNextHostMessageType(g_clientId, &uMsg, &uNumParms, true);
793 if (RT_SUCCESS(rc))
794 {
795 DO(("Got message %d\n", uMsg));
796 switch(uMsg)
797 {
798 case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
799 case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
800 case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
801 {
802 pEvent->uType = uMsg;
803 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
804 if (!pEvent->pszFormats)
805 return VERR_NO_MEMORY;
806 rc = vbglR3DnDHGProcessActionMessage(g_clientId,
807 uMsg,
808 &pEvent->uScreenId,
809 &pEvent->u.a.uXpos,
810 &pEvent->u.a.uYpos,
811 &pEvent->u.a.uDefAction,
812 &pEvent->u.a.uAllActions,
813 pEvent->pszFormats,
814 ccbFormats,
815 &pEvent->cbFormats);
816 break;
817 }
818 case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE:
819 {
820 pEvent->uType = uMsg;
821 rc = vbglR3DnDHGProcessLeaveMessage(g_clientId);
822 break;
823 }
824 case DragAndDropSvc::HOST_DND_HG_SND_DATA:
825 {
826 pEvent->uType = uMsg;
827 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
828 if (!pEvent->pszFormats)
829 return VERR_NO_MEMORY;
830 pEvent->u.b.pvData = RTMemAlloc(ccbData);
831 if (!pEvent->u.b.pvData)
832 {
833 RTMemFree(pEvent->pszFormats);
834 pEvent->pszFormats = NULL;
835 return VERR_NO_MEMORY;
836 }
837 rc = vbglR3DnDHGProcessSendDataMessage(g_clientId,
838 &pEvent->uScreenId,
839 pEvent->pszFormats,
840 ccbFormats,
841 &pEvent->cbFormats,
842 &pEvent->u.b.pvData,
843 ccbData,
844 &pEvent->u.b.cbData);
845 break;
846 }
847#ifdef VBOX_WITH_DRAG_AND_DROP_GH
848 case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
849 {
850 pEvent->uType = uMsg;
851 rc = vbglR3DnDGHProcessRequestPendingMessage(g_clientId,
852 &pEvent->uScreenId);
853 break;
854 }
855 case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
856 {
857 pEvent->uType = uMsg;
858 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
859 if (!pEvent->pszFormats)
860 return VERR_NO_MEMORY;
861 rc = vbglR3DnDGHProcessDroppedMessage(g_clientId,
862 pEvent->pszFormats,
863 ccbFormats,
864 &pEvent->cbFormats,
865 &pEvent->u.a.uDefAction);
866 break;
867 }
868#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
869 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
870 {
871 pEvent->uType = uMsg;
872 rc = vbglR3DnDHGProcessCancelMessage(g_clientId);
873 if (RT_SUCCESS(rc))
874 rc = VERR_CANCELLED;
875 break;
876 }
877 default: AssertMsgFailedReturn(("Message %u isn't expected in this context", uMsg), VERR_INVALID_PARAMETER); break;
878 }
879 }
880 return rc;
881}
882
883VBGLR3DECL(int) VbglR3DnDHGAcknowledgeOperation(uint32_t uAction)
884{
885 DO(("ACK: %u\n", uAction));
886 /* Initialize header */
887 DragAndDropSvc::VBOXDNDHGACKOPMSG Msg;
888 RT_ZERO(Msg);
889 Msg.hdr.result = VERR_WRONG_ORDER;
890 Msg.hdr.u32ClientID = g_clientId;
891 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_ACK_OP;
892 Msg.hdr.cParms = 1;
893 /* Initialize parameter */
894 Msg.uAction.SetUInt32(uAction);
895 /* Do request */
896 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
897 if (RT_SUCCESS(rc))
898 rc = Msg.hdr.result;
899 return rc;
900}
901
902VBGLR3DECL(int) VbglR3DnDHGRequestData(const char* pcszFormat)
903{
904 DO(("DATA_REQ: '%s'\n", pcszFormat));
905 /* Validate input */
906 AssertPtrReturn(pcszFormat, VERR_INVALID_PARAMETER);
907
908 /* Initialize header */
909 DragAndDropSvc::VBOXDNDHGREQDATAMSG Msg;
910 RT_ZERO(Msg);
911 Msg.hdr.result = VERR_WRONG_ORDER;
912 Msg.hdr.u32ClientID = g_clientId;
913 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_REQ_DATA;
914 Msg.hdr.cParms = 1;
915 /* Do request */
916 Msg.pFormat.SetPtr((void*)pcszFormat, (uint32_t)strlen(pcszFormat) + 1);
917 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
918 if (RT_SUCCESS(rc))
919 rc = Msg.hdr.result;
920 return rc;
921}
922
923VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending(uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormat)
924{
925 DO(("PEND: %u: %u (%s)\n", uDefAction, uAllActions, pcszFormat));
926 /* Validate input */
927 AssertPtrReturn(pcszFormat, VERR_INVALID_POINTER);
928
929 /* Initialize header */
930 DragAndDropSvc::VBOXDNDGHACKPENDINGMSG Msg;
931 RT_ZERO(Msg);
932 Msg.hdr.result = VERR_WRONG_ORDER;
933 Msg.hdr.u32ClientID = g_clientId;
934 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_ACK_PENDING;
935 Msg.hdr.cParms = 3;
936 /* Initialize parameter */
937 Msg.uDefAction.SetUInt32(uDefAction);
938 Msg.uAllActions.SetUInt32(uAllActions);
939 Msg.pFormat.SetPtr((void*)pcszFormat, static_cast<uint32_t>(strlen(pcszFormat) + 1));
940 /* Do request */
941 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
942 if (RT_SUCCESS(rc))
943 rc = Msg.hdr.result;
944 return rc;
945}
946
947VBGLR3DECL(int) VbglR3DnDGHSendData(void *pvData, uint32_t cbData)
948{
949 DO(("DATA: %x (%u)\n", pvData, cbData));
950 /* Validate input */
951 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
952 AssertReturn(cbData, VERR_INVALID_PARAMETER);
953
954 /* Todo: URI support. Currently only data is send over to the host. For URI
955 * support basically the same as in the H->G case (see
956 * HostServices/DragAndDrop/dndmanager.h/cpp) has to be done:
957 * 1. Parse the urilist
958 * 2. Recursively send "create dir" and "transfer file" msg to the host
959 * 3. Patch the urilist by removing all base dirnames
960 * 4. On the host all needs to received and the urilist patched afterwards
961 * to point to the new location
962 */
963
964 /* Initialize header */
965 DragAndDropSvc::VBOXDNDGHSENDDATAMSG Msg;
966 RT_ZERO(Msg);
967 Msg.hdr.result = VERR_WRONG_ORDER;
968 Msg.hdr.u32ClientID = g_clientId;
969 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DATA;
970 Msg.hdr.cParms = 2;
971 Msg.uSize.SetUInt32(cbData);
972 int rc = VINF_SUCCESS;
973 uint32_t cbMax = _1M;
974 uint32_t cbSend = 0;
975 while(cbSend < cbData)
976 {
977 /* Initialize parameter */
978 uint32_t cbToSend = RT_MIN(cbData - cbSend, cbMax);
979 Msg.pData.SetPtr(static_cast<uint8_t*>(pvData) + cbSend, cbToSend);
980 /* Do request */
981 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
982 if (RT_SUCCESS(rc))
983 {
984 rc = Msg.hdr.result;
985 /* Did the host cancel the event? */
986 if (rc == VERR_CANCELLED)
987 break;
988 }
989 else
990 break;
991 cbSend += cbToSend;
992// RTThreadSleep(500);
993 }
994 return rc;
995}
996
997VBGLR3DECL(int) VbglR3DnDGHErrorEvent(int rcOp)
998{
999 DO(("GH_ERROR\n"));
1000
1001 /* Initialize header */
1002 DragAndDropSvc::VBOXDNDGHEVTERRORMSG Msg;
1003 RT_ZERO(Msg);
1004 Msg.hdr.result = VERR_WRONG_ORDER;
1005 Msg.hdr.u32ClientID = g_clientId;
1006 Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_EVT_ERROR;
1007 Msg.hdr.cParms = 1;
1008 /* Initialize parameter */
1009 Msg.uRC.SetUInt32(rcOp);
1010 /* Do request */
1011 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
1012 if (RT_SUCCESS(rc))
1013 rc = Msg.hdr.result;
1014 return rc;
1015}
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