Index: /trunk/include/VBox/VMMDev.h
===================================================================
--- /trunk/include/VBox/VMMDev.h	(revision 35966)
+++ /trunk/include/VBox/VMMDev.h	(revision 35967)
@@ -679,5 +679,5 @@
     VBoxGuestFacilityType_VBoxTrayClient  = 101, /* VBoxTray (Windows), VBoxClient (Linux, Unix). */
     VBoxGuestFacilityType_Seamless        = 1000,
-    VBoxGuestFacilityType_Graphics        = 1001,
+    VBoxGuestFacilityType_Graphics        = 1100,
     VBoxGuestFacilityType_All             = 0x7ffffffe,
     VBoxGuestFacilityType_SizeHack        = 0x7fffffff
@@ -704,4 +704,22 @@
 } VBoxGuestFacilityStatus;
 AssertCompileSize(VBoxGuestFacilityStatus, 4);
+
+
+/**
+ * The facility class.
+ * This needs to be kept in sync with AdditionsFacilityClass of the Main API!
+ */
+typedef enum
+{
+    VBoxGuestFacilityClass_None       = 0,
+    VBoxGuestFacilityClass_Driver     = 10,
+    VBoxGuestFacilityClass_Service    = 30,
+    VBoxGuestFacilityClass_Program    = 50,
+    VBoxGuestFacilityClass_Feature    = 100,
+    VBoxGuestFacilityClass_ThirdParty = 999,
+    VBoxGuestFacilityClass_SizeHack   = 0x7fffffff
+} VBoxGuestFacilityClass;
+AssertCompileSize(VBoxGuestFacilityClass, 4);
+
 
 /**
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp	(revision 35966)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp	(revision 35967)
@@ -2069,60 +2069,51 @@
             }
 
-            if (details == VMINFO_FULL)
-            {
-                rc = guest->COMGETTER(AdditionsVersion)(guestString.asOutParam());
-                if (   SUCCEEDED(rc)
-                    && !guestString.isEmpty())
+            rc = guest->COMGETTER(AdditionsVersion)(guestString.asOutParam());
+            if (   SUCCEEDED(rc)
+                && !guestString.isEmpty())
+            {
+                if (details == VMINFO_MACHINEREADABLE)
+                    RTPrintf("GuestAdditionsVersion=\"%lS\"\n", guestString.raw());
+                else
+                    RTPrintf("Additions version:                   %lS\n\n", guestString.raw());
+            }
+
+            if (details != VMINFO_MACHINEREADABLE)
+                RTPrintf("\nGuest Facilities:\n\n");
+
+            /* Print information about known Guest Additions facilities: */
+            SafeIfaceArray <IAdditionsFacility> collFac;
+            CHECK_ERROR_RET(guest, COMGETTER(Facilities)(ComSafeArrayAsOutParam(collFac)), rc);
+            LONG64 lLastUpdatedMS;
+            char szLastUpdated[32];
+            AdditionsFacilityStatus_T curStatus;
+            for (size_t index = 0; index < collFac.size(); ++index)
+            {
+                ComPtr<IAdditionsFacility> fac = collFac[index];
+                if (fac)
                 {
-                    if (details == VMINFO_MACHINEREADABLE)
-                        RTPrintf("GuestAdditionsVersion=\"%lS\"\n", guestString.raw());
-                    else
-                        RTPrintf("Additions version:                   %lS\n\n", guestString.raw());
+                    CHECK_ERROR_RET(fac, COMGETTER(Name)(guestString.asOutParam()), rc);
+                    if (!guestString.isEmpty())
+                    {
+                        CHECK_ERROR_RET(fac, COMGETTER(Status)(&curStatus), rc);
+                        CHECK_ERROR_RET(fac, COMGETTER(LastUpdated)(&lLastUpdatedMS), rc);
+                        if (details == VMINFO_MACHINEREADABLE)
+                            RTPrintf("GuestAdditionsFacility_%lS=%u,%lld\n",
+                                     guestString.raw(), curStatus, lLastUpdatedMS);
+                        else
+                        {
+                            makeTimeStr(szLastUpdated, sizeof(szLastUpdated), lLastUpdatedMS);
+                            RTPrintf("Facility \"%lS\": %s (last update: %s)\n",
+                                     guestString.raw(), facilityStateToName(curStatus, false /* No short naming */), szLastUpdated);
+                        }
+                    }
+                    else
+                        AssertMsgFailed(("Facility with undefined name retrieved!\n"));
                 }
-
-                if (details != VMINFO_MACHINEREADABLE)
-                    RTPrintf("\nGuest Components:\n\n");
-
-                /* Print information about important Guest Additions parts: */
-                /** @todo Add a makeFacilityStatusStr() to translate facility states into a human readable string! */
-                AdditionsFacilityStatus_T faStatus;
-                LONG64 lLastUpdatedMS = 0;
-                char szLastUpdated[32];
-                rc = guest->GetFacilityStatus(AdditionsFacilityType_VBoxGuestDriver, &lLastUpdatedMS, &faStatus);
-                if (SUCCEEDED(rc))
-                {
-                    makeTimeStr(szLastUpdated, sizeof(szLastUpdated), lLastUpdatedMS);
-                    if (details == VMINFO_MACHINEREADABLE)
-                        RTPrintf("GuestAdditionsFacilityStatusGuestDriver=%u,%ld\n",
-                                 faStatus, lLastUpdatedMS);
-                    else
-                        RTPrintf("Guest driver:                        %u (last update: %s)\n",
-                                 facilityStateToName(faStatus, false /* No short naming */), szLastUpdated);
-                }
-
-                rc = guest->GetFacilityStatus(AdditionsFacilityType_VBoxService, &lLastUpdatedMS, &faStatus);
-                if (SUCCEEDED(rc))
-                {
-                    makeTimeStr(szLastUpdated, sizeof(szLastUpdated), lLastUpdatedMS);
-                    if (details == VMINFO_MACHINEREADABLE)
-                        RTPrintf("GuestAdditionsFacilityStatusVBoxService=%u,%ld\n",
-                                 faStatus, lLastUpdatedMS);
-                    else
-                        RTPrintf("VBoxService:                         %s (last update: %s)\n",
-                                 facilityStateToName(faStatus, false /* No short naming */), szLastUpdated);
-                }
-
-                rc = guest->GetFacilityStatus(AdditionsFacilityType_VBoxTrayClient, &lLastUpdatedMS, &faStatus);
-                if (SUCCEEDED(rc))
-                {
-                    makeTimeStr(szLastUpdated, sizeof(szLastUpdated), lLastUpdatedMS);
-                    if (details == VMINFO_MACHINEREADABLE)
-                        RTPrintf("GuestAdditionsFacilityStatusVBoxTrayClient=%u,%ld\n",
-                                 facilityStateToName(faStatus, false /* No short naming */), lLastUpdatedMS);
-                    else
-                        RTPrintf("VBoxTray / VBoxClient:               %u (last update: %s)\n",
-                                 faStatus, szLastUpdated);
-                }
-            }
+                else
+                    AssertMsgFailed(("Invalid facility returned!\n"));
+            }
+            if (!collFac.size() && details != VMINFO_MACHINEREADABLE)
+                RTPrintf("No active facilities.\n");
         }
     }
