2025-04-27 07:49:33 -04:00

861 lines
21 KiB
C++

/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
CONTEXT.CPP
Abstract:
CWbemContext Implementation
History:
--*/
#include "precomp.h"
#include <stdio.h>
#include <wbemcomn.h>
#include "context.h"
#define MAX_VARIANT_SIZE 8
DWORD GetBSTRMarshalSize(BSTR str)
{
return wcslen(str)*2 + sizeof(long);
}
HRESULT MarshalBSTR(IStream* pStream, BSTR str)
{
HRESULT hres;
long lLen = wcslen(str);
hres = pStream->Write((void*)&lLen, sizeof(lLen), NULL);
if(FAILED(hres)) return hres;
return pStream->Write((void*)str, lLen*2, NULL);
}
HRESULT UnmarshalBSTR(IStream* pStream, BSTR& str)
{
long lLen;
HRESULT hres;
hres = pStream->Read((void*)&lLen, sizeof(lLen), NULL);
if(FAILED(hres)) return hres;
str = SysAllocStringLen(NULL, lLen);
hres = pStream->Read((void*)str, lLen*2, NULL);
if(FAILED(hres))
{
SysFreeString(str);
return hres;
}
str[lLen] = 0;
return S_OK;
}
DWORD GetSafeArrayMarshalSize(VARTYPE vt, SAFEARRAY* psa)
{
HRESULT hres;
DWORD dwLen = sizeof(long)*2; // num elements and size of element
// Compute vital statistics
// ========================
long lLBound, lUBound;
SafeArrayGetLBound(psa, 1, &lLBound);
SafeArrayGetUBound(psa, 1, &lUBound);
long lNumElements = lUBound - lLBound + 1;
DWORD dwElemSize = SafeArrayGetElemsize(psa);
BYTE* pData;
SafeArrayAccessData(psa, (void**)&pData);
CUnaccessMe um(psa);
if(vt == VT_BSTR)
{
// Add all BSTR sizes
// ==================
BSTR* pstrData = (BSTR*)pData;
for(int i = 0; i < lNumElements; i++)
{
dwLen += GetBSTRMarshalSize(pstrData[i]);
}
}
else if(vt == VT_EMBEDDED_OBJECT)
{
I_EMBEDDED_OBJECT** apObjects = (I_EMBEDDED_OBJECT**)pData;
for(int i = 0; i < lNumElements; i++)
{
DWORD dwThis = 0;
hres = CoGetMarshalSizeMax(&dwThis, IID_IWbemClassObject,
apObjects[i],
MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL);
if(FAILED(hres)) return hres;
dwLen += dwThis;
}
}
else
{
dwLen += lNumElements*dwElemSize;
}
return dwLen;
}
HRESULT MarshalSafeArray(IStream* pStream, VARTYPE vt, SAFEARRAY* psa)
{
HRESULT hres;
// First, write the number of elements
// ===================================
long lLBound, lUBound;
SafeArrayGetLBound(psa, 1, &lLBound);
SafeArrayGetUBound(psa, 1, &lUBound);
long lNumElements = lUBound - lLBound + 1;
hres = pStream->Write((void*)&lNumElements, sizeof(lNumElements), NULL);
if(FAILED(hres)) return hres;
// Second, write element size
// ==========================
DWORD dwElemSize = SafeArrayGetElemsize(psa);
hres = pStream->Write((void*)&dwElemSize, sizeof(dwElemSize), NULL);
if(FAILED(hres)) return hres;
// Now, write all the elements out
// ===============================
BYTE* pData;
SafeArrayAccessData(psa, (void**)&pData);
CUnaccessMe um(psa);
if(vt == VT_BSTR)
{
BSTR* astrData = (BSTR*)pData;
for(int i = 0; i < lNumElements; i++)
{
MarshalBSTR(pStream, astrData[i]);
}
}
else if(vt == VT_EMBEDDED_OBJECT)
{
I_EMBEDDED_OBJECT** apObjects = (I_EMBEDDED_OBJECT**)pData;
for(int i = 0; i < lNumElements; i++)
{
hres = CoMarshalInterface(pStream, IID_IWbemClassObject,
apObjects[i], MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL);
if(FAILED(hres)) return hres;
}
}
else
{
// Just dump the data
// ==================
hres = pStream->Write((void*)pData, dwElemSize*lNumElements, NULL);
if(FAILED(hres)) return hres;
}
return S_OK;
}
HRESULT UnmarshalSafeArray(IStream* pStream, VARTYPE vt, SAFEARRAY*& psa)
{
HRESULT hres;
// Read the number of elements
// ===========================
long lNumElements;
hres = pStream->Read((void*)&lNumElements, sizeof(lNumElements), NULL);
if(FAILED(hres)) return hres;
// Read the size of an element
// ===========================
DWORD dwElemSize;
hres = pStream->Read((void*)&dwElemSize, sizeof(dwElemSize), NULL);
if(FAILED(hres)) return hres;
// Create the appropriate SafeArray
// ================================
SAFEARRAYBOUND sab;
sab.lLbound = 0;
sab.cElements = lNumElements;
psa = SafeArrayCreate(vt, 1, &sab);
if(psa == NULL)
return E_FAIL;
BYTE* pData;
SafeArrayAccessData(psa, (void**)&pData);
CUnaccessMe um(psa);
if(vt == VT_BSTR)
{
// Read all the BSTRs
// ==================
BSTR* astrData = (BSTR*)pData;
for(int i = 0; i < lNumElements; i++)
{
UnmarshalBSTR(pStream, astrData[i]);
}
}
else if(vt == VT_EMBEDDED_OBJECT)
{
// Read all the objects
// ====================
I_EMBEDDED_OBJECT** apObjects = (I_EMBEDDED_OBJECT**)pData;
for(int i = 0; i < lNumElements; i++)
{
hres = CoUnmarshalInterface(pStream, IID_IWbemClassObject,
(void**)(apObjects + i));
if(FAILED(hres)) return hres;
}
}
else
{
// Read the block
// ==============
hres = pStream->Read((void*)pData, dwElemSize*lNumElements, NULL);
if(FAILED(hres)) return hres;
}
return S_OK;
}
CWbemContext::CContextObj::CContextObj() : m_strName(NULL), m_lFlags(0)
{
VariantInit(&m_vValue);
}
CWbemContext::CContextObj::CContextObj(LPCWSTR wszName, long lFlags,
VARIANT* pvValue)
: m_lFlags(lFlags), m_strName(SysAllocString(wszName))
{
VariantInit(&m_vValue);
VariantCopy(&m_vValue, pvValue);
}
CWbemContext::CContextObj::CContextObj(const CContextObj& Obj)
: m_lFlags(Obj.m_lFlags), m_strName(SysAllocString(Obj.m_strName))
{
VariantInit(&m_vValue);
VariantCopy(&m_vValue, (VARIANT*)&Obj.m_vValue);
}
CWbemContext::CContextObj::~CContextObj()
{
VariantClear(&m_vValue);
SysFreeString(m_strName);
}
DWORD CWbemContext::CContextObj::GetMarshalSizeMax()
{
// First, the name
// ===============
DWORD dwLength = GetBSTRMarshalSize(m_strName);
// Then the flags
// ==============
dwLength += sizeof(m_lFlags);
// Then the VARTYPE
// ================
dwLength += sizeof(VARTYPE);
// Then the actual data
// ====================
switch(V_VT(&m_vValue))
{
case VT_NULL:
break;
case VT_BSTR:
dwLength += GetBSTRMarshalSize(V_BSTR(&m_vValue));
break;
case VT_EMBEDDED_OBJECT:
{
DWORD dwThis = 0;
CoGetMarshalSizeMax(&dwThis, IID_IWbemClassObject,
V_EMBEDDED_OBJECT(&m_vValue),
MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL);
dwLength += dwThis;
}
break;
default:
if(V_VT(&m_vValue) & VT_ARRAY)
{
dwLength += GetSafeArrayMarshalSize(V_VT(&m_vValue) & ~VT_ARRAY,
V_ARRAY(&m_vValue));
}
else
{
dwLength += MAX_VARIANT_SIZE;
}
}
return dwLength;
}
HRESULT CWbemContext::CContextObj::Marshal(IStream* pStream)
{
// Write the name
// ==============
MarshalBSTR(pStream, m_strName);
// Write the flags
// ===============
pStream->Write((void*)&m_lFlags, sizeof(m_lFlags), NULL);
// Write the VARTYPE
// =================
pStream->Write((void*)&V_VT(&m_vValue), sizeof(VARTYPE), NULL);
// Write the data
// ==============
switch(V_VT(&m_vValue))
{
case VT_NULL:
break;
case VT_BSTR:
MarshalBSTR(pStream, V_BSTR(&m_vValue));
break;
case VT_EMBEDDED_OBJECT:
CoMarshalInterface(pStream, IID_IWbemClassObject,
V_EMBEDDED_OBJECT(&m_vValue),
MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL);
break;
default:
if(V_VT(&m_vValue) & VT_ARRAY)
{
MarshalSafeArray(pStream, V_VT(&m_vValue) & ~VT_ARRAY,
V_ARRAY(&m_vValue));
}
else
{
pStream->Write(&V_UI1(&m_vValue), MAX_VARIANT_SIZE, NULL);
}
break;
}
return S_OK;
}
HRESULT CWbemContext::CContextObj::Unmarshal(IStream* pStream)
{
// Read the name
// =============
UnmarshalBSTR(pStream, m_strName);
// Read the flags
// ==============
pStream->Read((void*)&m_lFlags, sizeof(m_lFlags), NULL);
// Read the VARTYPE
// ================
pStream->Read((void*)&V_VT(&m_vValue), sizeof(VARTYPE), NULL);
// Read the data
// =============
switch(V_VT(&m_vValue))
{
case VT_NULL:
break;
case VT_BSTR:
UnmarshalBSTR(pStream, V_BSTR(&m_vValue));
break;
case VT_EMBEDDED_OBJECT:
CoUnmarshalInterface(pStream, IID_IWbemClassObject,
(void**)&V_EMBEDDED_OBJECT(&m_vValue));
break;
default:
if(V_VT(&m_vValue) & VT_ARRAY)
{
UnmarshalSafeArray(pStream, V_VT(&m_vValue) & ~VT_ARRAY,
V_ARRAY(&m_vValue));
}
else
{
pStream->Read(&V_UI1(&m_vValue), MAX_VARIANT_SIZE, NULL);
}
break;
}
return S_OK;
}
CWbemContext::CWbemContext(CLifeControl* pControl)
: m_lRef(0), m_dwCurrentIndex(0xFFFFFFFF), m_lNumChildren(0),
m_lNumParents(0), m_lNumSiblings(0), m_pControl( pControl )
{
if ( NULL != m_pControl )
{
m_pControl->ObjectCreated((IWbemContext*)this);
}
m_dwNumRequests = 1;
m_aRequests = new GUID;
AssignId();
}
CWbemContext::CWbemContext(const CWbemContext& Other, DWORD dwExtraSpace)
: m_lRef(0), m_dwCurrentIndex(0xFFFFFFFF), m_lNumChildren(0),
m_lNumParents(0), m_lNumSiblings(0), m_pControl( NULL )
{
// Copy the life control
m_pControl = Other.m_pControl;
if ( NULL != m_pControl )
{
m_pControl->ObjectCreated((IWbemContext*)this);
}
// Copy data
// =========
for(int i = 0; i < Other.m_aObjects.GetSize(); i++)
{
m_aObjects.Add(new CContextObj(*Other.m_aObjects[i]));
}
// Allocate causality string
// =========================
m_dwNumRequests = Other.m_dwNumRequests + dwExtraSpace;
m_aRequests = new GUID[m_dwNumRequests];
// Copy the current string, leaving space
// ======================================
if(Other.m_dwNumRequests > 0)
{
memcpy(m_aRequests + dwExtraSpace, Other.m_aRequests,
Other.m_dwNumRequests * sizeof(GUID));
}
}
CWbemContext::~CWbemContext()
{
delete [] m_aRequests;
if ( NULL != m_pControl )
{
m_pControl->ObjectDestroyed((IWbemContext*)this);
}
}
STDMETHODIMP CWbemContext::CreateChild(IWbemCausalityAccess** ppChild)
{
CInCritSec ics(&m_cs);
CWbemContext* pNewCtx = new CWbemContext(*this, 1);
pNewCtx->AssignId();
pNewCtx->m_lNumSiblings = m_lNumSiblings + m_lNumChildren;
pNewCtx->m_lNumParents = m_lNumParents + 1;
m_lNumChildren++;
return pNewCtx->QueryInterface(IID_IWbemCausalityAccess, (void**)ppChild);
}
STDMETHODIMP CWbemContext::GetRequestId(GUID* pId)
{
CInCritSec ics(&m_cs);
if(m_dwNumRequests == 0)
{
*pId = GUID_NULL;
return S_FALSE;
}
else
{
*pId = m_aRequests[0];
return S_OK;
}
}
STDMETHODIMP CWbemContext::GetParentId(GUID* pId)
{
CInCritSec ics(&m_cs);
if(m_dwNumRequests < 2)
{
*pId = GUID_NULL;
return S_FALSE;
}
else
{
*pId = m_aRequests[1];
return S_OK;
}
}
STDMETHODIMP CWbemContext::IsChildOf(GUID Id)
{
CInCritSec ics(&m_cs);
for(DWORD dw = 0; dw < m_dwNumRequests; dw++)
{
if(m_aRequests[dw] == Id)
return S_OK;
}
return S_FALSE;
}
STDMETHODIMP CWbemContext::GetHistoryInfo(long* plNumParents,
long* plNumSiblings)
{
CInCritSec ics(&m_cs);
*plNumParents = m_lNumParents;
*plNumSiblings = m_lNumSiblings;
return S_OK;
}
void CWbemContext::AssignId()
{
CInCritSec ics(&m_cs);
CoCreateGuid(m_aRequests);
}
DWORD CWbemContext::FindValue(LPCWSTR wszIndex)
{
CInCritSec ics(&m_cs);
for(int i = 0; i < m_aObjects.GetSize(); i++)
{
if(!wbem_wcsicmp(wszIndex, m_aObjects[i]->m_strName))
{
return i;
}
}
return 0xFFFFFFFF;
}
STDMETHODIMP CWbemContext::QueryInterface(REFIID riid, void** ppv)
{
if(riid == IID_IUnknown || riid == IID_IWbemContext)
{
*ppv = (void*)(IWbemContext*)this;
AddRef();
return S_OK;
}
if(riid == IID_IMarshal)
{
*ppv = (void*)(IMarshal*)this;
AddRef();
return S_OK;
}
if(riid == IID_IWbemCausalityAccess)
{
*ppv = (void*)(IWbemCausalityAccess*)this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP CWbemContext::Clone(IWbemContext** ppCopy)
{
if ( NULL == ppCopy )
{
return WBEM_E_INVALID_PARAMETER;
}
CInCritSec ics(&m_cs);
*ppCopy = new CWbemContext(*this);
(*ppCopy)->AddRef();
return WBEM_S_NO_ERROR;
}
STDMETHODIMP CWbemContext::GetNames(long lFlags, SAFEARRAY** pNames)
{
CInCritSec ics(&m_cs);
SAFEARRAYBOUND sab;
if(lFlags != 0 || !pNames)
return WBEM_E_INVALID_PARAMETER;
sab.cElements = m_aObjects.GetSize();
sab.lLbound = 0;
*pNames = SafeArrayCreate(VT_BSTR, 1, &sab);
for(long i = 0; i < m_aObjects.GetSize(); i++)
{
SafeArrayPutElement(*pNames, &i, m_aObjects[i]->m_strName);
}
return WBEM_S_NO_ERROR;
}
STDMETHODIMP CWbemContext::BeginEnumeration(long lFlags)
{
CInCritSec ics(&m_cs);
if(lFlags != 0)
return WBEM_E_INVALID_PARAMETER;
if(m_dwCurrentIndex != 0xFFFFFFFF)
return WBEM_E_UNEXPECTED;
m_dwCurrentIndex = 0;
return WBEM_S_NO_ERROR;
}
STDMETHODIMP CWbemContext::Next(long lFlags, BSTR* pName, VARIANT* pVal)
{
CInCritSec ics(&m_cs);
if(lFlags != 0)
return WBEM_E_INVALID_PARAMETER;
if(m_dwCurrentIndex == 0xFFFFFFFF)
return WBEM_E_UNEXPECTED;
if(m_dwCurrentIndex >= m_aObjects.GetSize())
return WBEM_S_NO_MORE_DATA;
if(pName)
{
*pName = SysAllocString(m_aObjects[m_dwCurrentIndex]->m_strName);
}
if(pVal)
{
VariantInit(pVal);
VariantCopy(pVal, &m_aObjects[m_dwCurrentIndex]->m_vValue);
}
m_dwCurrentIndex++;
return WBEM_S_NO_ERROR;
}
STDMETHODIMP CWbemContext::EndEnumeration()
{
CInCritSec ics(&m_cs);
if(m_dwCurrentIndex == 0xFFFFFFFF)
return WBEM_E_UNEXPECTED;
m_dwCurrentIndex = 0xFFFFFFFF;
return WBEM_S_NO_ERROR;
}
STDMETHODIMP CWbemContext::SetValue(LPCWSTR NameIndex, long lFlags,
VARIANT* pValue)
{
CInCritSec ics(&m_cs);
// These are all invalid parameters
if( lFlags != 0 || NULL == NameIndex || NULL == pValue )
{
return WBEM_E_INVALID_PARAMETER;
}
DWORD dwIndex = FindValue(NameIndex);
if(dwIndex == 0xFFFFFFFF)
{
m_aObjects.Add(new CContextObj(NameIndex, lFlags, pValue));
}
else
{
CContextObj* pObj = m_aObjects[dwIndex];
VariantCopy(&pObj->m_vValue, pValue);
pObj->m_lFlags = lFlags;
}
return WBEM_S_NO_ERROR;
}
STDMETHODIMP CWbemContext::GetValue(LPCWSTR NameIndex, long lFlags,
VARIANT* pValue)
{
CInCritSec ics(&m_cs);
if(lFlags != 0 || NameIndex == NULL || pValue == NULL)
return WBEM_E_INVALID_PARAMETER;
DWORD dwIndex = FindValue(NameIndex);
if(dwIndex == 0xFFFFFFFF)
return WBEM_E_NOT_FOUND;
VariantInit(pValue);
VariantCopy(pValue, &m_aObjects[dwIndex]->m_vValue);
return WBEM_S_NO_ERROR;
}
STDMETHODIMP CWbemContext::DeleteValue(LPCWSTR NameIndex, long lFlags)
{
CInCritSec ics(&m_cs);
if(lFlags != 0 || NameIndex == NULL)
return WBEM_E_INVALID_PARAMETER;
DWORD dwIndex = FindValue(NameIndex);
if(dwIndex == 0xFFFFFFFF)
{
return WBEM_S_FALSE;
}
m_aObjects.RemoveAt(dwIndex);
return WBEM_S_NO_ERROR;
}
STDMETHODIMP CWbemContext::DeleteAll()
{
CInCritSec ics(&m_cs);
m_aObjects.RemoveAll();
return WBEM_S_NO_ERROR;
}
STDMETHODIMP CWbemContext::MakeSpecial()
{
CInCritSec ics(&m_cs);
// Make the ID of this context NULL
// ================================
m_aRequests[0] = CLSID_NULL;
return S_OK;
}
STDMETHODIMP CWbemContext::IsSpecial()
{
CInCritSec ics(&m_cs);
// Check if the first GUID is NULL
// ===============================
if(m_aRequests[m_dwNumRequests-1] == CLSID_NULL)
return S_OK;
else
return S_FALSE;
}
// IMarshal methods
STDMETHODIMP CWbemContext::GetUnmarshalClass(REFIID riid, void* pv,
DWORD dwDestContext, void* pvReserved,
DWORD mshlFlags, CLSID* pClsid)
{
CInCritSec ics(&m_cs);
*pClsid = CLSID_WbemContext;
return S_OK;
}
STDMETHODIMP CWbemContext::GetMarshalSizeMax(REFIID riid, void* pv,
DWORD dwDestContext, void* pvReserved,
DWORD mshlFlags, ULONG* plSize)
{
CInCritSec ics(&m_cs);
DWORD dwLength = sizeof(DWORD); // length of causality string
dwLength += m_dwNumRequests * sizeof(GUID); // causality string
dwLength += sizeof(DWORD); // number of objects
for(int i = 0; i < m_aObjects.GetSize(); i++)
{
dwLength += m_aObjects[i]->GetMarshalSizeMax();
}
*plSize = dwLength;
return S_OK;
}
STDMETHODIMP CWbemContext::MarshalInterface(IStream* pStream, REFIID riid,
void* pv, DWORD dwDestContext, void* pvReserved,
DWORD mshlFlags)
{
CInCritSec ics(&m_cs);
HRESULT hres;
hres = pStream->Write((void*)&m_dwNumRequests, sizeof(DWORD), NULL);
if(FAILED(hres)) return hres;
hres = pStream->Write((void*)m_aRequests, sizeof(GUID) * m_dwNumRequests,
NULL);
if(FAILED(hres)) return hres;
DWORD dwNum = m_aObjects.GetSize();
hres = pStream->Write((void*)&dwNum, sizeof(DWORD), NULL);
if(FAILED(hres)) return hres;
for(int i = 0; i < m_aObjects.GetSize(); i++)
{
hres = m_aObjects[i]->Marshal(pStream);
if(FAILED(hres)) return hres;
}
return S_OK;
}
STDMETHODIMP CWbemContext::UnmarshalInterface(IStream* pStream, REFIID riid,
void** ppv)
{
CInCritSec ics(&m_cs);
HRESULT hres;
DWORD i;
hres = pStream->Read((void*)&m_dwNumRequests, sizeof(DWORD), NULL);
if(m_dwNumRequests > 0)
{
delete [] m_aRequests;
m_aRequests = new GUID[m_dwNumRequests];
hres = pStream->Read((void*)m_aRequests, sizeof(GUID) * m_dwNumRequests,
NULL);
if(FAILED(hres)) return hres;
}
DWORD dwNum;
hres = pStream->Read((void*)&dwNum, sizeof(DWORD), NULL);
if(FAILED(hres)) return hres;
for(i = 0; i < dwNum; i++)
{
m_aObjects.Add(new CContextObj);
hres = m_aObjects[i]->Unmarshal(pStream);
if(FAILED(hres)) return hres;
}
return QueryInterface(riid, ppv);
}
STDMETHODIMP CWbemContext::ReleaseMarshalData(IStream* pStream)
{
CInCritSec ics(&m_cs);
return S_OK;
}
STDMETHODIMP CWbemContext::DisconnectObject(DWORD dwReserved)
{
CInCritSec ics(&m_cs);
return S_OK;
}