1196 lines
26 KiB
C++
1196 lines
26 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (C) 1996-2001 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
#include "precomp.h"
|
||
|
#include <wbemint.h>
|
||
|
#include <wbemutil.h>
|
||
|
#include <md5wbem.h>
|
||
|
#include <arrtempl.h>
|
||
|
#include "smrtmrsh.h"
|
||
|
#include "buffer.h"
|
||
|
|
||
|
|
||
|
static DWORD g_dwSignature = 0xabcdefab;
|
||
|
static WORD g_dwVersion = 0;
|
||
|
|
||
|
enum { e_ClassIdNone=0,
|
||
|
e_ClassIdHash,
|
||
|
e_ClassIdHashAndPath } ClassIdType_e;
|
||
|
|
||
|
enum { e_DataPartial=0,
|
||
|
e_DataFull } DataType_e;
|
||
|
|
||
|
/****
|
||
|
|
||
|
Packed Object Format
|
||
|
|
||
|
- 4 byte magic number
|
||
|
- 2 byte version number
|
||
|
- 1 byte class id type
|
||
|
- 4 byte class id len
|
||
|
- N byte class id
|
||
|
- 1 byte data type
|
||
|
- 4 byte data len
|
||
|
- N byte data
|
||
|
|
||
|
*****/
|
||
|
|
||
|
#define HDRSIZE 16 // size of msg w/o variable length data.
|
||
|
#define HASHSIZE 16
|
||
|
|
||
|
|
||
|
/**************************************************************************
|
||
|
CWbemObjectWrapper - smooths out differences between Nova and Whistler
|
||
|
***************************************************************************/
|
||
|
|
||
|
class CWbemObjectWrapper
|
||
|
{
|
||
|
CWbemPtr<_IWmiObject> m_pWmiObj;
|
||
|
CWbemPtr<IWbemObjectAccess> m_pObjAccess;
|
||
|
// CWbemPtr<IWbemObjectInternals> m_pObjInt;
|
||
|
|
||
|
public:
|
||
|
|
||
|
HRESULT SetPointer( IWbemClassObject* pObj )
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = pObj->QueryInterface( IID__IWmiObject, (void**)&m_pWmiObj );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
hr = pObj->QueryInterface( IID_IWbemObjectAccess,
|
||
|
(void**)&m_pObjAccess );
|
||
|
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
// hr = pObj->QueryInterface( IID_IWbemObjectInternals,
|
||
|
// (void**)&m_pObjInt );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
operator IWbemObjectAccess* ()
|
||
|
{
|
||
|
IWbemObjectAccess* pAccess;
|
||
|
|
||
|
if ( m_pWmiObj != NULL )
|
||
|
{
|
||
|
pAccess = m_pWmiObj;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pAccess = m_pObjAccess;
|
||
|
}
|
||
|
|
||
|
return pAccess;
|
||
|
}
|
||
|
|
||
|
BOOL IsValid()
|
||
|
{
|
||
|
return m_pWmiObj != NULL || m_pObjAccess != NULL;
|
||
|
}
|
||
|
|
||
|
HRESULT SetObjectParts( LPVOID pMem,
|
||
|
DWORD dwDestBufSize,
|
||
|
DWORD dwParts )
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if ( m_pWmiObj != NULL )
|
||
|
{
|
||
|
hr = m_pWmiObj->SetObjectParts( pMem, dwDestBufSize, dwParts );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = WBEM_E_NOT_SUPPORTED;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT GetObjectParts( LPVOID pDestination,
|
||
|
DWORD dwDestBufSize,
|
||
|
DWORD dwParts,
|
||
|
DWORD *pdwUsed )
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if ( m_pWmiObj != NULL )
|
||
|
{
|
||
|
hr = m_pWmiObj->GetObjectParts( pDestination,
|
||
|
dwDestBufSize,
|
||
|
dwParts,
|
||
|
pdwUsed );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = WBEM_E_NOT_SUPPORTED;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT MergeClassPart( IWbemClassObject* pObj )
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if ( m_pWmiObj != NULL )
|
||
|
{
|
||
|
hr = m_pWmiObj->MergeClassPart( pObj );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = WBEM_E_NOT_SUPPORTED;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
HRESULT GetClassPath( IWbemClassObject* pObj,
|
||
|
LPCWSTR wszNamespace,
|
||
|
PBYTE pBuff,
|
||
|
ULONG cBuff,
|
||
|
ULONG* pcUsed )
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
*pcUsed = 0;
|
||
|
|
||
|
CPropVar vNamespace, vClass;
|
||
|
|
||
|
//
|
||
|
// before trying to optimize the property access, realize that
|
||
|
// class objects do not support handle access to the __Namespace prop.
|
||
|
//
|
||
|
|
||
|
hr = pObj->Get( L"__NAMESPACE", 0, &vNamespace, NULL, NULL );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
hr = pObj->Get( L"__CLASS", 0, &vClass, NULL, NULL );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
if ( V_VT(&vNamespace) == VT_BSTR )
|
||
|
{
|
||
|
wszNamespace = V_BSTR(&vNamespace);
|
||
|
}
|
||
|
|
||
|
if ( wszNamespace == NULL )
|
||
|
{
|
||
|
return WBEM_E_NOT_SUPPORTED;
|
||
|
}
|
||
|
|
||
|
if ( V_VT(&vClass) != VT_BSTR )
|
||
|
{
|
||
|
return WBEM_E_CRITICAL_ERROR;
|
||
|
}
|
||
|
|
||
|
ULONG cNamespace = wcslen(wszNamespace)*2;
|
||
|
ULONG cClass = wcslen(V_BSTR(&vClass))*2;
|
||
|
|
||
|
//
|
||
|
// add 4 for the two null terminators
|
||
|
//
|
||
|
|
||
|
*pcUsed = cNamespace + cClass + 4;
|
||
|
|
||
|
if ( cBuff < *pcUsed )
|
||
|
{
|
||
|
return WBEM_E_BUFFER_TOO_SMALL;
|
||
|
}
|
||
|
|
||
|
ULONG iBuff = 0;
|
||
|
|
||
|
memcpy( pBuff+iBuff, wszNamespace, cNamespace );
|
||
|
iBuff += cNamespace;
|
||
|
|
||
|
*(WCHAR*)(pBuff+iBuff) = ':';
|
||
|
iBuff+= 2;
|
||
|
|
||
|
memcpy( pBuff+iBuff, V_BSTR(&vClass), cClass );
|
||
|
iBuff += cClass;
|
||
|
|
||
|
*(WCHAR*)(pBuff+iBuff) = '\0';
|
||
|
iBuff+= 2;
|
||
|
|
||
|
_DBG_ASSERT( iBuff == *pcUsed );
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT GetClassPartHash( CWbemObjectWrapper& rWrap,
|
||
|
PBYTE pClassPartHash,
|
||
|
ULONG cClassPartHash )
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
//
|
||
|
// Too bad we have to perform a copy here, but no other way. This
|
||
|
// function requires the passed in buffer be big enough to hold both
|
||
|
// the class part and the hash. This is not really too limiting because
|
||
|
// in most cases where this function is used, the caller already has
|
||
|
// enough memory allocated to use here as a workarea.
|
||
|
//
|
||
|
|
||
|
DWORD dwSize;
|
||
|
|
||
|
if ( cClassPartHash >= HASHSIZE )
|
||
|
{
|
||
|
hr = rWrap.GetObjectParts( pClassPartHash+HASHSIZE,
|
||
|
cClassPartHash-HASHSIZE,
|
||
|
WBEM_OBJ_CLASS_PART,
|
||
|
&dwSize );
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
MD5::Transform( pClassPartHash+HASHSIZE, dwSize, pClassPartHash );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = WBEM_E_BUFFER_TOO_SMALL;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
/***************************************************************************
|
||
|
CSmartObjectMarshaler
|
||
|
****************************************************************************/
|
||
|
|
||
|
HRESULT CSmartObjectMarshaler::GetMaxMarshalSize( IWbemClassObject* pObj,
|
||
|
LPCWSTR wszNamespace,
|
||
|
DWORD dwFlags,
|
||
|
ULONG* pulSize )
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
CWbemPtr<IMarshal> pMrsh;
|
||
|
hr = pObj->QueryInterface( IID_IMarshal, (void**)&pMrsh );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// user is requesting the required size to pack object. For now,
|
||
|
// we always use the size of the entire object blob. However, the
|
||
|
// actual size of the object may be much smaller.
|
||
|
//
|
||
|
|
||
|
DWORD dwSize;
|
||
|
|
||
|
hr = pMrsh->GetMarshalSizeMax( IID_IWbemClassObject,
|
||
|
pObj,
|
||
|
MSHCTX_INPROC,
|
||
|
NULL,
|
||
|
0,
|
||
|
&dwSize );
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
*pulSize = dwSize + HDRSIZE + HASHSIZE;
|
||
|
|
||
|
if ( dwFlags == WMIMSG_FLAG_MRSH_PARTIAL )
|
||
|
{
|
||
|
hr = GetClassPath( pObj, wszNamespace, NULL, 0, &dwSize );
|
||
|
|
||
|
if ( hr == WBEM_E_BUFFER_TOO_SMALL )
|
||
|
{
|
||
|
*pulSize += dwSize;
|
||
|
hr = WBEM_S_NO_ERROR;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_DBG_ASSERT( FAILED(hr) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CSmartObjectMarshaler::InternalPack( IWbemClassObject* pObj,
|
||
|
LPCWSTR wszNamespace,
|
||
|
DWORD dwFlags,
|
||
|
ULONG cBuff,
|
||
|
BYTE* pBuff,
|
||
|
ULONG* pcUsed )
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
*pcUsed = 0;
|
||
|
|
||
|
//
|
||
|
// make sure we have enough room for at least the header data.
|
||
|
//
|
||
|
|
||
|
if ( cBuff < HDRSIZE )
|
||
|
{
|
||
|
return WBEM_E_BUFFER_TOO_SMALL;
|
||
|
}
|
||
|
|
||
|
ULONG iBuff = 0;
|
||
|
|
||
|
memcpy( pBuff + iBuff, &g_dwSignature, 4 );
|
||
|
iBuff += 4;
|
||
|
|
||
|
memcpy( pBuff + iBuff, &g_dwVersion, 2 );
|
||
|
iBuff += 2;
|
||
|
|
||
|
//
|
||
|
// write class information
|
||
|
//
|
||
|
|
||
|
DWORD dwSize;
|
||
|
BOOL bPartialData;
|
||
|
|
||
|
CWbemObjectWrapper ObjWrap;
|
||
|
PBYTE pClassPartHash = NULL;
|
||
|
|
||
|
if ( dwFlags == WMIMSG_FLAG_MRSH_FULL_ONCE )
|
||
|
{
|
||
|
hr = ObjWrap.SetPointer( pObj );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// send class part hash for class info
|
||
|
//
|
||
|
|
||
|
*(pBuff+iBuff) = char(e_ClassIdHash);
|
||
|
iBuff++;
|
||
|
|
||
|
dwSize = HASHSIZE;
|
||
|
memcpy( pBuff+iBuff, &dwSize, 4 );
|
||
|
iBuff += 4;
|
||
|
|
||
|
hr = GetClassPartHash( ObjWrap, pBuff+iBuff, cBuff-iBuff );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
pClassPartHash = pBuff+iBuff;
|
||
|
iBuff += HASHSIZE;
|
||
|
|
||
|
//
|
||
|
// see if we've sent the class part before
|
||
|
//
|
||
|
|
||
|
CInCritSec ics( &m_cs );
|
||
|
bPartialData = m_SentMap[pClassPartHash];
|
||
|
}
|
||
|
else if ( dwFlags == WMIMSG_FLAG_MRSH_PARTIAL )
|
||
|
{
|
||
|
hr = ObjWrap.SetPointer( pObj );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// send class path and class part hash for class info
|
||
|
//
|
||
|
|
||
|
*(pBuff+iBuff) = char(e_ClassIdHashAndPath);
|
||
|
iBuff++;
|
||
|
|
||
|
PBYTE pLen = pBuff+iBuff;
|
||
|
iBuff+= 4; // leave room for class info size
|
||
|
|
||
|
hr = GetClassPartHash( ObjWrap, pBuff+iBuff, cBuff-iBuff );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
iBuff += HASHSIZE;
|
||
|
|
||
|
hr = GetClassPath( pObj,
|
||
|
wszNamespace,
|
||
|
pBuff+iBuff,
|
||
|
cBuff-iBuff,
|
||
|
&dwSize );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
iBuff += dwSize;
|
||
|
|
||
|
dwSize += HASHSIZE; // size if both hash and path
|
||
|
|
||
|
memcpy( pLen, &dwSize, 4 );
|
||
|
|
||
|
bPartialData = TRUE;
|
||
|
}
|
||
|
else if ( dwFlags == WMIMSG_FLAG_MRSH_FULL )
|
||
|
{
|
||
|
//
|
||
|
// no class information
|
||
|
//
|
||
|
|
||
|
*(pBuff+iBuff) = char(e_ClassIdNone);
|
||
|
iBuff++;
|
||
|
|
||
|
memset( pBuff + iBuff, 0, 4 );
|
||
|
iBuff += 4;
|
||
|
|
||
|
bPartialData = FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return WBEM_E_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// write data
|
||
|
//
|
||
|
|
||
|
if ( bPartialData )
|
||
|
{
|
||
|
*(pBuff+iBuff) = char(e_DataPartial);
|
||
|
iBuff++;
|
||
|
|
||
|
PBYTE pLen = pBuff+iBuff;
|
||
|
|
||
|
iBuff += 4; // fill in length afterwords.
|
||
|
|
||
|
//
|
||
|
// now get instance part
|
||
|
//
|
||
|
|
||
|
_DBG_ASSERT( ObjWrap.IsValid() );
|
||
|
|
||
|
hr = ObjWrap.GetObjectParts( pBuff+iBuff,
|
||
|
cBuff-iBuff,
|
||
|
WBEM_OBJ_DECORATION_PART |
|
||
|
WBEM_OBJ_INSTANCE_PART,
|
||
|
&dwSize );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
iBuff += dwSize;
|
||
|
|
||
|
//
|
||
|
// go back and set length ..
|
||
|
//
|
||
|
|
||
|
memcpy( pLen, &dwSize, 4 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*(pBuff+iBuff) = char(e_DataFull);
|
||
|
|
||
|
iBuff++;
|
||
|
|
||
|
PBYTE pLen = pBuff+iBuff;
|
||
|
|
||
|
iBuff += 4; // fill in length afterwords.
|
||
|
|
||
|
//
|
||
|
// for now, use MarshalInterface() to marshal object. The reason
|
||
|
// for this is because SetObjectMemory() has a bug where
|
||
|
// it assumes ownership of the memory ( even though the client
|
||
|
// doesn't have access to the allocator used to free it ).
|
||
|
//
|
||
|
|
||
|
CBuffer Strm( pBuff+iBuff, cBuff-iBuff, FALSE );
|
||
|
|
||
|
CWbemPtr<IMarshal> pMrsh;
|
||
|
hr = pObj->QueryInterface( IID_IMarshal, (void**)&pMrsh );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
hr = pMrsh->MarshalInterface( &Strm,
|
||
|
IID_IWbemClassObject,
|
||
|
pObj,
|
||
|
MSHCTX_INPROC,
|
||
|
NULL,
|
||
|
0 );
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// check if we read more data than we can fit into our buffer. We
|
||
|
// can tell this if the buffer is no longer the one we passed in.
|
||
|
//
|
||
|
|
||
|
if ( Strm.GetRawData() != pBuff+iBuff )
|
||
|
{
|
||
|
return WBEM_E_BUFFER_TOO_SMALL;
|
||
|
}
|
||
|
|
||
|
dwSize = Strm.GetIndex();
|
||
|
|
||
|
iBuff += dwSize;
|
||
|
|
||
|
//
|
||
|
// go back and set length of the data.
|
||
|
//
|
||
|
|
||
|
memcpy( pLen, &dwSize, 4 );
|
||
|
|
||
|
if ( dwFlags == WMIMSG_FLAG_MRSH_FULL_ONCE )
|
||
|
{
|
||
|
//
|
||
|
// mark that we've successfully packed the class part once.
|
||
|
//
|
||
|
_DBG_ASSERT( pClassPartHash != NULL );
|
||
|
CInCritSec ics(&m_cs);
|
||
|
m_SentMap[pClassPartHash] = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*pcUsed = iBuff;
|
||
|
|
||
|
return WBEM_S_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP CSmartObjectMarshaler::Pack( IWbemClassObject* pObj,
|
||
|
LPCWSTR wszNamespace,
|
||
|
DWORD dwFlags,
|
||
|
ULONG cBuff,
|
||
|
BYTE* pBuff,
|
||
|
ULONG* pcUsed )
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
ENTER_API_CALL
|
||
|
|
||
|
hr = InternalPack( pObj, wszNamespace, dwFlags, cBuff, pBuff, pcUsed );
|
||
|
|
||
|
if ( hr == WBEM_E_BUFFER_TOO_SMALL )
|
||
|
{
|
||
|
HRESULT hr2;
|
||
|
|
||
|
hr2 = GetMaxMarshalSize( pObj, wszNamespace, dwFlags, pcUsed );
|
||
|
|
||
|
if ( FAILED(hr2) )
|
||
|
{
|
||
|
hr = hr2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
EXIT_API_CALL
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CSmartObjectMarshaler::Flush()
|
||
|
{
|
||
|
CInCritSec ics(&m_cs);
|
||
|
m_SentMap.clear();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
/***************************************************************************
|
||
|
CSmartObjectUnmarshaler
|
||
|
****************************************************************************/
|
||
|
|
||
|
HRESULT CSmartObjectUnmarshaler::EnsureInitialized()
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
CInCritSec ics( &m_cs );
|
||
|
|
||
|
if ( m_pEmptyClass != NULL )
|
||
|
{
|
||
|
return WBEM_S_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// allocate a template class object which we can use for spawning
|
||
|
// 'empty' instances from.
|
||
|
//
|
||
|
|
||
|
CWbemPtr<IWbemClassObject> pEmptyClass;
|
||
|
|
||
|
hr = CoCreateInstance( CLSID_WbemClassObject,
|
||
|
NULL,
|
||
|
CLSCTX_INPROC,
|
||
|
IID_IWbemClassObject,
|
||
|
(void**)&pEmptyClass );
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
VARIANT vName;
|
||
|
V_VT(&vName) = VT_BSTR;
|
||
|
V_BSTR(&vName) = L"__DummyClass";
|
||
|
|
||
|
hr = pEmptyClass->Put( L"__CLASS", 0, &vName, NULL );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// allocate a locator to access namespaces for obtaining class definitions.
|
||
|
//
|
||
|
|
||
|
CWbemPtr<IWbemLocator> pLocator;
|
||
|
|
||
|
hr = CoCreateInstance( CLSID_WbemLocator,
|
||
|
NULL,
|
||
|
CLSCTX_INPROC,
|
||
|
IID_IWbemLocator,
|
||
|
(void**)&pLocator );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate a full object unmarshaler. This is used to create classes
|
||
|
// or instances that were sent in full.
|
||
|
//
|
||
|
|
||
|
hr = CoCreateInstance( CLSID_WbemClassObjectProxy,
|
||
|
NULL,
|
||
|
CLSCTX_INPROC,
|
||
|
IID_IMarshal,
|
||
|
(void**)&m_pUnmrsh );
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
m_pEmptyClass = pEmptyClass;
|
||
|
m_pLocator = pLocator;
|
||
|
|
||
|
return WBEM_S_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
void CSmartObjectUnmarshaler::MakeRoomInCache( DWORD dwSize )
|
||
|
{
|
||
|
while ( !m_Cache.empty() && dwSize + m_ulCacheSize > m_ulMaxCacheSize )
|
||
|
{
|
||
|
DWORD dwLeastRecentTime = 0xffffffff;
|
||
|
ClassPartMap::iterator it, itLeastRecent;
|
||
|
|
||
|
for( it = m_Cache.begin(); it != m_Cache.end(); it++ )
|
||
|
{
|
||
|
CacheRecord& rCurrent = it->second;
|
||
|
|
||
|
if ( rCurrent.m_dwLastUsedTime <= dwLeastRecentTime )
|
||
|
{
|
||
|
itLeastRecent = it;
|
||
|
dwLeastRecentTime = rCurrent.m_dwLastUsedTime;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_DBG_ASSERT( m_ulCacheSize >= itLeastRecent->second.m_dwClassSize );
|
||
|
m_ulCacheSize -= itLeastRecent->second.m_dwClassSize;
|
||
|
m_Cache.erase( itLeastRecent );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT CSmartObjectUnmarshaler::CacheClassPart( PBYTE pClassHash,
|
||
|
DWORD dwSize,
|
||
|
IWbemClassObject* pClassPart )
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
CInCritSec ics(&m_cs);
|
||
|
|
||
|
ClassPartMap::iterator it = m_Cache.find( pClassHash );
|
||
|
|
||
|
if ( it == m_Cache.end() )
|
||
|
{
|
||
|
MakeRoomInCache( dwSize );
|
||
|
|
||
|
if ( dwSize + m_ulCacheSize < m_ulMaxCacheSize )
|
||
|
{
|
||
|
//
|
||
|
// create the record and add to cache.
|
||
|
//
|
||
|
|
||
|
CacheRecord Record;
|
||
|
|
||
|
Record.m_dwClassSize = dwSize;
|
||
|
Record.m_pClassPart = pClassPart;
|
||
|
Record.m_dwLastUsedTime = GetTickCount();
|
||
|
|
||
|
m_Cache[pClassHash] = Record;
|
||
|
m_ulCacheSize += dwSize;
|
||
|
|
||
|
hr = WBEM_S_NO_ERROR;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// the class part size is too big to store in the cache.
|
||
|
//
|
||
|
hr = WBEM_S_FALSE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// already in the cache.
|
||
|
//
|
||
|
hr = WBEM_S_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CSmartObjectUnmarshaler::FindClassPart( PBYTE pClassPartHash,
|
||
|
LPCWSTR wszClassPath,
|
||
|
IWbemClassObject** ppClassPart)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
//
|
||
|
// first try the cache ...
|
||
|
//
|
||
|
|
||
|
ClassPartMap::iterator it;
|
||
|
|
||
|
{
|
||
|
CInCritSec ics(&m_cs);
|
||
|
it = m_Cache.find( pClassPartHash );
|
||
|
|
||
|
if ( it != m_Cache.end() )
|
||
|
{
|
||
|
it->second.m_dwLastUsedTime = GetTickCount();
|
||
|
|
||
|
*ppClassPart = it->second.m_pClassPart;
|
||
|
(*ppClassPart)->AddRef();
|
||
|
|
||
|
// DEBUGTRACE((LOG_ESS,
|
||
|
// "MRSH: Cache Hit !!! %d bytes saved in transmission\n",
|
||
|
// it->second.m_dwClassSize ));
|
||
|
|
||
|
return WBEM_S_NO_ERROR;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// expensive route ... fetch the class object from wmi
|
||
|
//
|
||
|
|
||
|
if ( wszClassPath == NULL )
|
||
|
{
|
||
|
//
|
||
|
// there's nothing we can do.
|
||
|
//
|
||
|
return WBEM_E_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
CWbemPtr<IWbemServices> pSvc;
|
||
|
|
||
|
CWbemBSTR bsNamespace = wszClassPath;
|
||
|
WCHAR* pch = wcschr( bsNamespace, ':' );
|
||
|
|
||
|
if ( pch == NULL )
|
||
|
{
|
||
|
return WBEM_E_INVALID_OBJECT_PATH;
|
||
|
}
|
||
|
|
||
|
*pch++ = '\0';
|
||
|
|
||
|
hr = m_pLocator->ConnectServer( bsNamespace, NULL, NULL,
|
||
|
NULL, 0, NULL, NULL, &pSvc );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
CWbemBSTR bsRelpath = pch;
|
||
|
|
||
|
CWbemPtr<IWbemClassObject> pClass;
|
||
|
|
||
|
hr = pSvc->GetObject( bsRelpath, 0, NULL, &pClass, NULL );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
CWbemPtr<IWbemClassObject> pClassPart;
|
||
|
|
||
|
hr = pClass->SpawnInstance( 0, &pClassPart );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// now we have to verify that hash of the class part and the
|
||
|
// hash sent in the message are the same.
|
||
|
//
|
||
|
|
||
|
CWbemObjectWrapper ObjWrap;
|
||
|
|
||
|
hr = ObjWrap.SetPointer( pClassPart );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
DWORD dwSize;
|
||
|
|
||
|
hr = ObjWrap.GetObjectParts( NULL, 0, WBEM_OBJ_CLASS_PART, &dwSize );
|
||
|
|
||
|
if ( hr != WBEM_E_BUFFER_TOO_SMALL )
|
||
|
{
|
||
|
_DBG_ASSERT( FAILED(hr) );
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
PBYTE pBuff = new BYTE[dwSize+HASHSIZE];
|
||
|
|
||
|
if ( pBuff == NULL )
|
||
|
{
|
||
|
return WBEM_E_OUT_OF_MEMORY;
|
||
|
}
|
||
|
|
||
|
CVectorDeleteMe<BYTE> tdm( pBuff );
|
||
|
|
||
|
hr = GetClassPartHash( ObjWrap, pBuff, dwSize+HASHSIZE );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
if ( memcmp( pBuff, pClassPartHash, HASHSIZE ) == 0 )
|
||
|
{
|
||
|
//
|
||
|
// things look good so cache the class part.
|
||
|
//
|
||
|
|
||
|
hr = CacheClassPart( pClassPartHash, dwSize, pClassPart );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
*ppClassPart = pClassPart;
|
||
|
(*ppClassPart)->AddRef();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// class parts don't match up, nothing else we can do.
|
||
|
//
|
||
|
|
||
|
hr = WBEM_E_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CSmartObjectUnmarshaler::Unpack( ULONG cBuff,
|
||
|
PBYTE pBuff,
|
||
|
DWORD dwFlags,
|
||
|
IWbemClassObject** ppObj,
|
||
|
ULONG* pcUsed )
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
ENTER_API_CALL
|
||
|
|
||
|
*pcUsed = 0;
|
||
|
*ppObj = NULL;
|
||
|
|
||
|
hr = EnsureInitialized();
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
if ( cBuff < HDRSIZE )
|
||
|
{
|
||
|
return WMIMSG_E_INVALIDMESSAGE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// verify signature and version info
|
||
|
//
|
||
|
|
||
|
DWORD dw;
|
||
|
ULONG iBuff = 0;
|
||
|
|
||
|
memcpy( &dw, pBuff + iBuff, 4 );
|
||
|
|
||
|
iBuff += 6; // version info is not currently used;
|
||
|
|
||
|
if ( dw != g_dwSignature )
|
||
|
{
|
||
|
return WMIMSG_E_INVALIDMESSAGE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// obtain the class id type
|
||
|
//
|
||
|
|
||
|
char chClassIdType = *(pBuff + iBuff);
|
||
|
iBuff++;
|
||
|
|
||
|
memcpy( &dw, pBuff + iBuff, 4 );
|
||
|
iBuff += 4;
|
||
|
|
||
|
if ( cBuff - iBuff - 5 < dw ) // 5 is for what's left in the hdr to read
|
||
|
{
|
||
|
return WMIMSG_E_INVALIDMESSAGE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// obtain the class information associated with the data
|
||
|
//
|
||
|
|
||
|
PBYTE pClassPartHash = NULL;
|
||
|
LPCWSTR wszClassPath = NULL;
|
||
|
|
||
|
if ( chClassIdType == e_ClassIdHash )
|
||
|
{
|
||
|
pClassPartHash = pBuff+iBuff;
|
||
|
}
|
||
|
else if ( chClassIdType == e_ClassIdHashAndPath )
|
||
|
{
|
||
|
pClassPartHash = pBuff+iBuff;
|
||
|
wszClassPath = LPWSTR(pBuff+iBuff+HASHSIZE);
|
||
|
|
||
|
if ( *(WCHAR*)(pBuff+iBuff+dw-2) != '\0' )
|
||
|
{
|
||
|
return WMIMSG_E_INVALIDMESSAGE;
|
||
|
}
|
||
|
}
|
||
|
else if ( chClassIdType == e_ClassIdNone )
|
||
|
{
|
||
|
if ( dw != 0 )
|
||
|
{
|
||
|
return WMIMSG_E_INVALIDMESSAGE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return WMIMSG_E_INVALIDMESSAGE;
|
||
|
}
|
||
|
|
||
|
iBuff += dw;
|
||
|
|
||
|
//
|
||
|
// get data part info
|
||
|
//
|
||
|
|
||
|
char chDataType = *(pBuff+iBuff);
|
||
|
iBuff++;
|
||
|
|
||
|
memcpy( &dw, pBuff+iBuff, 4 );
|
||
|
iBuff += 4;
|
||
|
|
||
|
if ( dw > cBuff-iBuff )
|
||
|
{
|
||
|
return WMIMSG_E_INVALIDMESSAGE;
|
||
|
}
|
||
|
|
||
|
CWbemPtr<IWbemClassObject> pObj;
|
||
|
|
||
|
if ( chDataType == e_DataFull )
|
||
|
{
|
||
|
CBuffer Strm( pBuff+iBuff, cBuff-iBuff, FALSE );
|
||
|
|
||
|
hr = m_pUnmrsh->UnmarshalInterface( &Strm,
|
||
|
IID_IWbemClassObject,
|
||
|
(void**)&pObj );
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return WMIMSG_E_INVALIDMESSAGE;
|
||
|
}
|
||
|
|
||
|
dw = Strm.GetIndex();
|
||
|
|
||
|
//
|
||
|
// if there is an associated hash we need to store the class part
|
||
|
// of the unmarshaled object in our cache.
|
||
|
//
|
||
|
|
||
|
if ( pClassPartHash != NULL )
|
||
|
{
|
||
|
//
|
||
|
// create an empty version of the instance to store in the
|
||
|
// cache. All we're interested in storing is the class part.
|
||
|
//
|
||
|
|
||
|
CWbemPtr<IWbemClassObject> pClassPart;
|
||
|
hr = pObj->SpawnInstance( 0, &pClassPart );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
CWbemObjectWrapper ObjWrap;
|
||
|
|
||
|
hr = ObjWrap.SetPointer( pClassPart );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
DWORD dwSize;
|
||
|
|
||
|
hr = ObjWrap.GetObjectParts( NULL,
|
||
|
0,
|
||
|
WBEM_OBJ_CLASS_PART,
|
||
|
&dwSize );
|
||
|
|
||
|
if ( hr != WBEM_E_BUFFER_TOO_SMALL )
|
||
|
{
|
||
|
_DBG_ASSERT( FAILED(hr) );
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
hr = CacheClassPart( pClassPartHash, dwSize, pClassPart );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if ( chDataType == e_DataPartial )
|
||
|
{
|
||
|
CWbemPtr<IWbemClassObject> pClassPart;
|
||
|
|
||
|
_DBG_ASSERT( pClassPartHash != NULL );
|
||
|
|
||
|
hr = FindClassPart( pClassPartHash, wszClassPath, &pClassPart );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
hr = m_pEmptyClass->SpawnInstance( 0, &pObj );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
CWbemObjectWrapper ObjWrap;
|
||
|
|
||
|
hr = ObjWrap.SetPointer( pObj );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// aquires ownership of the memory -- must be CoTaskMemAlloc-ed
|
||
|
// kind of unfortunate - but the memory has to be allocated and
|
||
|
// copied sometime so guess its not that big of a deal.
|
||
|
//
|
||
|
|
||
|
PVOID pInstData = CoTaskMemAlloc( dw );
|
||
|
|
||
|
if ( NULL == pInstData )
|
||
|
{
|
||
|
return WBEM_E_OUT_OF_MEMORY;
|
||
|
}
|
||
|
|
||
|
memcpy( pInstData, pBuff+iBuff, dw );
|
||
|
|
||
|
hr = ObjWrap.SetObjectParts( pInstData,
|
||
|
dw,
|
||
|
WBEM_OBJ_DECORATION_PART |
|
||
|
WBEM_OBJ_INSTANCE_PART );
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
CoTaskMemFree( pInstData );
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
hr = ObjWrap.MergeClassPart( pClassPart );
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return WMIMSG_E_INVALIDMESSAGE;
|
||
|
}
|
||
|
|
||
|
iBuff += dw; // advance the index to account for the data part
|
||
|
|
||
|
pObj->AddRef();
|
||
|
*ppObj = pObj;
|
||
|
*pcUsed = iBuff;
|
||
|
|
||
|
EXIT_API_CALL
|
||
|
|
||
|
return WBEM_S_NO_ERROR;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CSmartObjectUnmarshaler::Flush()
|
||
|
{
|
||
|
CInCritSec ics(&m_cs);
|
||
|
m_Cache.clear();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|