Index: /trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/Makefile.kmk	(revision 35966)
+++ /trunk/src/VBox/Main/Makefile.kmk	(revision 35967)
@@ -637,4 +637,5 @@
 	src-all/VirtualBoxErrorInfoImpl.cpp \
 	$(if $(VBOX_WITH_EXTPACK),src-all/ExtPackManagerImpl.cpp src-all/ExtPackUtil.cpp,) \
+	src-client/AdditionsFacilityImpl.cpp \
 	src-client/AudioSnifferInterface.cpp \
 	src-client/BusAssignmentManager.cpp \
Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 35966)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 35967)
@@ -7910,4 +7910,32 @@
 
   <enum
+    name="AdditionsFacilityClass"
+    uuid="9cff7275-9a5b-4dcd-b164-523e001a5a9e"
+    >
+    <desc>
+      Guest Additions facility classes.
+    </desc>
+
+    <const name="None"                    value="0">
+      <desc>No/invalid class.</desc>
+    </const>
+    <const name="Driver"                  value="10">
+      <desc>Driver.</desc>
+    </const>
+    <const name="Service"                 value="30">
+      <desc>System service.</desc>
+    </const>
+    <const name="Program"                 value="50">
+      <desc>Program.</desc>
+    </const>
+    <const name="Feature"                 value="100">
+      <desc>Feature.</desc>
+    </const>
+    <const name="ThirdParty"              value="999">
+      <desc>Third party.</desc>
+    </const>
+  </enum>
+
+  <enum
     name="AdditionsFacilityStatus"
     uuid="ce06f9e1-394e-4fe9-9368-5a88c567dbde"
