VirtualBox

source: vbox/trunk/src/VBox/HostServices/DragAndDrop/service.cpp@ 55422

最後變更 在這個檔案從55422是 55422,由 vboxsync 提交於 10 年 前

DnD: Protocol overhaul with versioning added which now can communicate with Main.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 33.1 KB
 
1/* $Id: service.cpp 55422 2015-04-24 13:52:33Z vboxsync $ */
2/** @file
3 * Drag and Drop Service.
4 */
5
6/*
7 * Copyright (C) 2011-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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/** @page pg_svc_guest_control Guest Control HGCM Service
19 *
20 * This service acts as a proxy for handling and buffering host command requests
21 * and clients on the guest. It tries to be as transparent as possible to let
22 * the guest (client) and host side do their protocol handling as desired.
23 *
24 * The following terms are used:
25 * - Host: A host process (e.g. VBoxManage or another tool utilizing the Main API)
26 * which wants to control something on the guest.
27 * - Client: A client (e.g. VBoxService) running inside the guest OS waiting for
28 * new host commands to perform. There can be multiple clients connected
29 * to a service. A client is represented by its HGCM client ID.
30 * - Context ID: An (almost) unique ID automatically generated on the host (Main API)
31 * to not only distinguish clients but individual requests. Because
32 * the host does not know anything about connected clients it needs
33 * an indicator which it can refer to later. This context ID gets
34 * internally bound by the service to a client which actually processes
35 * the command in order to have a relationship between client<->context ID(s).
36 *
37 * The host can trigger commands which get buffered by the service (with full HGCM
38 * parameter info). As soon as a client connects (or is ready to do some new work)
39 * it gets a buffered host command to process it. This command then will be immediately
40 * removed from the command list. If there are ready clients but no new commands to be
41 * processed, these clients will be set into a deferred state (that is being blocked
42 * to return until a new command is available).
43 *
44 * If a client needs to inform the host that something happened, it can send a
45 * message to a low level HGCM callback registered in Main. This callback contains
46 * the actual data as well as the context ID to let the host do the next necessary
47 * steps for this context. This context ID makes it possible to wait for an event
48 * inside the host's Main API function (like starting a process on the guest and
49 * wait for getting its PID returned by the client) as well as cancelling blocking
50 * host calls in order the client terminated/crashed (HGCM detects disconnected
51 * clients and reports it to this service's callback).
52 */
53
54/******************************************************************************
55 * Header Files *
56 ******************************************************************************/
57#ifdef LOG_GROUP
58 #undef LOG_GROUP
59#endif
60#define LOG_GROUP LOG_GROUP_GUEST_DND
61
62#include <map>
63
64#include "dndmanager.h"
65
66/******************************************************************************
67 * Service class declaration *
68 ******************************************************************************/
69
70/** Map holding pointers to HGCM clients. Key is the (unique) HGCM client ID. */
71typedef std::map<uint32_t, HGCM::Client*> DnDClientMap;
72
73/**
74 * Specialized drag & drop service class.
75 */
76class DragAndDropService : public HGCM::AbstractService<DragAndDropService>
77{
78public:
79
80 explicit DragAndDropService(PVBOXHGCMSVCHELPERS pHelpers)
81 : HGCM::AbstractService<DragAndDropService>(pHelpers)
82 , m_pManager(NULL) {}
83
84protected:
85
86 int init(VBOXHGCMSVCFNTABLE *pTable);
87 int uninit(void);
88 int clientConnect(uint32_t u32ClientID, void *pvClient);
89 int clientDisconnect(uint32_t u32ClientID, void *pvClient);
90 void guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
91 int hostCall(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
92
93 int modeSet(uint32_t u32Mode);
94 inline uint32_t modeGet() { return m_u32Mode; };
95
96protected:
97
98 static DECLCALLBACK(int) progressCallback(uint32_t uStatus, uint32_t uPercentage, int rc, void *pvUser);
99
100protected:
101
102 DnDManager *m_pManager;
103 /** Map of all connected clients. */
104 DnDClientMap m_clientMap;
105 /** List of all clients which are queued up (deferred return) and ready
106 * to process new commands. */
107 RTCList<HGCM::Client*> m_clientQueue;
108 uint32_t m_u32Mode;
109};
110
111/******************************************************************************
112 * Service class implementation *
113 ******************************************************************************/
114
115int DragAndDropService::init(VBOXHGCMSVCFNTABLE *pTable)
116{
117 /* Register functions. */
118 pTable->pfnHostCall = svcHostCall;
119 pTable->pfnSaveState = NULL; /* The service is stateless, so the normal */
120 pTable->pfnLoadState = NULL; /* construction done before restoring suffices */
121 pTable->pfnRegisterExtension = svcRegisterExtension;
122
123 /* Drag'n drop mode is disabled by default. */
124 modeSet(VBOX_DRAG_AND_DROP_MODE_OFF);
125
126 int rc = VINF_SUCCESS;
127
128 try
129 {
130 m_pManager = new DnDManager(&DragAndDropService::progressCallback, this);
131 }
132 catch(std::bad_alloc &)
133 {
134 rc = VERR_NO_MEMORY;
135 }
136
137 LogFlowFuncLeaveRC(rc);
138 return rc;
139}
140
141int DragAndDropService::uninit(void)
142{
143 if (m_pManager)
144 {
145 delete m_pManager;
146 m_pManager = NULL;
147 }
148
149 return VINF_SUCCESS;
150}
151
152int DragAndDropService::clientConnect(uint32_t u32ClientID, void *pvClient)
153{
154 if (m_clientMap.size() >= UINT8_MAX) /* Don't allow too much clients at the same time. */
155 {
156 AssertMsgFailed(("Maximum number of clients reached\n"));
157 return VERR_BUFFER_OVERFLOW;
158 }
159
160 int rc = VINF_SUCCESS;
161
162 /*
163 * Add client to our client map.
164 */
165 if (m_clientMap.find(u32ClientID) != m_clientMap.end())
166 rc = VERR_ALREADY_EXISTS;
167
168 if (RT_SUCCESS(rc))
169 {
170 try
171 {
172 m_clientMap[u32ClientID] = new HGCM::Client(u32ClientID);
173 }
174 catch(std::bad_alloc &)
175 {
176 rc = VERR_NO_MEMORY;
177 }
178
179 if (RT_SUCCESS(rc))
180 {
181 /*
182 * Clear the message queue as soon as a new clients connect
183 * to ensure that every client has the same state.
184 */
185 if (m_pManager)
186 m_pManager->clear();
187 }
188 }
189
190 LogFlowFunc(("Client %RU32 connected, rc=%Rrc\n", u32ClientID, rc));
191 return rc;
192}
193
194int DragAndDropService::clientDisconnect(uint32_t u32ClientID, void *pvClient)
195{
196 /* Client not found? Bail out early. */
197 DnDClientMap::iterator itClient = m_clientMap.find(u32ClientID);
198 if (itClient == m_clientMap.end())
199 return VERR_NOT_FOUND;
200
201 /*
202 * Remove from waiters queue.
203 */
204 for (size_t i = 0; i < m_clientQueue.size(); i++)
205 {
206 HGCM::Client *pClient = m_clientQueue.at(i);
207 if (pClient->clientId() == u32ClientID)
208 {
209 if (m_pHelpers)
210 m_pHelpers->pfnCallComplete(pClient->handle(), VERR_INTERRUPTED);
211
212 m_clientQueue.removeAt(i);
213 delete pClient;
214
215 break;
216 }
217 }
218
219 /*
220 * Remove from client map and deallocate.
221 */
222 AssertPtr(itClient->second);
223 delete itClient->second;
224
225 m_clientMap.erase(itClient);
226
227 LogFlowFunc(("Client %RU32 disconnected\n", u32ClientID));
228 return VINF_SUCCESS;
229}
230
231int DragAndDropService::modeSet(uint32_t u32Mode)
232{
233 /** @todo Validate mode. */
234 switch (u32Mode)
235 {
236 case VBOX_DRAG_AND_DROP_MODE_OFF:
237 case VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST:
238 case VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST:
239 case VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL:
240 m_u32Mode = u32Mode;
241 break;
242
243 default:
244 m_u32Mode = VBOX_DRAG_AND_DROP_MODE_OFF;
245 break;
246 }
247
248 return VINF_SUCCESS;
249}
250
251void DragAndDropService::guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
252 void *pvClient, uint32_t u32Function,
253 uint32_t cParms, VBOXHGCMSVCPARM paParms[])
254{
255 LogFlowFunc(("u32ClientID=%RU32, u32Function=%RU32, cParms=%RU32\n",
256 u32ClientID, u32Function, cParms));
257
258 /* Check if we've the right mode set. */
259 int rc = VERR_ACCESS_DENIED; /* Play safe. */
260 switch (u32Function)
261 {
262 case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
263 {
264 if (modeGet() != VBOX_DRAG_AND_DROP_MODE_OFF)
265 {
266 rc = VINF_SUCCESS;
267 }
268 else
269 {
270 LogFlowFunc(("DnD disabled, deferring request\n"));
271 rc = VINF_HGCM_ASYNC_EXECUTE;
272 }
273 break;
274 }
275
276 /* Note: New since protocol version 2. */
277 case DragAndDropSvc::GUEST_DND_CONNECT:
278 /* Fall through is intentional. */
279 case DragAndDropSvc::GUEST_DND_HG_ACK_OP:
280 case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
281 case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS:
282 {
283 if ( modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
284 || modeGet() == VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST)
285 {
286 rc = VINF_SUCCESS;
287 }
288 else
289 LogFlowFunc(("Host -> Guest DnD mode disabled, ignoring request\n"));
290 break;
291 }
292
293 case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
294 case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
295 case DragAndDropSvc::GUEST_DND_GH_SND_DIR:
296 case DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR:
297 case DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA:
298 case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
299 {
300#ifdef VBOX_WITH_DRAG_AND_DROP_GH
301 if ( modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
302 || modeGet() == VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST)
303 {
304 rc = VINF_SUCCESS;
305 }
306 else
307#endif
308 LogFlowFunc(("Guest -> Host DnD mode disabled, ignoring request\n"));
309 break;
310 }
311
312 default:
313 /* Reach through to DnD manager. */
314 rc = VINF_SUCCESS;
315 break;
316 }
317
318#ifdef DEBUG_andy
319 LogFlowFunc(("Mode (%RU32) check rc=%Rrc\n", modeGet(), rc));
320#endif
321
322 if (rc == VINF_SUCCESS) /* Note: rc might be VINF_HGCM_ASYNC_EXECUTE! */
323 {
324 DnDClientMap::iterator itClient = m_clientMap.find(u32ClientID);
325 Assert(itClient != m_clientMap.end());
326
327 HGCM::Client *pClient = itClient->second;
328 AssertPtr(pClient);
329
330 switch (u32Function)
331 {
332 /*
333 * Note: Older VBox versions with enabled DnD guest->host support (< 5.0)
334 * used the same message ID (300) for GUEST_DND_GET_NEXT_HOST_MSG and
335 * HOST_DND_GH_REQ_PENDING, which led this service returning
336 * VERR_INVALID_PARAMETER when the guest wanted to actually
337 * handle HOST_DND_GH_REQ_PENDING.
338 */
339 case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
340 {
341 LogFlowFunc(("GUEST_DND_GET_NEXT_HOST_MSG\n"));
342 if ( cParms != 3
343 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* message */
344 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* parameter count */
345 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* blocking */)
346 {
347 rc = VERR_INVALID_PARAMETER;
348 }
349 else
350 {
351 rc = m_pManager->nextMessageInfo(&paParms[0].u.uint32 /* uMsg */, &paParms[1].u.uint32 /* cParms */);
352 if (RT_FAILURE(rc)) /* No queued messages available? */
353 {
354 if (m_pfnHostCallback) /* Try asking the host. */
355 {
356 DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSG data;
357 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG;
358 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
359 if (RT_SUCCESS(rc))
360 {
361 paParms[0].u.uint32 = data.uMsg; /* uMsg */
362 paParms[1].u.uint32 = data.cParms; /* cParms */
363 /* Note: paParms[2] was set by the guest as blocking flag. */
364 }
365 }
366 else
367 rc = VERR_NOT_FOUND;
368
369 if (RT_FAILURE(rc))
370 rc = m_pManager->nextMessage(u32Function, cParms, paParms);
371
372 /* Some error occurred? */
373 if ( RT_FAILURE(rc)
374 && paParms[2].u.uint32) /* Blocking flag set? */
375 {
376 /* Defer client returning. */
377 rc = VINF_HGCM_ASYNC_EXECUTE;
378 }
379 }
380 }
381 break;
382 }
383 case DragAndDropSvc::GUEST_DND_CONNECT:
384 {
385 LogFlowFunc(("GUEST_DND_CONNECT\n"));
386 if ( cParms != 2
387 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* protocol version */
388 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* additional connection flags */)
389 rc = VERR_INVALID_PARAMETER;
390 else
391 {
392 uint32_t uProtocol;
393 paParms[0].getUInt32(&uProtocol); /* Get protocol version. */
394
395 rc = pClient->setProtocol(uProtocol);
396 if (RT_SUCCESS(rc))
397 {
398 /** @todo Handle connection flags (paParms[1]). */
399 }
400
401 /* Note: Does not reach the host; the client's protocol version
402 * is only kept in this service. */
403 }
404 break;
405 }
406 case DragAndDropSvc::GUEST_DND_HG_ACK_OP:
407 {
408 LogFlowFunc(("GUEST_DND_HG_ACK_OP\n"));
409 if ( cParms != 1
410 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* action */)
411 rc = VERR_INVALID_PARAMETER;
412 else
413 {
414 DragAndDropSvc::VBOXDNDCBHGACKOPDATA data;
415 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_ACK_OP;
416 paParms[0].getUInt32(&data.uAction); /* Get drop action. */
417 if (m_pfnHostCallback)
418 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
419 }
420 break;
421 }
422 case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
423 {
424 LogFlowFunc(("GUEST_DND_HG_REQ_DATA\n"));
425 if ( cParms != 1
426 || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* format */)
427 rc = VERR_INVALID_PARAMETER;
428 else
429 {
430 DragAndDropSvc::VBOXDNDCBHGREQDATADATA data;
431 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_REQ_DATA;
432 uint32_t cTmp;
433 paParms[0].getPointer((void**)&data.pszFormat, &cTmp);
434 if (m_pfnHostCallback)
435 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
436 }
437 break;
438 }
439 case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS:
440 {
441 LogFlowFunc(("GUEST_DND_HG_EVT_PROGRESS\n"));
442 if ( cParms != 3
443 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* status */
444 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* percent */
445 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* rc */)
446 rc = VERR_INVALID_PARAMETER;
447 else
448 {
449 DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA data;
450 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS;
451 paParms[0].getUInt32(&data.uStatus);
452 paParms[1].getUInt32(&data.uPercentage);
453 paParms[2].getUInt32(&data.rc);
454 if (m_pfnHostCallback)
455 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
456 }
457 break;
458 }
459#ifdef VBOX_WITH_DRAG_AND_DROP_GH
460 case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
461 {
462 LogFlowFunc(("GUEST_DND_GH_ACK_PENDING\n"));
463 if ( cParms != 3
464 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* defaction */
465 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* alloctions */
466 || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR /* format */)
467 rc = VERR_INVALID_PARAMETER;
468 else
469 {
470 DragAndDropSvc::VBOXDNDCBGHACKPENDINGDATA data;
471 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_ACK_PENDING;
472 paParms[0].getUInt32(&data.uDefAction);
473 paParms[1].getUInt32(&data.uAllActions);
474 uint32_t cTmp;
475 paParms[2].getPointer((void**)&data.pszFormat, &cTmp);
476 if (m_pfnHostCallback)
477 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
478 }
479 break;
480 }
481 case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
482 {
483 LogFlowFunc(("GUEST_DND_GH_SND_DATA\n"));
484 if ( cParms != 2
485 || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* data */
486 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
487 rc = VERR_INVALID_PARAMETER;
488 else
489 {
490 DragAndDropSvc::VBOXDNDCBSNDDATADATA data;
491 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA;
492 paParms[0].getPointer((void**)&data.pvData, &data.cbData);
493 paParms[1].getUInt32(&data.cbTotalSize);
494 if (m_pfnHostCallback)
495 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
496 }
497 break;
498 }
499 case DragAndDropSvc::GUEST_DND_GH_SND_DIR:
500 {
501 LogFlowFunc(("GUEST_DND_GH_SND_DIR\n"));
502 if ( cParms != 3
503 || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* path */
504 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* path length */
505 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* creation mode */)
506 rc = VERR_INVALID_PARAMETER;
507 else
508 {
509 DragAndDropSvc::VBOXDNDCBSNDDIRDATA data;
510 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_DIR;
511 uint32_t cTmp;
512 paParms[0].getPointer((void**)&data.pszPath, &cTmp);
513 paParms[1].getUInt32(&data.cbPath);
514 paParms[2].getUInt32(&data.fMode);
515
516 LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x\n", data.pszPath, data.cbPath, data.fMode));
517 if (m_pfnHostCallback)
518 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
519 }
520 break;
521 }
522 /* Note: Since protocol v2 (>= VBox 5.0). */
523 case DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR:
524 {
525 LogFlowFunc(("GUEST_DND_GH_SND_FILE_HDR\n"));
526 if ( cParms != 6
527 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* context ID */
528 || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* file path */
529 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* file path length */
530 || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* flags */
531 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* file mode */
532 || paParms[5].type != VBOX_HGCM_SVC_PARM_64BIT /* file size */)
533 rc = VERR_INVALID_PARAMETER;
534 else
535 {
536 DragAndDropSvc::VBOXDNDCBSNDFILEHDRDATA data;
537 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_HDR;
538 uint32_t cTmp;
539 /* paParms[0] is context ID; unused yet. */
540 paParms[1].getPointer((void**)&data.pszFilePath, &cTmp);
541 paParms[2].getUInt32(&data.cbFilePath);
542 paParms[3].getUInt32(&data.fFlags);
543 paParms[4].getUInt32(&data.fMode);
544 paParms[5].getUInt64(&data.cbSize);
545
546 LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x, cbSize=%RU64\n",
547 data.pszFilePath, data.cbFilePath, data.fMode, data.cbSize));
548
549 if (m_pfnHostCallback)
550 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
551 }
552 break;
553 }
554 case DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA:
555 {
556 LogFlowFunc(("GUEST_DND_GH_SND_FILE_DATA\n"));
557
558 switch (pClient->protocol())
559 {
560 case 2: /* Protocol version 2 only sends the next data chunks to reduce traffic. */
561 {
562 if ( cParms != 3
563 /* paParms[0] is context ID; unused yet. */
564 || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* file data */
565 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* file data length */)
566 {
567 rc = VERR_INVALID_PARAMETER;
568 }
569 else
570 {
571 DragAndDropSvc::VBOXDNDCBSNDFILEDATADATA data;
572 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_DATA;
573 /* paParms[0] is context ID; unused yet. */
574 paParms[1].getPointer((void**)&data.pvData, &data.cbData);
575 paParms[2].getUInt32(&data.cbData);
576
577 LogFlowFunc(("cbData=%RU32, pvData=0x%p\n", data.cbData, data.pvData));
578
579 if (m_pfnHostCallback)
580 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
581 }
582 break;
583 }
584 default:
585 {
586 if ( cParms != 5
587 || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* file path */
588 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* file path length */
589 || paParms[2].type != VBOX_HGCM_SVC_PARM_PTR /* file data */
590 || paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* file data length */
591 || paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* creation mode */)
592 {
593 rc = VERR_INVALID_PARAMETER;
594 }
595 else
596 {
597 DragAndDropSvc::VBOXDNDCBSNDFILEDATADATA data;
598 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE_DATA;
599 uint32_t cTmp;
600 paParms[0].getPointer((void**)&data.u.v1.pszFilePath, &cTmp);
601 paParms[1].getUInt32(&data.u.v1.cbFilePath);
602 paParms[2].getPointer((void**)&data.pvData, &cTmp);
603 paParms[3].getUInt32(&data.cbData);
604 paParms[4].getUInt32(&data.u.v1.fMode);
605
606 LogFlowFunc(("pszFilePath=%s, cbData=%RU32, pvData=0x%p, fMode=0x%x\n",
607 data.u.v1.pszFilePath, data.cbData, data.pvData, data.u.v1.fMode));
608
609 if (m_pfnHostCallback)
610 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
611 }
612 break;
613 }
614 }
615 break;
616 }
617 case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
618 {
619 LogFlowFunc(("GUEST_DND_GH_EVT_ERROR\n"));
620 if ( cParms != 1
621 || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* rc */)
622 rc = VERR_INVALID_PARAMETER;
623 else
624 {
625 DragAndDropSvc::VBOXDNDCBEVTERRORDATA data;
626 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR;
627
628 uint32_t rcOp;
629 paParms[0].getUInt32(&rcOp);
630 data.rc = rcOp;
631
632 if (m_pfnHostCallback)
633 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
634 }
635 break;
636 }
637#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
638 default:
639 {
640 /* All other messages are handled by the DnD manager. */
641 rc = m_pManager->nextMessage(u32Function, cParms, paParms);
642 if (rc == VERR_NO_DATA) /* Manager has no new messsages? Try asking the host. */
643 {
644 if (m_pfnHostCallback)
645 {
646 DragAndDropSvc::VBOXDNDCBHGGETNEXTHOSTMSGDATA data;
647 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG_DATA;
648 data.uMsg = u32Function;
649 data.cParms = cParms;
650 data.paParms = paParms;
651
652 rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
653 if (RT_SUCCESS(rc))
654 {
655 cParms = data.cParms;
656 paParms = data.paParms;
657 }
658 }
659 }
660 break;
661 }
662 }
663 }
664
665 /*
666 * If async execution is requested, we didn't notify the guest yet about
667 * completion. The client is queued into the waiters list and will be
668 * notified as soon as a new event is available.
669 */
670 if (rc == VINF_HGCM_ASYNC_EXECUTE)
671 {
672 m_clientQueue.append(new HGCM::Client(u32ClientID, callHandle,
673 u32Function, cParms, paParms));
674 }
675
676 if ( rc != VINF_HGCM_ASYNC_EXECUTE
677 && m_pHelpers)
678 {
679 m_pHelpers->pfnCallComplete(callHandle, rc);
680 }
681
682 LogFlowFunc(("Returning rc=%Rrc\n", rc));
683}
684
685int DragAndDropService::hostCall(uint32_t u32Function,
686 uint32_t cParms, VBOXHGCMSVCPARM paParms[])
687{
688 LogFlowFunc(("u32Function=%RU32, cParms=%RU32, cClients=%zu, cQueue=%zu\n",
689 u32Function, cParms, m_clientMap.size(), m_clientQueue.size()));
690
691 int rc;
692 if (u32Function == DragAndDropSvc::HOST_DND_SET_MODE)
693 {
694 if (cParms != 1)
695 rc = VERR_INVALID_PARAMETER;
696 else if (paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT)
697 rc = VERR_INVALID_PARAMETER;
698 else
699 rc = modeSet(paParms[0].u.uint32);
700 }
701 else if (modeGet() != VBOX_DRAG_AND_DROP_MODE_OFF)
702 {
703 if (m_clientMap.size()) /* At least one client on the guest connected? */
704 {
705 /*
706 * Did the host call something which needs immediate processing?
707 * Prepend the message instead of appending to the command queue then.
708 */
709 bool fAppend;
710 switch (u32Function)
711 {
712 /* Cancelling the drag'n drop operation has higher priority than
713 * processing already buffered messages. */
714 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
715 fAppend = false;
716 break;
717
718 default:
719 fAppend = true;
720 break;
721 }
722
723 /*
724 * If we prepending the message (instead of appending) this mean we need
725 * to re-schedule the message queue in order to get the new command executed as
726 * soon as possible.
727 */
728 bool fReschedule = !fAppend;
729
730 rc = m_pManager->addMessage(u32Function, cParms, paParms, fAppend);
731 if ( RT_SUCCESS(rc)
732 && fReschedule)
733 {
734 rc = m_pManager->doReschedule();
735 }
736
737 if (RT_SUCCESS(rc))
738 {
739 if (m_clientQueue.size()) /* Any clients in our queue ready for processing the next command? */
740 {
741 HGCM::Client *pClient = m_clientQueue.first();
742 AssertPtr(pClient);
743
744 /*
745 * Check if this was a request for getting the next host
746 * message. If so, return the message ID and the parameter
747 * count. The message itself has to be queued.
748 */
749 uint32_t uMsg = pClient->message();
750 if (uMsg == DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG)
751 {
752 LogFlowFunc(("Client %RU32 is waiting for next host msg\n", pClient->clientId()));
753
754 uint32_t uMsg1;
755 uint32_t cParms1;
756 rc = m_pManager->nextMessageInfo(&uMsg1, &cParms1);
757 if (RT_SUCCESS(rc))
758 {
759 pClient->addMessageInfo(uMsg1, cParms1);
760 if ( m_pHelpers
761 && m_pHelpers->pfnCallComplete)
762 {
763 m_pHelpers->pfnCallComplete(pClient->handle(), rc);
764 }
765
766 m_clientQueue.removeFirst();
767
768 delete pClient;
769 pClient = NULL;
770 }
771 else
772 AssertMsgFailed(("m_pManager::nextMessageInfo failed with rc=%Rrc\n", rc));
773 }
774 else
775 AssertMsgFailed(("Client ID=%RU32 in wrong state with uMsg=%RU32\n",
776 pClient->clientId(), uMsg));
777 }
778 else
779 LogFlowFunc(("All clients busy; delaying execution\n"));
780 }
781 else
782 AssertMsgFailed(("Adding new message of type=%RU32 failed with rc=%Rrc\n",
783 u32Function, rc));
784 }
785 else
786 {
787 /*
788 * Tell the host that the guest does not support drag'n drop.
789 * This might happen due to not installed Guest Additions or
790 * not running VBoxTray/VBoxClient.
791 */
792 rc = VERR_NOT_SUPPORTED;
793 }
794 }
795 else
796 {
797 /* Tell the host that a wrong drag'n drop mode is set. */
798 rc = VERR_ACCESS_DENIED;
799 }
800
801 LogFlowFuncLeaveRC(rc);
802 return rc;
803}
804
805DECLCALLBACK(int) DragAndDropService::progressCallback(uint32_t uStatus, uint32_t uPercentage, int rc, void *pvUser)
806{
807 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
808
809 DragAndDropService *pSelf = static_cast<DragAndDropService *>(pvUser);
810 AssertPtr(pSelf);
811
812 if (pSelf->m_pfnHostCallback)
813 {
814 LogFlowFunc(("GUEST_DND_HG_EVT_PROGRESS: uStatus=%RU32, uPercentage=%RU32, rc=%Rrc\n",
815 uStatus, uPercentage, rc));
816
817 DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA data;
818 data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS;
819 data.uPercentage = RT_MIN(uPercentage, 100);
820 data.uStatus = uStatus;
821 data.rc = rc; /** @todo uin32_t vs. int. */
822
823 return pSelf->m_pfnHostCallback(pSelf->m_pvHostData,
824 DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS,
825 &data, sizeof(data));
826 }
827
828 return VINF_SUCCESS;
829}
830
831/**
832 * @copydoc VBOXHGCMSVCLOAD
833 */
834extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable)
835{
836 return DragAndDropService::svcLoad(pTable);
837}
838
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette