VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp@ 54438

Last change on this file since 54438 was 51799, checked in by vboxsync, 10 years ago

Main/GuestDnD: warings

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.2 KB
Line 
1/* $Id: GuestDnDSourceImpl.cpp 51799 2014-07-02 08:23:58Z vboxsync $ */
2/** @file
3 * VBox Console COM Class implementation - Guest drag'n drop source.
4 */
5
6/*
7 * Copyright (C) 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/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include "GuestImpl.h"
23#include "GuestDnDSourceImpl.h"
24#include "GuestDnDPrivate.h"
25
26#include "Global.h"
27#include "AutoCaller.h"
28
29#include <iprt/cpp/utils.h> /* For unconst(). */
30
31#include <VBox/com/array.h>
32#include <VBox/GuestHost/DragAndDrop.h>
33#include <VBox/HostServices/DragAndDropSvc.h>
34
35#ifdef LOG_GROUP
36 #undef LOG_GROUP
37#endif
38#define LOG_GROUP LOG_GROUP_GUEST_DND
39#include <VBox/log.h>
40
41
42// constructor / destructor
43/////////////////////////////////////////////////////////////////////////////
44
45DEFINE_EMPTY_CTOR_DTOR(GuestDnDSource)
46
47HRESULT GuestDnDSource::FinalConstruct(void)
48{
49 LogFlowThisFunc(("\n"));
50 return BaseFinalConstruct();
51}
52
53void GuestDnDSource::FinalRelease(void)
54{
55 LogFlowThisFuncEnter();
56 uninit();
57 BaseFinalRelease();
58 LogFlowThisFuncLeave();
59}
60
61// public initializer/uninitializer for internal purposes only
62/////////////////////////////////////////////////////////////////////////////
63
64int GuestDnDSource::init(const ComObjPtr<Guest>& pGuest)
65{
66 LogFlowThisFuncEnter();
67
68 /* Enclose the state transition NotReady->InInit->Ready. */
69 AutoInitSpan autoInitSpan(this);
70 AssertReturn(autoInitSpan.isOk(), E_FAIL);
71
72 unconst(m_pGuest) = pGuest;
73
74 /* Confirm a successful initialization when it's the case. */
75 autoInitSpan.setSucceeded();
76
77 return VINF_SUCCESS;
78}
79
80/**
81 * Uninitializes the instance.
82 * Called from FinalRelease().
83 */
84void GuestDnDSource::uninit(void)
85{
86 LogFlowThisFunc(("\n"));
87
88 /* Enclose the state transition Ready->InUninit->NotReady. */
89 AutoUninitSpan autoUninitSpan(this);
90 if (autoUninitSpan.uninitDone())
91 return;
92}
93
94// implementation of wrapped IDnDBase methods.
95/////////////////////////////////////////////////////////////////////////////
96
97HRESULT GuestDnDSource::isFormatSupported(const com::Utf8Str &aFormat,
98 BOOL *aSupported)
99{
100#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
101 ReturnComNotImplemented();
102#else /* VBOX_WITH_DRAG_AND_DROP */
103
104 AutoCaller autoCaller(this);
105 if (FAILED(autoCaller.rc())) return autoCaller.rc();
106
107 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
108
109 return GuestDnDBase::isFormatSupported(aFormat, aSupported);
110#endif /* VBOX_WITH_DRAG_AND_DROP */
111}
112
113HRESULT GuestDnDSource::getFormats(std::vector<com::Utf8Str> &aFormats)
114{
115#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
116 ReturnComNotImplemented();
117#else /* VBOX_WITH_DRAG_AND_DROP */
118
119 AutoCaller autoCaller(this);
120 if (FAILED(autoCaller.rc())) return autoCaller.rc();
121
122 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
123
124 return GuestDnDBase::getFormats(aFormats);
125#endif /* VBOX_WITH_DRAG_AND_DROP */
126}
127
128HRESULT GuestDnDSource::addFormats(const std::vector<com::Utf8Str> &aFormats)
129{
130#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
131 ReturnComNotImplemented();
132#else /* VBOX_WITH_DRAG_AND_DROP */
133
134 AutoCaller autoCaller(this);
135 if (FAILED(autoCaller.rc())) return autoCaller.rc();
136
137 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
138
139 return GuestDnDBase::addFormats(aFormats);
140#endif /* VBOX_WITH_DRAG_AND_DROP */
141}
142
143HRESULT GuestDnDSource::removeFormats(const std::vector<com::Utf8Str> &aFormats)
144{
145#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
146 ReturnComNotImplemented();
147#else /* VBOX_WITH_DRAG_AND_DROP */
148
149 AutoCaller autoCaller(this);
150 if (FAILED(autoCaller.rc())) return autoCaller.rc();
151
152 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
153
154 return GuestDnDBase::removeFormats(aFormats);
155#endif /* VBOX_WITH_DRAG_AND_DROP */
156}
157
158// implementation of wrapped IDnDTarget methods.
159/////////////////////////////////////////////////////////////////////////////
160
161HRESULT GuestDnDSource::dragIsPending(ULONG uScreenId,
162 std::vector<com::Utf8Str> &aFormats,
163 std::vector<DnDAction_T> &aAllowedActions,
164 DnDAction_T *aDefaultAction)
165{
166#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
167 ReturnComNotImplemented();
168#else /* VBOX_WITH_DRAG_AND_DROP */
169
170 AutoCaller autoCaller(this);
171 if (FAILED(autoCaller.rc())) return autoCaller.rc();
172
173 /* Default is ignoring the action. */
174 DnDAction_T defaultAction = DnDAction_Ignore;
175
176 HRESULT hr = S_OK;
177
178 VBOXHGCMSVCPARM paParms[1];
179 int i = 0;
180 paParms[i++].setUInt32(uScreenId);
181
182 int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_GH_REQ_PENDING,
183 i, paParms);
184 if (RT_SUCCESS(rc))
185 {
186 bool fFetchResult = true;
187 GuestDnDResponse *pResp = GuestDnDInst()->response();
188 if (pResp)
189 {
190 if (pResp->waitForGuestResponse() == VERR_TIMEOUT)
191 fFetchResult = false;
192
193 if (isDnDIgnoreAction(pResp->defAction()))
194 fFetchResult = false;
195
196 /* Fetch the default action to use. */
197 if (fFetchResult)
198 {
199 defaultAction = GuestDnD::toMainAction(pResp->defAction());
200
201 GuestDnD::toFormatVector(m_strFormats, pResp->format(), aFormats);
202 GuestDnD::toMainActions(pResp->allActions(), aAllowedActions);
203 }
204 }
205
206 if (aDefaultAction)
207 *aDefaultAction = defaultAction;
208 }
209
210 if (RT_FAILURE(rc))
211 hr = setError(VBOX_E_IPRT_ERROR,
212 tr("Unable to retrieve pending status (%Rrc)\n"), rc);
213
214 LogFlowFunc(("hr=%Rhrc, defaultAction=0x%x\n", hr, defaultAction));
215 return hr;
216#endif /* VBOX_WITH_DRAG_AND_DROP */
217}
218
219HRESULT GuestDnDSource::drop(const com::Utf8Str &aFormat,
220 DnDAction_T aAction, ComPtr<IProgress> &aProgress)
221{
222#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
223 ReturnComNotImplemented();
224#else /* VBOX_WITH_DRAG_AND_DROP */
225
226 /* Input validation. */
227 if (RT_UNLIKELY((aFormat.c_str()) == NULL || *(aFormat.c_str()) == '\0'))
228 return setError(E_INVALIDARG, tr("No drop format specified"));
229
230 AutoCaller autoCaller(this);
231 if (FAILED(autoCaller.rc())) return autoCaller.rc();
232
233 uint32_t uAction = GuestDnD::toHGCMAction(aAction);
234 /* If there is no usable action, ignore this request. */
235 if (isDnDIgnoreAction(uAction))
236 return S_OK;
237
238 HRESULT hr = S_OK;
239
240 const char *pcszFormat = aFormat.c_str();
241 bool fNeedsDropDir = DnDMIMENeedsDropDir(pcszFormat, strlen(pcszFormat));
242 LogFlowFunc(("strFormat=%s, uAction=0x%x, fNeedsDropDir=%RTbool\n",
243 pcszFormat, uAction, fNeedsDropDir));
244
245 GuestDnDResponse *pResp = GuestDnDInst()->response();
246 if (pResp)
247 {
248 /* Reset any old data. */
249 pResp->reset();
250 pResp->resetProgress(m_pGuest);
251
252 /* Set the format we are going to retrieve to have it around
253 * when retrieving the data later. */
254 pResp->setFormat(aFormat);
255
256 if (fNeedsDropDir)
257 {
258 char szDropDir[RTPATH_MAX];
259 int rc = DnDDirCreateDroppedFiles(szDropDir, sizeof(szDropDir));
260 LogFlowFunc(("rc=%Rrc, szDropDir=%s\n", rc, szDropDir));
261 if (RT_FAILURE(rc))
262 return setError(VBOX_E_IPRT_ERROR,
263 tr("Unable to create the temporary drag'n drop directory \"%s\" (%Rrc)\n"),
264 szDropDir, rc);
265
266 pResp->setDropDir(szDropDir);
267 }
268
269 VBOXHGCMSVCPARM paParms[4];
270 int i = 0;
271 paParms[i++].setPointer((void*)aFormat.c_str(), (uint32_t)aFormat.length() + 1);
272 paParms[i++].setUInt32((uint32_t)aFormat.length() + 1);
273 paParms[i++].setUInt32(uAction);
274
275 int rc = GuestDnDInst()->hostCall(DragAndDropSvc::HOST_DND_GH_EVT_DROPPED,
276 i, paParms);
277 if (RT_SUCCESS(rc))
278 {
279 /* Query the progress object to the caller. */
280 pResp->queryProgressTo(aProgress.asOutParam());
281 }
282 else
283 hr = setError(VBOX_E_IPRT_ERROR,
284 tr("Error signalling to drop data (%Rrc)\n"), rc);
285 }
286
287 LogFlowFunc(("Returning hr=%Rhrc\n", hr));
288 return hr;
289#endif /* VBOX_WITH_DRAG_AND_DROP */
290}
291
292HRESULT GuestDnDSource::receiveData(std::vector<BYTE> &aData)
293{
294#if !defined(VBOX_WITH_DRAG_AND_DROP) || !defined(VBOX_WITH_DRAG_AND_DROP_GH)
295 ReturnComNotImplemented();
296#else /* VBOX_WITH_DRAG_AND_DROP */
297
298 /* Input validation. */
299
300 AutoCaller autoCaller(this);
301 if (FAILED(autoCaller.rc())) return autoCaller.rc();
302
303 HRESULT hr = S_OK;
304
305 GuestDnDResponse *pResp = GuestDnDInst()->response();
306 if (pResp)
307 {
308 size_t cbData = pResp->size();
309 if (cbData)
310 {
311 const void *pvData = pResp->data();
312 AssertPtr(pvData);
313
314 Utf8Str strFormat = pResp->format();
315 LogFlowFunc(("strFormat=%s, cbData=%zu, pvData=0x%p\n",
316 strFormat.c_str(), cbData, pvData));
317
318 try
319 {
320 if (DnDMIMEHasFileURLs(strFormat.c_str(), strFormat.length()))
321 {
322 LogFlowFunc(("strDropDir=%s\n", pResp->dropDir().c_str()));
323
324 DnDURIList lstURI;
325 int rc2 = lstURI.RootFromURIData(pvData, cbData, 0 /* fFlags */);
326 if (RT_SUCCESS(rc2))
327 {
328 Utf8Str strURIs = lstURI.RootToString(pResp->dropDir());
329 size_t cbURIs = strURIs.length();
330
331 LogFlowFunc(("Found %zu root URIs (%zu bytes)\n",
332 lstURI.RootCount(), cbURIs));
333
334 aData.resize(cbURIs + 1 /* Include termination */);
335 memcpy(&aData.front(), strURIs.c_str(), cbURIs);
336 }
337 else
338 hr = VBOX_E_IPRT_ERROR;
339 }
340 else
341 {
342 /* Copy the data into a safe array of bytes. */
343 aData.resize(cbData);
344 memcpy(&aData.front(), pvData, cbData);
345 }
346 }
347 catch (std::bad_alloc &)
348 {
349 hr = E_OUTOFMEMORY;
350 }
351 }
352
353 /* Delete the data. */
354 pResp->reset();
355 }
356 else
357 hr = VBOX_E_INVALID_OBJECT_STATE;
358
359 LogFlowFunc(("Returning hr=%Rhrc\n", hr));
360 return hr;
361#endif /* VBOX_WITH_DRAG_AND_DROP */
362}
363
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