@@ -7945,4 +7973,34 @@
     </const>
   </enum>
+
+  <interface
+    name="IAdditionsFacility" extends="$unknown"
+    uuid="5b681761-e865-4bdd-9d6e-135aa8f26e66"
+    wsmap="struct"
+    >
+    <desc>
+      Structure representing a Guest Additions facility.
+    </desc>
+
+    <attribute name="class" type="AdditionsFacilityClass" readonly="yes">
+      <desc>Additions facility class.</desc>
+    </attribute>
+
+    <attribute name="lastUpdated" type="long long" readonly="yes">
+      <desc>Timestamp of last updated status.</desc>
+    </attribute>
+
+    <attribute name="name" type="wstring" readonly="yes">
+      <desc>Additions facility name.</desc>
+    </attribute>
+
+    <attribute name="status" type="AdditionsFacilityStatus" readonly="yes">
+      <desc>Additions facility status.</desc>
+    </attribute>
+
+    <attribute name="type" type="AdditionsFacilityType" readonly="yes">
+      <desc>Additions facility type.</desc>
+    </attribute>
+  </interface>
 
   <enum
@@ -8110,4 +8168,11 @@
         separated by dots + revision number) installed on the guest or empty
         when the Additions are not installed.
+      </desc>
+    </attribute>
+
+    <attribute name="facilities" type="IAdditionsFacility" readonly="yes" safearray="yes">
+      <desc>
+        Array of current known facilities. Only returns facilities where a status is known,
+        e.g. facilities with an unknown status will not be returned.
       </desc>
     </attribute>
Index: /trunk/src/VBox/Main/include/GuestImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestImpl.h	(revision 35966)
+++ /trunk/src/VBox/Main/include/GuestImpl.h	(revision 35967)
@@ -23,4 +23,5 @@
 #include <VBox/ostypes.h>
 
+#include "AdditionsFacilityImpl.h"
 #ifdef VBOX_WITH_GUEST_CONTROL
 # include <VBox/HostServices/GuestControlSvc.h>
@@ -76,4 +77,5 @@
     STDMETHOD(COMGETTER(AdditionsRunLevel)) (AdditionsRunLevelType_T *aRunLevel);
     STDMETHOD(COMGETTER(AdditionsVersion)) (BSTR *aAdditionsVersion);
+    STDMETHOD(COMGETTER(Facilities)) (ComSafeArrayOut(IAdditionsFacility*, aFacilities));
     STDMETHOD(COMGETTER(MemoryBalloonSize)) (ULONG *aMemoryBalloonSize);
     STDMETHOD(COMSETTER(MemoryBalloonSize)) (ULONG aMemoryBalloonSize);
