441 lines
12 KiB
C++
441 lines
12 KiB
C++
//=============================================================================
|
|
// Code used to manage threaded WMI refreshes.
|
|
//=============================================================================
|
|
|
|
#include "stdafx.h"
|
|
|
|
#if FALSE
|
|
//-----------------------------------------------------------------------------
|
|
// The CWMIObject abstract base class encapsulates a WMI object, which may
|
|
// in reality be a live WMI object, or an object recreated from the XML
|
|
// storage of an object.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
class CWMIObject
|
|
{
|
|
public:
|
|
CWMIObject();
|
|
virtual ~CWMIObject();
|
|
|
|
// The following methods return information about a property of this object.
|
|
//
|
|
// S_OK implies success
|
|
// E_MSINFO_NOPROPERTY means the named property doesn't exist
|
|
// E_MSINFO_NOVALUE means the property exists, but is empty
|
|
|
|
virtual HRESULT GetValue(LPCTSTR szProperty, VARIANT * pvarValue);
|
|
virtual HRESULT GetValueString(LPCTSTR szProperty, LPTSTR * pszValue);
|
|
virtual HRESULT GetValueDWORD(LPCTSTR szProperty, DWORD * pdwValue);
|
|
virtual HRESULT GetValueTime(LPCTSTR szProperty, SYSTEMTIME * psystimeValue);
|
|
virtual HRESULT GetValueDoubleFloat(LPCTSTR szProperty, double * pdblValue);
|
|
virtual HRESULT GetValueValueMap(LPCTSTR szProperty, LPTSTR * pszValue);
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The CWMIObjectCollection abstract base class encapsulates a collection
|
|
// of CWMIObject's. This collection may be treated like an enumeration.
|
|
// Subclases of this class may implement the collection as a WMI enumerator,
|
|
// or an existing blob of XML data.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
class CWMIObjectCollection
|
|
{
|
|
public:
|
|
CWMIObjectCollection();
|
|
virtual ~CWMIObjectCollection();
|
|
|
|
// The Create function creates the collection of objects (note - Create
|
|
// may be called multiple times on the same object). If the szProperties
|
|
// parameter is non-NULL, then it contains a comma delimited list of the
|
|
// minimum set of properties which should be included in the collection
|
|
// of objects. If it's NULL, then all available properties should be
|
|
// included.
|
|
|
|
virtual HRESULT Create(LPCTSTR szClass, LPCTSTR szProperties = NULL);
|
|
|
|
// The following two functions are used to manage the enumeration. GetNext
|
|
// returns the next enumerated CWMIObject. When there are no more objects,
|
|
// GetNext returns S_FALSE. Obviously, the caller is responsible for
|
|
// deleting the object returned.
|
|
|
|
virtual HRESULT GetNext(CWMIObject ** ppObject);
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The CWMILiveObject implements a CWMIObject using a real WMI object. It
|
|
// can be created with either a IWbemClassObject pointer, or a services
|
|
// pointer and a path.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
class CWMILiveObject : public CWMIObject
|
|
{
|
|
public:
|
|
CWMILiveObject();
|
|
virtual ~CWMILiveObject();
|
|
|
|
// Functions inherited from the base class:
|
|
|
|
HRESULT GetValue(LPCTSTR szProperty, VARIANT * pvarValue);
|
|
HRESULT GetValueString(LPCTSTR szProperty, LPTSTR * pszValue);
|
|
HRESULT GetValueDWORD(LPCTSTR szProperty, DWORD * pdwValue);
|
|
HRESULT GetValueTime(LPCTSTR szProperty, SYSTEMTIME * psystimeValue);
|
|
HRESULT GetValueDoubleFloat(LPCTSTR szProperty, double * pdblValue);
|
|
HRESULT GetValueValueMap(LPCTSTR szProperty, LPTSTR * pszValue);
|
|
|
|
// Functions specific to this subclass:
|
|
//
|
|
// Note - Create with an object pointer will addref() the pointer:
|
|
|
|
HRESULT Create(IWbemClassObject * pObject);
|
|
HRESULT Create(IWbemServices * pServices, LPCTSTR szObjectPath);
|
|
|
|
private:
|
|
IWbemClassObject * m_pObject;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The CWMILiveObjectCollection implements a collection of live WMI objects
|
|
// using a WMI enumerator. This collection can be created from an existing
|
|
// IEnumWbemClassObject pointer, from a WQL statement or from a WMI class name.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
class CWMILiveObjectCollection
|
|
{
|
|
public:
|
|
CWMILiveObjectCollection(IWbemServices * pServices);
|
|
virtual ~CWMILiveObjectCollection();
|
|
|
|
// Functions inherited from the base class:
|
|
|
|
HRESULT Create(LPCTSTR szClass, LPCTSTR szProperties = NULL);
|
|
HRESULT GetNext(CWMIObject ** ppObject);
|
|
|
|
// Functions specific to this subclass:
|
|
//
|
|
// Note - Create with an enum pointer will addref() the pointer:
|
|
|
|
public:
|
|
HRESULT Create(IEnumWbemClassObject * pEnum);
|
|
|
|
private:
|
|
IEnumWbemClassObject * m_pEnum;
|
|
IWbemServices * m_pServices;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The constructor and destructor for CWMILiveObjectCollection are very
|
|
// straightforward.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
CWMILiveObjectCollection::CWMILiveObjectCollection(IWbemServices * pServices) : m_pServices(pServices), m_pEnum(NULL)
|
|
{
|
|
ASSERT(m_pServices);
|
|
if (m_pServices)
|
|
m_pServices->AddRef();
|
|
}
|
|
|
|
CWMILiveObjectCollection::~CWMILiveObjectCollection()
|
|
{
|
|
if (m_pServices)
|
|
m_pServices->Release();
|
|
|
|
if (m_pEnum)
|
|
m_pEnum->Release();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Create the collection of WMI objects (a WMI enumerator) based on the
|
|
// class name and the requested properties.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT CWMILiveObjectCollection::Create(LPCTSTR szClass, LPCTSTR szProperties)
|
|
{
|
|
ASSERT(szClass);
|
|
|
|
if (m_pEnum)
|
|
m_pEnum->Release();
|
|
|
|
// Build the appopriate WQL query statement from the class and requested properties.
|
|
|
|
LPCTSTR szWQLProperties = (szProperties) ? szProperties : _T("*");
|
|
LPTSTR szQuery = new TCHAR[_tcsclen(szWQLProperties) + _tcsclen(szClass) + 14 /* length of "SELECT FROM " + 1 */);
|
|
if (szQuery == NULL)
|
|
return E_OUTOFMEMORY;
|
|
wsprintf(szQuery, _T("SELECT %s FROM %s"), szClass, szWQLProperties);
|
|
|
|
// Perform the query using our saved services pointer.
|
|
|
|
HRESULT hr;
|
|
BSTR bstrLanguage = SysAllocString(L"WQL");
|
|
#ifdef UNICODE
|
|
BSTR bstrQuery = SysAllocString(szQuery);
|
|
#else
|
|
USES_CONVERSION;
|
|
LPOLESTR szWideQuery = T2OLE(szQuery);
|
|
BSTR bstrQuery = SysAllocString(szWideQuery);
|
|
#endif
|
|
|
|
if (bstrLanguage && bstrQuery)
|
|
hr = pService->ExecQuery(bstrLanguage, bstrQuery, WBEM_FLAG_RETURN_IMMEDIATELY, 0, &m_pEnum);
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
if (bstrQuery)
|
|
SysFreeString(bstrQuery);
|
|
if (bstrLanguage)
|
|
SysFreeString(bstrLanguage);
|
|
|
|
delete [] szQuery;
|
|
return hr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Create this class of an existing enumerator. This may be a little odd,
|
|
// since the enumerators will interact if both are advancing.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT CWMILiveObjectCollection::Create(IEnumWbemClassObject * pEnum)
|
|
{
|
|
if (m_pEnum)
|
|
m_pEnum->Release();
|
|
|
|
m_pEnum = pEnum;
|
|
|
|
if (m_pEnum)
|
|
m_pEnum->AddRef();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Return the next item in the WMI enumerator as a CWMILiveObject object.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT CWMILiveObjectCollection::GetNext(CWMIObject ** ppObject)
|
|
{
|
|
ASSERT(ppObject);
|
|
if (m_pEnum == NULL)
|
|
{
|
|
ASSERT(0 && "CWMILiveObjectCollection::GetNext called on a null enumerator");
|
|
return E_FAIL;
|
|
}
|
|
|
|
IWbemClassObject * pRealWMIObject = NULL;
|
|
ULONG uReturned;
|
|
|
|
HRESULT hr = m_pEnum->Next(TIMEOUT, 1, &pRealWMIObject, &uReturned);
|
|
if (hr == S_OK && uReturned = 1)
|
|
{
|
|
*ppObject = new CWMILiveObject;
|
|
if (*ppObject)
|
|
hr = (*ppObject)->Create(pRealWMIObject);
|
|
else
|
|
hr = E_FAIL; // TBD memory error
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The constructor/destructor are really straight forward.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
CWMILiveObject::CWMILiveObject() : m_pObject(NULL)
|
|
{
|
|
}
|
|
|
|
CWMILiveObject::~CWMILiveObject()
|
|
{
|
|
if (m_pObject != NULL)
|
|
{
|
|
m_pObject->Release();
|
|
m_pObject = NULL;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The Create functions will either create the object from a WMI object, or
|
|
// from a service pointer and a path.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT CWMILiveObject::Create(IWbemClassObject * pObject)
|
|
{
|
|
ASSERT(pObject && "calling CWMILiveObject::Create with a null object");
|
|
if (m_pObject != NULL)
|
|
{
|
|
ASSERT(0 && "calling create on an already created CWMILiveObject");
|
|
m_pObject->Release();
|
|
}
|
|
|
|
m_pObject = pObject;
|
|
if (m_pObject)
|
|
m_pObject->AddRef();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CWMILiveObject::Create(IWbemServices * pServices, LPCTSTR szObjectPath)
|
|
{
|
|
ASSERT(pServices && szObjectPath);
|
|
if (m_pObject != NULL)
|
|
{
|
|
ASSERT(0 && "calling create on an already created CWMILiveObject");
|
|
m_pObject->Release();
|
|
m_pObject = NULL; // must be NULL or GetObject bitches
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
BSTR bstrPath = SysAllocString(szObjectPath);
|
|
#else
|
|
USES_CONVERSION;
|
|
LPOLESTR szWidePath = T2OLE(szObjectPath);
|
|
BSTR bstrPath = SysAllocString(szWidePath);
|
|
#endif
|
|
|
|
HRESULT hr;
|
|
if (bstrPath)
|
|
{
|
|
hr = pServices->GetObject(bstrPath, 0L, NULL, &m_pObject, NULL);
|
|
SysFreeString(bstrPath);
|
|
}
|
|
else
|
|
hr = E_FAIL;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The simple GetValue returns the named value as a variant.
|
|
//
|
|
// The pointer to an existing uninitialized VARIANT structure that receives
|
|
// the property value, if found. Because this is an output parameter, this
|
|
// method calls VariantInit on this VARIANT, so you must be sure that this
|
|
// is not pointing to an active VARIANT.
|
|
//
|
|
// Note: You must call VariantClear on the returned VARIANT when its value
|
|
// is no longer required. This will prevent memory leaks in the client process.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT CWMILiveObject::GetValue(LPCTSTR szProperty, VARIANT * pvarValue)
|
|
{
|
|
ASSERT(szProperty && pvarValue);
|
|
if (m_pObject == NULL)
|
|
{
|
|
ASSERT(0 && "CWMILiveObject::GetValue called on a null object");
|
|
return E_FAIL;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
BSTR bstrProperty = SysAllocString(szProperty);
|
|
#else
|
|
USES_CONVERSION;
|
|
LPOLESTR szWideProperty = T2OLE(szProperty);
|
|
BSTR bstrProperty = SysAllocString(szWideProperty);
|
|
#endif
|
|
|
|
HRESULT hr;
|
|
if (bstrProperty)
|
|
{
|
|
hr = pObject->Get(bstrProperty, 0L, pvarValue, NULL, NULL);
|
|
SysFreeString(bstrProperty);
|
|
|
|
if (FAILED(hr))
|
|
hr = E_MSINFO_NOPROPERTY;
|
|
}
|
|
else
|
|
hr = E_FAIL;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Get the named value as a string.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT CWMILiveObject::GetValueString(LPCTSTR szProperty, LPTSTR * pszValue)
|
|
{
|
|
VARIANT variant;
|
|
|
|
HRESULT hr = GetValue(szProperty, &variant);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If the property we just got is an array, we should convert it to string
|
|
// containing a list of the items in the array.
|
|
|
|
if ((variant.vt & VT_ARRAY) && (variant.vt & VT_BSTR) && variant.parray)
|
|
{
|
|
if (SafeArrayGetDim(variant.parray) == 1)
|
|
{
|
|
long lLower = 0, lUpper = 0;
|
|
|
|
SafeArrayGetLBound(variant.parray, 0, &lLower);
|
|
SafeArrayGetUBound(variant.parray, 0, &lUpper);
|
|
|
|
CString strWorking;
|
|
BSTR bstr = NULL;
|
|
for (long i = lLower; i <= lUpper; i++)
|
|
if (SUCCEEDED(SafeArrayGetElement(variant.parray, &i, (wchar_t*)&bstr)))
|
|
{
|
|
if (i != lLower)
|
|
strWorking += _T(", ");
|
|
strWorking += bstr;
|
|
}
|
|
*pstrValue = strWorking;
|
|
}
|
|
}
|
|
else if (VariantChangeType(&variant, &variant, 0, VT_BSTR) == S_OK)
|
|
{
|
|
*pstrValue = V_BSTR(&variant);
|
|
}
|
|
else
|
|
{
|
|
hr = E_MSINFO_NOVALUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CWMILiveObject::GetValueDWORD(LPCTSTR szProperty, DWORD * pdwValue)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT CWMILiveObject::GetValueTime(LPCTSTR szProperty, SYSTEMTIME * psystimeValue)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT CWMILiveObject::GetValueDoubleFloat(LPCTSTR szProperty, double * pdblValue)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT CWMILiveObject::GetValueValueMap(LPCTSTR szProperty, LPTSTR * pszValue)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
#endif |