COM组件中使用用户自定义数据类型
2002-05-20· ·lostall··COM集中营
(1) 从IUnknown继承的自定义接口
把数据结构直接传送给基于VTable接口的方法,只适用于由MIDL编译生成的proxy/stub DLL调度的接口,不能用于Invoke();(参UserDefinedDataType(1))
a.在一个新的.h文件中定义自定义数据结构.
b.在.idl文件最前面加入这个.h文件,比如:
#include "MyStruct.h"
c.给从IUnknown派生的接口加入使用了自定义数据结构的方法。
d.在客户程序的stadafx.h最下面加入#import指令,如:
#import "../test3.tlb" no_namespace
在生成的.tlh文件中,会自动包含了用户自定义数据结构的定义。
e.在客户程序需要的时侯调用组件接口函数。
整个过程非常简单,与使用一般的自定义数据类型无异。
另外也可以很方便的使用自定义数据结构数组,使用方法如下:
HRESULT Test2([in]int nCount, [in, size_is(nCount)]MyStruct *pStruct)
(2)从IDispatch继承的双接口
对于从IDispatch继承的双接口就不能象方法一那样直接在接口方法里申请自定义类型了,因为双接口必须要用与自动化兼容的类型。所以采用以下的步骤。
(参UserDefinedDataType(2))
a.首先在.idl文件中加入如下几句,定义一个自定义数据类型。
typedef [ uuid(44ABAE82-A173-11d4-98DB-0080C8F5B2E4)]
struct MyStruct
{
int x;
int y;
}MyStruct;
b.接口方法参数定义为VARIANT类型,指针也一样。
c.客户端通过ClassWiard导入类型库(用#import也可以,不过这里要验证自动化)
d.客户程序中要加入MyStruct的定义
e.客户程序中加入以下代码:
const GUID GUID_MyStruct=
{0x44ABAE82,0xA173,0x11d4,{0x98,0xDB,0x00,0x80,0xC8,0xF5,0xB2,0xE4}};
const GUID LIBID_TEST6Lib =
{0x67061661,0xa2cb,0x11d4,{0x98,0xdb,0x00,0x80,0xc8,0xf5,0xb2,0xe4}};
ITypeLib* pTypeLib=NULL;
ITypeInfo* pTypeInfo=NULL;
IRecordInfo* pRecordInfo=NULL;
LoadRegTypeLib(LIBID_TEST6Lib, 1, 0, LANG_NEUTRAL, &pTypeLib);
pTypeLib->GetTypeInfoOfGuid(GUID_MyStruct, &pTypeInfo);
GetRecordInfoFromTypeInfo(pTypeInfo, &pRecordInfo);
MyStruct *pMyStruct = new MyStruct;
pMyStruct->x = pMyStruct->y = 100;
VARIANT vr;
VariantInit(&vr);
vr.vt = VT_RECORD; //表明自定义类型
vr.pvRecord = (PVOID)pMyStruct; //指向实际数据
vr.pRecInfo = pRecordInfo; //包含了数据的一些信息
test6.Test2(vr); //调用接口方法
pTypeLib->Release();
pTypeInfo->Release();
pRecordInfo->Release();
f.在服务器组件接口方法的实现中加入以下几句:
if (vr.vt == VT_RECORD)
{
IRecordInfo *pRecordInfo = vr.pRecInfo;
PVOID pMyStruct = vr.pvRecord;
VARIANT varX, varY;
int x=0, y=0;
VariantInit(&varX);
VariantInit(&varY);
pRecordInfo->GetField(pMyStruct, L"x", &varX);//获得x字段的值
if (varX.vt == VT_INT)
{
x = varX.intVal;
}
pRecordInfo->GetField(pMyStruct, L"y", &varY);//获得y字段的值
if (varX.vt == VT_INT)
{
y = varY.intVal;
}
}
补:
a.通过VARIANT,VT_RECORD,IRecordInfo的这种方法可以用自动化来传递自定义类型数据,但实际上这种方法只适用于双接口的情况。其原因在于实现组件IDispatch接口的IDispatchImpl类身上,它是通过VTable来调用方法的。如果是纯Dispatch接口就不能用这种方法,而我经过试验,暂时无法用这种方法实现dispinterface的情况。
b.同样的方法适用于安全数组,如果传递一个自定义数据结构的数组,则要用到SAFEARRAY,注意用类似SafeArrayCreateEx(VT_RECORD,1,&rgbounds,pRecInfo)的方法来创建数组。
(3)用dispinterface说明的纯IDispatch接口暂时没找到方法。