@@ -110,5 +112,5 @@
     void setAdditionsInfo2(Bstr aAdditionsVersion, Bstr aVersionName, Bstr aRevision);
     bool facilityIsActive(VBoxGuestFacilityType enmFacility);
-    void updateFacility(VBoxGuestFacilityType enmFacility, VBoxGuestFacilityStatus enmStatus);
+    HRESULT facilityUpdate(VBoxGuestFacilityType enmFacility, VBoxGuestFacilityStatus enmStatus);
     void setAdditionsStatus(VBoxGuestFacilityType enmFacility, VBoxGuestFacilityStatus enmStatus, ULONG aFlags);
     void setSupportedFeatures(uint32_t aCaps);
@@ -180,11 +182,7 @@
 # endif
 
-    struct FacilityData
-    {
-        RTTIMESPEC                  tsLastUpdated;
-        AdditionsFacilityStatus_T   curStatus;
-    };
-    typedef std::map< AdditionsFacilityType_T, FacilityData > FacilityMap;
-    typedef std::map< AdditionsFacilityType_T, FacilityData >::iterator FacilityMapIter;
+    typedef std::map< AdditionsFacilityType_T, ComObjPtr<AdditionsFacility> > FacilityMap;
+    typedef std::map< AdditionsFacilityType_T, ComObjPtr<AdditionsFacility> >::iterator FacilityMapIter;
+    typedef std::map< AdditionsFacilityType_T, ComObjPtr<AdditionsFacility> >::const_iterator FacilityMapIterConst;
 
     struct Data
Index: /trunk/src/VBox/Main/src-client/GuestImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/GuestImpl.cpp	(revision 35966)
+++ /trunk/src/VBox/Main/src-client/GuestImpl.cpp	(revision 35967)
@@ -237,4 +237,19 @@
 }
 
+STDMETHODIMP Guest::COMGETTER(Facilities)(ComSafeArrayOut(IAdditionsFacility*, aFacilities))
+{
+    CheckComArgOutPointerValid(aFacilities);
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    SafeIfaceArray<IAdditionsFacility> fac(mData.mFacilityMap);
+    fac.detachTo(ComSafeArrayOutArg(aFacilities));
+
+    return S_OK;
+}
+
 BOOL Guest::isPageFusionEnabled()
 {
@@ -247,5 +262,5 @@
 }
 
-STDMETHODIMP Guest::COMGETTER(MemoryBalloonSize) (ULONG *aMemoryBalloonSize)
+STDMETHODIMP Guest::COMGETTER(MemoryBalloonSize)(ULONG *aMemoryBalloonSize)
 {
     CheckComArgOutPointerValid(aMemoryBalloonSize);
@@ -261,5 +276,5 @@
 }
 
