/////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Microsoft WMIOLE DB Provider // (C) Copyright 1999 Microsoft Corporation. All Rights Reserved. // // dataconvert.cpp // //////////////////////////////////////////////////////////////////////////// #include "headers.h" /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // This function returns the default OLE DB representation for a data type // // To be used only to create tables or any other things // But should not be used for setting properties of type ARRAYS // /////////////////////////////////////////////////////////////////////////////////////////////////////////////// HRESULT CDataMap::MapOLEDBTypeToCIMType(WORD wDataType, long & lCIMType) { HRESULT hr = S_OK; BOOL bArray = FALSE; if( wDataType & DBTYPE_ARRAY) { bArray = TRUE; wDataType = wDataType & ~DBTYPE_ARRAY; } switch( wDataType ){ case DBTYPE_I1: lCIMType = CIM_SINT8; break; case DBTYPE_UI1: lCIMType = CIM_UINT8; break; case DBTYPE_I2: lCIMType = CIM_SINT16; break; case DBTYPE_UI2: lCIMType = CIM_UINT16; break; case DBTYPE_I4: lCIMType = CIM_SINT32; break; case DBTYPE_UI4: lCIMType = CIM_UINT32; break; case DBTYPE_I8: lCIMType = CIM_SINT64; break; case DBTYPE_UI8: lCIMType = CIM_UINT64; break; case DBTYPE_R4: lCIMType = CIM_REAL32; break; case DBTYPE_R8: lCIMType = CIM_REAL64; break; case DBTYPE_BOOL: lCIMType = CIM_BOOLEAN; break; case DBTYPE_WSTR: case DBTYPE_BSTR: case DBTYPE_STR: lCIMType = CIM_STRING; break; case DBTYPE_DATE : case DBTYPE_DBTIME : case DBTYPE_DBTIMESTAMP: lCIMType = CIM_DATETIME; break; case DBTYPE_IDISPATCH : case DBTYPE_IUNKNOWN : lCIMType = CIM_IUNKNOWN; break; case DBTYPE_VARIANT: hr = E_FAIL; break; default: assert( !"Unmatched OLEDB Data Type to CIMTYPE." ); } if( bArray == TRUE) { lCIMType |= CIM_FLAG_ARRAY; } return hr; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Function to Map CIMType to OLEDB type and allocate memory for the data // NTRaid:111819 - 111822 // 06/07/00 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// HRESULT CDataMap::AllocateAndMapCIMTypeToOLEDBType(CVARIANT & vValue,BYTE *& pData,DBTYPE & dwColType,DBLENGTH & dwSize, DWORD &dwFlags) { HRESULT hr = S_OK; SAFEARRAY *pArray = NULL; LONG lType= 0; VARIANT *pVar = NULL,*pvar2 = NULL; pData = NULL; lType = vValue.GetType(); if(lType != VT_NULL && lType != VT_NULL) { lType = dwColType; // If the type is of some array if (dwColType & CIM_FLAG_ARRAY) { lType = CIM_FLAG_ARRAY; } } try { switch( lType ){ case VT_NULL: pData = NULL; hr = DBSTATUS_S_ISNULL; dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case VT_EMPTY: pData = NULL; hr = DBSTATUS_S_ISNULL; dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; // Arrays are always shown as ARRAY of VARIANTS to make it easily accessible with scripting case CIM_FLAG_ARRAY: lType = vValue.GetType(); // since date is given out as string from WMI if(IsDateType((DBTYPE)dwColType)) { lType = dwColType; } hr = ConvertToVariantArray(((VARIANT *)&vValue)->parray,(DBTYPE)lType,(SAFEARRAY **)&pData); dwSize = sizeof(SAFEARRAY); dwColType = VT_ARRAY | VT_VARIANT; dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_SINT8: case CIM_UINT8: pData = new BYTE[1]; if(pData) { *pData = (BYTE)vValue.GetByte(); dwSize = sizeof(BYTE); dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; } else { hr = E_OUTOFMEMORY; } break; case CIM_CHAR16: case CIM_SINT16: case CIM_UINT16: case CIM_BOOLEAN: { dwSize = sizeof(short); pData = new BYTE[dwSize]; short tmp = vValue.GetShort(); if(pData) { memcpy(pData,(BYTE*)&tmp,dwSize); } else { hr = E_OUTOFMEMORY; } } dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_SINT32: case CIM_UINT32: case CIM_REAL32: { dwSize = sizeof(long); long tmp = vValue.GetLONG(); pData = new BYTE[dwSize]; if(pData) { memset(pData,0,dwSize); memcpy(pData,(BYTE*)&tmp,dwSize); } else { hr = E_OUTOFMEMORY; } } dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_SINT64: case CIM_UINT64: case CIM_REAL64: { dwSize = 8; double dblVal = vValue.GetDouble(); pData = new BYTE[dwSize]; if(pData) { memcpy(pData,&dblVal,dwSize); } else { hr = E_OUTOFMEMORY; } } dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_DATETIME: case DBTYPE_DBTIMESTAMP: dwSize = sizeof(DBTIMESTAMP); dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; if( vValue.GetStr() != NULL) { pData = new BYTE[dwSize]; if(pData) { hr = ConvertDateToOledbType(vValue.GetStr(),(DBTIMESTAMP *)pData); dwColType = DBTYPE_DBTIMESTAMP; } else { hr = E_OUTOFMEMORY; } } else { hr = DBSTATUS_S_ISNULL; pData = NULL; dwSize = 0; } break; case VT_DATE: dwSize = sizeof(DBTIMESTAMP); pData = new BYTE[dwSize]; if(pData) { ConvertVariantDateOledbDate(&((VARIANT *)&vValue)->date,(DBTIMESTAMP *)pData); dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; dwColType = DBTYPE_DBTIMESTAMP; } else { hr = E_OUTOFMEMORY; } break; case CIM_STRING: pData = (BYTE *)Wmioledb_SysAllocString(vValue.GetStr()); dwSize = SysStringLen(vValue.GetStr()); break; case CIM_REFERENCE: break; case CIM_OBJECT: break; case CIM_IUNKNOWN: pData = new BYTE[sizeof(IUnknown *)]; if(pData) { memset(pData,0,sizeof(IUnknown *)); hr = vValue.GetUnknown()->QueryInterface(IID_IUnknown,(void **)pData); } else { hr = E_OUTOFMEMORY; } break; case VT_VARIANT: dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; dwSize = sizeof(VARIANT); pVar = new VARIANT; if(pVar) { VariantInit(pVar); hr = VariantCopy(pVar,vValue); dwColType = DBTYPE_VARIANT; pData = (BYTE *) pVar; pvar2 = (VARIANT *)pData; } else { hr = E_OUTOFMEMORY; } break; default: assert( !"Unmatched OLEDB Data Type to CIMTYPE." ); } } // try catch(...) { switch( lType ) { case CIM_FLAG_ARRAY: { if(pData) { SafeArrayDestroy((SAFEARRAY *)pData); } } break; case CIM_STRING: { if(pData) { SysFreeString((BSTR)pData); } } break; case VT_VARIANT: { SAFE_DELETE_PTR((VARIANT *&)pData); } break; case CIM_IUNKNOWN: if(pData) { (*(IUnknown **)pData)->Release(); SAFE_DELETE_ARRAY(pData); } break; default: { SAFE_DELETE_ARRAY(pData); } break; throw; } } return hr; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Free the data allocated to store data ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HRESULT CDataMap::FreeData(DBTYPE lType, BYTE *& pData) { HRESULT hr = S_OK; VARIANT *pVar = NULL; //======================================================================= // See if it is an array //======================================================================= /* if( lType & CIM_FLAG_ARRAY ){ lType = lType &~ CIM_FLAG_ARRAY; fArray = TRUE; } */ // If the pointer sent is not NULL if( lType & CIM_FLAG_ARRAY ) { lType = CIM_FLAG_ARRAY; } if(pData) { switch( lType ){ case VT_EMPTY: break; case VT_NULL: break; case CIM_FLAG_ARRAY: pVar = (VARIANT *)pData; hr = SafeArrayDestroy((SAFEARRAY *)pData); break; case CIM_UINT8: case CIM_SINT8: SAFE_DELETE_PTR((BYTE*)pData); break; case CIM_BOOLEAN: case CIM_CHAR16: case CIM_SINT16: case CIM_UINT16: SAFE_DELETE_PTR((short*&)pData); break; case CIM_REAL32: case CIM_SINT32: case CIM_UINT32: SAFE_DELETE_PTR((DWORD*&)pData); break; case CIM_SINT64: case CIM_UINT64: case CIM_REAL64: SAFE_DELETE_ARRAY((BYTE*)pData); break; case CIM_DATETIME: case DBTYPE_DBTIMESTAMP: SAFE_DELETE_PTR((DBTIMESTAMP *&)pData); break; case CIM_STRING: SysFreeString((BSTR)pData); break; case CIM_REFERENCE: break; case CIM_OBJECT: case CIM_IUNKNOWN: // case DBTYPE_IUNKNOWN: if(pData) { SAFE_RELEASE_PTR((*(IUnknown **)pData)); SAFE_DELETE_ARRAY(pData); } break; case VT_VARIANT: hr = VariantClear((VARIANT *)pData); SAFE_DELETE_PTR((VARIANT *&)pData); break; case DBTYPE_DATE: SAFE_DELETE_PTR((DATE *&)pData); break; default: assert( !"Unmatched OLEDB Data Type to CIMTYPE." ); } } if(hr == S_OK) pData = NULL; return hr; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // This function returns the default OLE DB representation for a data type // /////////////////////////////////////////////////////////////////////////////////////////////////////////////// HRESULT CDataMap::MapCIMTypeToOLEDBType(long lType, WORD & wdbOLEDBType, DBLENGTH & uColumnSize , DWORD &dwFlags) // OUT OLE DB type for DBColumnInfo { HRESULT hr = S_OK; LONG lCimType = lType; if ( lType & CIM_FLAG_ARRAY) { lCimType = CIM_FLAG_ARRAY; } switch( lCimType ){ case VT_EMPTY: wdbOLEDBType = DBTYPE_EMPTY; uColumnSize = 0; dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case VT_NULL: wdbOLEDBType = DBTYPE_NULL; uColumnSize = 0; dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_SINT8: wdbOLEDBType = DBTYPE_I1; uColumnSize = 1; dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_UINT8: wdbOLEDBType = DBTYPE_UI1; uColumnSize = 1; dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_SINT16: wdbOLEDBType = DBTYPE_I2; uColumnSize = 2; dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_UINT16: wdbOLEDBType = DBTYPE_UI2; uColumnSize = 2; dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_SINT32: wdbOLEDBType = DBTYPE_I4; uColumnSize = 4; dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_UINT32: wdbOLEDBType = DBTYPE_UI4; uColumnSize = 4; dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_SINT64: wdbOLEDBType = DBTYPE_I8 ; //DBTYPE_R8; //DBTYPE_I8; uColumnSize = 8; dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_UINT64: wdbOLEDBType = DBTYPE_UI8 ; //DBTYPE_R8; //DBTYPE_UI8; uColumnSize = 8; dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_REAL32: wdbOLEDBType = DBTYPE_R4; uColumnSize = 4; dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_REAL64: wdbOLEDBType = DBTYPE_R8; uColumnSize = 8; dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_BOOLEAN: wdbOLEDBType = DBTYPE_BOOL; uColumnSize = 2; dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_STRING: wdbOLEDBType = DBTYPE_BSTR; uColumnSize = ~0 ;//MAX_CIM_STRING_SIZE; //sizeof(BSTR); // set the size to -1 ( a variable length string) break; case CIM_DATETIME: case DBTYPE_DBTIMESTAMP: case VT_DATE : wdbOLEDBType = DBTYPE_DBTIMESTAMP; uColumnSize = sizeof(DBTIMESTAMP); dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_REFERENCE: wdbOLEDBType = DBTYPE_BSTR; uColumnSize = sizeof(BSTR); break; case CIM_CHAR16: wdbOLEDBType = DBTYPE_STR; uColumnSize = 2; dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_OBJECT: wdbOLEDBType = DBTYPE_BSTR; uColumnSize = sizeof(BSTR); break; case CIM_FLAG_ARRAY: wdbOLEDBType = VT_ARRAY | VT_VARIANT; uColumnSize = sizeof(SAFEARRAY); hr = S_OK; break; case DBTYPE_GUID: wdbOLEDBType = DBTYPE_GUID; uColumnSize = sizeof(GUID); dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; case CIM_IUNKNOWN: wdbOLEDBType = DBTYPE_IUNKNOWN; uColumnSize = sizeof(IUnknown *); dwFlags |= DBCOLUMNFLAGS_ISFIXEDLENGTH; break; default: assert( !"Unmatched CIMTYPE to OLEDB Data Type." ); } return hr; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // This function translates text strings to OLEDB types /////////////////////////////////////////////////////////////////////////////////////////////////////////////// HRESULT CDataMap::TranslateParameterStringToOLEDBType( DBTYPE & wDataType, WCHAR * str) { HRESULT hr = S_OK; // Arrays ???? wDataType = 999; if( 0 == _wcsicmp(L"DBTYPE_CHAR",str )){ wDataType = DBTYPE_STR; } else if( 0 == _wcsicmp(L"DBTYPE_VARCHAR",str )){ wDataType = DBTYPE_STR; } else if( 0 == _wcsicmp(L"DBTYPE_LONGVARCHAR",str )){ wDataType = DBTYPE_STR; } else if( 0 == _wcsicmp(L"DBTYPE_WCHAR",str )){ wDataType = DBTYPE_WSTR; } else if( 0 == _wcsicmp(L"DBTYPE_WVARCHAR",str )){ wDataType = DBTYPE_WSTR; } else if( 0 == _wcsicmp(L"DBTYPE_WLONGVARCHAR",str )){ wDataType = DBTYPE_WSTR; } else if( 0 == _wcsicmp(L"DBTYPE_UI1",str )){ wDataType = DBTYPE_UI1; } else if( 0 == _wcsicmp(L"DBTYPE_I1",str )){ wDataType = DBTYPE_I1; } else if( 0 == _wcsicmp(L"DBTYPE_I2",str )){ wDataType = DBTYPE_I2; } else if( 0 == _wcsicmp(L"DBTYPE_UI2",str )){ wDataType = DBTYPE_UI2; } else if( 0 == _wcsicmp(L"DBTYPE_I4",str )){ wDataType = DBTYPE_I4; } else if( 0 == _wcsicmp(L"DBTYPE_UI4",str )){ wDataType = DBTYPE_UI4; } else if( 0 == _wcsicmp(L"DBTYPE_I8",str )){ wDataType = DBTYPE_I8; } else if( 0 == _wcsicmp(L"DBTYPE_UI8",str )){ wDataType = DBTYPE_UI8; } else if( 0 == _wcsicmp(L"DBTYPE_R4",str )){ wDataType = DBTYPE_R4; } else if( 0 == _wcsicmp(L"DBTYPE_R8",str )){ wDataType = DBTYPE_R8; } else if( 0 == _wcsicmp(L"DBTYPE_BOOL",str )){ wDataType = DBTYPE_BOOL; } else if( 0 == _wcsicmp(L"DBTYPE_WSTR",str )){ wDataType = DBTYPE_WSTR; } else if( 0 == _wcsicmp(L"DBTYPE_BSTR",str )){ wDataType = DBTYPE_BSTR; } else if( 0 == _wcsicmp(L"DBTYPE_STR",str )){ wDataType = DBTYPE_STR; } else if( 0 == _wcsicmp(L"DBTYPE_DATE ",str )){ wDataType = DBTYPE_DATE ; } else if( 0 == _wcsicmp(L"DBTYPE_DBTIME ",str )){ wDataType = DBTYPE_DBTIME ; } else if( 0 == _wcsicmp(L"DBTYPE_DBTIMESTAMP",str )){ wDataType = DBTYPE_DBTIMESTAMP; } else if( 0 == _wcsicmp(L"DBTYPE_IDISPATCH",str )){ wDataType = DBTYPE_IDISPATCH; } else if( 0 == _wcsicmp(L"DBTYPE_IUNKNOWN",str )){ wDataType = DBTYPE_IUNKNOWN; } return hr; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // This function maps and converts OLEDBTYPE to CIMTYPE // // Note: // dwArrayCIMType = -1 - If data passed is not array // dwArrayCIMType = actual CIMTYPE - If the passed data is array // /////////////////////////////////////////////////////////////////////////////////////////////////////////////// HRESULT CDataMap::MapAndConvertOLEDBTypeToCIMType(DBTYPE wDataType, void *pData ,DBLENGTH dwSrcLength, VARIANT &varData,LONG_PTR lArrayCIMType) { HRESULT hr = S_OK; DWORD dwDstStatus = 0 , cbDstMaxLength = 0; void *pSrc = NULL; BSTR strDate=Wmioledb_SysAllocString(NULL); SAFEARRAY * pArrayTemp = NULL; DBLENGTH dbDstLen = 0; if(lArrayCIMType == -1) { if(wDataType == VT_BSTR) pSrc = &pData; else pSrc = pData; switch( wDataType ) { case DBTYPE_UI1: case DBTYPE_I1: wDataType = DBTYPE_I2; break; case DBTYPE_UI2: wDataType = DBTYPE_I2; break; case DBTYPE_UI4: wDataType = DBTYPE_I4; break; case DBTYPE_DBTIMESTAMP: if(IsValidDBTimeStamp((DBTIMESTAMP *)pData)) { // Converts OLEDB DBTIMESTAMP to DMTF date format ConvertOledbDateToCIMType((DBTIMESTAMP *)pData,strDate); pSrc = &strDate; wDataType = VT_BSTR; } else hr = DBSTATUS_E_CANTCONVERTVALUE; } } else // if the type is array then convert it into the appropriate type if( (wDataType & DBTYPE_ARRAY) && (lArrayCIMType & DBTYPE_ARRAY)) { hr = ConvertAndCopyArray((SAFEARRAY *)pData, &pArrayTemp, wDataType,(DBTYPE)lArrayCIMType,&dwDstStatus); wDataType = (DBTYPE)lArrayCIMType; pSrc = pArrayTemp; } if( hr == S_OK) { hr = g_pIDataConvert->DataConvert( wDataType, VT_VARIANT, dwSrcLength, &dbDstLen, pSrc, &varData, sizeof(VARIANT), 0, &dwDstStatus, 0, // bPrecision for conversion to DBNUMERIC 0, // bScale for conversion to DBNUMERIC DBDATACONVERT_DEFAULT); } // Release memory if( pArrayTemp) { SafeArrayDestroy(pArrayTemp); pArrayTemp = NULL; } SysFreeString(strDate); return hr; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // This function maps and converts OLEDBTYPE to CIMTYPE // // Note: // dwArrayCIMType = -1 - If data passed is not array // dwArrayCIMType = actual CIMTYPE - If the passed data is array // /////////////////////////////////////////////////////////////////////////////////////////////////////////////// HRESULT CDataMap::ConvertToCIMType(BYTE *pData, DBTYPE lType ,DBLENGTH lDataLength,LONG lCIMType ,VARIANT &varData) { HRESULT hr = DBSTATUS_E_CANTCONVERTVALUE; DWORD dwDstStatus = 0; DWORD cbDstMaxLength = 0; void * pDst = NULL; void * pSrc = NULL; void * pTemp = NULL; BYTE * pbTemp = NULL; BSTR strDate = Wmioledb_SysAllocString(NULL); SAFEARRAY * pArrayTemp = NULL; BOOL bAlloc = FALSE; DBLENGTH dbDstLen = 0; DBTYPE wDataType = 0; BOOL bConverted = FALSE; wDataType = (DBTYPE)lCIMType; if(! pData) { VariantClear(&varData); hr = S_OK; } else { switch(lCIMType) { case CIM_UINT8: wDataType = VT_I2; break; case CIM_UINT16: wDataType = VT_I2; break; case CIM_UINT32: wDataType = VT_I4; break; case CIM_DATETIME: BSTR strDate; pTemp = new BYTE[sizeof(DBTIMESTAMP)]; if( lType == VT_BSTR) pSrc = *(BSTR **)pData; else pSrc = pData; //NTRaid:111795 // 06/07/00 if(pTemp == NULL) { hr = E_OUTOFMEMORY; } else // Convert the given date to DBTIMESTAMP if( S_OK == (hr = g_pIDataConvert->DataConvert( (DBTYPE)lType,DBTYPE_DBTIMESTAMP, lDataLength,&dbDstLen, pSrc, pTemp, sizeof(DBTIMESTAMP), 0, &dwDstStatus, 0, // bPrecision for conversion to DBNUMERIC 0, // bScale for conversion to DBNUMERIC DBDATACONVERT_DEFAULT)) && dwDstStatus != DBSTATUS_S_ISNULL) { // Call this function to convert DBTIMESTAMP date to CIM date format if(S_OK == (hr = ConvertOledbDateToCIMType((DBTIMESTAMP*)pTemp,strDate))) { varData.vt = VT_BSTR; varData.bstrVal = Wmioledb_SysAllocString(strDate); SysFreeString(strDate); } } SAFE_DELETE_ARRAY(pTemp); bConverted = TRUE; break; } if(bConverted == FALSE) { pTemp = pData; hr = S_OK; // if the required type and the type of the data passed is different then convert the data to appropriate // type if( lType != (LONG)wDataType && (hr = g_pIDataConvert->CanConvert((DBTYPE)lType,(DBTYPE)wDataType)) == S_OK) { pTemp = NULL; if(SUCCEEDED(hr = AllocateData(wDataType,pTemp,dbDstLen))) { bAlloc = TRUE; if( lType == VT_BSTR) pSrc = (BYTE *)*((BSTR **)pData); else pSrc = pData; hr = g_pIDataConvert->DataConvert( (DBTYPE)lType,(DBTYPE)wDataType, lDataLength,&dbDstLen, pSrc, pTemp, dbDstLen, 0, &dwDstStatus, 0, // bPrecision for conversion to DBNUMERIC 0, // bScale for conversion to DBNUMERIC DBDATACONVERT_DEFAULT); } } if( hr == S_OK) { if( wDataType == VT_BSTR) pSrc = *(BSTR **)pTemp; else pSrc = pTemp; hr = g_pIDataConvert->DataConvert((DBTYPE)wDataType, VT_VARIANT, dbDstLen, &dbDstLen, pSrc, &varData, sizeof(VARIANT), 0, &dwDstStatus, 0, // bPrecision for conversion to DBNUMERIC 0, // bScale for conversion to DBNUMERIC DBDATACONVERT_DEFAULT); } if( bAlloc == TRUE) { pbTemp = (BYTE *)pTemp; FreeData(wDataType,pbTemp); } } } SysFreeString(strDate); return hr; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // This function convert data to the OLEDBTYPE required. It also allocates memory for the data // /////////////////////////////////////////////////////////////////////////////////////////////////////////////// HRESULT CDataMap::AllocateAndConvertToOLEDBType(VARIANT &varData,LONG lCimType , DBTYPE lOledbType,BYTE *&pData, DBLENGTH &lDataLength, DBSTATUS &dwStatus) { HRESULT hr = DBSTATUS_E_CANTCONVERTVALUE; DBTYPE wDataType = 0; DBLENGTH dwDstLength = 0; BYTE *pSrc = NULL; void *pTemp = NULL; void *pDst = NULL; BOOL bConvert = FALSE; BOOL bAlloc = FALSE; DBLENGTH dbDstLen = 0; wDataType = (DBTYPE)lCimType; if(wDataType & CIM_FLAG_ARRAY) { wDataType = CIM_FLAG_ARRAY; } if(varData.vt == VT_NULL || varData.vt == VT_EMPTY) { pData = NULL; lDataLength = NULL; dwStatus = DBSTATUS_S_ISNULL; return S_OK; } switch(wDataType) { // Arrays are always shown as ARRAY of VARIANTS to make it easily accessible with scripting case CIM_FLAG_ARRAY: // if(lOledbType != VT_ARRAY || VT_VARIANT) // Bug number 103751 in Windows bugs hr = DBSTATUS_E_CANTCONVERTVALUE; if(lOledbType == (VT_ARRAY | VT_VARIANT)) { hr = ConvertToVariantArray(((VARIANT *)&varData)->parray,varData.vt,(SAFEARRAY **)&pData); } bConvert = TRUE; break; case CIM_DATETIME: case DBTYPE_DBTIMESTAMP: lDataLength = sizeof(DBTIMESTAMP); if( varData.bstrVal != NULL) { // NTRaid:111818 // 06/13/00 pSrc = new BYTE[lDataLength]; if(pSrc) { bAlloc = TRUE; hr = ConvertDateToOledbType(varData.bstrVal,(DBTIMESTAMP *)pSrc); wDataType = DBTYPE_DBTIMESTAMP; } else { hr = E_OUTOFMEMORY; } } else { hr = S_OK; pSrc = NULL; lDataLength = 0; bConvert = TRUE; } break; default: wDataType = VT_VARIANT; lDataLength = sizeof(VARIANT); pSrc = (BYTE *)&varData; // NTRaid:111818 // 06/13/00 hr = S_OK; } // NTRaid:111818 // 06/13/00 if(SUCCEEDED(hr) && bConvert == FALSE && pSrc != NULL && g_pIDataConvert->CanConvert((DBTYPE)wDataType,(DBTYPE)lOledbType) == S_OK) { //AllocateData(lOledbType,pDst,dwDstLength); if(wDataType == VT_BSTR) pDst = *(BSTR **)pData; else pDst = (void *)pData; hr = g_pIDataConvert->DataConvert( (DBTYPE)wDataType,(DBTYPE)lOledbType, lDataLength,&dbDstLen, pSrc, pDst, dbDstLen, 0, &dwStatus, 0, // bPrecision for conversion to DBNUMERIC 0, // bScale for conversion to DBNUMERIC DBDATACONVERT_DEFAULT); if( hr == S_OK) { pData = (BYTE *)pDst; } } if(bAlloc == TRUE) { delete [] pSrc; } lDataLength = (LONG)dbDstLen; return hr; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Function to convert the data to variant type /////////////////////////////////////////////////////////////////////////////////////////////////////////////// HRESULT CDataMap::ConvertVariantType(VARIANT &varSrc, VARIANT varDst ,CIMTYPE lDstType) { HRESULT hr = E_FAIL; switch(lDstType) { case CIM_DATETIME: case DBTYPE_DBTIMESTAMP: case DBTYPE_DATE: case DBTYPE_DBTIME: lDstType = DBTYPE_BSTR; break; case CIM_REFERENCE : case CIM_CHAR16: case CIM_OBJECT: case CIM_FLAG_ARRAY: break; case CIM_UINT64: case CIM_SINT64: lDstType = VT_R8; }; hr = VariantChangeType(&varSrc,&varDst,0,(SHORT)lDstType); return hr; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Function to compare data of same types and check if both are same /////////////////////////////////////////////////////////////////////////////////////////////////////////////// BOOL CDataMap::CompareData(DWORD dwType,void * pData1 , void *pData2) { BOOL bRet = FALSE; long lType = VT_NULL; if(pData1 == NULL || pData2 == NULL) { if(pData1 == pData2) bRet = TRUE; return bRet; } // If the type is of some array if (dwType & VT_ARRAY) { lType = CIM_FLAG_ARRAY; } else lType = dwType; switch( lType ){ case VT_NULL: case VT_EMPTY: bRet = TRUE; break; case CIM_FLAG_ARRAY: bRet = FALSE; break; case CIM_SINT8: case CIM_UINT8: if(!memcmp(pData1,pData2,1)) bRet = TRUE; break; case CIM_CHAR16: case CIM_SINT16: case CIM_UINT16: case CIM_BOOLEAN: if(!memcmp(pData1,pData2,2)) bRet = TRUE; break; case CIM_SINT32: case CIM_UINT32: case CIM_REAL32: if(!memcmp(pData1,pData2,4)) bRet = TRUE; break; case CIM_SINT64: case CIM_UINT64: case CIM_REAL64: if(!memcmp(pData1,pData2,8)) bRet = TRUE; break; case CIM_DATETIME: case DBTYPE_DBTIMESTAMP: if(!memcmp(pData1,pData2,sizeof(DBTIMESTAMP))) bRet = TRUE; break; case CIM_STRING: if( pData1 != NULL && pData2 != NULL) { if(!_wcsicmp((WCHAR *)pData1,(WCHAR *)pData2)) bRet = TRUE; } break; case CIM_REFERENCE: case CIM_OBJECT: case VT_VARIANT: case CIM_IUNKNOWN: break; case DBTYPE_DATE: if(!memcmp(pData1,pData2,sizeof(DATE))) bRet = TRUE; break; default: assert( !"Unmatched OLEDB Data Type to CIMTYPE." ); } return bRet; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Function to check if a Safearray is Empty or not // NOTE :Works on Single dimensional array /////////////////////////////////////////////////////////////////////////////////////////////////////////////// BOOL CDataMap::IsSafeArrayEmpty(SAFEARRAY *psa) { BOOL bRet = TRUE; long lUBound = 0,lLBound = 0; HRESULT hr = 0; hr = SafeArrayGetUBound(psa,1,&lUBound); hr = SafeArrayGetLBound(psa,1,&lLBound); if( hr == S_OK && lLBound <= lUBound) { bRet = FALSE; } return bRet; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Function to convert a safearray of one type to safearray of another type if, // the source and destination arrays are of different type // and this will just copy the safearray to the destination if the arraytypes are of same type // NOTE: Works on Single dimensional array /////////////////////////////////////////////////////////////////////////////////////////////////////////////// HRESULT CDataMap::ConvertAndCopyArray(SAFEARRAY *psaSrc, SAFEARRAY **ppsaDst, DBTYPE dwSrcType,DBTYPE dwDstType,DBSTATUS *pdwStatus) { HRESULT hr = S_OK; SAFEARRAYBOUND sabound; LONG lUBound = 0; LONG lLBound = 0; int nArrayIndex = 0; void * pSrc = NULL; void * pDst = NULL; void * pTemp = NULL; DBLENGTH dbSrcLen = 0; DBLENGTH dbDstLen = 0; BSTR * pTempStr; BYTE * pbTemp = NULL; short dwSrcElemType = (SHORT) dwSrcType & ~DBTYPE_ARRAY; short dwDstElemType = (SHORT)dwDstType & ~DBTYPE_ARRAY; *pdwStatus = DBSTATUS_S_OK; // If the array is not a single dimenstion array , then there is an error if(SafeArrayGetDim(psaSrc) != 1) return E_FAIL; // Bad array, or too many dimensions // If the source safearray is not empty if(!IsSafeArrayEmpty(psaSrc)) { // if source and destination safe array is same then we can // copy the safearray using SafeArrayCopy if( dwSrcType != dwDstType) { // if the destination type is array of DBDATETIME then // set error and status if( IsDateType(dwDstType) && dwDstElemType == DBTYPE_DBTIMESTAMP) { hr = E_FAIL; *pdwStatus = DBSTATUS_E_BADSTATUS; } else // If the data type of the elements of the array can be converted // if the source type is date then conversion will be from the string in CIMDATE formate // which will be done by a utility function and not from the OLEDB conversion routine if( SUCCEEDED (hr = g_pIDataConvert->CanConvert(dwSrcElemType, dwDstElemType)) || IsDateType(dwSrcElemType)) { dbSrcLen = SafeArrayGetElemsize(psaSrc); memset(&sabound,0,sizeof(SAFEARRAYBOUND)); hr = SafeArrayGetUBound(psaSrc,1,&lUBound); hr = SafeArrayGetLBound(psaSrc,1,&lLBound); if( lUBound > lLBound) { sabound.lLbound = lLBound; sabound.cElements = lUBound - lLBound +1; // Create the safearray *ppsaDst = SafeArrayCreate(dwDstElemType, 1, &sabound); pSrc = new BYTE[dbSrcLen]; if(SUCCEEDED(hr = AllocateData(dwDstElemType,pDst,dbDstLen))) { if(dwDstElemType == VT_BSTR) pTemp = *(BSTR **)pDst; else pTemp = pDst; // Navigate thru each element in the dimension of the array for(nArrayIndex = lLBound ; nArrayIndex <= lUBound ; nArrayIndex++) { hr = SafeArrayGetElement(psaSrc,(long *)&nArrayIndex,pSrc); if(hr == S_OK && dbDstLen > 0) { if( IsDateType(dwSrcType) || IsDateType(dwDstType)) { // Convert the element data hr = ConvertDateTypes( dwSrcElemType, dwDstElemType, dbSrcLen, &dbDstLen, &(((VARIANT *)pSrc)->bstrVal), pTemp, dbDstLen, pdwStatus); } else { // Free the previous string allocated from previous // conversion if( dwDstElemType == VT_BSTR && pDst != NULL) { pTempStr = *(BSTR **)pDst; SysFreeString(*pTempStr); } // Convert the element data hr = g_pIDataConvert->DataConvert( dwSrcElemType, dwDstElemType, dbSrcLen, &dbDstLen, pSrc, pTemp, dbDstLen, 0, pdwStatus, 0, 0, DBDATACONVERT_DEFAULT); if(hr == DB_E_UNSUPPORTEDCONVERSION && pdwStatus != NULL) *pdwStatus = DBSTATUS_E_CANTCONVERTVALUE; } // Put the data to the destination array hr = SafeArrayPutElement(*ppsaDst,(long *)&nArrayIndex,pTemp); } else { hr = E_FAIL; *pdwStatus = DBSTATUS_E_BADSTATUS; break; } }// for } } SAFE_DELETE_ARRAY(pSrc); pbTemp = (BYTE *)pDst; FreeData(dwDstElemType,pbTemp); pDst = pbTemp; } else // Else if the data types of src and dst is not convertible then set the status { *pdwStatus = DBSTATUS_E_CANTCONVERTVALUE; } } else // if the src and dst or of same type then just copy the arrays { hr = SafeArrayCopy(psaSrc,ppsaDst); } } else { ppsaDst = NULL; *pdwStatus = DBSTATUS_S_ISNULL; } return hr; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Function to allocate memory // Used by ConvertAndCopyArray function to allocate data for elements for converting // the data type and putting it to the array /////////////////////////////////////////////////////////////////////////////////////////////////////////////// HRESULT CDataMap::AllocateData(DBTYPE dwType,void *& pData,DBLENGTH &dwLength) { HRESULT hr = S_OK; long lType = dwType; SAFEARRAY *pArray = NULL; dwLength = 0; // If the type is of some array if (lType & CIM_FLAG_ARRAY) { lType = CIM_FLAG_ARRAY; } try { switch( lType ){ case VT_NULL: pData = NULL; hr = DBSTATUS_S_ISNULL; break; case VT_EMPTY: pData = NULL; hr = DBSTATUS_S_ISNULL; break; case CIM_FLAG_ARRAY: break; case CIM_SINT8: case CIM_UINT8: pData = new BYTE[1]; dwLength = sizeof(BYTE); if(!pData) { hr = E_OUTOFMEMORY; } break; case CIM_CHAR16: case CIM_SINT16: case CIM_UINT16: case CIM_BOOLEAN: dwLength = sizeof(short); pData = new BYTE[dwLength]; if(!pData) { hr = E_OUTOFMEMORY; } break; case CIM_SINT32: case CIM_UINT32: case CIM_REAL32: dwLength = sizeof(long); pData = new BYTE[dwLength]; if(!pData) { hr = E_OUTOFMEMORY; } break; case CIM_SINT64: case CIM_UINT64: case CIM_REAL64: dwLength = 8; pData = new BYTE[8]; if(!pData) { hr = E_OUTOFMEMORY; } break; case CIM_DATETIME: case DBTYPE_DBTIMESTAMP: dwLength = sizeof(DBTIMESTAMP); pData = new BYTE[dwLength]; if(!pData) { hr = E_OUTOFMEMORY; } break; case DBTYPE_DATE: dwLength = sizeof(DATE); pData = new BYTE[dwLength]; if(!pData) { hr = E_OUTOFMEMORY; } break; case CIM_STRING: pData = new BYTE[sizeof(BSTR)]; dwLength = sizeof(BSTR); if(!pData) { hr = E_OUTOFMEMORY; } break; case CIM_REFERENCE: break; case CIM_OBJECT: break; case VT_VARIANT: dwLength = sizeof(VARIANT); pData = new BYTE[sizeof(VARIANT)]; if(!pData) { hr = E_OUTOFMEMORY; } else { VariantInit((VARIANT *)pData); } break; default: hr = E_FAIL; // assert( !"Unmatched OLEDB Data Type to CIMTYPE." ); } } // try catch(...) { SAFE_DELETE_ARRAY(pData); throw; } return hr; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Function to convert WMI (DMTF) formate date to OLEDB format /////////////////////////////////////////////////////////////////////////////////////////////////////////////// HRESULT CDataMap::ConvertDateToOledbType(BSTR strDate,DBTIMESTAMP *pTimeStamp) { WBEMTime wbemTime(strDate); if(wbemTime.IsOk()) { SYSTEMTIME sysTime; memset(&sysTime,0,sizeof(SYSTEMTIME)); wbemTime.GetSYSTEMTIME(&sysTime); pTimeStamp->year = (SHORT) sysTime.wYear; pTimeStamp->month = (USHORT)sysTime.wMonth; pTimeStamp->day = (USHORT)sysTime.wDay; pTimeStamp->hour = (USHORT)sysTime.wHour; pTimeStamp->minute = (USHORT)sysTime.wMinute; pTimeStamp->second = (USHORT)sysTime.wSecond; pTimeStamp->fraction= (ULONG)sysTime.wMilliseconds * 1000000; // converting into billionth of second return S_OK; } return DBSTATUS_E_CANTCONVERTVALUE; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Function to convert VARIANT date format to OLEDB format /////////////////////////////////////////////////////////////////////////////////////////////////////////////// HRESULT CDataMap::ConvertVariantDateOledbDate(DATE *pDate,DBTIMESTAMP *pTimeStamp) { HRESULT hr = S_OK; DWORD dwDstStatus = 0 ,cbDstMaxLength = 0; DBLENGTH dbDstLen = 0; hr = g_pIDataConvert->DataConvert( VT_DATE, DBTYPE_DBTIMESTAMP, sizeof(DATE), &dbDstLen, pDate, pTimeStamp, sizeof(DBTIMESTAMP), 0, &dwDstStatus, 0, // bPrecision for conversion to DBNUMERIC 0, // bScale for conversion to DBNUMERIC DBDATACONVERT_DEFAULT); return hr; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Function to convert OLEDB format to WMI (DMTF) format /////////////////////////////////////////////////////////////////////////////////////////////////////////////// HRESULT CDataMap::ConvertOledbDateToCIMType(DBTIMESTAMP *pTimeStamp,BSTR &strDate) { WBEMTime wbemTime; SYSTEMTIME sysTime; memset(&sysTime,0,sizeof(SYSTEMTIME)); sysTime.wYear = pTimeStamp->year; sysTime.wMonth = pTimeStamp->month; sysTime.wDay = pTimeStamp->day; sysTime.wHour = pTimeStamp->hour; sysTime.wMinute = pTimeStamp->minute; sysTime.wSecond = pTimeStamp->second; sysTime.wMilliseconds = (WORD)pTimeStamp->fraction/ 1000000; // converting into micosecond wbemTime = sysTime; strDate = wbemTime.GetDMTF(); return S_OK; } HRESULT CDataMap::ConvertOledbDateToCIMType(VARIANT *vTimeStamp,BSTR &strDate) { WBEMTime wbemTime; SYSTEMTIME sysTime; memset(&sysTime,0,sizeof(SYSTEMTIME)); DBTIMESTAMP *pTimeStamp; assert(vTimeStamp->vt == (VT_ARRAY | VT_UI1) || vTimeStamp->vt == (VT_ARRAY | VT_I1)); SafeArrayAccessData(vTimeStamp->parray,(void **)&pTimeStamp); ConvertOledbDateToCIMType(pTimeStamp,strDate); SafeArrayUnaccessData(vTimeStamp->parray); return S_OK; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Function to convert OLEDB format to WMI (DMTF) format /////////////////////////////////////////////////////////////////////////////////////////////////////////////// HRESULT CDataMap::ConvertVariantDateToCIMType(DATE *pDate,BSTR &strDate) { DBTIMESTAMP dbTimeStamp; memset(&dbTimeStamp,0,sizeof(DBTIMESTAMP)); ConvertVariantDateOledbDate(pDate,&dbTimeStamp); ConvertOledbDateToCIMType(&dbTimeStamp,strDate); return S_OK; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Check if the DTIMESTAMP passed is valid or not /////////////////////////////////////////////////////////////////////////////////////////////////////////////// BOOL CDataMap::IsValidDBTimeStamp(DBTIMESTAMP *pTimeStamp) { HRESULT hr = S_OK; DWORD dwDstStatus = 0 , cbDstMaxLength = 0; void *pSrc = NULL; CVARIANT varDate; DBLENGTH dbDstLen = 0; hr = g_pIDataConvert->DataConvert( DBTYPE_DBTIMESTAMP, VT_VARIANT, sizeof(DBTIMESTAMP), &dbDstLen, pTimeStamp, &varDate, sizeof(VARIANT), 0, &dwDstStatus, 0, // bPrecision for conversion to DBNUMERIC 0, // bScale for conversion to DBNUMERIC DBDATACONVERT_DEFAULT); if( hr != S_OK) return FALSE; return TRUE; } BOOL CDataMap::IsDateType(DWORD dwType) { BOOL bRet = FALSE; if(dwType & VT_ARRAY) dwType = dwType & ~(VT_ARRAY); switch(dwType) { case DBTYPE_DATE: case DBTYPE_DBTIMESTAMP: case DBTYPE_DBTIME: case CIM_DATETIME: bRet = TRUE; break; } return bRet; } HRESULT CDataMap::ConvertDateTypes( DWORD dwSrcType, DWORD dwDstType, DBLENGTH dwSrcLen, DBLENGTH* pdwDstLen, void * pSrc, void * & pDst, DBLENGTH dbDstLen, DWORD * pdwStatus) { HRESULT hr = S_OK; DBTIMESTAMP *pSrcTimeStamp = NULL; pSrcTimeStamp = new DBTIMESTAMP; // NTRaid:111817 // 06/07/00 if(!pSrcTimeStamp) { hr = E_OUTOFMEMORY; } else { memset(pSrcTimeStamp,0,sizeof(DBTIMESTAMP)); switch(dwSrcType) { case CIM_DATETIME: hr = ConvertDateToOledbType(*(BSTR*)pSrc ,pSrcTimeStamp); break; default : hr = g_pIDataConvert->DataConvert( (USHORT)dwSrcType , DBTYPE_DBTIMESTAMP, dwSrcLen, &dbDstLen, pSrc, pSrcTimeStamp, sizeof(DBTIMESTAMP), 0, pdwStatus, 0, // bPrecision for conversion to DBNUMERIC 0, // bScale for conversion to DBNUMERIC DBDATACONVERT_DEFAULT); } if( hr == S_OK) { switch(dwDstType) { case CIM_DATETIME: hr = ConvertOledbDateToCIMType(pSrcTimeStamp,(BSTR)*(BSTR *)pDst); default: hr = g_pIDataConvert->DataConvert( DBTYPE_DBTIMESTAMP, (USHORT)dwDstType, sizeof(DBTIMESTAMP), &dbDstLen, pSrcTimeStamp, pDst, dbDstLen, 0, pdwStatus, 0, // bPrecision for conversion to DBNUMERIC 0, // bScale for conversion to DBNUMERIC DBDATACONVERT_DEFAULT); } } SAFE_DELETE_PTR(pSrcTimeStamp); } return hr; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Clear data for a particular DBTYPE ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HRESULT CDataMap::ClearData(DBTYPE lType, void * pData) { HRESULT hr = S_OK; VARIANT *pVar = NULL; BSTR * pStr;; //======================================================================= // See if it is an array //======================================================================= // If the pointer sent is not NULL if( lType & CIM_FLAG_ARRAY ) { lType = CIM_FLAG_ARRAY; } if(pData) { switch( lType ){ case DBTYPE_EMPTY: break; case DBTYPE_NULL: break; case DBTYPE_ARRAY: pVar = (VARIANT *)pData; hr = SafeArrayDestroy((SAFEARRAY *)pData); break; case DBTYPE_I1: case DBTYPE_UI1: memset(pData,0,sizeof(BYTE)); break; case DBTYPE_BOOL: case DBTYPE_I2: case DBTYPE_UI2: memset(pData,0,sizeof(short)); break; case DBTYPE_R4: case DBTYPE_UI4: case DBTYPE_I4: memset(pData,0,sizeof(long)); break; case DBTYPE_R8: case DBTYPE_I8: case DBTYPE_UI8: memset(pData,0,8); break; case DBTYPE_DBTIMESTAMP: memset(pData,0,sizeof(DBTIMESTAMP)); break; case DBTYPE_BSTR: pStr = (BSTR *)pData; SysFreeString(*pStr); break; case DBTYPE_STR: wcscpy((WCHAR *)pData,L""); case DBTYPE_VARIANT: hr = VariantClear((VARIANT *)pData); break; case DBTYPE_DATE: memset(pData,0,sizeof(DATE)); break; case DBTYPE_WSTR: memset(pData,0,sizeof(WCHAR)); break; case DBTYPE_IUNKNOWN: pData = NULL; break; default: assert( !"Unmatched OLEDB Data Type to CIMTYPE." ); } } if(hr == S_OK) pData = NULL; return hr; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Convert a SAFEARRAY or any type to SAFEARRAY of VARIANT ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HRESULT CDataMap::ConvertToVariantArray(SAFEARRAY *pArray,DBTYPE dwSrcType,SAFEARRAY ** ppArrayOut) { DWORD dwStatus = 0; return ConvertAndCopyArray(pArray, ppArrayOut, dwSrcType,VT_ARRAY|VT_VARIANT,&dwStatus); }