|
|
/*++
Copyright (C) 1995-2001 Microsoft Corporation
Module Name:
CVARIANT.CPP
Abstract:
Defines the CVarinat class which is a purpose object to wrap VARIANT structures.
History:
a-davj 4-27-95 Created.
--*/
#include "precomp.h"
#include "impdyn.h"
#include "cvariant.h"
//#include <afxpriv.h>
BSTR SysAllocBstrFromTCHAR(TCHAR * pFrom) { #ifdef UNICODE
return SysAllocString(pFrom); #else
WCHAR * pTemp = new WCHAR[lstrlen(pFrom)+1]; if(pTemp == NULL) return NULL; mbstowcs(pTemp, pFrom, lstrlen(pFrom)+1); BSTR bRet = SysAllocString(pTemp); delete pTemp; return bRet; #endif
} //***************************************************************************
//
// int CVariant::CalcNumStrings
//
// DESCRIPTION:
//
// Calculates the number of strings
//
// PARAMETERS:
//
// pTest points to string to test
//
// RETURN VALUE:
// Return - the number of strings in a multistring block.
//
//***************************************************************************
int CVariant::CalcNumStrings( IN TCHAR *pTest) { int iRet = 0; if(pTest == NULL) return 0; while(*pTest) { iRet++; pTest += lstrlen(pTest)+1; } return iRet; }
//***************************************************************************
//
// CVariant::ChangeType
//
// DESCRIPTION:
//
// Changes the CVariant data into a new type.
//
// PARAMETERS:
//
// vtNew Type to convert to
//
// RETURN VALUE:
//
// S_OK if alright, otherwise an error set by OMSVariantChangeType
//
//***************************************************************************
SCODE CVariant::ChangeType( IN VARTYPE vtNew) { SCODE sc;
// if type doesnt need changing, then already done!
if(vtNew == var.vt) return S_OK;
// Create and initialize a temp VARIANT
VARIANTARG vTemp; VariantInit(&vTemp); // Change to the desired type. Then delete the current value
// and copy the temp copy
sc = OMSVariantChangeType(&vTemp,&var,0,vtNew); OMSVariantClear(&var); var = vTemp; // structure copy
return sc; }
//***************************************************************************
//
// CVariant::Clear
//
// DESCRIPTION:
//
// Clears out the VARIANT.
//
//***************************************************************************
void CVariant::Clear(void) { OMSVariantClear(&var); }
//***************************************************************************
//
// CVariant::
// CVariant::~CVariant
//
// DESCRIPTION:
//
// Constructor and destructor.
//
//***************************************************************************
CVariant::CVariant() { VariantInit(&var); memset((void *)&var.lVal,0,8); }
CVariant::CVariant(LPWSTR pwcStr) { VariantInit(&var); if(pwcStr) { var.bstrVal = SysAllocString(pwcStr); if(var.bstrVal) var.vt = VT_BSTR; } }
CVariant::~CVariant() { OMSVariantClear(&var); }
//***************************************************************************
//
// SCODE CVariant::DoPut
//
// DESCRIPTION:
//
// "Puts" the data out to the WBEM server (if pClassInt isnt NULL), or just
// copies the data to the variant.
//
// PARAMETERS:
//
// lFlags flags to pass along to wbem server
// pClassInt pointer to class/instance object
// PropName property name
// pVar variant value
//
// RETURN VALUE:
//
// S_OK if no error other wise see wbemsvc error codes when, pClass isnt
// null, or see the OMSVariantChangeType function.
//
//***************************************************************************
SCODE CVariant::DoPut( IN long lFlags, IN IWbemClassObject FAR * pClassInt, IN BSTR PropName, IN CVariant * pVar) { SCODE sc;
if(pClassInt) {
sc = pClassInt->Put(PropName,lFlags,&var,0); } else if(pVar) { pVar->Clear(); sc = OMSVariantChangeType(&pVar->var,&var,0,var.vt); } else sc = WBEM_E_FAILED; return sc; }
//***************************************************************************
//
// SCODE CVariant::GetArrayData
//
// DESCRIPTION:
//
// Converts array data into a single data block. This is used by the
// registry provider when it writes out array data.
//
// PARAMETERS:
//
// ppData pointer to the return data. Note it is the job of the
// caller to free this when the return code is S_OK
// pdwSize Size of returned data
//
// RETURN VALUE:
//
// S_OK if all is well
// WBEM_E_OUT_OF_MEMORY when we memory allocation fails
// WBEM_E_FAILED when variant has bogus type.
// ??? when failure is in SafeArrayGetElement
//
//***************************************************************************
SCODE CVariant::GetArrayData( OUT void ** ppData, OUT DWORD * pdwSize) { SCODE sc; DWORD dwSoFar = 0; SAFEARRAY * psa; long ix[2] = {0,0}; BYTE * pb; TCHAR * ptc; BOOL bString = ((var.vt & ~VT_ARRAY) == CHARTYPE ||(var.vt & ~VT_ARRAY) == VT_BSTR );
int iNumElements = GetNumElements();
int iSizeOfType = iTypeSize(var.vt); if(iSizeOfType < 1) return WBEM_E_FAILED; // Calculate necessary size;
psa = var.parray; if(bString) { *pdwSize = CHARSIZE; // 1 for the final double null!
for(ix[0] = 0; ix[0] < iNumElements; ix[0]++) { BSTR bstr; sc = SafeArrayGetElement(psa,ix,&bstr); if(FAILED(sc)) return sc; #ifdef UNICODE
*pdwSize += 2 * (wcslen(bstr) +1); #else
int iWCSLen = wcslen(bstr) + 1; *pdwSize += wcstombs(NULL,bstr,iWCSLen) + 1; #endif
SysFreeString(bstr); } } else { *pdwSize = iNumElements * iSizeOfType; }
// Allocate the memory to be filled
*ppData = CoTaskMemAlloc(*pdwSize); if(*ppData == NULL) return WBEM_E_OUT_OF_MEMORY;
pb = (BYTE *)*ppData; ptc = (TCHAR *)*ppData;
// loop for each array element
sc = S_OK; for(ix[0] = 0; ix[0] < iNumElements && sc == S_OK; ix[0]++) { if (bString) { BSTR bstr; sc = SafeArrayGetElement(psa,ix,&bstr); if(sc != S_OK) break; DWORD dwBytesLeft = *pdwSize-dwSoFar; #ifdef UNICODE
lstrcpyn(ptc,bstr,dwBytesLeft/2); #else
wcstombs(ptc,bstr,dwBytesLeft); #endif
dwSoFar += CHARSIZE * (lstrlen(ptc) + 1); ptc += lstrlen(ptc) + 1; SysFreeString(bstr); *ptc = 0; // double null
} else { sc = SafeArrayGetElement(psa,ix,pb); pb += iSizeOfType; } } if(sc != S_OK) CoTaskMemFree(*ppData); return S_OK; }
//***************************************************************************
//
// SCODE CVariant::GetData
//
// DESCRIPTION:
//
// Used by the registry provider to take the data from VARIANT arg format
// into a raw block for output. Note that the data allocated and stuck into
// *ppData should be freed using CoTaskMemFree!
//
// PARAMETERS:
//
// ppData Pointer to output data.
// dwRegType Type to convert to
// pdwSize Pointer to size of returned data
//
// RETURN VALUE:
//
// S_OK if all is well, otherwise a error code which is set by either
// OMSVariantChangeType, or GetArrayData.
//
//***************************************************************************
SCODE CVariant::GetData( OUT void ** ppData, IN DWORD dwRegType, OUT DWORD * pdwSize) {
SCODE sc = S_OK;
// Determine the type it may need to be converted to. Note that binary
// data is not converted intentionally.
switch(dwRegType) { case REG_DWORD: sc = ChangeType(VT_I4); break; case REG_SZ: sc = ChangeType(VT_BSTR); break;
case REG_MULTI_SZ: sc = ChangeType(VT_BSTR | VT_ARRAY); break; default: break; }
if(sc != S_OK) return sc;
// Special case for arrays
if(dwRegType == REG_BINARY || dwRegType == REG_MULTI_SZ) return GetArrayData(ppData, pdwSize);
// Allocate some memory and move the data into it.
if(dwRegType == REG_SZ) { #ifdef UNICODE
*pdwSize = 2 * (wcslen(var.bstrVal)+1); *ppData = CoTaskMemAlloc(*pdwSize); if(*ppData == NULL) return WBEM_E_OUT_OF_MEMORY; StringCchCopyW((WCHAR *)*ppData, *pdwSize/sizeof(WCHAR),var.bstrVal); #else
*ppData = WideToNarrow(var.bstrVal); if(*ppData == NULL) return WBEM_E_OUT_OF_MEMORY; *pdwSize = lstrlenA((char *)*ppData)+1; #endif
} else { *pdwSize = iTypeSize(var.vt); *ppData = CoTaskMemAlloc(*pdwSize); if(*ppData == NULL) return WBEM_E_OUT_OF_MEMORY; memcpy(*ppData,(void *)&var.lVal,*pdwSize); }
return S_OK; }
//***************************************************************************
//
// CVariant::GetNumElements
//
// DESCRIPTION:
//
// Gets the number of elements in an array.
//
// RETURN VALUE:
//
// number of elements. Scalers return a 1.
//
//***************************************************************************
DWORD CVariant::GetNumElements(void) { SCODE sc; if(!IsArray()) return 1; SAFEARRAY * psa = var.parray; long uLower, uUpper; sc = SafeArrayGetLBound(psa,1,&uLower); sc |= SafeArrayGetUBound(psa,1,&uUpper); if(sc != S_OK) return 0; else return uUpper - uLower +1; }
//***************************************************************************
//
// SCODE CVariant::SetArrayData
//
// DESCRIPTION:
//
// Sets the CVariant value using raw data. Used by the reg provider.
//
// PARAMETERS:
//
// pData pointer to data to set
// vtSimple Type to set the data to
// iSize size of data pointed to by pData
//
// RETURN VALUE:
//
// S_OK if OK.
// WBEM_E_INVALID_PARAMETER if the arguments are bad
// WBEM_E_OUT_OF_MEMORY if out of memory
// other wise error from SafeArrayPutElement
//
//***************************************************************************
SCODE CVariant::SetArrayData( IN void * pData, IN VARTYPE vtSimple, IN int iSize) { SCODE sc; int iNumElements; BYTE * pNext; long ix[2] = {0,0}; DWORD dwLeftOver = 0; int iSizeOfType = iTypeSize(vtSimple); if(pData == NULL || iSizeOfType < 1 || iSize < 1) return WBEM_E_INVALID_PARAMETER; // Calculate the number of elements and make sure it is a type that
// is supported
if(vtSimple == VT_BSTR) { iNumElements = CalcNumStrings((TCHAR *)pData); } else { iNumElements = iSize / iSizeOfType; dwLeftOver = iSize % iSizeOfType; } // Allocate array
int iNumCreate = (dwLeftOver) ? iNumElements + 1 : iNumElements; SAFEARRAY * psa = OMSSafeArrayCreate(vtSimple,iNumCreate); if(psa == NULL) return WBEM_E_FAILED;
// Set each element of the array
for(ix[0] = 0, pNext = (BYTE *)pData; ix[0] < iNumElements; ix[0]++) { if(vtSimple == VT_BSTR) { BSTR bstr; bstr = SysAllocBstrFromTCHAR((LPTSTR)pNext); if(bstr == NULL) { // todo, free previously allocated strings!
SafeArrayDestroy(psa); return WBEM_E_OUT_OF_MEMORY; } sc = SafeArrayPutElement(psa,ix,(void*)bstr); pNext += sizeof(TCHAR)*(lstrlen((TCHAR *)pNext) + 1); SysFreeString(bstr); } else { sc = SafeArrayPutElement(psa,ix,pNext); pNext += iSizeOfType; } if(sc) { // todo, cleanup???
SafeArrayDestroy(psa); return sc; } }
// it is possible that the number of bytes being set doesnt evenly factor
// into the type size. For instance, there may be 10 bytes of registry
// data being put into a DWORD array. In this case, the last two bytes
// are left overs
if(dwLeftOver) { __int64 iTemp = 0; memcpy((void *)&iTemp,(void *)pNext,dwLeftOver); sc = SafeArrayPutElement(psa,ix,&iTemp); }
var.vt = vtSimple | VT_ARRAY; var.parray = psa; return S_OK; }
//***************************************************************************
//
// CVariant::SetData
//
// Sets the CVariant value using raw data. Used by the reg provider.
//
// DESCRIPTION:
//
// PARAMETERS:
//
// pData Data to be set
// vtChangeTo Type to change the data to
// iSize size of data pointed to by pData
//
// RETURN VALUE:
//
// S_OK if OK.
// WBEM_E_INVALID_PARAMETER if the arguments are bad
// WBEM_E_OUT_OF_MEMORY if out of memory
// other wise error from SafeArrayPutElement
//
//***************************************************************************
SCODE CVariant::SetData( IN void * pData, IN VARTYPE vtChangeTo, IN int iSize) { int iToSize = iTypeSize(vtChangeTo);
// check arguments and clear the variant
if(pData == NULL || iToSize < 1) return WBEM_E_INVALID_PARAMETER; OMSVariantClear(&var); if(iSize < 1) iSize = iToSize;
// Special case for arrays!
if(vtChangeTo & VT_ARRAY) return SetArrayData(pData,vtChangeTo & ~VT_ARRAY,iSize);
if(vtChangeTo == CIM_SINT64 || vtChangeTo == CIM_UINT64) {
// int64 and uint64 need to be converted to strings
WCHAR wcTemp[50]; __int64 iLong; memcpy((void *)&iLong, pData, 8); if(vtChangeTo == CIM_SINT64) StringCchPrintfW(wcTemp, 50, L"%I64d", iLong); else StringCchPrintfW(wcTemp, 50, L"%I64u", iLong); var.bstrVal = SysAllocString(wcTemp); if(var.bstrVal == NULL) return WBEM_E_OUT_OF_MEMORY; var.vt = VT_BSTR; } else if(vtChangeTo == VT_BSTR) {
// All strings are stored as BSTRS
var.bstrVal = SysAllocBstrFromTCHAR((LPTSTR)pData); if(var.bstrVal == NULL) return WBEM_E_OUT_OF_MEMORY; var.vt = VT_BSTR; } else { memcpy((void *)&var.lVal,pData,iToSize); var.vt = vtChangeTo; } return S_OK; }
|