VirtualBox

source: vbox/trunk/src/VBox/HostServices/DragAndDrop/dndmanager.cpp@ 50463

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

DnD: build fix and warnings

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.0 KB
Line 
1/* $Id: dndmanager.cpp 50463 2014-02-14 10:29:32Z vboxsync $ */
2/** @file
3 * Drag and Drop manager.
4 */
5
6/*
7 * Copyright (C) 2011-2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/******************************************************************************
19 * Header Files *
20 ******************************************************************************/
21
22#ifdef LOG_GROUP
23 #undef LOG_GROUP
24#endif
25#define LOG_GROUP LOG_GROUP_GUEST_DND
26
27#include "dndmanager.h"
28
29#include <VBox/log.h>
30#include <iprt/file.h>
31#include <iprt/dir.h>
32#include <iprt/path.h>
33#include <iprt/uri.h>
34
35/******************************************************************************
36 * Private declarations *
37 ******************************************************************************/
38
39typedef DECLCALLBACK(int) FNDNDPRIVATEPROGRESS(size_t cbDone, void *pvUser);
40typedef FNDNDPRIVATEPROGRESS *PFNDNDPRIVATEPROGRESS;
41
42/**
43 * Internal DnD message class for informing the guest about a new directory.
44 *
45 * @see DnDHGSendDataMessage
46 */
47class DnDHGSendDirPrivate: public DnDMessage
48{
49public:
50
51 DnDHGSendDirPrivate(const RTCString &strPath,
52 uint32_t fMode, uint64_t cbSize,
53 PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser)
54 : m_strPath(strPath)
55 , m_cbSize(cbSize)
56 , m_pfnProgressCallback(pfnProgressCallback)
57 , m_pvProgressUser(pvProgressUser)
58 {
59 VBOXHGCMSVCPARM paTmpParms[3];
60 paTmpParms[0].setString(m_strPath.c_str());
61 paTmpParms[1].setUInt32((uint32_t)(m_strPath.length() + 1));
62 paTmpParms[2].setUInt32(fMode);
63
64 m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_DIR, 3, paTmpParms);
65 }
66
67 int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
68 {
69 int rc = DnDMessage::currentMessage(uMsg, cParms, paParms);
70 /* Advance progress info */
71 if ( RT_SUCCESS(rc)
72 && m_pfnProgressCallback)
73 rc = m_pfnProgressCallback(m_cbSize, m_pvProgressUser);
74
75 return rc;
76 }
77
78protected:
79 RTCString m_strPath;
80
81 /* Progress stuff */
82 size_t m_cbSize;
83 PFNDNDPRIVATEPROGRESS m_pfnProgressCallback;
84 void *m_pvProgressUser;
85};
86
87/**
88 * Internal DnD message class for informing the guest about a new file.
89 *
90 * @see DnDHGSendDataMessage
91 */
92class DnDHGSendFilePrivate: public DnDMessage
93{
94public:
95
96 DnDHGSendFilePrivate(const RTCString &strHostPath,
97 const RTCString &strGuestPath,
98 uint32_t fMode, uint64_t cbSize,
99 PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser);
100 virtual ~DnDHGSendFilePrivate(void);
101
102 int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
103
104protected:
105 RTCString m_strHostPath;
106 RTCString m_strGuestPath;
107 uint64_t m_cbFileSize;
108 uint64_t m_cbFileProcessed;
109 RTFILE m_hCurFile;
110 VBOXHGCMSVCPARM m_paSkelParms[5];
111
112 /* Progress stuff */
113 PFNDNDPRIVATEPROGRESS m_pfnProgressCallback;
114 void *m_pvProgressUser;
115};
116
117/**
118 * Internal DnD message class for informing the guest about new drag & drop
119 * data.
120 *
121 * @see DnDHGSendDataMessage
122 */
123class DnDHGSendDataMessagePrivate: public DnDMessage
124{
125public:
126
127 DnDHGSendDataMessagePrivate(uint32_t uMsg, uint32_t cParms,
128 VBOXHGCMSVCPARM paParms[],
129 PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser);
130 int currentMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
131
132protected:
133 size_t m_cbSize;
134 size_t m_cbDone;
135
136 /* Progress stuff */
137 PFNDNDPRIVATEPROGRESS m_pfnProgressCallback;
138 void *m_pvProgressUser;
139};
140
141/******************************************************************************
142 * Implementation *
143 ******************************************************************************/
144
145/******************************************************************************
146 * DnDHGSendFilePrivate *
147 ******************************************************************************/
148
149DnDHGSendFilePrivate::DnDHGSendFilePrivate(const RTCString &strHostPath, const RTCString &strGuestPath,
150 uint32_t fMode, uint64_t cbSize,
151 PFNDNDPRIVATEPROGRESS pfnProgressCallback, void *pvProgressUser)
152 : m_strHostPath(strHostPath)
153 , m_strGuestPath(strGuestPath)
154 , m_cbFileSize(cbSize)
155 , m_cbFileProcessed(0)
156 , m_hCurFile(0)
157 , m_pfnProgressCallback(pfnProgressCallback)
158 , m_pvProgressUser(pvProgressUser)
159{
160 m_paSkelParms[0].setString(m_strGuestPath.c_str());
161 m_paSkelParms[1].setUInt32((uint32_t)(m_strGuestPath.length() + 1));
162 m_paSkelParms[2].setPointer(NULL, 0);
163 m_paSkelParms[3].setUInt32(0);
164 m_paSkelParms[4].setUInt32(fMode);
165
166 m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_FILE, 5, m_paSkelParms);
167}
168
169DnDHGSendFilePrivate::~DnDHGSendFilePrivate(void)
170{
171 if (m_hCurFile)
172 RTFileClose(m_hCurFile);
173}
174
175int DnDHGSendFilePrivate::currentMessage(uint32_t uMsg, uint32_t cParms,
176 VBOXHGCMSVCPARM paParms[])
177{
178 if (!m_pNextMsg)
179 return VERR_NO_DATA;
180
181 int rc = m_pNextMsg->getData(uMsg, cParms, paParms);
182 clearNextMsg();
183 if (RT_FAILURE(rc))
184 return rc;
185
186 if (!m_hCurFile)
187 {
188 /* Open files on the host with RTFILE_O_DENY_WRITE to prevent races where the host
189 * writes to the file while the guest transfers it over. */
190 rc = RTFileOpen(&m_hCurFile, m_strHostPath.c_str(),
191 RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
192 }
193
194 size_t cbRead;
195 if (RT_SUCCESS(rc))
196 {
197 /* Get buffer size + pointer to buffer from guest side. */
198 uint32_t cbToRead = paParms[2].u.pointer.size;
199 Assert(cbToRead);
200 void *pvBuf = paParms[2].u.pointer.addr;
201 AssertPtr(pvBuf);
202 rc = RTFileRead(m_hCurFile, pvBuf, cbToRead, &cbRead);
203 if (RT_LIKELY(RT_SUCCESS(rc)))
204 {
205 /* Advance. */
206 m_cbFileProcessed += cbRead;
207 Assert(m_cbFileProcessed <= m_cbFileSize);
208
209 /* Tell the guest the actual size. */
210 paParms[3].setUInt32((uint32_t)cbRead);
211 }
212 }
213
214 if (RT_SUCCESS(rc))
215 {
216 /* Check if we are done. */
217 Assert(m_cbFileProcessed <= m_cbFileSize);
218 bool fDone = m_cbFileSize == m_cbFileProcessed;
219 if (!fDone)
220 {
221 try
222 {
223 /* More data! Prepare the next message. */
224 m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_FILE, 5 /* cParms */,
225 m_paSkelParms);
226 }
227 catch(std::bad_alloc &)
228 {
229 rc = VERR_NO_MEMORY;
230 }
231 }
232
233 /* Advance progress info. */
234 if ( RT_SUCCESS(rc)
235 && m_pfnProgressCallback)
236 {
237 rc = m_pfnProgressCallback(cbRead, m_pvProgressUser);
238 }
239
240 if ( fDone
241 || RT_FAILURE(rc))
242 {
243 RTFileClose(m_hCurFile);
244 m_hCurFile = NIL_RTFILE;
245 }
246 }
247
248 return rc;
249}
250
251/******************************************************************************
252 * DnDHGSendDataMessagePrivate *
253 ******************************************************************************/
254
255DnDHGSendDataMessagePrivate::DnDHGSendDataMessagePrivate(uint32_t uMsg, uint32_t cParms,
256 VBOXHGCMSVCPARM paParms[],
257 PFNDNDPRIVATEPROGRESS pfnProgressCallback,
258 void *pvProgressUser)
259 : m_cbSize(paParms[4].u.uint32)
260 , m_cbDone(0)
261 , m_pfnProgressCallback(pfnProgressCallback)
262 , m_pvProgressUser(pvProgressUser)
263{
264 /* Create the initial data message. This might throw
265 * a bad_alloc exception. */
266 m_pNextMsg = new HGCM::Message(uMsg, cParms, paParms);
267}
268
269int DnDHGSendDataMessagePrivate::currentMessage(uint32_t uMsg, uint32_t cParms,
270 VBOXHGCMSVCPARM paParms[])
271{
272 /** @todo Don't copy the data parts ... just move the data pointer in
273 * the original data ptr. */
274 if (!m_pNextMsg)
275 return VERR_NO_DATA;
276
277 int rc = VINF_SUCCESS;
278
279 HGCM::Message *pCurMsg = m_pNextMsg;
280 AssertPtr(pCurMsg);
281
282 m_pNextMsg = 0;
283 rc = pCurMsg->getData(uMsg, cParms, paParms);
284
285 /* Depending on the current message, the data pointer is on a
286 * different position (HOST_DND_HG_SND_DATA=3;
287 * HOST_DND_HG_SND_MORE_DATA=0). */
288 int iPos = uMsg == DragAndDropSvc::HOST_DND_HG_SND_DATA ? 3 : 0;
289 m_cbDone += paParms[iPos + 1].u.uint32;
290
291 /* Info + data send already? */
292 if (rc == VERR_BUFFER_OVERFLOW)
293 {
294 paParms[iPos + 1].u.uint32 = paParms[iPos].u.pointer.size;
295 VBOXHGCMSVCPARM paTmpParms[2];
296 void *pvOldData;
297 uint32_t cOldData;
298 pCurMsg->getParmPtrInfo(iPos, &pvOldData, &cOldData);
299 paTmpParms[0].setPointer(static_cast<uint8_t*>(pvOldData) + paParms[iPos].u.pointer.size, cOldData - paParms[iPos].u.pointer.size);
300 paTmpParms[1].setUInt32(cOldData - paParms[iPos].u.pointer.size);
301
302 try
303 {
304 m_pNextMsg = new HGCM::Message(DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA, 2, paTmpParms);
305 }
306 catch(std::bad_alloc &)
307 {
308 rc = VERR_NO_MEMORY;
309 }
310 }
311
312 if (pCurMsg)
313 delete pCurMsg;
314
315 /* Advance progress info. */
316 if ( RT_SUCCESS(rc)
317 && m_pfnProgressCallback)
318 {
319 rc = m_pfnProgressCallback(m_cbDone, m_pvProgressUser);
320 }
321
322 return rc;
323}
324
325/******************************************************************************
326 * DnDHGSendDataMessage *
327 ******************************************************************************/
328
329/*
330 * This class is a meta message class. It doesn't consist of any own message
331 * data, but handle the meta info, the data itself as well as any files or
332 * directories which have to be transfered to the guest.
333 */
334DnDHGSendDataMessage::DnDHGSendDataMessage(uint32_t uMsg, uint32_t cParms,
335 VBOXHGCMSVCPARM paParms[],
336 PFNDNDPROGRESS pfnProgressCallback,
337 void *pvProgressUser)
338 : m_cbTotal(0)
339 , m_cbTransfered(0)
340 , m_pfnProgressCallback(pfnProgressCallback)
341 , m_pvProgressUser(pvProgressUser)
342{
343 if (cParms < 5) /* Paranoia. */
344 return;
345
346 const char *pszFormat = static_cast<const char*>(paParms[1].u.pointer.addr);
347 uint32_t cbFormat = paParms[1].u.pointer.size;
348
349 int rc = VINF_SUCCESS;
350 RTCString strNewURIs;
351
352 /* Do we need to build up a file tree? */
353 if (DnDMIMEHasFileURLs(pszFormat, cbFormat))
354 {
355 const char *pszList = static_cast<const char*>(paParms[3].u.pointer.addr);
356 AssertPtr(pszList);
357 uint32_t cbList = paParms[3].u.pointer.size;
358 Assert(cbList);
359
360 LogFlowFunc(("Old data: '%s'\n", pszList));
361
362 /* The list is separated by newline (even if only one file is listed). */
363 RTCList<RTCString> lstURIOrg
364 = RTCString(pszList, cbList).split("\r\n");
365 if (!lstURIOrg.isEmpty())
366 {
367 rc = m_lstURI.AppendPathsFromList(lstURIOrg, 0 /* fFlags */);
368 if (RT_SUCCESS(rc))
369 {
370 /* Add the total size of all meta data + files transferred to
371 * the message's total count. */
372 m_cbTotal += m_lstURI.TotalBytes();
373
374 /* We have to change the actual DnD data. Remove any host paths and
375 * just decode the filename into the new data. The guest tools will
376 * add the correct path again, before sending the DnD drop event to
377 * some window. */
378 strNewURIs = m_lstURI.RootToString();
379
380 /* Note: We don't delete the old pointer here, cause this is done
381 * by the caller. We just use the RTString data, which has the
382 * scope of this ctor. This is enough cause the data is copied in
383 * the DnDHGSendDataMessagePrivate anyway. */
384 paParms[3].u.pointer.addr = (void *)strNewURIs.c_str();
385 paParms[3].u.pointer.size = (uint32_t)(strNewURIs.length() + 1);
386 paParms[4].u.uint32 = (uint32_t)(strNewURIs.length() + 1);
387
388 LogFlowFunc(("Set new data: '%s'\n", (char*)paParms[3].u.pointer.addr));
389 }
390 }
391 }
392
393 /* Add the size of the data to the todo list. */
394 m_cbTotal += paParms[4].u.uint32;
395 LogFlowFunc(("cbTotal=%zu\n", m_cbTotal));
396
397 /* The first message is the meta info for the data and the data itself. */
398 m_pNextPathMsg = new DnDHGSendDataMessagePrivate(uMsg, cParms, paParms,
399 &DnDHGSendDataMessage::progressCallback, this);
400}
401
402DnDHGSendDataMessage::~DnDHGSendDataMessage(void)
403{
404 if (m_pNextPathMsg)
405 delete m_pNextPathMsg;
406}
407
408HGCM::Message* DnDHGSendDataMessage::nextHGCMMessage(void)
409{
410 if (!m_pNextPathMsg)
411 return NULL;
412
413 return m_pNextPathMsg->nextHGCMMessage();
414}
415
416int DnDHGSendDataMessage::currentMessageInfo(uint32_t *puMsg, uint32_t *pcParms)
417{
418 if (!m_pNextPathMsg)
419 return VERR_NO_DATA;
420
421 return m_pNextPathMsg->currentMessageInfo(puMsg, pcParms);
422}
423
424int DnDHGSendDataMessage::currentMessage(uint32_t uMsg,
425 uint32_t cParms, VBOXHGCMSVCPARM paParms[])
426{
427 if (!m_pNextPathMsg)
428 return VERR_NO_DATA;
429
430 /* Fill the data out of our current queued message. */
431 int rc = m_pNextPathMsg->currentMessage(uMsg, cParms, paParms);
432 /* Has this message more data to deliver? */
433 if (!m_pNextPathMsg->isMessageWaiting())
434 {
435 delete m_pNextPathMsg;
436 m_pNextPathMsg = NULL;
437 }
438
439 /* File/directory data to send? */
440 if (!m_pNextPathMsg)
441 {
442 if (m_lstURI.IsEmpty())
443 return rc;
444
445 /* Create new messages based on our internal path list. Currently
446 * this could be directories or regular files. */
447 const DnDURIPath &nextPath = m_lstURI.First();
448 try
449 {
450 LogFlowFunc(("Processing srcPath=%s, dstPath=%s, fMode=0x%x, cbSize=%RU32, fIsDir=%RTbool, fIsFile=%RTbool\n",
451 nextPath.m_strSrcPath.c_str(), nextPath.m_strDstPath.c_str(),
452 nextPath.m_fMode, nextPath.m_cbSize,
453 RTFS_IS_DIRECTORY(nextPath.m_fMode), RTFS_IS_FILE(nextPath.m_fMode)));
454
455 if (RTFS_IS_DIRECTORY(nextPath.m_fMode))
456 m_pNextPathMsg = new DnDHGSendDirPrivate(nextPath.m_strDstPath,
457 nextPath.m_fMode, nextPath.m_cbSize,
458 &DnDHGSendDataMessage::progressCallback,
459 this /* pvProgressUser */);
460 else if (RTFS_IS_FILE(nextPath.m_fMode))
461 m_pNextPathMsg = new DnDHGSendFilePrivate(nextPath.m_strSrcPath, nextPath.m_strDstPath,
462 nextPath.m_fMode, nextPath.m_cbSize,
463 &DnDHGSendDataMessage::progressCallback,
464 this /* pvProgressUser */);
465 else
466 AssertMsgFailedReturn(("fMode=0x%x is not supported for srcPath=%s, dstPath=%s\n",
467 nextPath.m_fMode, nextPath.m_strSrcPath.c_str(), nextPath.m_strDstPath),
468 VERR_NO_DATA);
469
470 m_lstURI.RemoveFirst();
471 }
472 catch(std::bad_alloc &)
473 {
474 rc = VERR_NO_MEMORY;
475 }
476 }
477
478 return rc;
479}
480
481int DnDHGSendDataMessage::progressCallback(size_t cbDone, void *pvUser)
482{
483 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
484
485 DnDHGSendDataMessage *pSelf = static_cast<DnDHGSendDataMessage *>(pvUser);
486 AssertPtr(pSelf);
487
488 /* How many bytes are transfered already. */
489 pSelf->m_cbTransfered += cbDone;
490
491 /* Advance progress info. */
492 int rc = VINF_SUCCESS;
493 if ( pSelf->m_pfnProgressCallback
494 && pSelf->m_cbTotal)
495 {
496 AssertMsg(pSelf->m_cbTransfered <= pSelf->m_cbTotal,
497 ("More bytes transferred (%zu) than expected (%zu), cbDone=%zu\n",
498 pSelf->m_cbTransfered, pSelf->m_cbTotal, cbDone));
499
500 unsigned uPercentage = (unsigned)((uint64_t)pSelf->m_cbTransfered * 100 / pSelf->m_cbTotal);
501 rc = pSelf->m_pfnProgressCallback(RT_MIN(uPercentage, 100),
502 DragAndDropSvc::DND_PROGRESS_RUNNING,
503 VINF_SUCCESS /* rc */, pSelf->m_pvProgressUser);
504 }
505
506 return rc;
507}
508
509/******************************************************************************
510 * DnDManager *
511 ******************************************************************************/
512
513int DnDManager::addMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
514{
515 int rc = VINF_SUCCESS;
516
517 try
518 {
519 switch (uMsg)
520 {
521 case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
522 {
523 clear();
524 LogFlowFunc(("HOST_DND_HG_EVT_ENTER\n"));
525
526 /* Verify parameter count and types. */
527 if ( cParms != 7
528 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */
529 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* x-pos */
530 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* y-pos */
531 || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* default action */
532 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* allowed actions */
533 || paParms[5].type != VBOX_HGCM_SVC_PARM_PTR /* data */
534 || paParms[6].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
535 rc = VERR_INVALID_PARAMETER;
536 else
537 {
538 m_fOpInProcess = true;
539 DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
540 m_dndMessageQueue.append(pMessage);
541 }
542 break;
543 }
544
545 case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
546 {
547 LogFlowFunc(("HOST_DND_HG_EVT_MOVE\n"));
548
549 /* Verify parameter count and types. */
550 if ( cParms != 7
551 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */
552 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* x-pos */
553 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* y-pos */
554 || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* default action */
555 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* allowed actions */
556 || paParms[5].type != VBOX_HGCM_SVC_PARM_PTR /* data */
557 || paParms[6].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
558 {
559 rc = VERR_INVALID_PARAMETER;
560 }
561 else
562 {
563 m_fOpInProcess = true;
564 DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
565 m_dndMessageQueue.append(pMessage);
566 }
567 break;
568 }
569
570 case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE:
571 {
572 LogFlowFunc(("HOST_DND_HG_EVT_LEAVE\n"));
573
574 /* Verify parameter count and types. */
575 if (cParms != 0)
576 rc = VERR_INVALID_PARAMETER;
577 else
578 {
579 DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
580 m_dndMessageQueue.append(pMessage);
581 }
582
583 m_fOpInProcess = false;
584 break;
585 }
586
587 case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
588 {
589 LogFlowFunc(("HOST_DND_HG_EVT_DROPPED\n"));
590
591 /* Verify parameter count and types. */
592 if ( cParms != 7
593 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */
594 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* x-pos */
595 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* y-pos */
596 || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* default action */
597 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* allowed actions */
598 || paParms[5].type != VBOX_HGCM_SVC_PARM_PTR /* data */
599 || paParms[6].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
600 {
601 rc = VERR_INVALID_PARAMETER;
602 }
603 else
604 {
605 DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
606 m_dndMessageQueue.append(pMessage);
607 }
608 break;
609 }
610
611 case DragAndDropSvc::HOST_DND_HG_SND_DATA:
612 {
613 LogFlowFunc(("HOST_DND_HG_SND_DATA\n"));
614
615 /* Verify parameter count and types. */
616 if ( cParms != 5
617 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */
618 || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* format */
619 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* format size */
620 || paParms[3].type != VBOX_HGCM_SVC_PARM_PTR /* data */
621 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* data size */)
622 {
623 rc = VERR_INVALID_PARAMETER;
624 }
625 else
626 {
627 DnDHGSendDataMessage *pMessage =
628 new DnDHGSendDataMessage(uMsg, cParms, paParms,
629 m_pfnProgressCallback, m_pvProgressUser);
630 m_dndMessageQueue.append(pMessage);
631 }
632 break;
633 }
634
635#ifdef VBOX_WITH_DRAG_AND_DROP_GH
636 case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
637 {
638 LogFlowFunc(("HOST_DND_GH_REQ_PENDING\n"));
639
640 /* Verify parameter count and types. */
641 if ( cParms != 1
642 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* screen id */)
643 {
644 rc = VERR_INVALID_PARAMETER;
645 }
646 else
647 {
648 DnDGenericMessage *pMessage = new DnDGenericMessage(uMsg, cParms, paParms);
649 m_dndMessageQueue.append(pMessage);
650 }
651 break;
652 }
653
654 case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
655 {
656 LogFlowFunc(("HOST_DND_GH_EVT_DROPPED\n"));
657
658 /* Verify parameter count and types. */
659 if ( cParms != 3
660 || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* format */
661 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* format size */
662 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* action */)
663 {
664 rc = VERR_INVALID_PARAMETER;
665 }
666 else
667 {
668 try
669 {
670 DnDGenericMessage *pMessage
671 = new DnDGenericMessage(uMsg, cParms, paParms);
672 m_dndMessageQueue.append(pMessage);
673 }
674 catch(std::bad_alloc &)
675 {
676 rc = VERR_NO_MEMORY;
677 }
678 }
679 break;
680 }
681#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
682
683 default:
684 rc = VERR_NOT_IMPLEMENTED;
685 break;
686 }
687 }
688 catch(std::bad_alloc &)
689 {
690 rc = VERR_NO_MEMORY;
691 }
692
693 return rc;
694}
695
696HGCM::Message* DnDManager::nextHGCMMessage(void)
697{
698 if (m_pCurMsg)
699 return m_pCurMsg->nextHGCMMessage();
700
701 if (m_dndMessageQueue.isEmpty())
702 return NULL;
703
704 return m_dndMessageQueue.first()->nextHGCMMessage();
705}
706
707int DnDManager::nextMessageInfo(uint32_t *puMsg, uint32_t *pcParms)
708{
709 AssertPtrReturn(puMsg, VERR_INVALID_POINTER);
710 AssertPtrReturn(pcParms, VERR_INVALID_POINTER);
711
712 int rc = VINF_SUCCESS;
713
714 if (m_pCurMsg)
715 rc = m_pCurMsg->currentMessageInfo(puMsg, pcParms);
716 else
717 {
718 if (m_dndMessageQueue.isEmpty())
719 {
720 rc = VERR_NO_DATA;
721// if (m_pfnProgressCallback)
722// m_pfnProgressCallback(100.0, DragAndDropSvc::DND_OP_CANCELLED, m_pvProgressUser);
723 }
724 else
725 rc = m_dndMessageQueue.first()->currentMessageInfo(puMsg, pcParms);
726 }
727
728 LogFlowFunc(("Returning puMsg=%RU32, pcParms=%RU32, rc=%Rrc\n", *puMsg, *pcParms, rc));
729 return rc;
730}
731
732int DnDManager::nextMessage(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
733{
734 LogFlowFunc(("uMsg=%RU32, cParms=%RU32\n", uMsg, cParms));
735
736 if (!m_pCurMsg)
737 {
738 /* Check for pending messages in our queue. */
739 if (m_dndMessageQueue.isEmpty())
740 {
741 LogFlowFunc(("Message queue is empty, returning\n"));
742 return VERR_NO_DATA;
743 }
744
745 m_pCurMsg = m_dndMessageQueue.first();
746 m_dndMessageQueue.removeFirst();
747 }
748
749 /* Fetch the current message info */
750 int rc = m_pCurMsg->currentMessage(uMsg, cParms, paParms);
751 /* If this message doesn't provide any additional sub messages, clear it. */
752 if (!m_pCurMsg->isMessageWaiting())
753 {
754 delete m_pCurMsg;
755 m_pCurMsg = NULL;
756 }
757
758 /*
759 * If there was an error handling the current message or the user has canceled
760 * the operation, we need to cleanup all pending events and inform the progress
761 * callback about our exit.
762 */
763 if ( RT_FAILURE(rc)
764 && m_pfnProgressCallback)
765 {
766 /* Clear any pending messages. */
767 clear();
768
769 /* Create a new cancel message to inform the guest + call
770 * the host whether the current transfer was canceled or aborted
771 * due to an error. */
772 try
773 {
774 Assert(!m_pCurMsg);
775 m_pCurMsg = new DnDHGCancelMessage();
776 m_pfnProgressCallback(100 /* Percent */,
777 rc == VERR_CANCELLED
778 ? DragAndDropSvc::DND_PROGRESS_CANCELLED
779 : DragAndDropSvc::DND_PROGRESS_ERROR, rc, m_pvProgressUser);
780 }
781 catch(std::bad_alloc &)
782 {
783 rc = VERR_NO_MEMORY;
784 }
785 }
786
787 LogFlowFunc(("Message processed with rc=%Rrc\n", rc));
788 return rc;
789}
790
791void DnDManager::clear(void)
792{
793 if (m_pCurMsg)
794 {
795 delete m_pCurMsg;
796 m_pCurMsg = 0;
797 }
798
799 while (!m_dndMessageQueue.isEmpty())
800 {
801 delete m_dndMessageQueue.last();
802 m_dndMessageQueue.removeLast();
803 }
804}
805
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