VirtualBox

source: vbox/trunk/src/VBox/HostServices/DragAndDrop/VBoxDragAndDropSvc.cpp@ 97748

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

DnD: Renamed GUEST_DND_FN_GH_EVT_ERROR -> GUEST_DND_FN_EVT_ERROR to make this message more generic and not only bound to guest -> host (G->H) transfers. We also need a way to pass back errors for host -> guest (H->G) transfers.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 46.7 KB
 
1/* $Id: VBoxDragAndDropSvc.cpp 97748 2022-12-06 09:26:48Z vboxsync $ */
2/** @file
3 * Drag and Drop Service.
4 */
5
6/*
7 * Copyright (C) 2011-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.alldomusa.eu.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/** @page pg_svc_dnd Drag and drop HGCM Service
29 *
30 * @sa See src/VBox/Main/src-client/GuestDnDPrivate.cpp for more information.
31 */
32
33
34/*********************************************************************************************************************************
35* Header Files *
36*********************************************************************************************************************************/
37#define LOG_GROUP LOG_GROUP_GUEST_DND
38#include <VBox/GuestHost/DragAndDrop.h>
39#include <VBox/GuestHost/DragAndDropDefs.h>
40#include <VBox/HostServices/Service.h>
41#include <VBox/HostServices/DragAndDropSvc.h>
42#include <VBox/AssertGuest.h>
43
44#include <VBox/err.h>
45
46#include <algorithm>
47#include <list>
48#include <map>
49
50#include "dndmanager.h"
51
52using namespace DragAndDropSvc;
53
54
55/*********************************************************************************************************************************
56* Service class declaration *
57*********************************************************************************************************************************/
58
59class DragAndDropClient : public HGCM::Client
60{
61public:
62
63 DragAndDropClient(uint32_t idClient)
64 : HGCM::Client(idClient)
65 , uProtocolVerDeprecated(0)
66 , fGuestFeatures0(VBOX_DND_GF_NONE)
67 , fGuestFeatures1(VBOX_DND_GF_NONE)
68 {
69 RT_ZERO(m_SvcCtx);
70 }
71
72 virtual ~DragAndDropClient(void)
73 {
74 disconnect();
75 }
76
77public:
78
79 void disconnect(void) RT_NOEXCEPT;
80
81public:
82
83 /** Protocol version used by this client.
84 * Deprecated; only used for keeping backwards compatibility. */
85 uint32_t uProtocolVerDeprecated;
86 /** Guest feature flags, VBOX_DND_GF_0_XXX. */
87 uint64_t fGuestFeatures0;
88 /** Guest feature flags, VBOX_DND_GF_1_XXX. */
89 uint64_t fGuestFeatures1;
90};
91
92/** Map holding pointers to drag and drop clients. Key is the (unique) HGCM client ID. */
93typedef std::map<uint32_t, DragAndDropClient*> DnDClientMap;
94
95/** Simple queue (list) which holds deferred (waiting) clients. */
96typedef std::list<uint32_t> DnDClientQueue;
97
98/**
99 * Specialized drag & drop service class.
100 */
101class DragAndDropService : public HGCM::AbstractService<DragAndDropService>
102{
103public:
104 explicit DragAndDropService(PVBOXHGCMSVCHELPERS pHelpers)
105 : HGCM::AbstractService<DragAndDropService>(pHelpers)
106 , m_pManager(NULL)
107 , m_u32Mode(VBOX_DRAG_AND_DROP_MODE_OFF)
108 {}
109
110protected:
111 int init(VBOXHGCMSVCFNTABLE *pTable) RT_NOEXCEPT RT_OVERRIDE;
112 int uninit(void) RT_NOEXCEPT RT_OVERRIDE;
113 int clientConnect(uint32_t idClient, void *pvClient) RT_NOEXCEPT RT_OVERRIDE;
114 int clientDisconnect(uint32_t idClient, void *pvClient) RT_NOEXCEPT RT_OVERRIDE;
115 int clientQueryFeatures(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT;
116 int clientReportFeatures(DragAndDropClient *pClient, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT;
117 void guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t idClient, void *pvClient, uint32_t u32Function,
118 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT RT_OVERRIDE;
119 int hostCall(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT RT_OVERRIDE;
120
121private:
122 int modeSet(uint32_t u32Mode) RT_NOEXCEPT;
123 inline uint32_t modeGet(void) const RT_NOEXCEPT
124 { return m_u32Mode; };
125
126 static DECLCALLBACK(int) progressCallback(uint32_t uStatus, uint32_t uPercentage, int rc, void *pvUser);
127
128private:
129 /** Pointer to our DnD manager instance. */
130 DnDManager *m_pManager;
131 /** Map of all connected clients.
132 * The primary key is the (unique) client ID, the secondary value
133 * an allocated pointer to the DragAndDropClient class, managed
134 * by this service class. */
135 DnDClientMap m_clientMap;
136 /** List of all clients which are queued up (deferred return) and ready
137 * to process new commands. The key is the (unique) client ID. */
138 DnDClientQueue m_clientQueue;
139 /** Current drag and drop mode, VBOX_DRAG_AND_DROP_MODE_XXX. */
140 uint32_t m_u32Mode;
141 /** Host feature mask (VBOX_DND_HF_0_XXX) for DND_GUEST_REPORT_FEATURES
142 * and DND_GUEST_QUERY_FEATURES. */
143 uint64_t m_fHostFeatures0;
144};
145
146
147/*********************************************************************************************************************************
148* Client implementation *
149*********************************************************************************************************************************/
150
151/**
152 * Called when the HGCM client disconnected on the guest side.
153 *
154 * This function takes care of the client's data cleanup and also lets the host
155 * know that the client has been disconnected.
156 */
157void DragAndDropClient::disconnect(void) RT_NOEXCEPT
158{
159 LogFlowThisFunc(("uClient=%RU32, fDeferred=%RTbool\n", m_idClient, IsDeferred()));
160
161 /*
162 * If the client still is waiting for a message (i.e in deferred mode),
163 * complete the call with a VERR_CANCELED status so that the client (VBoxTray / VBoxClient) knows
164 * it should bail out.
165 */
166 if (IsDeferred())
167 CompleteDeferred(VERR_CANCELLED);
168
169 /*
170 * Let the host know.
171 */
172 VBOXDNDCBDISCONNECTMSGDATA data;
173 RT_ZERO(data);
174 /** @todo Magic needed? */
175 /** @todo Add context ID. */
176
177 if (m_SvcCtx.pfnHostCallback)
178 {
179 int rc2 = m_SvcCtx.pfnHostCallback(m_SvcCtx.pvHostData, GUEST_DND_FN_DISCONNECT, &data, sizeof(data));
180 if (RT_FAILURE(rc2))
181 LogFlowFunc(("Warning: Unable to notify host about client %RU32 disconnect, rc=%Rrc\n", m_idClient, rc2));
182 /* Not fatal. */
183 }
184}
185
186
187/*********************************************************************************************************************************
188* Service class implementation *
189*********************************************************************************************************************************/
190
191int DragAndDropService::init(VBOXHGCMSVCFNTABLE *pTable) RT_NOEXCEPT
192{
193 /* Legacy clients map to the root category. */
194 pTable->idxLegacyClientCategory = HGCM_CLIENT_CATEGORY_ROOT;
195
196 /* Limit to 255 clients (see also DragAndDropService::clientConnect). */
197 for (uintptr_t i = 0; i < RT_ELEMENTS(pTable->acMaxClients); i++)
198 pTable->acMaxClients[i] = UINT8_MAX;
199
200 /* Limit the number of concurrent calls to 256 (playing safe). */
201 /** @todo Properly determin the max number of pending/concurrent calls for DnD. */
202 for (uintptr_t i = 0; i < RT_ELEMENTS(pTable->acMaxClients); i++)
203 pTable->acMaxCallsPerClient[i] = 256;
204
205 /* Register functions. */
206 pTable->pfnHostCall = svcHostCall;
207 pTable->pfnSaveState = NULL; /* The service is stateless, so the normal */
208 pTable->pfnLoadState = NULL; /* construction done before restoring suffices */
209 pTable->pfnRegisterExtension = svcRegisterExtension;
210 pTable->pfnNotify = NULL;
211
212 /* Drag'n drop mode is disabled by default. */
213 modeSet(VBOX_DRAG_AND_DROP_MODE_OFF);
214
215 /* Set host features. */
216 m_fHostFeatures0 = VBOX_DND_HF_NONE;
217
218 int rc = VINF_SUCCESS;
219
220 try
221 {
222 m_pManager = new DnDManager(&DragAndDropService::progressCallback, this);
223 }
224 catch (std::bad_alloc &)
225 {
226 rc = VERR_NO_MEMORY;
227 }
228
229 LogFlowFuncLeaveRC(rc);
230 return rc;
231}
232
233int DragAndDropService::uninit(void) RT_NOEXCEPT
234{
235 LogFlowFuncEnter();
236
237 if (m_pManager)
238 {
239 delete m_pManager;
240 m_pManager = NULL;
241 }
242
243 DnDClientMap::iterator itClient = m_clientMap.begin();
244 while (itClient != m_clientMap.end())
245 {
246 delete itClient->second;
247 m_clientMap.erase(itClient);
248 itClient = m_clientMap.begin();
249 }
250
251 LogFlowFuncLeave();
252 return VINF_SUCCESS;
253}
254
255int DragAndDropService::clientConnect(uint32_t idClient, void *pvClient) RT_NOEXCEPT
256{
257 RT_NOREF1(pvClient);
258 if (m_clientMap.size() >= UINT8_MAX) /* Don't allow too much clients at the same time. */
259 {
260 AssertMsgFailed(("Maximum number of clients reached\n"));
261 return VERR_MAX_PROCS_REACHED;
262 }
263
264
265 /*
266 * Add client to our client map.
267 */
268 if (m_clientMap.find(idClient) != m_clientMap.end())
269 {
270 LogFunc(("Client %RU32 is already connected!\n", idClient));
271 return VERR_ALREADY_EXISTS;
272 }
273
274 try
275 {
276 DragAndDropClient *pClient = new DragAndDropClient(idClient);
277 pClient->SetSvcContext(m_SvcCtx);
278 m_clientMap[idClient] = pClient;
279 }
280 catch (std::bad_alloc &)
281 {
282 LogFunc(("Client %RU32 - VERR_NO_MEMORY!\n", idClient));
283 return VERR_NO_MEMORY;
284 }
285
286 /*
287 * Reset the message queue as soon as a new clients connect
288 * to ensure that every client has the same state.
289 */
290 if (m_pManager)
291 m_pManager->Reset();
292
293 LogFlowFunc(("Client %RU32 connected (VINF_SUCCESS)\n", idClient));
294 return VINF_SUCCESS;
295}
296
297int DragAndDropService::clientDisconnect(uint32_t idClient, void *pvClient) RT_NOEXCEPT
298{
299 RT_NOREF1(pvClient);
300
301 /* Client not found? Bail out early. */
302 DnDClientMap::iterator itClient = m_clientMap.find(idClient);
303 if (itClient == m_clientMap.end())
304 {
305 LogFunc(("Client %RU32 not found!\n", idClient));
306 return VERR_NOT_FOUND;
307 }
308
309 /*
310 * Remove from waiters queue.
311 */
312 m_clientQueue.remove(idClient);
313
314 /*
315 * Remove from client map and deallocate.
316 */
317 AssertPtr(itClient->second);
318 delete itClient->second;
319
320 m_clientMap.erase(itClient);
321
322 LogFlowFunc(("Client %RU32 disconnected\n", idClient));
323 return VINF_SUCCESS;
324}
325
326/**
327 * Implements GUEST_DND_FN_REPORT_FEATURES.
328 *
329 * @returns VBox status code.
330 * @retval VINF_HGCM_ASYNC_EXECUTE on success (we complete the message here).
331 * @retval VERR_ACCESS_DENIED if not master
332 * @retval VERR_INVALID_PARAMETER if bit 63 in the 2nd parameter isn't set.
333 * @retval VERR_WRONG_PARAMETER_COUNT
334 *
335 * @param pClient The client state.
336 * @param cParms Number of parameters.
337 * @param paParms Array of parameters.
338 */
339int DragAndDropService::clientReportFeatures(DragAndDropClient *pClient, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT
340{
341 RT_NOREF(pClient);
342
343 /*
344 * Validate the request.
345 */
346 ASSERT_GUEST_RETURN(cParms == 2, VERR_WRONG_PARAMETER_COUNT);
347 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
348 uint64_t const fFeatures0 = paParms[0].u.uint64;
349 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
350 uint64_t const fFeatures1 = paParms[1].u.uint64;
351 ASSERT_GUEST_RETURN(fFeatures1 & VBOX_DND_GF_1_MUST_BE_ONE, VERR_INVALID_PARAMETER);
352
353 /*
354 * Report back the host features.
355 */
356 paParms[0].u.uint64 = m_fHostFeatures0;
357 paParms[1].u.uint64 = 0;
358
359 pClient->fGuestFeatures0 = fFeatures0;
360 pClient->fGuestFeatures1 = fFeatures1;
361
362 Log(("[Client %RU32] features: %#RX64 %#RX64\n", pClient->GetClientID(), fFeatures0, fFeatures1));
363
364 return VINF_SUCCESS;
365}
366
367/**
368 * Implements GUEST_DND_FN_QUERY_FEATURES.
369 *
370 * @returns VBox status code.
371 * @retval VINF_HGCM_ASYNC_EXECUTE on success (we complete the message here).
372 * @retval VERR_WRONG_PARAMETER_COUNT
373 *
374 * @param cParms Number of parameters.
375 * @param paParms Array of parameters.
376 */
377int DragAndDropService::clientQueryFeatures(uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT
378{
379 /*
380 * Validate the request.
381 */
382 ASSERT_GUEST_RETURN(cParms == 2, VERR_WRONG_PARAMETER_COUNT);
383 ASSERT_GUEST_RETURN(paParms[0].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
384 ASSERT_GUEST_RETURN(paParms[1].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
385 ASSERT_GUEST(paParms[1].u.uint64 & RT_BIT_64(63));
386
387 /*
388 * Report back the host features.
389 */
390 paParms[0].u.uint64 = m_fHostFeatures0;
391 paParms[1].u.uint64 = 0;
392
393 return VINF_SUCCESS;
394}
395
396int DragAndDropService::modeSet(uint32_t u32Mode) RT_NOEXCEPT
397{
398#ifndef VBOX_WITH_DRAG_AND_DROP_GH
399 if ( u32Mode == VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST
400 || u32Mode == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL)
401 {
402 m_u32Mode = VBOX_DRAG_AND_DROP_MODE_OFF;
403 return VERR_NOT_SUPPORTED;
404 }
405#endif
406
407 switch (u32Mode)
408 {
409 case VBOX_DRAG_AND_DROP_MODE_OFF:
410 case VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST:
411 case VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST:
412 case VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL:
413 m_u32Mode = u32Mode;
414 break;
415
416 default:
417 m_u32Mode = VBOX_DRAG_AND_DROP_MODE_OFF;
418 break;
419 }
420
421 return VINF_SUCCESS;
422}
423
424void DragAndDropService::guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t idClient,
425 void *pvClient, uint32_t u32Function,
426 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT
427{
428 RT_NOREF1(pvClient);
429 LogFlowFunc(("idClient=%RU32, u32Function=%s (%#x), cParms=%RU32\n",
430 idClient, DnDGuestMsgToStr(u32Function), u32Function, cParms));
431
432 /* Check if we've the right mode set. */
433 int rc = VERR_ACCESS_DENIED; /* Play safe. */
434 switch (u32Function)
435 {
436 case GUEST_DND_FN_GET_NEXT_HOST_MSG:
437 {
438 if (modeGet() != VBOX_DRAG_AND_DROP_MODE_OFF)
439 rc = VINF_SUCCESS;
440 else
441 {
442 LogRel(("DnD: Feature is disabled, ignoring request from guest\n"));
443 rc = VINF_HGCM_ASYNC_EXECUTE;
444 }
445 break;
446 }
447
448 /* New since protocol v2. */
449 case GUEST_DND_FN_CONNECT:
450 RT_FALL_THROUGH();
451 /* New since VBox 6.1.x. */
452 case GUEST_DND_FN_REPORT_FEATURES:
453 RT_FALL_THROUGH();
454 /* New since VBox 6.1.x. */
455 case GUEST_DND_FN_QUERY_FEATURES:
456 {
457 /*
458 * Never block these calls, as the clients issues those when
459 * initializing and might get stuck if drag and drop is set to "disabled" at
460 * that time.
461 */
462 rc = VINF_SUCCESS;
463 break;
464 }
465
466 /* New since VBOx 7.0.x. See define for details. */
467 case GUEST_DND_FN_EVT_ERROR:
468 {
469 rc = VINF_SUCCESS;
470 break;
471 }
472
473 case GUEST_DND_FN_HG_ACK_OP:
474 case GUEST_DND_FN_HG_REQ_DATA:
475 case GUEST_DND_FN_HG_EVT_PROGRESS:
476 {
477 if ( modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
478 || modeGet() == VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST)
479 rc = VINF_SUCCESS;
480 else
481 LogRel(("DnD: Host -> Guest mode disabled, ignoring request from guest\n"));
482 break;
483 }
484
485 case GUEST_DND_FN_GH_ACK_PENDING:
486 case GUEST_DND_FN_GH_SND_DATA_HDR:
487 case GUEST_DND_FN_GH_SND_DATA:
488 case GUEST_DND_FN_GH_SND_DIR:
489 case GUEST_DND_FN_GH_SND_FILE_HDR:
490 case GUEST_DND_FN_GH_SND_FILE_DATA:
491 {
492#ifdef VBOX_WITH_DRAG_AND_DROP_GH
493 if ( modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
494 || modeGet() == VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST)
495 rc = VINF_SUCCESS;
496 else
497#endif
498 LogRel(("DnD: Guest -> Host mode disabled, ignoring request from guest\n"));
499 break;
500 }
501
502 default:
503 /* Reach through to DnD manager. */
504 rc = VINF_SUCCESS;
505 break;
506 }
507
508#define DO_HOST_CALLBACK(); \
509 if ( RT_SUCCESS(rc) \
510 && m_SvcCtx.pfnHostCallback) \
511 { \
512 rc = m_SvcCtx.pfnHostCallback(m_SvcCtx.pvHostData, u32Function, &data, sizeof(data)); \
513 }
514
515 /*
516 * Lookup client.
517 */
518 DragAndDropClient *pClient = NULL;
519
520 DnDClientMap::iterator itClient = m_clientMap.find(idClient);
521 if (itClient != m_clientMap.end())
522 {
523 pClient = itClient->second;
524 AssertPtr(pClient);
525 }
526 else
527 {
528 LogFunc(("Client %RU32 was not found\n", idClient));
529 rc = VERR_NOT_FOUND;
530 }
531
532/* Verifies that an uint32 parameter has the expected buffer size set.
533 * Will set rc to VERR_INVALID_PARAMETER otherwise. See #9777. */
534#define VERIFY_BUFFER_SIZE_UINT32(a_ParmUInt32, a_SizeExpected) \
535do { \
536 uint32_t cbTemp = 0; \
537 rc = HGCMSvcGetU32(&a_ParmUInt32, &cbTemp); \
538 ASSERT_GUEST_BREAK(RT_SUCCESS(rc) && cbTemp == a_SizeExpected); \
539} while (0)
540
541/* Gets the context ID from the first parameter and store it into the data header.
542 * Then increments idxParm by one if more than one parameter is available. */
543#define GET_CONTEXT_ID_PARM0() \
544 if (fHasCtxID) \
545 { \
546 ASSERT_GUEST_BREAK(cParms >= 1); \
547 rc = HGCMSvcGetU32(&paParms[0], &data.hdr.uContextID); \
548 ASSERT_GUEST_BREAK(RT_SUCCESS(rc)); \
549 if (cParms > 1) \
550 idxParm++; \
551 }
552
553 if (rc == VINF_SUCCESS) /* Note: rc might be VINF_HGCM_ASYNC_EXECUTE! */
554 {
555 rc = VERR_INVALID_PARAMETER; /* Play safe by default. */
556
557 /* Whether the client's advertised protocol sends context IDs with commands. */
558 const bool fHasCtxID = pClient->uProtocolVerDeprecated >= 3;
559
560 /* Current parameter index to process. */
561 unsigned idxParm = 0;
562
563 switch (u32Function)
564 {
565 /*
566 * Note: Older VBox versions with enabled DnD guest->host support (< 5.0)
567 * used the same message ID (300) for GUEST_DND_FN_GET_NEXT_HOST_MSG and
568 * HOST_DND_FN_GH_REQ_PENDING, which led this service returning
569 * VERR_INVALID_PARAMETER when the guest wanted to actually
570 * handle HOST_DND_FN_GH_REQ_PENDING.
571 */
572 case GUEST_DND_FN_GET_NEXT_HOST_MSG:
573 {
574 if (cParms == 3)
575 {
576 rc = m_pManager->GetNextMsgInfo(&paParms[0].u.uint32 /* uMsg */, &paParms[1].u.uint32 /* cParms */);
577 if (RT_FAILURE(rc)) /* No queued messages available? */
578 {
579 if (m_SvcCtx.pfnHostCallback) /* Try asking the host. */
580 {
581 VBOXDNDCBHGGETNEXTHOSTMSG data;
582 RT_ZERO(data);
583 data.hdr.uMagic = CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG;
584 rc = m_SvcCtx.pfnHostCallback(m_SvcCtx.pvHostData, u32Function, &data, sizeof(data));
585 if (RT_SUCCESS(rc))
586 {
587 paParms[0].u.uint32 = data.uMsg; /* uMsg */
588 paParms[1].u.uint32 = data.cParms; /* cParms */
589 /* Note: paParms[2] was set by the guest as blocking flag. */
590 }
591 }
592 else /* No host callback in place, so drag and drop is not supported by the host. */
593 rc = VERR_NOT_SUPPORTED;
594
595 if (RT_FAILURE(rc))
596 rc = m_pManager->GetNextMsg(u32Function, cParms, paParms);
597
598 /* Some error occurred or no (new) messages available? */
599 if (RT_FAILURE(rc))
600 {
601 uint32_t fFlags = 0;
602 int rc2 = HGCMSvcGetU32(&paParms[2], &fFlags);
603 if ( RT_SUCCESS(rc2)
604 && fFlags) /* Blocking flag set? */
605 {
606 /* Defer client returning. */
607 rc = VINF_HGCM_ASYNC_EXECUTE;
608 }
609 else
610 rc = VERR_INVALID_PARAMETER;
611
612 LogFlowFunc(("Message queue is empty, returning %Rrc to guest\n", rc));
613 }
614 }
615 }
616 break;
617 }
618 case GUEST_DND_FN_CONNECT:
619 {
620 ASSERT_GUEST_BREAK(cParms >= 2);
621
622 VBOXDNDCBCONNECTDATA data;
623 RT_ZERO(data);
624 data.hdr.uMagic = CB_MAGIC_DND_CONNECT;
625
626 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.hdr.uContextID); \
627 ASSERT_GUEST_RC_BREAK(rc);
628 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uProtocolVersion);
629 ASSERT_GUEST_RC_BREAK(rc);
630 rc = HGCMSvcGetU32(&paParms[idxParm], &data.fFlags);
631 ASSERT_GUEST_RC_BREAK(rc);
632
633 unsigned uProtocolVer = 3; /* The protocol version we're going to use. */
634
635 /* Make sure we're only setting a protocl version we're supporting on the host. */
636 if (data.uProtocolVersion > uProtocolVer)
637 data.uProtocolVersion = uProtocolVer;
638
639 pClient->uProtocolVerDeprecated = data.uProtocolVersion;
640
641 /* Return the highest protocol version we're supporting. */
642 AssertBreak(idxParm);
643 ASSERT_GUEST_BREAK(idxParm);
644 paParms[idxParm - 1].u.uint32 = data.uProtocolVersion;
645
646 LogFlowFunc(("Client %RU32 is now using protocol v%RU32\n",
647 pClient->GetClientID(), pClient->uProtocolVerDeprecated));
648
649 DO_HOST_CALLBACK();
650 break;
651 }
652 case GUEST_DND_FN_REPORT_FEATURES:
653 {
654 rc = clientReportFeatures(pClient, cParms, paParms);
655 if (RT_SUCCESS(rc))
656 {
657 VBOXDNDCBREPORTFEATURESDATA data;
658 RT_ZERO(data);
659 data.hdr.uMagic = CB_MAGIC_DND_REPORT_FEATURES;
660
661 data.fGuestFeatures0 = pClient->fGuestFeatures0;
662 /* fGuestFeatures1 is not used yet. */
663
664 /* Don't touch initial rc. */
665 int rc2 = m_SvcCtx.pfnHostCallback(m_SvcCtx.pvHostData, u32Function, &data, sizeof(data));
666 AssertRC(rc2);
667 }
668 break;
669 }
670 case GUEST_DND_FN_QUERY_FEATURES:
671 {
672 rc = clientQueryFeatures(cParms, paParms);
673 break;
674 }
675 case GUEST_DND_FN_HG_ACK_OP:
676 {
677 ASSERT_GUEST_BREAK(cParms >= 2);
678
679 VBOXDNDCBHGACKOPDATA data;
680 RT_ZERO(data);
681 data.hdr.uMagic = CB_MAGIC_DND_HG_ACK_OP;
682
683 GET_CONTEXT_ID_PARM0();
684 rc = HGCMSvcGetU32(&paParms[idxParm], &data.uAction); /* Get drop action. */
685 ASSERT_GUEST_RC_BREAK(rc);
686
687 DO_HOST_CALLBACK();
688 break;
689 }
690 case GUEST_DND_FN_HG_REQ_DATA:
691 {
692 VBOXDNDCBHGREQDATADATA data;
693 RT_ZERO(data);
694 data.hdr.uMagic = CB_MAGIC_DND_HG_REQ_DATA;
695
696 switch (pClient->uProtocolVerDeprecated)
697 {
698 case 3:
699 {
700 ASSERT_GUEST_BREAK(cParms == 3);
701 GET_CONTEXT_ID_PARM0();
702 rc = HGCMSvcGetPv(&paParms[idxParm++], (void **)&data.pszFormat, &data.cbFormat);
703 ASSERT_GUEST_RC_BREAK(rc);
704 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm], data.cbFormat);
705 break;
706 }
707
708 case 2:
709 RT_FALL_THROUGH();
710 default:
711 {
712 ASSERT_GUEST_BREAK(cParms == 1);
713 rc = HGCMSvcGetPv(&paParms[idxParm], (void**)&data.pszFormat, &data.cbFormat);
714 ASSERT_GUEST_RC_BREAK(rc);
715 break;
716 }
717 }
718
719 DO_HOST_CALLBACK();
720 break;
721 }
722 case GUEST_DND_FN_HG_EVT_PROGRESS:
723 {
724 ASSERT_GUEST_BREAK(cParms >= 3);
725
726 VBOXDNDCBHGEVTPROGRESSDATA data;
727 RT_ZERO(data);
728 data.hdr.uMagic = CB_MAGIC_DND_HG_EVT_PROGRESS;
729
730 GET_CONTEXT_ID_PARM0();
731 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uStatus);
732 ASSERT_GUEST_RC_BREAK(rc);
733 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uPercentage);
734 ASSERT_GUEST_RC_BREAK(rc);
735 rc = HGCMSvcGetU32(&paParms[idxParm], &data.rc);
736 ASSERT_GUEST_RC_BREAK(rc);
737
738 DO_HOST_CALLBACK();
739 break;
740 }
741#ifdef VBOX_WITH_DRAG_AND_DROP_GH
742 case GUEST_DND_FN_GH_ACK_PENDING:
743 {
744 VBOXDNDCBGHACKPENDINGDATA data;
745 RT_ZERO(data);
746 data.hdr.uMagic = CB_MAGIC_DND_GH_ACK_PENDING;
747
748 switch (pClient->uProtocolVerDeprecated)
749 {
750 case 3:
751 {
752 ASSERT_GUEST_BREAK(cParms == 5);
753 GET_CONTEXT_ID_PARM0();
754 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uDefAction);
755 ASSERT_GUEST_RC_BREAK(rc);
756 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uAllActions);
757 ASSERT_GUEST_RC_BREAK(rc);
758 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.pszFormat, &data.cbFormat);
759 ASSERT_GUEST_RC_BREAK(rc);
760 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm], data.cbFormat);
761 break;
762 }
763
764 case 2:
765 default:
766 {
767 ASSERT_GUEST_BREAK(cParms == 3);
768 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uDefAction);
769 ASSERT_GUEST_RC_BREAK(rc);
770 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.uAllActions);
771 ASSERT_GUEST_RC_BREAK(rc);
772 rc = HGCMSvcGetPv(&paParms[idxParm], (void**)&data.pszFormat, &data.cbFormat);
773 ASSERT_GUEST_RC_BREAK(rc);
774 break;
775 }
776 }
777
778 DO_HOST_CALLBACK();
779 break;
780 }
781 /* New since protocol v3. */
782 case GUEST_DND_FN_GH_SND_DATA_HDR:
783 {
784 ASSERT_GUEST_BREAK(cParms == 12);
785
786 VBOXDNDCBSNDDATAHDRDATA data;
787 RT_ZERO(data);
788 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_DATA_HDR;
789
790 GET_CONTEXT_ID_PARM0();
791 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.data.uFlags);
792 ASSERT_GUEST_RC_BREAK(rc);
793 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.data.uScreenId);
794 ASSERT_GUEST_RC_BREAK(rc);
795 rc = HGCMSvcGetU64(&paParms[idxParm++], &data.data.cbTotal);
796 ASSERT_GUEST_RC_BREAK(rc);
797 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.data.cbMeta);
798 ASSERT_GUEST_RC_BREAK(rc);
799 ASSERT_GUEST_BREAK(data.data.cbMeta <= data.data.cbTotal);
800 rc = HGCMSvcGetPv(&paParms[idxParm++], &data.data.pvMetaFmt, &data.data.cbMetaFmt);
801 ASSERT_GUEST_RC_BREAK(rc);
802 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.data.cbMetaFmt);
803 rc = HGCMSvcGetU64(&paParms[idxParm++], &data.data.cObjects);
804 ASSERT_GUEST_RC_BREAK(rc);
805 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.data.enmCompression);
806 ASSERT_GUEST_RC_BREAK(rc);
807 rc = HGCMSvcGetU32(&paParms[idxParm++], (uint32_t *)&data.data.enmChecksumType);
808 ASSERT_GUEST_RC_BREAK(rc);
809 rc = HGCMSvcGetPv(&paParms[idxParm++], &data.data.pvChecksum, &data.data.cbChecksum);
810 ASSERT_GUEST_RC_BREAK(rc);
811 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm], data.data.cbChecksum);
812
813 DO_HOST_CALLBACK();
814 break;
815 }
816 case GUEST_DND_FN_GH_SND_DATA:
817 {
818 switch (pClient->uProtocolVerDeprecated)
819 {
820 case 3:
821 {
822 ASSERT_GUEST_BREAK(cParms == 5);
823
824 VBOXDNDCBSNDDATADATA data;
825 RT_ZERO(data);
826 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_DATA;
827
828 GET_CONTEXT_ID_PARM0();
829 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.data.u.v3.pvData, &data.data.u.v3.cbData);
830 ASSERT_GUEST_RC_BREAK(rc);
831 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.data.u.v3.cbData);
832 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.data.u.v3.pvChecksum, &data.data.u.v3.cbChecksum);
833 ASSERT_GUEST_RC_BREAK(rc);
834 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm], data.data.u.v3.cbChecksum);
835
836 DO_HOST_CALLBACK();
837 break;
838 }
839
840 case 2:
841 RT_FALL_THROUGH();
842 default:
843 {
844 ASSERT_GUEST_BREAK(cParms == 2);
845
846 VBOXDNDCBSNDDATADATA data;
847 RT_ZERO(data);
848 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_DATA;
849
850 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.data.u.v1.pvData, &data.data.u.v1.cbData);
851 ASSERT_GUEST_RC_BREAK(rc);
852 rc = HGCMSvcGetU32(&paParms[idxParm], &data.data.u.v1.cbTotalSize);
853 ASSERT_GUEST_RC_BREAK(rc);
854
855 DO_HOST_CALLBACK();
856 break;
857 }
858 }
859 break;
860 }
861 case GUEST_DND_FN_GH_SND_DIR:
862 {
863 ASSERT_GUEST_BREAK(cParms >= 3);
864
865 VBOXDNDCBSNDDIRDATA data;
866 RT_ZERO(data);
867 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_DIR;
868
869 GET_CONTEXT_ID_PARM0();
870 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.pszPath, &data.cbPath);
871 ASSERT_GUEST_RC_BREAK(rc);
872 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.cbPath);
873 rc = HGCMSvcGetU32(&paParms[idxParm], &data.fMode);
874 ASSERT_GUEST_RC_BREAK(rc);
875
876 DO_HOST_CALLBACK();
877 break;
878 }
879 /* New since protocol v2 (>= VBox 5.0). */
880 case GUEST_DND_FN_GH_SND_FILE_HDR:
881 {
882 ASSERT_GUEST_BREAK(cParms == 6);
883
884 VBOXDNDCBSNDFILEHDRDATA data;
885 RT_ZERO(data);
886 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_FILE_HDR;
887
888 GET_CONTEXT_ID_PARM0();
889 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.pszFilePath, &data.cbFilePath);
890 ASSERT_GUEST_RC_BREAK(rc);
891 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.cbFilePath);
892 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.fFlags);
893 ASSERT_GUEST_RC_BREAK(rc);
894 rc = HGCMSvcGetU32(&paParms[idxParm++], &data.fMode);
895 ASSERT_GUEST_RC_BREAK(rc);
896 rc = HGCMSvcGetU64(&paParms[idxParm], &data.cbSize);
897 ASSERT_GUEST_RC_BREAK(rc);
898
899 DO_HOST_CALLBACK();
900 break;
901 }
902 case GUEST_DND_FN_GH_SND_FILE_DATA:
903 {
904 switch (pClient->uProtocolVerDeprecated)
905 {
906 /* Protocol v3 adds (optional) checksums. */
907 case 3:
908 {
909 ASSERT_GUEST_BREAK(cParms == 5);
910
911 VBOXDNDCBSNDFILEDATADATA data;
912 RT_ZERO(data);
913 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_FILE_DATA;
914
915 GET_CONTEXT_ID_PARM0();
916 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.pvData, &data.cbData);
917 ASSERT_GUEST_RC_BREAK(rc);
918 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.cbData);
919 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.u.v3.pvChecksum, &data.u.v3.cbChecksum);
920 ASSERT_GUEST_RC_BREAK(rc);
921 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm], data.u.v3.cbChecksum);
922
923 DO_HOST_CALLBACK();
924 break;
925 }
926 /* Protocol v2 only sends the next data chunks to reduce traffic. */
927 case 2:
928 {
929 ASSERT_GUEST_BREAK(cParms == 3);
930
931 VBOXDNDCBSNDFILEDATADATA data;
932 RT_ZERO(data);
933 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_FILE_DATA;
934
935 GET_CONTEXT_ID_PARM0();
936 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.pvData, &data.cbData);
937 ASSERT_GUEST_RC_BREAK(rc);
938 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm], data.cbData);
939
940 DO_HOST_CALLBACK();
941 break;
942 }
943 /* Protocol v1 sends the file path and attributes for every file chunk (!). */
944 default:
945 {
946 ASSERT_GUEST_BREAK(cParms == 5);
947
948 VBOXDNDCBSNDFILEDATADATA data;
949 RT_ZERO(data);
950 data.hdr.uMagic = CB_MAGIC_DND_GH_SND_FILE_DATA;
951
952 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.u.v1.pszFilePath, &data.u.v1.cbFilePath);
953 ASSERT_GUEST_RC_BREAK(rc);
954 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.u.v1.cbFilePath);
955 rc = HGCMSvcGetPv(&paParms[idxParm++], (void**)&data.pvData, &data.cbData);
956 ASSERT_GUEST_RC_BREAK(rc);
957 VERIFY_BUFFER_SIZE_UINT32(paParms[idxParm++], data.cbData);
958 rc = HGCMSvcGetU32(&paParms[idxParm], &data.u.v1.fMode);
959 ASSERT_GUEST_RC_BREAK(rc);
960
961 DO_HOST_CALLBACK();
962 break;
963 }
964 }
965 break;
966 }
967 case GUEST_DND_FN_EVT_ERROR:
968 {
969 ASSERT_GUEST_BREAK(cParms >= 1);
970
971 VBOXDNDCBEVTERRORDATA data;
972 RT_ZERO(data);
973 data.hdr.uMagic = CB_MAGIC_DND_EVT_ERROR;
974
975 GET_CONTEXT_ID_PARM0();
976 rc = HGCMSvcGetU32(&paParms[idxParm], (uint32_t *)&data.rc);
977 ASSERT_GUEST_RC_BREAK(rc);
978
979 DO_HOST_CALLBACK();
980 break;
981 }
982#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
983
984 default:
985 {
986 LogFlowFunc(("u32Function=%s (%#x), cParms=%RU32\n", DnDHostMsgToStr(u32Function), u32Function, cParms));
987
988 /* All other messages are handled by the DnD manager. */
989 rc = m_pManager->GetNextMsg(u32Function, cParms, paParms);
990 if (rc == VERR_NO_DATA) /* Manager has no new messsages? Try asking the host. */
991 {
992 if (m_SvcCtx.pfnHostCallback)
993 {
994 VBOXDNDCBHGGETNEXTHOSTMSGDATA data;
995 RT_ZERO(data);
996
997 data.hdr.uMagic = VBOX_DND_CB_MAGIC_MAKE(0 /* uFn */, 0 /* uVer */);
998
999 data.uMsg = u32Function;
1000 data.cParms = cParms;
1001 data.paParms = paParms;
1002
1003 rc = m_SvcCtx.pfnHostCallback(m_SvcCtx.pvHostData, u32Function,
1004 &data, sizeof(data));
1005 if (RT_SUCCESS(rc))
1006 {
1007 cParms = data.cParms;
1008 paParms = data.paParms;
1009 }
1010 else
1011 {
1012 /*
1013 * In case the guest is too fast asking for the next message
1014 * and the host did not supply it yet, just defer the client's
1015 * return until a response from the host available.
1016 */
1017 LogFlowFunc(("No new messages from the host (yet), deferring request: %Rrc\n", rc));
1018 rc = VINF_HGCM_ASYNC_EXECUTE;
1019 }
1020 }
1021 else /* No host callback in place, so drag and drop is not supported by the host. */
1022 rc = VERR_NOT_SUPPORTED;
1023 }
1024 break;
1025 }
1026 }
1027 }
1028
1029#undef VERIFY_BUFFER_SIZE_UINT32
1030
1031 /*
1032 * If async execution is requested, we didn't notify the guest yet about
1033 * completion. The client is queued into the waiters list and will be
1034 * notified as soon as a new event is available.
1035 */
1036 if (rc == VINF_HGCM_ASYNC_EXECUTE)
1037 {
1038 LogFlowFunc(("Deferring client %RU32\n", idClient));
1039
1040 try
1041 {
1042 AssertPtr(pClient);
1043 pClient->SetDeferred(callHandle, u32Function, cParms, paParms);
1044 m_clientQueue.push_back(idClient);
1045 }
1046 catch (std::bad_alloc &)
1047 {
1048 rc = VERR_NO_MEMORY;
1049 /* Don't report to guest. */
1050 }
1051 }
1052 else if (pClient)
1053 {
1054 /* Complete the call on the guest side. */
1055 pClient->Complete(callHandle, rc);
1056 }
1057 else
1058 {
1059 AssertMsgFailed(("Guest call failed with %Rrc\n", rc));
1060 rc = VERR_NOT_IMPLEMENTED;
1061 }
1062
1063 LogFlowFunc(("Returning rc=%Rrc\n", rc));
1064}
1065
1066int DragAndDropService::hostCall(uint32_t u32Function,
1067 uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT
1068{
1069 LogFlowFunc(("u32Function=%s (%#x), cParms=%RU32, cClients=%zu, cQueue=%zu\n",
1070 DnDHostMsgToStr(u32Function), u32Function, cParms, m_clientMap.size(), m_clientQueue.size()));
1071
1072 int rc;
1073 bool fSendToGuest = false; /* Whether to send the message down to the guest side or not. */
1074
1075 switch (u32Function)
1076 {
1077 case HOST_DND_FN_SET_MODE:
1078 {
1079 if (cParms != 1)
1080 rc = VERR_INVALID_PARAMETER;
1081 else if (paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT)
1082 rc = VERR_INVALID_PARAMETER;
1083 else
1084 rc = modeSet(paParms[0].u.uint32);
1085 break;
1086 }
1087
1088 case HOST_DND_FN_CANCEL:
1089 {
1090 LogFlowFunc(("Cancelling all waiting clients ...\n"));
1091
1092 /* Reset the message queue as the host cancelled the whole operation. */
1093 m_pManager->Reset();
1094
1095 rc = m_pManager->AddMsg(u32Function, cParms, paParms, true /* fAppend */);
1096 if (RT_FAILURE(rc))
1097 {
1098 AssertMsgFailed(("Adding new message of type=%RU32 failed with rc=%Rrc\n", u32Function, rc));
1099 break;
1100 }
1101
1102 /*
1103 * Wake up all deferred clients and tell them to process
1104 * the cancelling message next.
1105 */
1106 DnDClientQueue::iterator itQueue = m_clientQueue.begin();
1107 while (itQueue != m_clientQueue.end())
1108 {
1109 DnDClientMap::iterator itClient = m_clientMap.find(*itQueue);
1110 Assert(itClient != m_clientMap.end());
1111
1112 DragAndDropClient *pClient = itClient->second;
1113 AssertPtr(pClient);
1114
1115 int rc2 = pClient->SetDeferredMsgInfo(HOST_DND_FN_CANCEL,
1116 /* Protocol v3+ also contains the context ID. */
1117 pClient->uProtocolVerDeprecated >= 3 ? 1 : 0);
1118 pClient->CompleteDeferred(rc2);
1119
1120 m_clientQueue.erase(itQueue);
1121 itQueue = m_clientQueue.begin();
1122 }
1123
1124 Assert(m_clientQueue.empty());
1125
1126 /* Tell the host that everything went well. */
1127 rc = VINF_SUCCESS;
1128 break;
1129 }
1130
1131 case HOST_DND_FN_HG_EVT_ENTER:
1132 {
1133 /* Reset the message queue as a new DnD operation just began. */
1134 m_pManager->Reset();
1135
1136 fSendToGuest = true;
1137 rc = VINF_SUCCESS;
1138 break;
1139 }
1140
1141 default:
1142 {
1143 fSendToGuest = true;
1144 rc = VINF_SUCCESS;
1145 break;
1146 }
1147 }
1148
1149 do /* goto avoidance break-loop. */
1150 {
1151 if (fSendToGuest)
1152 {
1153 if (modeGet() == VBOX_DRAG_AND_DROP_MODE_OFF)
1154 {
1155 /* Tell the host that a wrong drag'n drop mode is set. */
1156 rc = VERR_ACCESS_DENIED;
1157 break;
1158 }
1159
1160 if (m_clientMap.empty()) /* At least one client on the guest connected? */
1161 {
1162 /*
1163 * Tell the host that the guest does not support drag'n drop.
1164 * This might happen due to not installed Guest Additions or
1165 * not running VBoxTray/VBoxClient.
1166 */
1167 rc = VERR_NOT_SUPPORTED;
1168 break;
1169 }
1170
1171 rc = m_pManager->AddMsg(u32Function, cParms, paParms, true /* fAppend */);
1172 if (RT_FAILURE(rc))
1173 {
1174 AssertMsgFailed(("Adding new message of type=%RU32 failed with rc=%Rrc\n", u32Function, rc));
1175 break;
1176 }
1177
1178 /* Any clients in our queue ready for processing the next command? */
1179 if (m_clientQueue.empty())
1180 {
1181 LogFlowFunc(("All clients (%zu) busy -- delaying execution\n", m_clientMap.size()));
1182 break;
1183 }
1184
1185 uint32_t uClientNext = m_clientQueue.front();
1186 DnDClientMap::iterator itClientNext = m_clientMap.find(uClientNext);
1187 Assert(itClientNext != m_clientMap.end());
1188
1189 DragAndDropClient *pClient = itClientNext->second;
1190 AssertPtr(pClient);
1191
1192 /*
1193 * Check if this was a request for getting the next host
1194 * message. If so, return the message ID and the parameter
1195 * count. The message itself has to be queued.
1196 */
1197 uint32_t uMsgClient = pClient->GetMsgType();
1198
1199 uint32_t uMsgNext = 0;
1200 uint32_t cParmsNext = 0;
1201 int rcNext = m_pManager->GetNextMsgInfo(&uMsgNext, &cParmsNext);
1202
1203 LogFlowFunc(("uMsgClient=%s (%#x), uMsgNext=%s (%#x), cParmsNext=%RU32, rcNext=%Rrc\n",
1204 DnDGuestMsgToStr(uMsgClient), uMsgClient, DnDHostMsgToStr(uMsgNext), uMsgNext, cParmsNext, rcNext));
1205
1206 if (RT_SUCCESS(rcNext))
1207 {
1208 if (uMsgClient == GUEST_DND_FN_GET_NEXT_HOST_MSG)
1209 {
1210 rc = pClient->SetDeferredMsgInfo(uMsgNext, cParmsNext);
1211
1212 /* Note: Report the current rc back to the guest. */
1213 pClient->CompleteDeferred(rc);
1214 }
1215 /*
1216 * Does the message the client is waiting for match the message
1217 * next in the queue? Process it right away then.
1218 */
1219 else if (uMsgClient == uMsgNext)
1220 {
1221 rc = m_pManager->GetNextMsg(u32Function, cParms, paParms);
1222
1223 /* Note: Report the current rc back to the guest. */
1224 pClient->CompleteDeferred(rc);
1225 }
1226 else /* Should not happen; cancel the operation on the guest. */
1227 {
1228 LogFunc(("Client ID=%RU32 in wrong state with uMsg=%RU32 (next message in queue: %RU32), cancelling\n",
1229 pClient->GetClientID(), uMsgClient, uMsgNext));
1230
1231 pClient->CompleteDeferred(VERR_CANCELLED);
1232 }
1233
1234 m_clientQueue.pop_front();
1235 }
1236
1237 } /* fSendToGuest */
1238
1239 } while (0); /* To use breaks. */
1240
1241 LogFlowFuncLeaveRC(rc);
1242 return rc;
1243}
1244
1245DECLCALLBACK(int) DragAndDropService::progressCallback(uint32_t uStatus, uint32_t uPercentage, int rc, void *pvUser)
1246{
1247 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
1248
1249 DragAndDropService *pSelf = static_cast<DragAndDropService *>(pvUser);
1250 AssertPtr(pSelf);
1251
1252 if (pSelf->m_SvcCtx.pfnHostCallback)
1253 {
1254 LogFlowFunc(("GUEST_DND_FN_HG_EVT_PROGRESS: uStatus=%RU32, uPercentage=%RU32, rc=%Rrc\n",
1255 uStatus, uPercentage, rc));
1256
1257 VBOXDNDCBHGEVTPROGRESSDATA data;
1258 data.hdr.uMagic = CB_MAGIC_DND_HG_EVT_PROGRESS;
1259 data.uPercentage = RT_MIN(uPercentage, 100);
1260 data.uStatus = uStatus;
1261 data.rc = rc; /** @todo uin32_t vs. int. */
1262
1263 return pSelf->m_SvcCtx.pfnHostCallback(pSelf->m_SvcCtx.pvHostData,
1264 GUEST_DND_FN_HG_EVT_PROGRESS,
1265 &data, sizeof(data));
1266 }
1267
1268 return VINF_SUCCESS;
1269}
1270
1271/**
1272 * @copydoc FNVBOXHGCMSVCLOAD
1273 */
1274extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable)
1275{
1276 return DragAndDropService::svcLoad(pTable);
1277}
1278
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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