From: lostall - COM集中营

 

(1) IUnknown继承的自定义接口

 

把数据结构直接传送给基于VTable接口的方法,只适用于由MIDL编译生成的proxy/stub DLL调度的接口,不能用于Invoke(); (UserDefinedDataType(1))

 

a.在一个新的.h文件中定义自定义数据结构.

 

b..idl文件最前面加入这个.h文件,比如:

 

[DRAFT]COM组件中使用用户自定义数据类型(zz)#include "MyStruct.h" 

c.给从IUnknown派生的接口加入使用了自定义数据结构的方法。

 

d.在客户程序的stadafx.h最下面加入#import指令,如:

 

[DRAFT]COM组件中使用用户自定义数据类型(zz)#import "..\test3.tlb" no_namespace

在生成的.tlh文件中,会自动包含了用户自定义数据结构的定义。

 

e.在客户程序需要的时侯调用组件接口函数。

 

整个过程非常简单,与使用一般的自定义数据类型无异。

 

另外也可以很方便的使用自定义数据结构数组,使用方法如下:

 

[DRAFT]COM组件中使用用户自定义数据类型(zz)HRESULT Test2 ( [in]int nCount, [in, size_is(nCount)]MyStruct *pStruct )

(2)IDispatch继承的双接口

 

对于从IDispatch继承的双接口就不能象方法一那样直接在接口方法里申请自定义类型了,因为双接口必须要用与自动化兼容的类型。所以采用以下的步骤。(UserDefinedDataType(2))

 

a.首先在.idl文件中加入如下几句,定义一个自定义数据类型。

[DRAFT]COM组件中使用用户自定义数据类型(zz)typedef  [ uuid(44ABAE82-A173-11d4-98DB-0080C8F5B2E4) ][DRAFT]COM组件中使用用户自定义数据类型(zz)
[DRAFT]COM组件中使用用户自定义数据类型(zz)
struct  MyStruct 

[DRAFT]COM组件中使用用户自定义数据类型(zz)  
int x; 
[DRAFT]COM组件中使用用户自定义数据类型(zz)  
int y; 
[DRAFT]COM组件中使用用户自定义数据类型(zz)}
MyStruct; 

 

b.接口方法参数定义为VARIANT类型,指针也一样。

 

