STL数组和com数组相互转换的做法

作者:朱金灿

来源:http://blog.csdn.net/clever101

   

        STL的泛型数组是vetor,com的泛型数组类型是VARIANT。二者怎样能相互转化呢?就是说怎么把一个vector对象封装进VARIANT对象,又怎么将VARIANT对象封装进vector对象。经过一番研究,找到了办法。需要注意的是,数值数组和字符串数组是需要单独处理的。首先谈谈数组类型的数组如何转换,比如std::vector<int>转换为一个VARIANT对象。需要一个模板类来实现,代码如下:

template<class T>
class CVariantPack
{
private:

	CVariantPack(void){};

	~CVariantPack(void){};

public:

	static bool SetTPtrVariant(VARENUM ElementType,const std::vector<T>& vecData,VARIANT &vdata)
	{
		try
		{   
			if(vecData.empty())
			{
				return false;
			}
			SAFEARRAYBOUND rgsabound[1];
			rgsabound[0].lLbound = 0;
			rgsabound[0].cElements = (ULONG)vecData.size();

			SAFEARRAY *psa = SafeArrayCreate(ElementType,1, rgsabound );
			if( psa )
			{
				for( long i=0; i<(long)vecData.size(); i++ )
				{
					SafeArrayPutElement( psa, &i, (void *)(&vecData[i]));
				}
				vdata.vt = VT_ARRAY|ElementType;
				vdata.parray = psa;
				SafeArrayUnaccessData( psa );
				return true;    
			}
			else
			{
				return false;
			}
		}
		catch(...)
		{
			return false;
		}
	}

	static int GetTPtrVariant (VARENUM ElementType,std::vector<T>& vecData,const VARIANT vdata)
	{
		try
		{
			if( vdata.vt==VT_NULL || vdata.vt==VT_EMPTY )
			{
				return -1;
			}
			if( !(vdata.vt & VT_ARRAY)  )
			{
				return -2;
			}
			SAFEARRAY *psa = vdata.parray;
			UINT nDims = SafeArrayGetDim( psa );
			if( nDims != 1 )
			{
				return -3;
			}
			//检查数组元素类型
			VARTYPE vt = 0;
			SafeArrayGetVartype( psa, &vt );
			if( vt != ElementType )
			{
				return -4;
			}
			//检查数组上下限和元素个数是否为偶数个
			LONG lUBound =0, lLBound = 0;
			SafeArrayGetUBound( psa, 1, &lUBound );
			SafeArrayGetLBound( psa, 1, &lLBound );
			int lElements = lUBound - lLBound + 1;
			if( lElements <= 0 )
			{
				return -5;
			}
			T *pTmp = NULL;
			SafeArrayAccessData( psa, (void **)&pTmp );
			if( NULL == pTmp )
			{
				return -6;
			}
			for (int i = 0;i<lElements;i++)
			{
                 vecData.push_back(*(pTmp+i));
			}

			SafeArrayUnaccessData( psa );
			return lElements;   
		}
		catch(...)
		{
			return -1;
		};
	}

};

测试函数如下:


bool TestVariantPack1(void)
{
	std::vector<long> a;
a.push_back(1);
a.push_back(2);
a.push_back(3);
	VARIANT vdata;
	//long 数组封装到variant
	if( !CVariantPack<long>::packtptrvariant(v_long,a,3,vdata))
	{
		return false;
	}
	std::vector<long> b;
	//从variant获取long数组数据
	int num= CVariantPack<long>::GetTPtrVariant(VT_I4,b,vdata); 
	if( num<=0 )
	{
		return false;
	}
}
下面再谈谈字符串数组的相互转换。

// std::vector< std::wstring>转换为一个VARIANT对象
	bool StringArrayToVariant(const std::vector< std::wstring >& vecData,VARIANT& vdata)
	{
		if(vecData.empty())
		{
			return false;
		}

		SAFEARRAY *psa;
		SAFEARRAYBOUND rgsabound;
		rgsabound.cElements = (ULONG)vecData.size();
		rgsabound.lLbound = 0;
		psa = SafeArrayCreate(VT_BSTR, 1, &rgsabound);//设置为一位BSTR数组
		if( psa )
		{
			BSTR* bstrArray;
			::SafeArrayAccessData(psa,(void**)&bstrArray);//将数据引出进行操作,并加锁
			for (int i = 0 ; i < vecData.size(); ++i)
			{
// bstrArray[i] =  arExport[i].AllocSysString(); // 如果是std::vector<CString>,请用这句代码
				bstrArray[i] =  const_cast<TCHAR*>(vecData[i].c_str());
			}

			vdata.vt = VT_ARRAY|VT_BSTR;
			vdata.parray = psa;
			::SafeArrayUnaccessData(psa);
			return true;    
		}
		return false;
	}

//VARIANT对象转换为std::vector< std::wstring>
	int VariantToStringArray(const VARIANT& vdata,std::vector<std::wstring >& vecData)
	{
		if( vdata.vt==VT_NULL || vdata.vt==VT_EMPTY )
		{
			return -1;
		}
		if( !(vdata.vt & VT_ARRAY)  )
		{
			return -2;
		}
		SAFEARRAY *psa = vdata.parray;
		UINT nDims = SafeArrayGetDim( psa );
		if( nDims != 1 )
		{
			return -3;
		}
		//检查数组元素类型
		VARTYPE vt = 0;
		SafeArrayGetVartype( psa, &vt );
		if( vt != VT_BSTR )
		{
			return -4;
		}
		//检查数组上下限和元素个数是否为偶数个
		LONG lUBound =0, lLBound = 0;
		SafeArrayGetUBound( psa, 1, &lUBound );
		SafeArrayGetLBound( psa, 1, &lLBound );
		int lElements = lUBound - lLBound + 1;
		if( lElements <= 0 )
		{
			return -5;
		}
		BSTR* pTmp = NULL;
		SafeArrayAccessData( psa, (void **)&pTmp );
		if( NULL == pTmp )
		{
			return -6;
		}
		for (int i = 0;i<lElements;i++)
		{
			vecData.push_back(*(pTmp+i));
		}

		SafeArrayUnaccessData( psa );
		return lElements;   
	}

这里需要注意的是,com只支持unicode字符,所以对应的stl字符串数组类型为std::vector<std::wstring>。

 测试函数如下:

bool TestVariantPack(void)
{
	std::vector<std::wstring> vecString;
    vecString.push_back(_T("HelloWorld"));
    vecString.push_back(_T(","));
    vecString.push_back(_T("I am from China!"));

	VARIANT vdata;
	// std::vector<std::wstring> 数组封装到variant
	if( !SysUtility::StringArrayToVariant(vecString,vdata))
	{
		return false;
	}
	std::vector<std::wstring> vecString2;
	//从variant获取std::vector<std::wstring>数组数据
	int num= SysUtility::VariantToStringArray(vdata,vecString2); 
	if( num<=0 )
	{
		return false;
	}
	return true;
}

参考文献:

1. 关于在C#中调用MFC编写Activex控件中传入字符串数组的有关问题

原文地址:https://www.cnblogs.com/lanzhi/p/6470090.html