-STDMETHODIMP Guest::COMSETTER(MemoryBalloonSize) (ULONG aMemoryBalloonSize)
+STDMETHODIMP Guest::COMSETTER(MemoryBalloonSize)(ULONG aMemoryBalloonSize)
 {
     AutoCaller autoCaller(this);
@@ -427,10 +442,12 @@
     /* Not checking for aTimestamp is intentional; it's optional. */
 
-    FacilityMapIter it = mData.mFacilityMap.find(aType);
+    FacilityMapIterConst it = mData.mFacilityMap.find(aType);
     if (it != mData.mFacilityMap.end())
     {
-        *aStatus = it->second.curStatus;
+        AdditionsFacility *pFacility = it->second;
+        ComAssert(pFacility);
+        *aStatus = pFacility->getStatus();
         if (aTimestamp)
-            *aTimestamp = RTTimeSpecGetMilli(&it->second.tsLastUpdated);
+            *aTimestamp = pFacility->getLastUpdated();
     }
     else
@@ -560,5 +577,5 @@
      * and use the setSupportedFeatures function instead.
      */
-    updateFacility(VBoxGuestFacilityType_Graphics, facilityIsActive(VBoxGuestFacilityType_VBoxGuestDriver) ?
+    facilityUpdate(VBoxGuestFacilityType_Graphics, facilityIsActive(VBoxGuestFacilityType_VBoxGuestDriver) ?
                    VBoxGuestFacilityStatus_Active : VBoxGuestFacilityStatus_Inactive);
 
@@ -597,18 +614,42 @@
 bool Guest::facilityIsActive(VBoxGuestFacilityType enmFacility)
 {
-    return mData.mFacilityMap[(AdditionsFacilityType_T)enmFacility].curStatus == AdditionsFacilityStatus_Active;
-}
-
-void Guest::updateFacility(VBoxGuestFacilityType enmFacility, VBoxGuestFacilityStatus enmStatus)
-{
     Assert(enmFacility < UINT32_MAX);
-    FacilityData *pData = &mData.mFacilityMap[(AdditionsFacilityType_T)enmFacility];
-    AssertPtr(pData);
-
-    RTTimeNow(&pData->tsLastUpdated);
-    pData->curStatus = (AdditionsFacilityStatus_T)enmStatus;
-
-    LogFlowFunc(("Setting guest facility %u = %u (%u)\n",
-                 enmFacility, pData->curStatus, pData->tsLastUpdated));
+    FacilityMapIterConst it = mData.mFacilityMap.find((AdditionsFacilityType_T)enmFacility);
+    if (it != mData.mFacilityMap.end())
+    {
+        AdditionsFacility *pFac = it->second;
+        return (pFac->getStatus() == AdditionsFacilityStatus_Active);
+    }
+    return false;
+}
+
+HRESULT Guest::facilityUpdate(VBoxGuestFacilityType enmFacility, VBoxGuestFacilityStatus enmStatus)
+{
+    ComAssertRet(enmFacility < UINT32_MAX, E_INVALIDARG);
+
+    HRESULT rc;
+    RTTIMESPEC tsNow;
+    RTTimeNow(&tsNow);
+
+    FacilityMapIter it = mData.mFacilityMap.find((AdditionsFacilityType_T)enmFacility);
+    if (it != mData.mFacilityMap.end())
+    {
+        AdditionsFacility *pFac = it->second;
+        rc = pFac->update((AdditionsFacilityStatus_T)enmStatus, tsNow);
+    }
+    else
+    {
+        ComObjPtr<AdditionsFacility> pFacility;
+        pFacility.createObject();
+        ComAssert(!pFacility.isNull());
+        rc = pFacility->init(this,
+                             (AdditionsFacilityType_T)enmFacility,
+                             (AdditionsFacilityStatus_T)enmStatus);
+        if (SUCCEEDED(rc))
+            mData.mFacilityMap.insert(std::make_pair((AdditionsFacilityType_T)enmFacility, pFacility));
+    }
+
+    LogFlowFunc(("Returned with rc=%Rrc\n"));
+    return rc;
 }
 
@@ -666,10 +707,10 @@
             while (it != mData.mFacilityMap.end())
             {
-                updateFacility((VBoxGuestFacilityType)it->first, enmStatus);
+                facilityUpdate((VBoxGuestFacilityType)it->first, enmStatus);
                 it++;
             }
         }
         else /* Update one facility only. */
-            updateFacility(enmFacility, enmStatus);
+            facilityUpdate(enmFacility, enmStatus);
     }
 }
@@ -687,8 +728,8 @@
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    updateFacility(VBoxGuestFacilityType_Seamless, aCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ?
+    facilityUpdate(VBoxGuestFacilityType_Seamless, aCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ?
                    VBoxGuestFacilityStatus_Active : VBoxGuestFacilityStatus_Inactive);
     /** @todo Add VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING */
-    updateFacility(VBoxGuestFacilityType_Graphics, aCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS ?
+    facilityUpdate(VBoxGuestFacilityType_Graphics, aCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS ?
                    VBoxGuestFacilityStatus_Active : VBoxGuestFacilityStatus_Inactive);
 }
