VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/GuestImpl.cpp@ 39890

Last change on this file since 39890 was 39890, checked in by vboxsync, 13 years ago

VMMDev,IGuest,IAdditionsFacility,VBoxGuest,iprt/types.h: VMMDev must track the guest facility reports so they can be saved and restored correctly. Also fixed a reset bug related to guestInfo2. Restrict who can report the status of which facilities. Recalc the runlevel based on which facilities are active. Restrict the number of facilities main tracks.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.7 KB
Line 
1/* $Id: GuestImpl.cpp 39890 2012-01-26 19:42:19Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation: Guest
4 */
5
6/*
7 * Copyright (C) 2006-2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "GuestImpl.h"
19
20#include "Global.h"
21#include "ConsoleImpl.h"
22#include "ProgressImpl.h"
23#ifdef VBOX_WITH_DRAG_AND_DROP
24# include "GuestDnDImpl.h"
25#endif
26#include "VMMDev.h"
27
28#include "AutoCaller.h"
29#include "Logging.h"
30
31#include <VBox/VMMDev.h>
32#ifdef VBOX_WITH_GUEST_CONTROL
33# include <VBox/com/array.h>
34# include <VBox/com/ErrorInfo.h>
35#endif
36#include <iprt/cpp/utils.h>
37#include <VBox/vmm/pgm.h>
38#include <VBox/version.h>
39
40// defines
41/////////////////////////////////////////////////////////////////////////////
42
43// constructor / destructor
44/////////////////////////////////////////////////////////////////////////////
45
46DEFINE_EMPTY_CTOR_DTOR (Guest)
47
48HRESULT Guest::FinalConstruct()
49{
50 return BaseFinalConstruct();
51}
52
53void Guest::FinalRelease()
54{
55 uninit ();
56 BaseFinalRelease();
57}
58
59// public methods only for internal purposes
60/////////////////////////////////////////////////////////////////////////////
61
62/**
63 * Initializes the guest object.
64 */
65HRESULT Guest::init(Console *aParent)
66{
67 LogFlowThisFunc(("aParent=%p\n", aParent));
68
69 ComAssertRet(aParent, E_INVALIDARG);
70
71 /* Enclose the state transition NotReady->InInit->Ready */
72 AutoInitSpan autoInitSpan(this);
73 AssertReturn(autoInitSpan.isOk(), E_FAIL);
74
75 unconst(mParent) = aParent;
76
77 /* Confirm a successful initialization when it's the case */
78 autoInitSpan.setSucceeded();
79
80 ULONG aMemoryBalloonSize;
81 HRESULT ret = mParent->machine()->COMGETTER(MemoryBalloonSize)(&aMemoryBalloonSize);
82 if (ret == S_OK)
83 mMemoryBalloonSize = aMemoryBalloonSize;
84 else
85 mMemoryBalloonSize = 0; /* Default is no ballooning */
86
87 BOOL fPageFusionEnabled;
88 ret = mParent->machine()->COMGETTER(PageFusionEnabled)(&fPageFusionEnabled);
89 if (ret == S_OK)
90 mfPageFusionEnabled = fPageFusionEnabled;
91 else
92 mfPageFusionEnabled = false; /* Default is no page fusion*/
93
94 mStatUpdateInterval = 0; /* Default is not to report guest statistics at all */
95
96 /* Clear statistics. */
97 for (unsigned i = 0 ; i < GUESTSTATTYPE_MAX; i++)
98 mCurrentGuestStat[i] = 0;
99
100#ifdef VBOX_WITH_GUEST_CONTROL
101 /* Init the context ID counter at 1000. */
102 mNextContextID = 1000;
103#endif
104
105#ifdef VBOX_WITH_DRAG_AND_DROP
106 m_pGuestDnD = new GuestDnD(this);
107#endif
108
109 return S_OK;
110}
111
112/**
113 * Uninitializes the instance and sets the ready flag to FALSE.
114 * Called either from FinalRelease() or by the parent when it gets destroyed.
115 */
116void Guest::uninit()
117{
118 LogFlowThisFunc(("\n"));
119
120#ifdef VBOX_WITH_GUEST_CONTROL
121 /* r=poetzsch: Not sure if this is really right. Please note that
122 * IGuest::uninit is called twice (which I also consider a bug). So the
123 * test for uninitDone should be always first! */
124 /* Scope write lock as much as possible. */
125 {
126 /*
127 * Cleanup must be done *before* AutoUninitSpan to cancel all
128 * all outstanding waits in API functions (which hold AutoCaller
129 * ref counts).
130 */
131 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
132
133 /* Notify left over callbacks that we are about to shutdown ... */
134 CallbackMapIter it;
135 for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++)
136 {
137 int rc2 = callbackNotifyEx(it->first, VERR_CANCELLED,
138 Guest::tr("VM is shutting down, canceling uncompleted guest requests ..."));
139 AssertRC(rc2);
140 }
141
142 /* Destroy left over callback data. */
143 for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++)
144 callbackDestroy(it->first);
145
146 /* Clear process map. */
147 mGuestProcessMap.clear();
148 }
149#endif
150
151 /* Enclose the state transition Ready->InUninit->NotReady */
152 AutoUninitSpan autoUninitSpan(this);
153 if (autoUninitSpan.uninitDone())
154 return;
155
156#ifdef VBOX_WITH_DRAG_AND_DROP
157 delete m_pGuestDnD;
158 m_pGuestDnD = NULL;
159#endif
160
161 unconst(mParent) = NULL;
162}
163
164// IGuest properties
165/////////////////////////////////////////////////////////////////////////////
166
167STDMETHODIMP Guest::COMGETTER(OSTypeId)(BSTR *a_pbstrOSTypeId)
168{
169 CheckComArgOutPointerValid(a_pbstrOSTypeId);
170
171 AutoCaller autoCaller(this);
172 HRESULT hrc = autoCaller.rc();
173 if (SUCCEEDED(hrc))
174 {
175 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
176 if (!mData.mInterfaceVersion.isEmpty())
177 mData.mOSTypeId.cloneTo(a_pbstrOSTypeId);
178 else
179 {
180 /* Redirect the call to IMachine if no additions are installed. */
181 ComPtr<IMachine> ptrMachine(mParent->machine());
182 alock.release();
183 hrc = ptrMachine->COMGETTER(OSTypeId)(a_pbstrOSTypeId);
184 }
185 }
186 return hrc;
187}
188
189STDMETHODIMP Guest::COMGETTER(AdditionsRunLevel) (AdditionsRunLevelType_T *aRunLevel)
190{
191 AutoCaller autoCaller(this);
192 if (FAILED(autoCaller.rc())) return autoCaller.rc();
193
194 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
195
196 *aRunLevel = mData.mAdditionsRunLevel;
197
198 return S_OK;
199}
200
201STDMETHODIMP Guest::COMGETTER(AdditionsVersion)(BSTR *a_pbstrAdditionsVersion)
202{
203 CheckComArgOutPointerValid(a_pbstrAdditionsVersion);
204
205 AutoCaller autoCaller(this);
206 HRESULT hrc = autoCaller.rc();
207 if (SUCCEEDED(hrc))
208 {
209 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
210
211 /*
212 * Return the ReportGuestInfo2 version info if available.
213 */
214 if ( !mData.mAdditionsVersionNew.isEmpty()
215 || mData.mAdditionsRunLevel <= AdditionsRunLevelType_None)
216 mData.mAdditionsVersionNew.cloneTo(a_pbstrAdditionsVersion);
217 else
218 {
219 /*
220 * If we're running older guest additions (< 3.2.0) try get it from
221 * the guest properties.
222 */
223 ComPtr<IMachine> ptrMachine = mParent->machine();
224 alock.release(); /* No need to hold this during the IPC fun. */
225
226 Bstr bstr;
227 hrc = ptrMachine->GetGuestPropertyValue(Bstr("/VirtualBox/GuestAdd/Version").raw(), bstr.asOutParam());
228 if (SUCCEEDED(hrc))
229 bstr.detachTo(a_pbstrAdditionsVersion);
230 else
231 {
232 /* Returning 1.4 is better than nothing. */
233 alock.acquire();
234 mData.mInterfaceVersion.cloneTo(a_pbstrAdditionsVersion);
235 hrc = S_OK;
236 }
237 }
238 }
239 return hrc;
240}
241
242STDMETHODIMP Guest::COMGETTER(AdditionsRevision)(ULONG *a_puAdditionsRevision)
243{
244 CheckComArgOutPointerValid(a_puAdditionsRevision);
245
246 AutoCaller autoCaller(this);
247 HRESULT hrc = autoCaller.rc();
248 if (SUCCEEDED(hrc))
249 {
250 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
251
252 /*
253 * Return the ReportGuestInfo2 version info if available.
254 */
255 if ( !mData.mAdditionsVersionNew.isEmpty()
256 || mData.mAdditionsRunLevel <= AdditionsRunLevelType_None)
257 *a_puAdditionsRevision = mData.mAdditionsRevision;
258 else
259 {
260 /*
261 * If we're running older guest additions (< 3.2.0) try get it from
262 * the guest properties.
263 */
264 ComPtr<IMachine> ptrMachine = mParent->machine();
265 alock.release(); /* No need to hold this during the IPC fun. */
266
267 Bstr bstr;
268 hrc = ptrMachine->GetGuestPropertyValue(Bstr("/VirtualBox/GuestAdd/Revision").raw(), bstr.asOutParam());
269 if (SUCCEEDED(hrc))
270 {
271 Utf8Str str(bstr);
272 uint32_t uRevision;
273 int vrc = RTStrToUInt32Full(str.c_str(), 0, &uRevision);
274 if (vrc == VINF_SUCCESS)
275 *a_puAdditionsRevision = uRevision;
276 else
277 hrc = VBOX_E_IPRT_ERROR;
278 }
279 if (FAILED(hrc))
280 {
281 /* Return 0 if we don't know. */
282 *a_puAdditionsRevision = 0;
283 hrc = 0;
284 }
285 }
286 }
287 return hrc;
288}
289
290STDMETHODIMP Guest::COMGETTER(Facilities)(ComSafeArrayOut(IAdditionsFacility*, aFacilities))
291{
292 CheckComArgOutSafeArrayPointerValid(aFacilities);
293
294 AutoCaller autoCaller(this);
295 if (FAILED(autoCaller.rc())) return autoCaller.rc();
296
297 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
298
299 SafeIfaceArray<IAdditionsFacility> fac(mData.mFacilityMap);
300 fac.detachTo(ComSafeArrayOutArg(aFacilities));
301
302 return S_OK;
303}
304
305BOOL Guest::isPageFusionEnabled()
306{
307 AutoCaller autoCaller(this);
308 if (FAILED(autoCaller.rc())) return false;
309
310 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
311
312 return mfPageFusionEnabled;
313}
314
315STDMETHODIMP Guest::COMGETTER(MemoryBalloonSize)(ULONG *aMemoryBalloonSize)
316{
317 CheckComArgOutPointerValid(aMemoryBalloonSize);
318
319 AutoCaller autoCaller(this);
320 if (FAILED(autoCaller.rc())) return autoCaller.rc();
321
322 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
323
324 *aMemoryBalloonSize = mMemoryBalloonSize;
325
326 return S_OK;
327}
328
329STDMETHODIMP Guest::COMSETTER(MemoryBalloonSize)(ULONG aMemoryBalloonSize)
330{
331 AutoCaller autoCaller(this);
332 if (FAILED(autoCaller.rc())) return autoCaller.rc();
333
334 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
335
336 /* We must be 100% sure that IMachine::COMSETTER(MemoryBalloonSize)
337 * does not call us back in any way! */
338 HRESULT ret = mParent->machine()->COMSETTER(MemoryBalloonSize)(aMemoryBalloonSize);
339 if (ret == S_OK)
340 {
341 mMemoryBalloonSize = aMemoryBalloonSize;
342 /* forward the information to the VMM device */
343 VMMDev *pVMMDev = mParent->getVMMDev();
344 /* MUST release all locks before calling VMM device as its critsect
345 * has higher lock order than anything in Main. */
346 alock.release();
347 if (pVMMDev)
348 {
349 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
350 if (pVMMDevPort)
351 pVMMDevPort->pfnSetMemoryBalloon(pVMMDevPort, aMemoryBalloonSize);
352 }
353 }
354
355 return ret;
356}
357
358STDMETHODIMP Guest::COMGETTER(StatisticsUpdateInterval)(ULONG *aUpdateInterval)
359{
360 CheckComArgOutPointerValid(aUpdateInterval);
361
362 AutoCaller autoCaller(this);
363 if (FAILED(autoCaller.rc())) return autoCaller.rc();
364
365 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
366
367 *aUpdateInterval = mStatUpdateInterval;
368 return S_OK;
369}
370
371STDMETHODIMP Guest::COMSETTER(StatisticsUpdateInterval)(ULONG aUpdateInterval)
372{
373 AutoCaller autoCaller(this);
374 if (FAILED(autoCaller.rc())) return autoCaller.rc();
375
376 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
377
378 mStatUpdateInterval = aUpdateInterval;
379 /* forward the information to the VMM device */
380 VMMDev *pVMMDev = mParent->getVMMDev();
381 /* MUST release all locks before calling VMM device as its critsect
382 * has higher lock order than anything in Main. */
383 alock.release();
384 if (pVMMDev)
385 {
386 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
387 if (pVMMDevPort)
388 pVMMDevPort->pfnSetStatisticsInterval(pVMMDevPort, aUpdateInterval);
389 }
390
391 return S_OK;
392}
393
394STDMETHODIMP Guest::InternalGetStatistics(ULONG *aCpuUser, ULONG *aCpuKernel, ULONG *aCpuIdle,
395 ULONG *aMemTotal, ULONG *aMemFree, ULONG *aMemBalloon, ULONG *aMemShared,
396 ULONG *aMemCache, ULONG *aPageTotal,
397 ULONG *aMemAllocTotal, ULONG *aMemFreeTotal, ULONG *aMemBalloonTotal, ULONG *aMemSharedTotal)
398{
399 CheckComArgOutPointerValid(aCpuUser);
400 CheckComArgOutPointerValid(aCpuKernel);
401 CheckComArgOutPointerValid(aCpuIdle);
402 CheckComArgOutPointerValid(aMemTotal);
403 CheckComArgOutPointerValid(aMemFree);
404 CheckComArgOutPointerValid(aMemBalloon);
405 CheckComArgOutPointerValid(aMemShared);
406 CheckComArgOutPointerValid(aMemCache);
407 CheckComArgOutPointerValid(aPageTotal);
408 CheckComArgOutPointerValid(aMemAllocTotal);
409 CheckComArgOutPointerValid(aMemFreeTotal);
410 CheckComArgOutPointerValid(aMemBalloonTotal);
411 CheckComArgOutPointerValid(aMemSharedTotal);
412
413 AutoCaller autoCaller(this);
414 if (FAILED(autoCaller.rc())) return autoCaller.rc();
415
416 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
417
418 *aCpuUser = mCurrentGuestStat[GUESTSTATTYPE_CPUUSER];
419 *aCpuKernel = mCurrentGuestStat[GUESTSTATTYPE_CPUKERNEL];
420 *aCpuIdle = mCurrentGuestStat[GUESTSTATTYPE_CPUIDLE];
421 *aMemTotal = mCurrentGuestStat[GUESTSTATTYPE_MEMTOTAL] * (_4K/_1K); /* page (4K) -> 1KB units */
422 *aMemFree = mCurrentGuestStat[GUESTSTATTYPE_MEMFREE] * (_4K/_1K); /* page (4K) -> 1KB units */
423 *aMemBalloon = mCurrentGuestStat[GUESTSTATTYPE_MEMBALLOON] * (_4K/_1K); /* page (4K) -> 1KB units */
424 *aMemCache = mCurrentGuestStat[GUESTSTATTYPE_MEMCACHE] * (_4K/_1K); /* page (4K) -> 1KB units */
425 *aPageTotal = mCurrentGuestStat[GUESTSTATTYPE_PAGETOTAL] * (_4K/_1K); /* page (4K) -> 1KB units */
426
427 /* MUST release all locks before calling any PGM statistics queries,
428 * as they are executed by EMT and that might deadlock us by VMM device
429 * activity which waits for the Guest object lock. */
430 alock.release();
431 Console::SafeVMPtr pVM (mParent);
432 if (pVM.isOk())
433 {
434 uint64_t uFreeTotal, uAllocTotal, uBalloonedTotal, uSharedTotal;
435 *aMemFreeTotal = 0;
436 int rc = PGMR3QueryGlobalMemoryStats(pVM.raw(), &uAllocTotal, &uFreeTotal, &uBalloonedTotal, &uSharedTotal);
437 AssertRC(rc);
438 if (rc == VINF_SUCCESS)
439 {
440 *aMemAllocTotal = (ULONG)(uAllocTotal / _1K); /* bytes -> KB */
441 *aMemFreeTotal = (ULONG)(uFreeTotal / _1K);
442 *aMemBalloonTotal = (ULONG)(uBalloonedTotal / _1K);
443 *aMemSharedTotal = (ULONG)(uSharedTotal / _1K);
444 }
445 else
446 return E_FAIL;
447
448 /* Query the missing per-VM memory statistics. */
449 *aMemShared = 0;
450 uint64_t uTotalMem, uPrivateMem, uSharedMem, uZeroMem;
451 rc = PGMR3QueryMemoryStats(pVM.raw(), &uTotalMem, &uPrivateMem, &uSharedMem, &uZeroMem);
452 if (rc == VINF_SUCCESS)
453 {
454 *aMemShared = (ULONG)(uSharedMem / _1K);
455 }
456 else
457 return E_FAIL;
458 }
459 else
460 {
461 *aMemAllocTotal = 0;
462 *aMemFreeTotal = 0;
463 *aMemBalloonTotal = 0;
464 *aMemSharedTotal = 0;
465 *aMemShared = 0;
466 return E_FAIL;
467 }
468
469 return S_OK;
470}
471
472HRESULT Guest::setStatistic(ULONG aCpuId, GUESTSTATTYPE enmType, ULONG aVal)
473{
474 AutoCaller autoCaller(this);
475 if (FAILED(autoCaller.rc())) return autoCaller.rc();
476
477 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
478
479 if (enmType >= GUESTSTATTYPE_MAX)
480 return E_INVALIDARG;
481
482 mCurrentGuestStat[enmType] = aVal;
483 return S_OK;
484}
485
486/**
487 * Returns the status of a specified Guest Additions facility.
488 *
489 * @return aStatus Current status of specified facility.
490 * @param aType Facility to get the status from.
491 * @param aTimestamp Timestamp of last facility status update in ms (optional).
492 */
493STDMETHODIMP Guest::GetFacilityStatus(AdditionsFacilityType_T aType, LONG64 *aTimestamp, AdditionsFacilityStatus_T *aStatus)
494{
495 AutoCaller autoCaller(this);
496 if (FAILED(autoCaller.rc())) return autoCaller.rc();
497
498 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
499
500 CheckComArgNotNull(aStatus);
501 /* Not checking for aTimestamp is intentional; it's optional. */
502
503 FacilityMapIterConst it = mData.mFacilityMap.find(aType);
504 if (it != mData.mFacilityMap.end())
505 {
506 AdditionsFacility *pFacility = it->second;
507 ComAssert(pFacility);
508 *aStatus = pFacility->getStatus();
509 if (aTimestamp)
510 *aTimestamp = pFacility->getLastUpdated();
511 }
512 else
513 {
514 /*
515 * Do not fail here -- could be that the facility never has been brought up (yet) but
516 * the host wants to have its status anyway. So just tell we don't know at this point.
517 */
518 *aStatus = AdditionsFacilityStatus_Unknown;
519 if (aTimestamp)
520 *aTimestamp = RTTimeMilliTS();
521 }
522 return S_OK;
523}
524
525STDMETHODIMP Guest::GetAdditionsStatus(AdditionsRunLevelType_T aLevel, BOOL *aActive)
526{
527 AutoCaller autoCaller(this);
528 if (FAILED(autoCaller.rc())) return autoCaller.rc();
529
530 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
531
532 HRESULT rc = S_OK;
533 switch (aLevel)
534 {
535 case AdditionsRunLevelType_System:
536 *aActive = (mData.mAdditionsRunLevel > AdditionsRunLevelType_None);
537 break;
538
539 case AdditionsRunLevelType_Userland:
540 *aActive = (mData.mAdditionsRunLevel >= AdditionsRunLevelType_Userland);
541 break;
542
543 case AdditionsRunLevelType_Desktop:
544 *aActive = (mData.mAdditionsRunLevel >= AdditionsRunLevelType_Desktop);
545 break;
546
547 default:
548 rc = setError(VBOX_E_NOT_SUPPORTED,
549 tr("Invalid status level defined: %u"), aLevel);
550 break;
551 }
552
553 return rc;
554}
555
556STDMETHODIMP Guest::SetCredentials(IN_BSTR aUserName, IN_BSTR aPassword,
557 IN_BSTR aDomain, BOOL aAllowInteractiveLogon)
558{
559 AutoCaller autoCaller(this);
560 if (FAILED(autoCaller.rc())) return autoCaller.rc();
561
562 /* forward the information to the VMM device */
563 VMMDev *pVMMDev = mParent->getVMMDev();
564 if (pVMMDev)
565 {
566 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
567 if (pVMMDevPort)
568 {
569 uint32_t u32Flags = VMMDEV_SETCREDENTIALS_GUESTLOGON;
570 if (!aAllowInteractiveLogon)
571 u32Flags = VMMDEV_SETCREDENTIALS_NOLOCALLOGON;
572
573 pVMMDevPort->pfnSetCredentials(pVMMDevPort,
574 Utf8Str(aUserName).c_str(),
575 Utf8Str(aPassword).c_str(),
576 Utf8Str(aDomain).c_str(),
577 u32Flags);
578 return S_OK;
579 }
580 }
581
582 return setError(VBOX_E_VM_ERROR,
583 tr("VMM device is not available (is the VM running?)"));
584}
585
586STDMETHODIMP Guest::DragHGEnter(ULONG uScreenId, ULONG uX, ULONG uY, DragAndDropAction_T defaultAction, ComSafeArrayIn(DragAndDropAction_T, allowedActions), ComSafeArrayIn(IN_BSTR, formats), DragAndDropAction_T *pResultAction)
587{
588 /* Input validation */
589 CheckComArgSafeArrayNotNull(allowedActions);
590 CheckComArgSafeArrayNotNull(formats);
591 CheckComArgOutPointerValid(pResultAction);
592
593 AutoCaller autoCaller(this);
594 if (FAILED(autoCaller.rc())) return autoCaller.rc();
595
596#ifdef VBOX_WITH_DRAG_AND_DROP
597 return m_pGuestDnD->dragHGEnter(uScreenId, uX, uY, defaultAction, ComSafeArrayInArg(allowedActions), ComSafeArrayInArg(formats), pResultAction);
598#else /* VBOX_WITH_DRAG_AND_DROP */
599 ReturnComNotImplemented();
600#endif /* !VBOX_WITH_DRAG_AND_DROP */
601}
602
603STDMETHODIMP Guest::DragHGMove(ULONG uScreenId, ULONG uX, ULONG uY, DragAndDropAction_T defaultAction, ComSafeArrayIn(DragAndDropAction_T, allowedActions), ComSafeArrayIn(IN_BSTR, formats), DragAndDropAction_T *pResultAction)
604{
605 /* Input validation */
606 CheckComArgSafeArrayNotNull(allowedActions);
607 CheckComArgSafeArrayNotNull(formats);
608 CheckComArgOutPointerValid(pResultAction);
609
610 AutoCaller autoCaller(this);
611 if (FAILED(autoCaller.rc())) return autoCaller.rc();
612
613#ifdef VBOX_WITH_DRAG_AND_DROP
614 return m_pGuestDnD->dragHGMove(uScreenId, uX, uY, defaultAction, ComSafeArrayInArg(allowedActions), ComSafeArrayInArg(formats), pResultAction);
615#else /* VBOX_WITH_DRAG_AND_DROP */
616 ReturnComNotImplemented();
617#endif /* !VBOX_WITH_DRAG_AND_DROP */
618}
619
620STDMETHODIMP Guest::DragHGLeave(ULONG uScreenId)
621{
622 AutoCaller autoCaller(this);
623 if (FAILED(autoCaller.rc())) return autoCaller.rc();
624
625#ifdef VBOX_WITH_DRAG_AND_DROP
626 return m_pGuestDnD->dragHGLeave(uScreenId);
627#else /* VBOX_WITH_DRAG_AND_DROP */
628 ReturnComNotImplemented();
629#endif /* !VBOX_WITH_DRAG_AND_DROP */
630}
631
632STDMETHODIMP Guest::DragHGDrop(ULONG uScreenId, ULONG uX, ULONG uY, DragAndDropAction_T defaultAction, ComSafeArrayIn(DragAndDropAction_T, allowedActions), ComSafeArrayIn(IN_BSTR, formats), BSTR *pstrFormat, DragAndDropAction_T *pResultAction)
633{
634 /* Input validation */
635 CheckComArgSafeArrayNotNull(allowedActions);
636 CheckComArgSafeArrayNotNull(formats);
637 CheckComArgOutPointerValid(pstrFormat);
638 CheckComArgOutPointerValid(pResultAction);
639
640 AutoCaller autoCaller(this);
641 if (FAILED(autoCaller.rc())) return autoCaller.rc();
642
643#ifdef VBOX_WITH_DRAG_AND_DROP
644 return m_pGuestDnD->dragHGDrop(uScreenId, uX, uY, defaultAction, ComSafeArrayInArg(allowedActions), ComSafeArrayInArg(formats), pstrFormat, pResultAction);
645#else /* VBOX_WITH_DRAG_AND_DROP */
646 ReturnComNotImplemented();
647#endif /* !VBOX_WITH_DRAG_AND_DROP */
648}
649
650STDMETHODIMP Guest::DragHGPutData(ULONG uScreenId, IN_BSTR bstrFormat, ComSafeArrayIn(BYTE, data), IProgress **ppProgress)
651{
652 /* Input validation */
653 CheckComArgStrNotEmptyOrNull(bstrFormat);
654 CheckComArgSafeArrayNotNull(data);
655 CheckComArgOutPointerValid(ppProgress);
656
657 AutoCaller autoCaller(this);
658 if (FAILED(autoCaller.rc())) return autoCaller.rc();
659
660#ifdef VBOX_WITH_DRAG_AND_DROP
661 return m_pGuestDnD->dragHGPutData(uScreenId, bstrFormat, ComSafeArrayInArg(data), ppProgress);
662#else /* VBOX_WITH_DRAG_AND_DROP */
663 ReturnComNotImplemented();
664#endif /* !VBOX_WITH_DRAG_AND_DROP */
665}
666
667STDMETHODIMP Guest::DragGHPending(ULONG uScreenId, ComSafeArrayOut(BSTR, formats), ComSafeArrayOut(DragAndDropAction_T, allowedActions), DragAndDropAction_T *pDefaultAction)
668{
669 /* Input validation */
670 CheckComArgSafeArrayNotNull(formats);
671 CheckComArgSafeArrayNotNull(allowedActions);
672 CheckComArgOutPointerValid(pDefaultAction);
673
674 AutoCaller autoCaller(this);
675 if (FAILED(autoCaller.rc())) return autoCaller.rc();
676
677#ifdef VBOX_WITH_DRAG_AND_DROP
678 return m_pGuestDnD->dragGHPending(uScreenId, ComSafeArrayOutArg(formats), ComSafeArrayOutArg(allowedActions), pDefaultAction);
679#else /* VBOX_WITH_DRAG_AND_DROP */
680 ReturnComNotImplemented();
681#endif /* !VBOX_WITH_DRAG_AND_DROP */
682}
683
684STDMETHODIMP Guest::DragGHDropped(IN_BSTR bstrFormat, DragAndDropAction_T action, IProgress **ppProgress)
685{
686 /* Input validation */
687 CheckComArgStrNotEmptyOrNull(bstrFormat);
688 CheckComArgOutPointerValid(ppProgress);
689
690 AutoCaller autoCaller(this);
691 if (FAILED(autoCaller.rc())) return autoCaller.rc();
692
693#ifdef VBOX_WITH_DRAG_AND_DROP
694 return m_pGuestDnD->dragGHDropped(bstrFormat, action, ppProgress);
695#else /* VBOX_WITH_DRAG_AND_DROP */
696 ReturnComNotImplemented();
697#endif /* !VBOX_WITH_DRAG_AND_DROP */
698}
699
700STDMETHODIMP Guest::DragGHGetData(ComSafeArrayOut(BYTE, data))
701{
702 /* Input validation */
703 CheckComArgSafeArrayNotNull(data);
704
705 AutoCaller autoCaller(this);
706 if (FAILED(autoCaller.rc())) return autoCaller.rc();
707
708#ifdef VBOX_WITH_DRAG_AND_DROP
709 return m_pGuestDnD->dragGHGetData(ComSafeArrayOutArg(data));
710#else /* VBOX_WITH_DRAG_AND_DROP */
711 ReturnComNotImplemented();
712#endif /* !VBOX_WITH_DRAG_AND_DROP */
713}
714
715// public methods only for internal purposes
716/////////////////////////////////////////////////////////////////////////////
717
718/**
719 * Sets the general Guest Additions information like
720 * API (interface) version and OS type. Gets called by
721 * vmmdevUpdateGuestInfo.
722 *
723 * @param aInterfaceVersion
724 * @param aOsType
725 */
726void Guest::setAdditionsInfo(Bstr aInterfaceVersion, VBOXOSTYPE aOsType)
727{
728 RTTIMESPEC TimeSpecTS;
729 RTTimeNow(&TimeSpecTS);
730
731 AutoCaller autoCaller(this);
732 AssertComRCReturnVoid(autoCaller.rc());
733
734 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
735
736
737 /*
738 * Note: The Guest Additions API (interface) version is deprecated
739 * and will not be used anymore! We might need it to at least report
740 * something as version number if *really* ancient Guest Additions are
741 * installed (without the guest version + revision properties having set).
742 */
743 mData.mInterfaceVersion = aInterfaceVersion;
744
745 /*
746 * Older Additions rely on the Additions API version whether they
747 * are assumed to be active or not. Since newer Additions do report
748 * the Additions version *before* calling this function (by calling
749 * VMMDevReportGuestInfo2, VMMDevReportGuestStatus, VMMDevReportGuestInfo,
750 * in that order) we can tell apart old and new Additions here. Old
751 * Additions never would set VMMDevReportGuestInfo2 (which set mData.mAdditionsVersion)
752 * so they just rely on the aInterfaceVersion string (which gets set by
753 * VMMDevReportGuestInfo).
754 *
755 * So only mark the Additions as being active (run level = system) when we
756 * don't have the Additions version set.
757 */
758 if (mData.mAdditionsVersionNew.isEmpty())
759 {
760 if (aInterfaceVersion.isEmpty())
761 mData.mAdditionsRunLevel = AdditionsRunLevelType_None;
762 else
763 {
764 mData.mAdditionsRunLevel = AdditionsRunLevelType_System;
765
766 /*
767 * To keep it compatible with the old Guest Additions behavior we need to set the
768 * "graphics" (feature) facility to active as soon as we got the Guest Additions
769 * interface version.
770 */
771 facilityUpdate(VBoxGuestFacilityType_Graphics, VBoxGuestFacilityStatus_Active, 0 /*fFlags*/, &TimeSpecTS);
772 }
773 }
774
775 /*
776 * Older Additions didn't have this finer grained capability bit,
777 * so enable it by default. Newer Additions will not enable this here
778 * and use the setSupportedFeatures function instead.
779 */
780 /** @todo r=bird: I don't get the above comment nor the code below...
781 * One talks about capability bits, the one always does something to a facility.
782 * Then there is the comment below it all, which is placed like it addresses the
783 * mOSTypeId, but talks about something which doesn't remotely like mOSTypeId...
784 *
785 * Andy, could you please try clarify and make the comments shorter and more
786 * coherent! Also, explain why this is important and what depends on it.
787 *
788 * PS. There is the VMMDEV_GUEST_SUPPORTS_GRAPHICS capability* report... It
789 * should come in pretty quickly after this update, normally.
790 */
791 facilityUpdate(VBoxGuestFacilityType_Graphics,
792 facilityIsActive(VBoxGuestFacilityType_VBoxGuestDriver)
793 ? VBoxGuestFacilityStatus_Active : VBoxGuestFacilityStatus_Inactive,
794 0 /*fFlags*/, &TimeSpecTS); /** @todo the timestamp isn't gonna be right here on saved state restore. */
795
796 /*
797 * Note! There is a race going on between setting mAdditionsRunLevel and
798 * mSupportsGraphics here and disabling/enabling it later according to
799 * its real status when using new(er) Guest Additions.
800 */
801 mData.mOSTypeId = Global::OSTypeId(aOsType);
802}
803
804/**
805 * Sets the Guest Additions version information details.
806 *
807 * Gets called by vmmdevUpdateGuestInfo2 and vmmdevUpdateGuestInfo (to clear the
808 * state).
809 *
810 * @param a_uFullVersion VBoxGuestInfo2::additionsMajor,
811 * VBoxGuestInfo2::additionsMinor and
812 * VBoxGuestInfo2::additionsBuild combined into
813 * one value by VBOX_FULL_VERSION_MAKE.
814 *
815 * When this is 0, it's vmmdevUpdateGuestInfo
816 * calling to reset the state.
817 *
818 * @param a_pszName Build type tag and/or publisher tag, empty
819 * string if neiter of those are present.
820 * @param a_uRevision See VBoxGuestInfo2::additionsRevision.
821 * @param a_fFeatures See VBoxGuestInfo2::additionsFeatures.
822 */
823void Guest::setAdditionsInfo2(uint32_t a_uFullVersion, const char *a_pszName, uint32_t a_uRevision, uint32_t a_fFeatures)
824{
825 AutoCaller autoCaller(this);
826 AssertComRCReturnVoid(autoCaller.rc());
827
828 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
829
830 if (a_uFullVersion)
831 {
832 mData.mAdditionsVersionNew = BstrFmt(*a_pszName ? "%u.%u.%u_%s" : "%u.%u.%u",
833 VBOX_FULL_VERSION_GET_MAJOR(a_uFullVersion),
834 VBOX_FULL_VERSION_GET_MINOR(a_uFullVersion),
835 VBOX_FULL_VERSION_GET_BUILD(a_uFullVersion),
836 a_pszName);
837 mData.mAdditionsVersionFull = a_uFullVersion;
838 mData.mAdditionsRevision = a_uRevision;
839 mData.mAdditionsFeatures = a_fFeatures;
840 }
841 else
842 {
843 Assert(!a_fFeatures && !a_uRevision && !*a_pszName);
844 mData.mAdditionsVersionNew.setNull();
845 mData.mAdditionsVersionFull = 0;
846 mData.mAdditionsRevision = 0;
847 mData.mAdditionsFeatures = 0;
848 }
849}
850
851bool Guest::facilityIsActive(VBoxGuestFacilityType enmFacility)
852{
853 Assert(enmFacility < INT32_MAX);
854 FacilityMapIterConst it = mData.mFacilityMap.find((AdditionsFacilityType_T)enmFacility);
855 if (it != mData.mFacilityMap.end())
856 {
857 AdditionsFacility *pFac = it->second;
858 return (pFac->getStatus() == AdditionsFacilityStatus_Active);
859 }
860 return false;
861}
862
863void Guest::facilityUpdate(VBoxGuestFacilityType a_enmFacility, VBoxGuestFacilityStatus a_enmStatus,
864 uint32_t a_fFlags, PCRTTIMESPEC a_pTimeSpecTS)
865{
866 AssertReturnVoid( a_enmFacility < VBoxGuestFacilityType_All
867 && a_enmFacility > VBoxGuestFacilityType_Unknown);
868
869 FacilityMapIter it = mData.mFacilityMap.find((AdditionsFacilityType_T)a_enmFacility);
870 if (it != mData.mFacilityMap.end())
871 {
872 AdditionsFacility *pFac = it->second;
873 pFac->update((AdditionsFacilityStatus_T)a_enmStatus, a_fFlags, a_pTimeSpecTS);
874 }
875 else
876 {
877 if (mData.mFacilityMap.size() > 64)
878 {
879 /* The easy way out for now. We could automatically destroy
880 inactive facilities like VMMDev does if we like... */
881 AssertFailedReturnVoid();
882 }
883
884 ComObjPtr<AdditionsFacility> ptrFac;
885 ptrFac.createObject();
886 AssertReturnVoid(!ptrFac.isNull());
887
888 HRESULT hrc = ptrFac->init(this, (AdditionsFacilityType_T)a_enmFacility, (AdditionsFacilityStatus_T)a_enmStatus,
889 a_fFlags, a_pTimeSpecTS);
890 if (SUCCEEDED(hrc))
891 mData.mFacilityMap.insert(std::make_pair((AdditionsFacilityType_T)a_enmFacility, ptrFac));
892 }
893}
894
895/**
896 * Sets the status of a certain Guest Additions facility.
897 *
898 * Gets called by vmmdevUpdateGuestStatus, which just passes the report along.
899 *
900 * @param a_pInterface Pointer to this interface.
901 * @param a_enmFacility The facility.
902 * @param a_enmStatus The status.
903 * @param a_fFlags Flags assoicated with the update. Currently
904 * reserved and should be ignored.
905 * @param a_pTimeSpecTS Pointer to the timestamp of this report.
906 * @sa PDMIVMMDEVCONNECTOR::pfnUpdateGuestStatus, vmmdevUpdateGuestStatus
907 * @thread The emulation thread.
908 */
909void Guest::setAdditionsStatus(VBoxGuestFacilityType a_enmFacility, VBoxGuestFacilityStatus a_enmStatus,
910 uint32_t a_fFlags, PCRTTIMESPEC a_pTimeSpecTS)
911{
912 Assert( a_enmFacility > VBoxGuestFacilityType_Unknown
913 && a_enmFacility <= VBoxGuestFacilityType_All); /* Paranoia, VMMDev checks for this. */
914
915 AutoCaller autoCaller(this);
916 AssertComRCReturnVoid(autoCaller.rc());
917
918 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
919
920 /*
921 * Set a specific facility status.
922 */
923 if (a_enmFacility == VBoxGuestFacilityType_All)
924 for (FacilityMapIter it = mData.mFacilityMap.begin(); it != mData.mFacilityMap.end(); ++it)
925 facilityUpdate((VBoxGuestFacilityType)it->first, a_enmStatus, a_fFlags, a_pTimeSpecTS);
926 else /* Update one facility only. */
927 facilityUpdate(a_enmFacility, a_enmStatus, a_fFlags, a_pTimeSpecTS);
928
929 /*
930 * Recalc the runlevel.
931 */
932 if (facilityIsActive(VBoxGuestFacilityType_VBoxTrayClient))
933 mData.mAdditionsRunLevel = AdditionsRunLevelType_Desktop;
934 else if (facilityIsActive(VBoxGuestFacilityType_VBoxService))
935 mData.mAdditionsRunLevel = AdditionsRunLevelType_Userland;
936 else if (facilityIsActive(VBoxGuestFacilityType_VBoxGuestDriver))
937 mData.mAdditionsRunLevel = AdditionsRunLevelType_System;
938 else
939 mData.mAdditionsRunLevel = AdditionsRunLevelType_None;
940}
941
942/**
943 * Sets the supported features (and whether they are active or not).
944 *
945 * @param fCaps Guest capability bit mask (VMMDEV_GUEST_SUPPORTS_XXX).
946 */
947void Guest::setSupportedFeatures(uint32_t aCaps)
948{
949 AutoCaller autoCaller(this);
950 AssertComRCReturnVoid(autoCaller.rc());
951
952 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
953
954 /** @todo A nit: The timestamp is wrong on saved state restore. Would be better
955 * to move the graphics and seamless capability -> facility translation to
956 * VMMDev so this could be saved. */
957 RTTIMESPEC TimeSpecTS;
958 RTTimeNow(&TimeSpecTS);
959
960 facilityUpdate(VBoxGuestFacilityType_Seamless,
961 aCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? VBoxGuestFacilityStatus_Active : VBoxGuestFacilityStatus_Inactive,
962 0 /*fFlags*/, &TimeSpecTS);
963 /** @todo Add VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING */
964 facilityUpdate(VBoxGuestFacilityType_Graphics,
965 aCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS ? VBoxGuestFacilityStatus_Active : VBoxGuestFacilityStatus_Inactive,
966 0 /*fFlags*/, &TimeSpecTS);
967}
968/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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