/*++ Copyright (C) 1996-2001 Microsoft Corporation Module Name: VAR.H Abstract: CVar & CVarVector implemntation History: 16-Apr-96 a-raymcc Created. 12//17/98 sanjes - Partially Reviewed for Out of Memory. 18-Mar-99 a-dcrews Added out-of-memory exception handling --*/ #include "precomp.h" #include #include #include #include #include #include #include #include #include static wchar_t g_szNullVarString[1] = {0}; static wchar_t* g_pszNullVarString = &g_szNullVarString[0]; //*************************************************************************** // // CVar::Empty // // Constructor helper. // // This merely clears everything. VT_EMPTY is the default. // //*************************************************************************** void CVar::Init() { m_nStatus = no_error; m_vt = VT_EMPTY; m_bCanDelete = TRUE; memset(&m_value, 0, sizeof(METAVALUE)); } //*************************************************************************** // // CVar::~CVar // // Destructor. // //*************************************************************************** CVar::~CVar() { Empty(); } //*************************************************************************** // // CVar::CVar // // Copy constructor. This is implemented via the assignment operator. // //*************************************************************************** CVar::CVar(const CVar &Src) { m_vt = VT_EMPTY; m_nStatus = no_error; memset(&m_value, 0, sizeof(METAVALUE)); *this = Src; } //*************************************************************************** // // CVar::operator = // // NOTES: // Observe that VT_EX_CVARVECTOR is dedicated to embedded CVarVector objects. // Also, only pointer types require a new allocation + copy, whereas // most of the simple types are directly assignable, in the // label of the switch statement. // //*************************************************************************** CVar& CVar::operator =(const CVar &Src) { Empty(); m_vt = Src.m_vt; m_nStatus = m_nStatus; m_bCanDelete = TRUE; switch (m_vt) { case VT_LPSTR: // Check for an allocation failure if ( NULL != Src.m_value.pStr ) { size_t stringLength = strlen(Src.m_value.pStr) + 1; m_value.pStr = new char[stringLength]; if ( NULL == m_value.pStr ) { throw CX_MemoryException(); } StringCchCopyA( m_value.pStr, stringLength, Src.m_value.pStr ); } else { m_value.pStr = NULL; } break; case VT_LPWSTR: // Check for an allocation failure if ( NULL != Src.m_value.pWStr ) { size_t stringLength = wcslen(Src.m_value.pWStr) + 1; m_value.pWStr = new wchar_t[stringLength]; if ( NULL == m_value.pWStr ) { throw CX_MemoryException(); } StringCchCopyW( m_value.pWStr, stringLength, Src.m_value.pWStr ); } else { m_value.pWStr = NULL; } break; case VT_BSTR: // Check for an allocation failure if ( NULL != Src.m_value.Str ) { m_value.Str = SysAllocString(Src.m_value.Str); if ( NULL == m_value.Str ) { throw CX_MemoryException(); } } else { m_value.Str = NULL; } break; case VT_BLOB: // This will natively throw an exception, but make sure the // original value is cleared in case an exception is thrown // so we don't AV destructing this object ZeroMemory( &m_value.Blob, sizeof( m_value.Blob ) ); m_value.Blob = BlobCopy(&Src.m_value.Blob); break; case VT_CLSID: m_value.pClsId = new CLSID(*Src.m_value.pClsId); // Check for a failed allocation if ( NULL == m_value.pClsId ) { throw CX_MemoryException(); } break; case VT_DISPATCH: m_value.pDisp = Src.m_value.pDisp; if(m_value.pDisp) m_value.pDisp->AddRef(); break; case VT_UNKNOWN: m_value.pUnk = Src.m_value.pUnk; if(m_value.pUnk) m_value.pUnk->AddRef(); break; // CVarVector // ========== case VT_EX_CVARVECTOR: m_value.pVarVector = new CVarVector(*Src.m_value.pVarVector); // Check for a failed allocation if ( NULL == m_value.pVarVector ) { throw CX_MemoryException(); } break; // All remaining simple types. // =========================== default: m_value = Src.m_value; } return *this; } //*************************************************************************** // // CVar::operator == // // Equality test operator. // //*************************************************************************** int CVar::operator ==(CVar &Src) { return CompareTo(Src, TRUE); } BOOL CVar::CompareTo(CVar& Src, BOOL bIgnoreCase) { // If types are not the same, forget the test. // =========================================== if (m_vt != Src.m_vt) return 0; // If here, the types are the same, so test // the fields. // ======================================== switch (m_vt) { case VT_LPSTR: if(bIgnoreCase) { if (wbem_stricmp(m_value.pStr, Src.m_value.pStr) == 0) return 1; } else { if (strcmp(m_value.pStr, Src.m_value.pStr) == 0) return 1; } break; case VT_LPWSTR: case VT_BSTR: if(bIgnoreCase) { if (wbem_wcsicmp(m_value.pWStr, Src.m_value.pWStr) == 0) return 1; } else { if (wcscmp( m_value.pWStr, Src.m_value.pWStr) == 0) return 1; } break; case VT_BLOB: if (BlobLength(&m_value.Blob) != BlobLength(&Src.m_value.Blob)) return 0; if (memcmp(BlobDataPtr(&m_value.Blob), BlobDataPtr(&Src.m_value.Blob), BlobLength(&m_value.Blob)) == 0) return 1; break; case VT_CLSID: if (memcmp(m_value.pClsId, Src.m_value.pClsId, sizeof(CLSID)) == 0) return 1; break; // CVarVector // ========== case VT_EX_CVARVECTOR: if (m_value.pVarVector == Src.m_value.pVarVector) return 1; if (m_value.pVarVector == 0 || Src.m_value.pVarVector == 0) return 0; return *m_value.pVarVector == *Src.m_value.pVarVector; // All remaining simple types. // =========================== case VT_I1: return m_value.cVal == Src.m_value.cVal; case VT_UI1: return m_value.bVal == Src.m_value.bVal; case VT_I2: return m_value.iVal == Src.m_value.iVal; case VT_UI2: return m_value.wVal == Src.m_value.wVal; case VT_I4: return m_value.lVal == Src.m_value.lVal; case VT_UI4: return m_value.dwVal == Src.m_value.dwVal; case VT_BOOL: return m_value.boolVal == Src.m_value.boolVal; case VT_R8: return m_value.dblVal == Src.m_value.dblVal; case VT_R4: return m_value.fltVal == Src.m_value.fltVal; case VT_DISPATCH: // Note: no proper comparison of embedded objects. return m_value.pDisp == Src.m_value.pDisp; case VT_UNKNOWN: // Note: no proper comparison of embedded objects. return m_value.pUnk == Src.m_value.pUnk; case VT_FILETIME: if (memcmp(&m_value.Time, &Src.m_value.Time, sizeof(FILETIME)) == 0) return 1; case VT_NULL: return 1; } return 0; } //*************************************************************************** // // CVar::Empty // // Clears the CVar to 'empty', deallocates any objects based on pointers, // unless bCanDelete is set to FALSE, indicating that the stored pointer // is owned by somebody else. // //*************************************************************************** void CVar::Empty() { if(m_bCanDelete) { // Only pointer types require a deallocation phase. // ================================================= switch (m_vt) { case VT_LPSTR: delete m_value.pStr; break; case VT_LPWSTR: delete m_value.pWStr; break; case VT_BSTR: SysFreeString(m_value.Str); break; case VT_BLOB: BlobClear(&m_value.Blob); break; case VT_CLSID: delete m_value.pClsId; break; case VT_EX_CVARVECTOR: delete m_value.pVarVector; break; case VT_DISPATCH: if(m_value.pDisp) m_value.pDisp->Release(); break; case VT_UNKNOWN: if(m_value.pUnk) m_value.pUnk->Release(); break; } } memset(&m_value, 0, sizeof(METAVALUE)); m_vt = VT_EMPTY; m_nStatus = no_error; m_bCanDelete = TRUE; } //*************************************************************************** // // CVar::IsDataNull // // Determines if this CVar contains a NULL pointer. // //*************************************************************************** BOOL CVar::IsDataNull() { if(m_vt == VT_LPWSTR && m_value.pWStr == NULL) return TRUE; if(m_vt == VT_LPSTR && m_value.pStr == NULL) return TRUE; if(m_vt == VT_BSTR && m_value.Str == NULL) return TRUE; if(m_vt == VT_DISPATCH && m_value.pDisp == NULL) return TRUE; if(m_vt == VT_UNKNOWN && m_value.pUnk == NULL) return TRUE; return FALSE; } //*************************************************************************** // // CVar::SetRaw // // Creates a CVar from raw data. Sets the type and copies the right // number of bytes from the source to METAVALUE. // //*************************************************************************** void CVar::SetRaw(int vt, void* pvData, int nDataLen) { m_vt = vt; memcpy(&m_value, pvData, nDataLen); m_nStatus = no_error; m_bCanDelete = TRUE; } //*************************************************************************** // // CVar::SetSafeArray // // PARAMETERS: // nType // This is the VT_ type indicator of the SAFEARRAY. // pArray // This is the pointer to the SAFEARRAY which will be used as // a source. The SAFEARRAY is not acquired; it is copied. // //*************************************************************************** void CVar::SetSafeArray(int nType, SAFEARRAY *pArray) { CVarVector *pVec = NULL; m_nStatus = no_error; try { pVec = new CVarVector(nType, pArray); // Check for a failed allocation if ( NULL == pVec ) { throw CX_MemoryException(); } SetVarVector(pVec, TRUE); } catch (CX_MemoryException) { // SetVarVector can throw an exception // m_value aquires the pVec pointer, so auto delete will not work if (NULL != pVec) { delete pVec; pVec = NULL; } throw; } } //*************************************************************************** // // CVar::GetNewSafeArray // // RETURN VALUE: // A pointer to newly allocated SAFEARRAY which must be released by // SafeArrayDestroy. // //*************************************************************************** SAFEARRAY *CVar::GetNewSafeArray() { CVarVector *p = (CVarVector *) GetVarVector(); return p->GetNewSafeArray(); } //*************************************************************************** // // CVar::SetValue // // Sets the value based on an incoming VARIANT. A VARIANT containing // a SAFEARRAY is supported as long as it is not an array of VARIANTs. // Some of the other VARIANT types, such as IUnknown, Currency, etc., // are not supported. The complete list is: // VT_UI1, VT_I2, VT_I4, VT_BSTR, VT_BOOL // VT_R4, VT_R8, or SAFEARRAY of any of these. // // PARAMETERS: // pSrc // A pointer to the source VARIANT. This is treated as read-only. // // RETURN VALUES: // no_error // Returned on succcess. // unsupported // Returned if the VARIANT contains unsupported types. // //*************************************************************************** int CVar::SetVariant(VARIANT *pSrc, BOOL fOptimize /*=FALSE*/) { if(pSrc == NULL) { SetAsNull(); return no_error; } // If a SAFEARRAY, check it. // ========================= if (pSrc->vt & VT_ARRAY) { CVarVector *pVec = NULL; try { int nType = pSrc->vt & 0xFF; // Find the type of the array // BEGIN MODIFIED by a-levn // First, check if the incoming SAFEARRAY is NULL // ============================================== SAFEARRAY *pSafeArr; /* if(pSrc->parray == NULL) { pSafeArr = NULL; } else { // Make a copy of the SAFEARRAY using CSafeArray which will NOT // autodestruct // ============================================================ CSafeArray array(pSrc->parray, nType, CSafeArray::no_delete, 0); pSafeArr = array.GetArray(); } */ pSafeArr = pSrc->parray; pVec = new CVarVector( nType, pSafeArr, fOptimize ); // Check for an allocation failure. if ( NULL == pVec ) { throw CX_MemoryException(); } // END MODIFIED if (pVec->Status() != no_error) { // If here, the SAFEARRAY was not compatible. // ========================================== delete pVec; pVec = NULL; m_nStatus = unsupported; m_vt = VT_EMPTY; return unsupported; } SetVarVector(pVec, TRUE); return no_error; } catch(CX_MemoryException) { // new and SetVarVector can throw exceptions // m_value aquires the pVec pointer, so an auto delete will not work if (NULL != pVec) { delete pVec; pVec = NULL; } throw; } } // Simple copies. // ============== switch (pSrc->vt) { case VT_NULL: SetAsNull(); return no_error; case VT_UI1: SetByte(pSrc->bVal); return no_error; case VT_I2: SetShort(pSrc->iVal); return no_error; case VT_I4: SetLong(pSrc->lVal); return no_error; case VT_R4: SetFloat(pSrc->fltVal); return no_error; case VT_R8: SetDouble(pSrc->dblVal); return no_error; case VT_BSTR: SetBSTR(pSrc->bstrVal); return no_error; case VT_BOOL: SetBool(pSrc->boolVal); return no_error; case VT_DISPATCH: SetDispatch(V_DISPATCH(pSrc)); return no_error; case VT_UNKNOWN: SetUnknown(V_UNKNOWN(pSrc)); return no_error; } m_nStatus = unsupported; return unsupported; } //*************************************************************************** // // CVar::GetNewVariant // // RETURN VALUE: // A pointer to a new VARIANT which contains the value of object. // If the original value was a SAFEARRAY, then the VARIANT will contain // the embedded SAFEARRAY. // //*************************************************************************** void CVar::FillVariant(VARIANT* pNew, BOOL fOptimized/* = FALSE*/) { switch (m_vt) { case VT_NULL: V_VT(pNew) = VT_NULL; break; case VT_BOOL: V_VT(pNew) = VT_BOOL; V_BOOL(pNew) = (m_value.boolVal ? VARIANT_TRUE : VARIANT_FALSE); break; case VT_BSTR: // Set type afterwards here so if the SysAlloc throws an exception, the // type will not have been reset to a VT_BSTR which could cause a subtle // memory corruption (or worse) if VariantClear is called - SJS V_BSTR(pNew) = COleAuto::_SysAllocString(m_value.Str); V_VT(pNew) = VT_BSTR; break; case VT_DISPATCH: V_VT(pNew) = VT_DISPATCH; V_DISPATCH(pNew) = m_value.pDisp; if(m_value.pDisp) m_value.pDisp->AddRef(); break; case VT_UNKNOWN: V_VT(pNew) = VT_UNKNOWN; V_UNKNOWN(pNew) = m_value.pUnk; if(m_value.pUnk) m_value.pUnk->AddRef(); break; case VT_UI1: V_VT(pNew) = VT_UI1; V_UI1(pNew) = m_value.bVal; break; case VT_I4: V_VT(pNew) = VT_I4; V_I4(pNew) = m_value.lVal; break; case VT_I2: V_VT(pNew) = VT_I2; V_I2(pNew) = m_value.iVal; break; case VT_R4: V_VT(pNew) = VT_R4; V_R4(pNew) = m_value.fltVal; break; case VT_R8: V_VT(pNew) = VT_R8; V_R8(pNew) = m_value.dblVal; break; // An embedded CVarVector which must be converted // to a SAFEARRAY. // ============================================== case VT_EX_CVARVECTOR: { // Set type afterwards here so if GetNewSafeArray throws an exception, the // type will not have been reset to an Array which could cause a subtle // memory corruption (or worse) if VariantClear is called - SJS if ( fOptimized && m_value.pVarVector->IsOptimized() ) { // This will get the actual SAFEARRAY pointer without // copying what's underneath. Underlying code should // not clear the array, since it is being acquired V_ARRAY(pNew) = m_value.pVarVector->GetSafeArray( TRUE ); V_VT(pNew) = m_value.pVarVector->GetType() | VT_ARRAY; } else { V_ARRAY(pNew) = m_value.pVarVector->GetNewSafeArray(); V_VT(pNew) = m_value.pVarVector->GetType() | VT_ARRAY; } } break; default: COleAuto::_VariantClear(pNew); } } VARIANT *CVar::GetNewVariant() { VARIANT *pNew = new VARIANT; // Check for an allocation failure. if ( NULL == pNew ) { throw CX_MemoryException(); } COleAuto::_VariantInit(pNew); FillVariant(pNew); return pNew; } //*************************************************************************** // //*************************************************************************** int CVar::DumpText(FILE *fStream) { return unsupported; } //*************************************************************************** // // CVar::SetLPWSTR // // Sets the value of the CVar to the indicated LPWSTR. // // PARAMETERS: // pStr // A pointer to the source string. // bAcquire // If TRUE, then the ownership of pStr is trasferred and becomes // the internal pointer to the string. If FALSE, then the string // is copied. // //*************************************************************************** BOOL CVar::SetLPWSTR(LPWSTR pStr, BOOL bAcquire) { m_vt = VT_LPWSTR; if (bAcquire) { m_value.pWStr = pStr; return TRUE; } else { // Check for an allocation failure if ( NULL != pStr ) { size_t stringLength = wcslen(pStr) + 1; m_value.pWStr = new wchar_t[stringLength]; if ( NULL == m_value.pWStr ) { throw CX_MemoryException(); } StringCchCopyW( m_value.pWStr, stringLength, pStr ); } else { m_value.pWStr = NULL; } return TRUE; } } //*************************************************************************** // // CVar::SetLPSTR // // Sets the value of the CVar to the indicated LPSTR. // // PARAMETERS: // pStr // A pointer to the source string. // bAcquire // If TRUE, then the ownership of pStr is trasferred and becomes // the internal pointer to the string. If FALSE, then the string // is copied (it must have been allocated with operator new). // //*************************************************************************** BOOL CVar::SetLPSTR(LPSTR pStr, BOOL bAcquire) { m_vt = VT_LPSTR; if (bAcquire) { m_value.pStr = pStr; return TRUE; } else { if ( NULL != pStr) { size_t stringLength = strlen(pStr) + 1; m_value.pStr = new char[stringLength]; // On failure, throw an exception if ( NULL == m_value.pStr ) { throw CX_MemoryException(); } StringCchCopyA( m_value.pStr, stringLength, pStr ); } else { m_value.pStr = NULL; } return TRUE; } } //*************************************************************************** // // CVar::SetBSTR // // Sets the value of the CVar to the indicated BSTR. // // NOTE: This BSTR value is actually stored as an LPWSTR to avoid // apartment-threading restrictions on real BSTR objects allocated // with COleAuto::_SysAllocString. // // PARAMETERS: // str // A pointer to the string, which is copied into an internal LPWSTR. // bAcquire // If FALSE, then the BSTR is treated as read-only and copied. // If TRUE, then this function becomes owner of the BSTR and // frees it after the copy is made. // //*************************************************************************** BOOL CVar::SetBSTR(BSTR str) { m_vt = VT_BSTR; if (0 == str) { m_value.Str = 0; return TRUE; } m_value.Str = SysAllocString(str); if ( NULL == m_value.Str ) { throw CX_MemoryException(); } // return whether or not we obtained a value return (TRUE ); } //*************************************************************************** // // CVar::SetBSTR // // Sets the value of the CVar to the indicated BSTR. // // NOTE: This BSTR value is actually stored as an LPWSTR to avoid // apartment-threading restrictions on real BSTR objects allocated // with COleAuto::_SysAllocString. // // PARAMETERS: // str // A pointer to the string, which is copied into an internal LPWSTR. // bAcquire // If FALSE, then the BSTR is treated as read-only and copied. // If TRUE, then this function becomes owner of the BSTR and // frees it after the copy is made. // //*************************************************************************** BOOL CVar::SetBSTR(auto_bstr str) { m_vt = VT_BSTR; m_value.Str = str.release(); return TRUE; } //*************************************************************************** // // CVar::GetBSTR // // Returns the BSTR value of the current object. // // RETURN VALUE: // A newly allocated BSTR which must be freed with COleAuto::_SysFreeString(). // //*************************************************************************** BSTR CVar::GetBSTR() { if (m_vt != VT_BSTR) return NULL; return COleAuto::_SysAllocString(m_value.pWStr); } void CVar::SetDispatch(IDispatch* pDisp) { m_vt = VT_DISPATCH; m_value.pDisp = pDisp; if(pDisp) { pDisp->AddRef(); } } void CVar::SetUnknown(IUnknown* pUnk) { m_vt = VT_UNKNOWN; m_value.pUnk = pUnk; if(pUnk) { pUnk->AddRef(); } } //*************************************************************************** // // CVar::SetBlob // // Sets the object to the value of the BLOB object. // // PARAMETERS: // pBlob // A pointer to a valid VT_BLOB object. // bAcquire // If TRUE, then the pointer to the data will be acquired. It must // have been allocated with operator new in the current process, // since operator delete will be used to free it. // //*************************************************************************** void CVar::SetBlob(BLOB *pBlob, BOOL bAcquire) { m_vt = VT_BLOB; if (pBlob == 0) BlobClear(&m_value.Blob); else if (!bAcquire) m_value.Blob = BlobCopy(pBlob); else m_value.Blob = *pBlob; } //*************************************************************************** // // CVar::SetClsId // // Sets the value of the object to a CLSID. // // PARAMETERS: // pClsId // Points the source CLSID. // bAcquire // If TRUE, the ownership of the pointer is transferred to the // object. The CLSID must have been allocated with operator new. // If FALSE, the caller retains ownership and a copy is made. // //*************************************************************************** void CVar::SetClsId(CLSID *pClsId, BOOL bAcquire) { m_vt = VT_CLSID; if (pClsId == 0) m_value.pClsId = 0; else { m_value.pClsId = new CLSID(*pClsId); // Check for an allocation failure. if ( NULL == m_value.pClsId ) { throw CX_MemoryException(); } } } //*************************************************************************** // // CVar::SetVarVector // // Sets the value of the object to the specified CVarVector. This // allows the CVar to contain a complete array. // // PARAMETERS: // pVec // A pointer to the CVarVector object which is the source. // bAcquire // If TRUE, then ownership of the CVarVector is transferred to // the object. If FALSE, a new copy of the CVarVector is made and // the caller retains ownership. // //*************************************************************************** void CVar::SetVarVector(CVarVector *pVec, BOOL bAcquire) { m_vt = VT_EX_CVARVECTOR; if (bAcquire) { // If here, we acquire the caller's pointer. // ========================================= m_value.pVarVector = pVec; return; } // If here, make a copy. // ===================== m_value.pVarVector = new CVarVector(*pVec); // Check for an allocation failure. if ( NULL == m_value.pVarVector ) { throw CX_MemoryException(); } } int CVar::GetOleType() { if(m_vt == VT_EX_CVARVECTOR) { if(m_value.pVarVector == NULL) return VT_ARRAY; else return VT_ARRAY | m_value.pVarVector->GetType(); } else { return m_vt; } } //*************************************************************************** // // CVar::GetText // // Produces textual representation of the Var's type and data // // PARAMETERS: // long lFlags reseved, must be 0 // long lType CIM_TYPE // LPCWSTR szFormat optional formatting string // // //*************************************************************************** BSTR CVar::GetText(long lFlags, long lType, LPCWSTR szFormat) { if(m_vt == VT_EX_CVARVECTOR) { // When we get the text for the array, make sure the CIM_FLAG_ARRAY is masked out BSTR strTemp = GetVarVector()->GetText(lFlags, lType & ~CIM_FLAG_ARRAY); CSysFreeMe auto1(strTemp); size_t bufferSize = COleAuto::_SysStringLen(strTemp) + 3; WCHAR* wszValue = new WCHAR[bufferSize]; // Check for allocation failures if ( NULL == wszValue ) { throw CX_MemoryException(); } CVectorDeleteMe auto2(wszValue); StringCchCopyW(wszValue, bufferSize, L"{"); StringCchCatW(wszValue, bufferSize, strTemp); StringCchCatW(wszValue, bufferSize, L"}"); BSTR strRet = COleAuto::_SysAllocString(wszValue); return strRet; } WCHAR* wszValue = new WCHAR[100]; // Check for allocation failures if ( NULL == wszValue ) { throw CX_MemoryException(); } WCHAR* pwc; int i; if(m_vt == VT_NULL) { delete [] wszValue; return NULL; } if(lType == 0) lType = m_vt; try { switch(lType) { case CIM_SINT8: StringCchPrintfW(wszValue, 100, szFormat ? szFormat : L"%d", (long)(signed char)GetByte()); break; case CIM_UINT8: StringCchPrintfW(wszValue, 100, szFormat ? szFormat : L"%d", GetByte()); break; case CIM_SINT16: StringCchPrintfW(wszValue, 100, szFormat ? szFormat : L"%d", (long)GetShort()); break; case CIM_UINT16: StringCchPrintfW(wszValue, 100, szFormat ? szFormat : L"%d", (long)(USHORT)GetShort()); break; case CIM_SINT32: StringCchPrintfW(wszValue, 100, szFormat ? szFormat : L"%d", GetLong()); break; case CIM_UINT32: StringCchPrintfW(wszValue, 100, szFormat ? szFormat : L"%lu", (ULONG)GetLong()); break; case CIM_BOOLEAN: StringCchPrintfW(wszValue, 100, L"%s", (GetBool()?L"TRUE":L"FALSE")); break; case CIM_REAL32: { // Since the decimal point can be localized, and MOF text should // always be english, we will return values localized to 0x409, CVar var( GetFloat() ); // If this fails, we can't guarantee a good value, // so throw an exception. if ( !var.ChangeTypeToEx( VT_BSTR ) ) { throw CX_Exception(); } StringCchCopyW( wszValue, 100, var.GetLPWSTR() ); } break; case CIM_REAL64: { // Since the decimal point can be localized, and MOF text should // always be english, we will return values localized to 0x409, CVar var( GetDouble() ); // If this fails, we can't guarantee a good value, // so throw an exception. if ( !var.ChangeTypeToEx( VT_BSTR ) ) { throw CX_Exception(); } StringCchCopyW( wszValue, 100, var.GetLPWSTR() ); } break; case CIM_CHAR16: if(GetShort() == 0) StringCchCopyW(wszValue, 100, L"0x0"); else StringCchPrintfW(wszValue, 100, L"'\\x%X'", (WCHAR)GetShort()); break; case CIM_OBJECT: StringCchPrintfW(wszValue, 100, L"\"not supported\""); break; case CIM_REFERENCE: case CIM_DATETIME: case CIM_STRING: case CIM_SINT64: case CIM_UINT64: { // Escape all the quotes // ===================== int nStrLen = wcslen(GetLPWSTR()); delete [] wszValue; wszValue = NULL; wszValue = new WCHAR[nStrLen*2+10]; // Check for allocation failures if ( NULL == wszValue ) { throw CX_MemoryException(); } wszValue[0] = L'"'; pwc = wszValue+1; for(i = 0; i < (int)nStrLen; i++) { WCHAR wch = GetLPWSTR()[i]; if(wch == L'\n') { *(pwc++) = L'\\'; *(pwc++) = L'n'; } else if(wch == L'\t') { *(pwc++) = L'\\'; *(pwc++) = L't'; } else if(wch == L'"' || wch == L'\\') { *(pwc++) = L'\\'; *(pwc++) = wch; } else { *(pwc++) = wch; } } *(pwc++) = L'"'; *pwc = 0; } break; default: StringCchPrintfW(wszValue, 100, L"\"not supported\""); break; } BSTR strRes = COleAuto::_SysAllocString(wszValue); // Still need to clean up this value delete [] wszValue; return strRes; } catch (...) { // Cleanup always if this has a value if ( NULL != wszValue ) { delete [] wszValue; } // Rethrow the exception throw; } } BSTR CVar::TypeToText(int nType) { const WCHAR* pwcType; switch(nType) { case VT_I1: pwcType = L"sint8"; break; case VT_UI1: pwcType = L"uint8"; break; case VT_I2: pwcType = L"sint16"; break; case VT_UI2: pwcType = L"uint16"; break; case VT_I4: pwcType = L"sint32"; break; case VT_UI4: pwcType = L"uint32"; break; case VT_I8: pwcType = L"sint64"; break; case VT_UI8: pwcType = L"uint64"; break; case VT_BOOL: pwcType = L"boolean"; break; case VT_R4: pwcType = L"real32"; break; case VT_R8: pwcType = L"real64"; break; case VT_BSTR: pwcType = L"string"; break; case VT_DISPATCH: pwcType = L"object"; break; case VT_UNKNOWN: pwcType = L"object"; break; default: return NULL; } return COleAuto::_SysAllocString(pwcType); } BSTR CVar::GetTypeText() { if ( m_vt == VT_EX_CVARVECTOR ) { return TypeToText(GetVarVector()->GetType()); } else { return TypeToText(m_vt); } } BOOL CVar::ChangeTypeTo(VARTYPE vtNew) { // TBD: there are more efficient ways! // =================================== // Create a VARIANT // ================ VARIANT v; CClearMe auto1(&v); COleAuto::_VariantInit(&v); FillVariant(&v); // Coerce it // ========= HRESULT hres = COleAuto::_WbemVariantChangeType(&v, &v, vtNew); if(FAILED(hres)) return FALSE; // Load it back in // =============== Empty(); SetVariant(&v, TRUE); // If this is an array, we will now be sitting on an optimized array // meaning that we will have acquired the actual safe array - so we should // make sure that the CVarVector cleans up the array when it is no longer // necessary. We will clear out the variant so it doesn't get deleted // when VariantClear is called. if ( m_vt == VT_EX_CVARVECTOR ) { m_value.pVarVector->SetRawArrayBinding( CSafeArray::auto_delete ); ZeroMemory( &v, sizeof(v) ); } return TRUE; } // Performs localized changes (defaults to 0x409 for this) BOOL CVar::ChangeTypeToEx(VARTYPE vtNew, LCID lcid /*=0x409*/) { // TBD: there are more efficient ways! // =================================== // Create a VARIANT // ================ VARIANT v; CClearMe auto1(&v); COleAuto::_VariantInit(&v); FillVariant(&v); // Coerce it // ========= try { HRESULT hres = COleAuto::_VariantChangeTypeEx(&v, &v, lcid, 0L, vtNew); if(FAILED(hres)) return FALSE; } catch(...) { return FALSE; } // Load it back in // =============== Empty(); SetVariant(&v, TRUE); // If this is an array, we will now be sitting on an optimized array // meaning that we will have acquired the actual safe array - so we should // make sure that the CVarVector cleans up the array when it is no longer // necessary. We will clear out the variant so it doesn't get deleted // when VariantClear is called. if ( m_vt == VT_EX_CVARVECTOR ) { m_value.pVarVector->SetRawArrayBinding( CSafeArray::auto_delete ); ZeroMemory( &v, sizeof(v) ); } return TRUE; } BOOL CVar::ToSingleChar() { // Defer to CVarVector for arrays // ============================== if(m_vt == VT_EX_CVARVECTOR) { return GetVarVector()->ToSingleChar(); } // Anything that's not a string follows normal OLE rules // ===================================================== if(m_vt != VT_BSTR) { return ChangeTypeTo(VT_I2); } // It's a string. Make sure the length is 1 // ======================================== LPCWSTR wsz = GetLPWSTR(); if(wcslen(wsz) != 1) return FALSE; // Take the first character // ======================== WCHAR wc = wsz[0]; Empty(); SetShort(wc); return TRUE; } BOOL CVar::ToUI4() { // Defer to CVarVector for arrays // ============================== if(m_vt == VT_EX_CVARVECTOR) { return GetVarVector()->ToUI4(); } // Create a VARIANT // ================ VARIANT v; CClearMe auto1(&v); COleAuto::_VariantInit(&v); FillVariant(&v); // Coerce it // ========= HRESULT hres = COleAuto::_WbemVariantChangeType(&v, &v, VT_UI4); if(FAILED(hres)) return FALSE; // Load it back in // =============== Empty(); // Here we cheat and reset to VT_I4 so we can natively reset V_VT(&v) = VT_I4; SetVariant(&v); return TRUE; } //*************************************************************************** // // CVarVector::CVarVector // // Default constructor. The caller should not attempt to add any // elements when the internal type is VT_EMPTY. Objects constructed // with this constructor should only be used as l-values in an // assignment of CVarVector objects. // //*************************************************************************** CVarVector::CVarVector() : m_pSafeArray( NULL ), m_pRawData( NULL ) { m_Array.Empty(); m_nType = VT_EMPTY; m_nStatus = no_error; } //*************************************************************************** // // CVarVector::CVarVector // // This is the standard constructor. // // PARAMETERS: // nVarType // An OLE VT_ type indicator. Heterogeneous arrays are possible // if the type VT_EX_CVAR is used. Embedded CVarVectors can // occur, since a CVar can in turn hold a CVarVector. // // nInitSize // The starting size of the internal CFlexArray. See FLEXARRY.CPP. // nGrowBy // The "grow by" factor of the internal CFlexArray. See FLEXARRAY.CPP. // //*************************************************************************** CVarVector::CVarVector( int nVarType, int nInitSize, int nGrowBy ) : m_Array(nInitSize, nGrowBy), m_pSafeArray( NULL ), m_pRawData( NULL ) { m_nType = nVarType; m_nStatus = no_error; } //*************************************************************************** // // CVarVector::CVarVector // // Alternate constructor to build a new CVarVector based on a // SAFEARRAY object. The only supported types for the SAFEARRAY // are VT_BSTR, VT_UI1, VT_I2, VT_I4, VT_R4, and VT_R8. // // PARAMETERS: // nVarType // The VT_ type indicator of the incoming SAFEARRAY. // pSrc // A pointer to a SAFEARRAY, which is treated as read-only. // // NOTES: // This will set the internal m_nStatus variable to if // an unsupported VT_ type is in the SAFEARRAY. The caller can immediately // call CVarVector::Status() after construction to see if the operation // was successful. // //*************************************************************************** CVarVector::CVarVector(int nVarType, SAFEARRAY *pSrc, BOOL fOptimized /*= FALSE*/) : m_pSafeArray( NULL ), m_pRawData( NULL ) { SAFEARRAY* pNew = NULL; try { m_nType = nVarType; // If not a valid vector type, this is unsupported if ( !IsValidVectorArray( nVarType, pSrc ) ) { m_nStatus = unsupported; return; } if(pSrc == NULL) { // NULL safearray --- empty // ======================== m_nStatus = no_error; return; } // Bind to the incoming SAFEARRAY, but don't delete it during destruct. // ==================================================================== if(COleAuto::_SafeArrayGetDim(pSrc) != 1) { m_nStatus = unsupported; return; } long lLBound, lUBound; COleAuto::_SafeArrayGetLBound(pSrc, 1, &lLBound); COleAuto::_SafeArrayGetUBound(pSrc, 1, &lUBound); if(lLBound != 0) { // Non-0-based safearray --- since CSafeArray doesn't support that, and // we can't change pSrc, create a copy // ==================================================================== if(FAILED(COleAuto::_SafeArrayCopy(pSrc, &pNew))) { m_nStatus = failed; return; } SAFEARRAYBOUND sfb; sfb.cElements = (lUBound - lLBound) + 1; sfb.lLbound = 0; COleAuto::_SafeArrayRedim(pNew, &sfb); } else { pNew = pSrc; } if ( fOptimized ) { // If we rebased the array, then we need to clean it up on delete, otherwise, // we don't if ( pNew != pSrc ) { m_pSafeArray = new CSafeArray( pNew, nVarType, CSafeArray::auto_delete | CSafeArray::bind); } else { m_pSafeArray = new CSafeArray( pNew, nVarType, CSafeArray::no_delete | CSafeArray::bind); } if ( NULL == m_pSafeArray ) { throw CX_MemoryException(); } if ( m_pSafeArray->Status() != CSafeArray::no_error ) { delete m_pSafeArray; m_pSafeArray = NULL; m_nStatus = failed; } m_nStatus = no_error; } else { CSafeArray sa(pNew, nVarType, CSafeArray::no_delete | CSafeArray::bind); for (int i = 0; i < sa.Size(); i++) { CVar* pVar = NULL; switch (m_nType) { case VT_BOOL: { VARIANT_BOOL boolVal = sa.GetBoolAt(i); pVar = new CVar(boolVal, VT_BOOL); // Check for allocation failure if ( NULL == pVar ) { throw CX_MemoryException(); } if ( m_Array.Add( pVar ) != CFlexArray::no_error ) { delete pVar; throw CX_MemoryException(); } break; } case VT_UI1: { BYTE b = sa.GetByteAt(i); pVar = new CVar(b); // Check for allocation failure if ( NULL == pVar ) { throw CX_MemoryException(); } if ( m_Array.Add( pVar ) != CFlexArray::no_error ) { delete pVar; throw CX_MemoryException(); } break; } case VT_I2: { SHORT s = sa.GetShortAt(i); pVar = new CVar(s); // Check for allocation failure if ( NULL == pVar ) { throw CX_MemoryException(); } if ( m_Array.Add( pVar ) != CFlexArray::no_error ) { delete pVar; throw CX_MemoryException(); } break; } case VT_I4: { LONG l = sa.GetLongAt(i); pVar = new CVar(l); // Check for allocation failure if ( NULL == pVar ) { throw CX_MemoryException(); } if ( m_Array.Add( pVar ) != CFlexArray::no_error ) { delete pVar; throw CX_MemoryException(); } break; } case VT_R4: { float f = sa.GetFloatAt(i); pVar = new CVar(f); // Check for allocation failure if ( NULL == pVar ) { throw CX_MemoryException(); } if ( m_Array.Add( pVar ) != CFlexArray::no_error ) { delete pVar; throw CX_MemoryException(); } break; } case VT_R8: { double d = sa.GetDoubleAt(i); pVar = new CVar(d); // Check for allocation failure if ( NULL == pVar ) { throw CX_MemoryException(); } if ( m_Array.Add( pVar ) != CFlexArray::no_error ) { delete pVar; throw CX_MemoryException(); } break; } case VT_BSTR: { BSTR bstr = sa.GetBSTRAtThrow(i); CSysFreeMe auto1(bstr); pVar = new CVar(VT_BSTR, bstr); // Check for allocation failure if ( NULL == pVar ) { throw CX_MemoryException(); } if ( m_Array.Add( pVar ) != CFlexArray::no_error ) { delete pVar; throw CX_MemoryException(); } break; } case VT_DISPATCH: { IDispatch* pDisp = sa.GetDispatchAt(i); CReleaseMe auto2(pDisp); pVar = new CVar; // Check for allocation failure if ( NULL == pVar ) { throw CX_MemoryException(); } pVar->SetDispatch(pDisp); if ( m_Array.Add( pVar ) != CFlexArray::no_error ) { delete pVar; throw CX_MemoryException(); } break; } case VT_UNKNOWN: { IUnknown* pUnk = sa.GetUnknownAt(i); CReleaseMe auto3(pUnk); pVar = new CVar; // Check for allocation failure if ( NULL == pVar ) { throw CX_MemoryException(); } pVar->SetUnknown(pUnk); if ( m_Array.Add( pVar ) != CFlexArray::no_error ) { delete pVar; throw CX_MemoryException(); } break; } default: m_nStatus = unsupported; if(pNew != pSrc) COleAuto::_SafeArrayDestroy(pNew); return; } } if(pNew != pSrc) COleAuto::_SafeArrayDestroy(pNew); m_nStatus = no_error; } // Else not bound } catch (CX_MemoryException) { // SafeArrayCopy, GetBSTRAtThrow, new can all throw exceptions m_nStatus = failed; if(pNew != pSrc) COleAuto::_SafeArrayDestroy(pNew); throw; } } //*************************************************************************** // // CVarVector::GetNewSafeArray // // Allocates a new SAFEARRAY equivalent to the current CVarVector. // // RETURN VALUE: // A new SAFEARRAY pointer which must be deallocated with // SafeArrayDestroy(). Returns NULL on error or unsupported types. // //*************************************************************************** SAFEARRAY *CVarVector::GetNewSafeArray() { SAFEARRAY *pRetValue = NULL; CSafeArray *pArray = new CSafeArray(m_nType, CSafeArray::no_delete); // Check for an allocation failure if ( NULL == pArray ) { throw CX_MemoryException(); } CDeleteMe auto1(pArray); int nSize = Size(); for (int i = 0; i < nSize; i++) { CVar v; FillCVarAt( i, v ); switch (m_nType) { case VT_UI1: pArray->AddByte(v.GetByte()); break; case VT_I2: pArray->AddShort(v.GetShort()); break; case VT_I4: pArray->AddLong(v.GetLong()); break; case VT_R4: pArray->AddFloat(v.GetFloat()); break; case VT_R8: pArray->AddDouble(v.GetDouble()); break; case VT_BOOL: pArray->AddBool(v.GetBool()); break; case VT_BSTR: { BSTR s = v.GetBSTR(); CSysFreeMe auto2(s); pArray->AddBSTR(s); break; } case VT_DISPATCH: { IDispatch* pDisp = v.GetDispatch(); CReleaseMe auto3(pDisp); pArray->AddDispatch(pDisp); break; } case VT_UNKNOWN: { IUnknown* pUnk = v.GetUnknown(); CReleaseMe auto4(pUnk); pArray->AddUnknown(pUnk); break; } default: // For unsupported types, return a NULL. // Since we constructed the SAFEARRAY object to // not delete the SAFEARRAY and we have encountered // a condition where the internal SAFEARRAY of // CSafeArray should not be returned, we have // to switch our destruct policy. // ================================================ pArray->SetDestructorPolicy(CSafeArray::auto_delete); return 0; } // SWITCH }// FOR enum elements // Final cleanup. Get the SAFEARRAY pointer, and delete // the wrapper. // ===================================================== pArray->Trim(); pRetValue = pArray->GetArray(); return pRetValue; } //*************************************************************************** // // CVarVector::GetSafeArray // // Returns a direct pointer to the underlying SafeArray. If fAcquire is // set, the array is returned, and cleared from underneath // // RETURN VALUE: // A SAFEARRAY pointer which must be deallocated with // SafeArrayDestroy() if fAcquire is set to TRUE // //*************************************************************************** SAFEARRAY *CVarVector::GetSafeArray( BOOL fAcquire /* = FALSE */) { SAFEARRAY* psa = NULL; _DBG_ASSERT( NULL != m_pSafeArray ); if ( NULL != m_pSafeArray ) { if ( fAcquire ) { // Unaccess data if appropriate if ( NULL != m_pRawData ) { m_pSafeArray->Unaccess(); m_pRawData = NULL; } psa = m_pSafeArray->GetArray(); // Now clear the array m_pSafeArray->SetDestructorPolicy( CSafeArray::no_delete ); delete m_pSafeArray; m_pSafeArray = NULL; } else { psa = m_pSafeArray->GetArray(); } } return psa; } //*************************************************************************** // // CVarVector::~CVarVector // // Destructor. // //*************************************************************************** CVarVector::~CVarVector() { Empty(); } //*************************************************************************** // // CVarVector::Empty // //*************************************************************************** void CVarVector::Empty() { if ( NULL != m_pSafeArray ) { delete m_pSafeArray; } for (int i = 0; i < m_Array.Size(); i++) { delete (CVar *) m_Array[i]; } m_Array.Empty(); m_nType = VT_EMPTY; m_nStatus = no_error; m_pSafeArray = NULL; m_pRawData = NULL; } //*************************************************************************** // // CVarVector::CVarVector // // Copy constructor. This is implemented via the assignment operator. // //*************************************************************************** CVarVector::CVarVector(CVarVector &Src) : m_pSafeArray( NULL ), m_pRawData( NULL ) { m_nType = 0; m_nStatus = no_error; *this = Src; } //*************************************************************************** // // CVarVector::operator = // // Assignment operator. // //*************************************************************************** CVarVector& CVarVector::operator =(CVarVector &Src) { Empty(); if ( NULL != Src.m_pSafeArray ) { m_pSafeArray = new CSafeArray( *Src.m_pSafeArray ); if ( NULL != m_pSafeArray ) { if ( m_pSafeArray->Status() != CSafeArray::no_error ) { delete m_pSafeArray; throw CX_MemoryException(); } } else { throw CX_MemoryException(); } } else { for (int i = 0; i < Src.m_Array.Size(); i++) { CVar* pVar = new CVar(*(CVar *) Src.m_Array[i]); // Check for an allocation failure if ( NULL == pVar ) { throw CX_MemoryException(); } if ( m_Array.Add( pVar ) != CFlexArray::no_error ) { delete pVar; throw CX_MemoryException(); } } } m_nStatus = Src.m_nStatus; m_nType = Src.m_nType; return *this; } //*************************************************************************** // // CVarVector::operator == // // Equality test operator. // //*************************************************************************** int CVarVector::operator ==(CVarVector &Src) { return CompareTo(Src, TRUE); } BOOL CVarVector::CompareTo(CVarVector& Src, BOOL bIgnoreCase) { if (m_nType != Src.m_nType) return 0; // Need to do things indirectly here, since we are possibly mixing // CVarVectors not on SAFEARRAYs and those on SAFEARRAYs int Src_Size = Src.Size(); if ( Size() != Src_Size ) return 0; // Allocate the variants for (int i = 0; i < Src_Size; i++) { CVar varThis; CVar varThat; FillCVarAt( i, varThis ); Src.FillCVarAt( i, varThat ); if ( !varThis.CompareTo( varThat, bIgnoreCase ) ) return 0; } return 1; } //*************************************************************************** // // CVarVector::Add // // Adds a new CVar to the array. A reference is used so that anonymous // objects can be constructed in the Add() call: // // pVec->Add(CVar(33)); // // PARAMETERS: // Value // A reference to a CVar object of the correct type for the array. // No type checking is done. // // RETURN VALUE: // no_error // failed // //*************************************************************************** int CVarVector::Add(CVar &Value) { if ( NULL != m_pSafeArray ) { switch ( Value.GetType() ) { case VT_BOOL: // We can store differently from what is expected in Variants, hence we // need to make sure to convert m_pSafeArray->AddBool( Value.GetBool() ? VARIANT_TRUE : VARIANT_FALSE ); break; case VT_UI1: m_pSafeArray->AddByte( Value.GetByte() ); break; case VT_I2: m_pSafeArray->AddShort( Value.GetShort() ); break; case VT_I4: m_pSafeArray->AddLong( Value.GetLong() ); break; case VT_R4: m_pSafeArray->AddFloat( Value.GetFloat() ); break; case VT_R8: m_pSafeArray->AddDouble( Value.GetDouble() ); break; case VT_BSTR: m_pSafeArray->AddBSTR( Value.GetBSTR() ); break; case VT_UNKNOWN: m_pSafeArray->AddUnknown( Value.GetUnknown() ); break; default: return failed; } return no_error; } else { CVar *p = new CVar(Value); // Check for allocation failures if ( NULL == p ) { return failed; } if (m_Array.Add(p) != CFlexArray::no_error) { delete p; return failed; } return no_error; } } //*************************************************************************** // // CVarVector::Add // // Adds a new CVar to the array. This overload simply takes ownership // of the incoming pointer and adds it directly. // // PARAMETERS: // pAcquiredPtr // A pointer to a CVar object which is acquired by the vector. // // RETURN VALUE: // no_error // failed // //*************************************************************************** int CVarVector::Add(CVar *pAcquiredPtr) { // Not a valid operation if we are sitting on a SAFEARRAY _DBG_ASSERT( NULL == m_pSafeArray ); // We don't support this if we are optimized to // us a safe array directly if ( NULL != m_pSafeArray ) { return failed; } if (m_Array.Add(pAcquiredPtr) != CFlexArray::no_error) { return failed; } return no_error; } //*************************************************************************** // // CVarVector::RemoveAt // // Removes the array element at the specified index. // // PARAMETERS: // nIndex // The location at which to remove the element. // // RETURN VALUE: // no_error // On success. // failed // On range errors, etc. // //*************************************************************************** int CVarVector::RemoveAt(int nIndex) { if ( NULL != m_pSafeArray ) { if ( m_pSafeArray->RemoveAt( nIndex ) != CSafeArray::no_error ) { return failed; } } else { CVar *p = (CVar *) m_Array[nIndex]; delete p; if (m_Array.RemoveAt(nIndex) != CFlexArray::no_error) return failed; } return no_error; } //*************************************************************************** // // CVarVector::InsertAt // // Inserts the new element at the specified location. // // PARAMETERS: // nIndex // The location at which to add the new element. // Value // A reference to the new value. // // RETURN VALUE: // no_error // On success. // failed // An invalid nIndex value was specified. // //*************************************************************************** int CVarVector::InsertAt(int nIndex, CVar &Value) { // We don't support this if we are optimized to // us a safe array directly _DBG_ASSERT( NULL == m_pSafeArray ); if ( NULL != m_pSafeArray ) { return failed; } CVar *pNew = new CVar(Value); // Check for allocation failures if ( NULL == pNew ) { return failed; } if (m_Array.InsertAt(nIndex, pNew) != CFlexArray::no_error) { delete pNew; return failed; } return no_error; } BSTR CVarVector::GetText(long lFlags, long lType/* = 0 */) { // Construct an array of values // ============================ BSTR* aTexts = NULL; int i; try { aTexts = new BSTR[Size()]; // Check for allocation failures if ( NULL == aTexts ) { throw CX_MemoryException(); } memset(aTexts, 0, Size() * sizeof(BSTR)); int nTotal = 0; for(i = 0; i < Size(); i++) { CVar v; FillCVarAt( i, v ); aTexts[i] = v.GetText(lFlags, lType); nTotal += COleAuto::_SysStringLen(aTexts[i]) + 2; // 2: for ", " } // Allocate a BSTR to contain them all // =================================== BSTR strRes = COleAuto::_SysAllocStringLen(NULL, nTotal); CSysFreeMe auto2(strRes); *strRes = 0; for(i = 0; i < Size(); i++) { if(i != 0) { StringCchCatW(strRes, nTotal+1, L", "); } StringCchCatW(strRes, nTotal+1, aTexts[i]); COleAuto::_SysFreeString(aTexts[i]); } delete [] aTexts; aTexts = NULL; BSTR strPerfectRes = COleAuto::_SysAllocString(strRes); return strPerfectRes; } catch(CX_MemoryException) { // new, GetText, COleAuto::_SysAllocStringLen and COleAuto::_SysAllocString can all throw exceptions if (NULL != aTexts) { for(int x = 0; x < Size(); x++) { if (NULL != aTexts[x]) COleAuto::_SysFreeString(aTexts[x]); } delete [] aTexts; aTexts = NULL; } throw; } } BOOL CVarVector::ToSingleChar() { // Handle this differently if we are sitting directly on a safearray if ( NULL != m_pSafeArray ) { int nSize = Size(); // One element at a time is converted and copied into the new array CSafeArray* pNewArray = new CSafeArray( VT_I2, CSafeArray::auto_delete, nSize ); for ( int i = 0; i < nSize; i++ ) { CVar v; FillCVarAt( i, v ); if ( !v.ToSingleChar() ) { delete pNewArray; return FALSE; } if ( pNewArray->AddShort( v.GetShort() ) != CSafeArray::no_error ) { delete pNewArray; return FALSE; } } // Now replace the old pointer delete m_pSafeArray; m_pSafeArray = pNewArray; } else { // One element at a time, convert in place for(int i = 0; i < Size(); i++) { if(!GetAt(i).ToSingleChar()) return FALSE; } } // Since all of the conversions succeeded, we will // assume the vector type is now VT_I2. m_nType = VT_I2; return TRUE; } BOOL CVarVector::ToUI4() { // Handle this differently if we are sitting directly on a safearray if ( NULL != m_pSafeArray ) { int nSize = Size(); // One element at a time is converted and copied into the new array CSafeArray* pNewArray = new CSafeArray( VT_I4, CSafeArray::auto_delete, nSize ); for ( int i = 0; i < nSize; i++ ) { CVar v; FillCVarAt( i, v ); if ( !v.ToUI4() ) { delete pNewArray; return FALSE; } if ( pNewArray->AddLong( v.GetLong() ) != CSafeArray::no_error ) { delete pNewArray; return FALSE; } } // Now replace the old pointer delete m_pSafeArray; m_pSafeArray = pNewArray; } else { // One element at a time, convert in place for(int i = 0; i < Size(); i++) { if(!GetAt(i).ToUI4()) return FALSE; } } // Since all of the conversions succeeded, we will // assume the vector type is now VT_I4. m_nType = VT_I4; return TRUE; } BOOL CVarVector::IsValidVectorType( int nVarType ) { if ( VT_BOOL == nVarType || VT_UI1 == nVarType || VT_I2 == nVarType || VT_I4 == nVarType || VT_R4 == nVarType || VT_R8 == nVarType || VT_BSTR == nVarType || VT_DISPATCH == nVarType || VT_UNKNOWN == nVarType ) { return TRUE; } else { return FALSE; } } BOOL CVarVector::IsValidVectorArray( int nVarType, SAFEARRAY* pArray ) { BOOL fReturn = IsValidVectorType( nVarType ); if ( !fReturn ) { // We do supprt VT_VARIANT if the array is zero length if ( VT_VARIANT == nVarType ) { if ( NULL != pArray ) { // If lUBound is 1 less than lLBound, it's a zero length array long lLBound = 0, lUBound = 0; COleAuto::_SafeArrayGetLBound(pArray, 1, &lLBound); COleAuto::_SafeArrayGetUBound(pArray, 1, &lUBound); fReturn = ( lUBound == ( lLBound - 1 ) ); } } // IF VT_VARIANT } // IF Invalid Type return fReturn; } int CVarVector::Size() { if ( NULL == m_pSafeArray ) { return m_Array.Size(); } else { return m_pSafeArray->Size(); } } HRESULT CVarVector::AccessRawArray( void** ppv ) { if ( NULL == m_pSafeArray ) { return E_FAIL; } return m_pSafeArray->Access( ppv ); } HRESULT CVarVector::UnaccessRawArray( void ) { if ( NULL == m_pSafeArray ) { return E_FAIL; } if ( NULL != m_pRawData ) { m_pRawData = NULL; } return m_pSafeArray->Unaccess(); } HRESULT CVarVector::InternalRawArrayAccess( void ) { if ( NULL == m_pSafeArray ) { return E_FAIL; } if ( NULL != m_pRawData ) { return WBEM_E_INVALID_OPERATION; } return m_pSafeArray->Access( &m_pRawData ); } CVar& CVarVector::GetAt(int nIndex) { // Not a valid operation if we are sitting on a SAFEARRAY _DBG_ASSERT( NULL == m_pSafeArray ); if ( NULL == m_pSafeArray ) { return *(CVar *) m_Array[nIndex]; } else { throw CX_VarVectorException(); } } CVar& CVarVector::operator [](int nIndex) { // Not a valid operation if we are sitting on a SAFEARRAY _DBG_ASSERT( NULL == m_pSafeArray ); if ( NULL == m_pSafeArray ) { return *(CVar *) m_Array[nIndex]; } else { throw CX_VarVectorException(); } } void CVarVector::FillCVarAt(int nIndex, CVar& vTemp) { if ( NULL == m_pSafeArray ) { vTemp = *(CVar *) m_Array[nIndex]; } else if ( NULL == m_pRawData ) { switch( m_nType ) { case VT_BOOL: vTemp.SetBool( m_pSafeArray->GetBoolAt( nIndex ) ); break; case VT_UI1: vTemp.SetByte( m_pSafeArray->GetByteAt( nIndex ) ); break; case VT_I2: vTemp.SetShort( m_pSafeArray->GetShortAt( nIndex ) ); break; case VT_I4: vTemp.SetLong( m_pSafeArray->GetLongAt( nIndex ) ); break; case VT_R4: vTemp.SetFloat( m_pSafeArray->GetFloatAt( nIndex ) ); break; case VT_R8: vTemp.SetDouble( m_pSafeArray->GetDoubleAt( nIndex ) ); break; case VT_BSTR: vTemp.SetBSTR( auto_bstr(m_pSafeArray->GetBSTRAtThrow( nIndex ))); break; case VT_UNKNOWN: IUnknown* pUnk = m_pSafeArray->GetUnknownAt(nIndex); CReleaseMe rm( pUnk ); vTemp.SetUnknown( pUnk ); break; } } else { // When we pull data in this state, we're using the CVar as a // passthrough, so it won't do any allocations or addref() // hence it shouldn't do any cleanup either. int nDataLen = 0L; void* pvElement = m_pRawData; switch( m_nType ) { case VT_UI1: nDataLen = sizeof(BYTE); pvElement = (void*) &((BYTE*) m_pRawData)[nIndex]; break; case VT_BOOL: case VT_I2: nDataLen = sizeof(short); pvElement = (void*) &((short*) m_pRawData)[nIndex]; break; case VT_I4: nDataLen = sizeof(long); pvElement = (void*) &((long*) m_pRawData)[nIndex]; break; case VT_R4: nDataLen = sizeof(float); pvElement = (void*) &((float*) m_pRawData)[nIndex]; break; case VT_R8: nDataLen = sizeof(double); pvElement = (void*) &((double*) m_pRawData)[nIndex]; break; case VT_BSTR: nDataLen = sizeof(BSTR); pvElement = (void*) &((BSTR*) m_pRawData)[nIndex]; // If the BSTR is a NULL, old code converted to "", so // we will point to a pointer to "". if ( (*(BSTR*) pvElement ) == NULL ) { pvElement = (void*) &g_pszNullVarString; } break; case VT_UNKNOWN: nDataLen = sizeof(IUnknown*); pvElement = (void*) &((IUnknown**) m_pRawData)[nIndex]; break; } // Splat the raw value in, and Can Delete is FALSE // This is strictly to support optimized pass-through logic vTemp.SetRaw( m_nType, pvElement, nDataLen); vTemp.SetCanDelete( FALSE ); } } // This only works if there are no elements in the safe array BOOL CVarVector::MakeOptimized( int nVarType, int nInitSize, int nGrowBy ) { BOOL fReturn = FALSE; if ( NULL == m_pSafeArray ) { if ( m_Array.Size() == 0 ) { m_pSafeArray = new CSafeArray( nVarType, CSafeArray::auto_delete, nInitSize, nGrowBy ); if ( NULL != m_pSafeArray ) { if ( m_pSafeArray->Status() == CSafeArray::no_error ) { m_nType = nVarType; m_nStatus = no_error; fReturn = TRUE; } else { delete m_pSafeArray; m_pSafeArray = NULL; m_nStatus = failed; } } else { m_nStatus = failed; } } // IF no elements in array } return fReturn; } BOOL CVarVector::DoesVectorTypeMatchArrayType( void ) { // If we have an underlying safe array, sometimes the actualy type of the // data in the safe array may be different from the type that was reported // to us in VARANTARG. This info is critical in determining how we will // go about handling certain operations BOOL fReturn = TRUE; if ( NULL != m_pSafeArray ) { VARTYPE vt; // Only return TRUE if the actual types are equal if ( m_pSafeArray->GetActualVarType( &vt ) == no_error ) { fReturn = ( vt == m_nType ); } else { fReturn = FALSE; } } return fReturn; } void CVarVector::SetRawArrayBinding( int nBinding ) { if ( NULL != m_pSafeArray ) { m_pSafeArray->SetDestructorPolicy( nBinding ); } } HRESULT CVarVector::SetRawArrayData( void* pvData, int nNumElements, int nElementSize ) { _DBG_ASSERT( NULL != m_pSafeArray ); HRESULT hr = WBEM_S_NO_ERROR; if ( NULL != m_pSafeArray ) { if ( m_pSafeArray->SetRawData( pvData, nNumElements, nElementSize ) != CSafeArray::no_error ) hr = WBEM_E_FAILED; } else { hr = WBEM_E_FAILED; } return hr; } HRESULT CVarVector::GetRawArrayData( void* pvDest, int nBuffSize ) { _DBG_ASSERT( NULL != m_pSafeArray ); HRESULT hr = WBEM_S_NO_ERROR; if ( NULL != m_pSafeArray ) { if ( m_pSafeArray->GetRawData( pvDest, nBuffSize ) != CSafeArray::no_error ) hr = WBEM_E_FAILED; } else { hr = WBEM_E_FAILED; } return hr; } BOOL CVarVector::SetRawArraySize( int nSize ) { _DBG_ASSERT( NULL != m_pSafeArray ); BOOL fReturn = FALSE; if ( NULL != m_pSafeArray ) { m_pSafeArray->SetRawArrayMaxElement( nSize - 1 ); fReturn = TRUE; } return fReturn; } int CVarVector::GetElementSize( void ) { _DBG_ASSERT( NULL != m_pSafeArray ); int nReturn = 0L; if ( NULL != m_pSafeArray ) { nReturn = m_pSafeArray->ElementSize(); } return nReturn; }