在C#中调用COM时,VARIANT变量遇到的问题。
最近在做一项目,需要在C#中调用COM组件,但组件提供的是VARIANT变量,传递的是一个float数组。
本人刚开始用C#,之前一直用VC;本想C#做起来更简单些。先做一个测试程序,发现一运行就报
“从非托管 VARIANT 转换为托管对象的过程中检测到无效 VARIANT。
将无效 VARIANT 传递给 CLR 会导致意外的异常、损坏或数据丢失。”
觉得自己本身水平有限,就到网上四处查找原因,还是没有解决;实在没有办法,决定先做一个简
单的ATL程序和C#的测试程序连接试试。具体的ATL程序就不说了,只把接口函数写出来:
STDMETHODIMP CTest::GetDatas( VARIANT* pVar)
{
pVar->vt = VT_R4;
pVar->dblVal = 1.1;
return S_OK;
}
先传递一个float数据。
C#的程序:
private void Button_Click(object sender, RoutedEventArgs e)
{
object ob=new object();
ITest.GetDatas( ob );
MessageBox.Show(ob .ToString());
}
测试了一下,顺利输出数据;
在改为float数组;
STDMETHODIMP CTest::GetDatas( VARIANT* pVar)
{
//pVar->vt = VT_R4;
//pVar->dblVal = 1.1;
SAFEARRAYBOUND sab;
sab.cElements = 10;
sab.lLbound = 0;
SAFEARRAY* psa = SafeArrayCreate(VT_R4,1,&sab);
for (long i = 0; i < 10; i++)
{
float f=i*1.1;
SafeArrayPutElement(psa,&i , &f);
}
pVar->vt = VT_ARRAY;
pVar->parray = psa;
return S_OK;
}
C#程序不用修改。
一旦运行开始在 ITest.GetDatas( ob );处报 “从非托管 VARIANT ......”的错误。
试着修改C#内的ob变量的定义和网上提到的各种方法都没有用。
最后看到MSDN处对VARIANT的定义
SAFEARRAY FAR* parray; VT_ARRAY|*
才想到问题可能处在变量定义出;
修改变量的数据类型赋值:
STDMETHODIMP CTest::GetDatas( VARIANT* pVar)
{
//pVar->vt = VT_R4;
//pVar->dblVal = 1.1;
SAFEARRAYBOUND sab;
sab.cElements = 10;
sab.lLbound = 0;
SAFEARRAY* psa = SafeArrayCreate(VT_R4,1,&sab);
for (long i = 0; i < 10; i++)
{
float f=i*1.1;
SafeArrayPutElement(psa,&i , &f);
}
pVar->vt = VT_ARRAY| VT_R4;
pVar->parray = psa;
return S_OK;
}
再次运行C#测试程序,程序正常得到数据。
由此可见C#的对VARIANT的封装做的还是很完善的,在用object作为VARIANT的对应数据,
在其内部一定是做了数据转换的,转换时vt的值是判断数据类型的关键(这是显然的)。
我又用C++做了测试程序连接ATL,但在C++下,使用SafeArrayGetElement()函数获取数据。
不管写成 pVar->vt = VT_ARRAY| VT_R4;
还是 pVar->vt = VT_ARRAY;
都没有问题,应为使用SafeArrayGetElement前已经定义了变量的类型来获取数据。
至此,问题解决。