c.客户端通过ClassWiard导入类型库(#import也可以,不过这里要验证自动化)

 

d.客户程序中要加入MyStruct的定义

 

e.客户程序中加入以下代码:

 

[DRAFT]COM组件中使用用户自定义数据类型(zz)const GUID GUID_MyStruct=[DRAFT]COM组件中使用用户自定义数据类型(zz)

[DRAFT]COM组件中使用用户自定义数据类型(zz)
[DRAFT]COM组件中使用用户自定义数据类型(zz)
const GUID LIBID_TEST6Lib =[DRAFT]COM组件中使用用户自定义数据类型(zz)

[DRAFT]COM组件中使用用户自定义数据类型(zz)[DRAFT]COM组件中使用用户自定义数据类型(zz)
[DRAFT]COM组件中使用用户自定义数据类型(zz)ITypeLib
* pTypeLib=NULL; 
[DRAFT]COM组件中使用用户自定义数据类型(zz)ITypeInfo
* pTypeInfo=NULL;[DRAFT]COM组件中使用用户自定义数据类型(zz)
[DRAFT]COM组件中使用用户自定义数据类型(zz)IRecordInfo
* pRecordInfo=NULL; 
[DRAFT]COM组件中使用用户自定义数据类型(zz)[DRAFT]COM组件中使用用户自定义数据类型(zz)
[DRAFT]COM组件中使用用户自定义数据类型(zz)LoadRegTypeLib(LIBID_TEST6Lib, 
10, LANG_NEUTRAL, &pTypeLib); 
[DRAFT]COM组件中使用用户自定义数据类型(zz)pTypeLib
->GetTypeInfoOfGuid(GUID_MyStruct, &pTypeInfo); 
[DRAFT]COM组件中使用用户自定义数据类型(zz)GetRecordInfoFromTypeInfo(pTypeInfo, 
&pRecordInfo); 
[DRAFT]COM组件中使用用户自定义数据类型(zz)[DRAFT]COM组件中使用用户自定义数据类型(zz)
[DRAFT]COM组件中使用用户自定义数据类型(zz)MyStruct 
*pMyStruct = new MyStruct; 
[DRAFT]COM组件中使用用户自定义数据类型(zz)pMyStruct
->= pMyStruct->= 100
[DRAFT]COM组件中使用用户自定义数据类型(zz)
[DRAFT]COM组件中使用用户自定义数据类型(zz)VARIANT vr; 
[DRAFT]COM组件中使用用户自定义数据类型(zz)VariantInit(
&vr); 
[DRAFT]COM组件中使用用户自定义数据类型(zz)vr.vt 
= VT_RECORD; //表明自定义类型 
[DRAFT]COM组件中使用用户自定义数据类型(zz)
vr.pvRecord = (PVOID)pMyStruct; //指向实际数据 
[DRAFT]COM组件中使用用户自定义数据类型(zz)
vr.pRecInfo = pRecordInfo; //包含了数据的一些信息 
[DRAFT]COM组件中使用用户自定义数据类型(zz)
test6.Test2(vr); //调用接口方法 
[DRAFT]COM组件中使用用户自定义数据类型(zz)
[DRAFT]COM组件中使用用户自定义数据类型(zz)
[DRAFT]COM组件中使用用户自定义数据类型(zz)pTypeLib
->Release(); 
[DRAFT]COM组件中使用用户自定义数据类型(zz)pTypeInfo
->Release(); 
[DRAFT]COM组件中使用用户自定义数据类型(zz)pRecordInfo
->Release(); 

 

f.在服务器组件接口方法的实现中加入以下几句:

 

[DRAFT]COM组件中使用用户自定义数据类型(zz)if (vr.vt == VT_RECORD) 

[DRAFT]COM组件中使用用户自定义数据类型(zz)  IRecordInfo 
*pRecordInfo = vr.pRecInfo; 
[DRAFT]COM组件中使用用户自定义数据类型(zz)  PVOID pMyStruct
= vr.pvRecord; 
[DRAFT]COM组件中使用用户自定义数据类型(zz)  VARIANT varX, varY; 
[DRAFT]COM组件中使用用户自定义数据类型(zz)  
int x=0, y=0
[DRAFT]COM组件中使用用户自定义数据类型(zz)
[DRAFT]COM组件中使用用户自定义数据类型(zz)  VariantInit(
&varX); 
[DRAFT]COM组件中使用用户自定义数据类型(zz)  VariantInit(
&varY); 
[DRAFT]COM组件中使用用户自定义数据类型(zz)
[DRAFT]COM组件中使用用户自定义数据类型(zz)  pRecordInfo
->GetField(pMyStruct, L"x"&varX); //获得x字段的值 
[DRAFT]COM组件中使用用户自定义数据类型(zz)

[DRAFT]COM组件中使用用户自定义数据类型(zz)  
if (varX.vt == VT_INT) 

[DRAFT]COM组件中使用用户自定义数据类型(zz)    x 
= varX.intVal; 
[DRAFT]COM组件中使用用户自定义数据类型(zz)  }
 
[DRAFT]COM组件中使用用户自定义数据类型(zz)
[DRAFT]COM组件中使用用户自定义数据类型(zz)  pRecordInfo
->GetField(pMyStruct, L"y"&varY); //获得y字段的值 
[DRAFT]COM组件中使用用户自定义数据类型(zz)

[DRAFT]COM组件中使用用户自定义数据类型(zz)  
if (varX.vt == VT_INT) 

[DRAFT]COM组件中使用用户自定义数据类型(zz)    y 
= varY.intVal; 
[DRAFT]COM组件中使用用户自定义数据类型(zz)  }
 
[DRAFT]COM组件中使用用户自定义数据类型(zz)}
 

 

补充:

 

a.通过VARIANT,VT_RECORD,IRecordInfo的这种方法可以用自动化来传递自定义类型数据,但实际上这种方法只适用于双接口的情况。其原因在于实现组件IDispatch接口的IDispatchImpl类身上,它是通过VTable来调用方法的。如果是纯Dispatch接口就不能用这种方法,而我经过试验,暂时无法用这种方法实现dispinterface的情况。

 

b.同样的方法适用于安全数组,如果传递一个自定义数据结构的数组,则要用到SAFEARRAY,注意用类似SafeArrayCreateEx(VT_RECORD,1,&rgbounds,pRecInfo)的方法来创建数组。

 

(3)dispinterface说明的纯IDispatch接口暂时没找到方法。


下载源代码:(1), (2)

相关文章: