COM 组件技术实验7

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

COM 组件技术实验7---
自动化组件的应用(二):双接口(及其调用)的原理
一、实验内容
1、本次实验将通过编写客户程序来达到进一步理解双接口模型的目的。

故组件可使用实验6中的双接口自动化组件,在入参类型判断处需要略做修改(详见实验步骤)。

2、使用VC++编写2个客户程序来调用该组件。

一个通过vtable直接调用接口方法;另一个则通过IDispatch去调用。

二、实验步骤
1、修改实验6时完成的Add方法
STDMETHODIMP CDispSimple::Add(VARIANT a, VARIANT b, VARIANT *pVal)
{
::VariantInit( pVal ); //初始化返回值
CComVariant v_1( a ); //ATL提供
CComVariant v_2( b );
if((a.vt == VT_R8) && (b.vt == VT_R8) )// 如果都是小数类型(当客户程序使用VC时,此处直接使用==进行判断;当客户程序使用Vb时,使用&进行判断,因为vb在调用该方法时进行了处理,同学们在完成实验后可自行通过调试的手段进行观察)
{
v_1.ChangeType( VT_R8 ); // 转换为小数
v_2.ChangeType( VT_R8 ); // 转换为小数
pVal->vt = VT_R8;
pVal->dblVal = v_1.dblVal + v_2.dblVal; // 加法}
else if((a.vt == VT_I4) && (b.vt == VT_I4) )// 如果都是整数类型
{ v_1.ChangeType( VT_I4 ); // 转换为整数
v_2.ChangeType( VT_I4 ); // 转换为整数
pVal->vt = VT_I4;
pVal->lVal = v_1.lVal + v_2.lVal; // 加法}
else //其他情况做为字符串处理
{
v_1.ChangeType( VT_BSTR ); // 转换为字符串
v_2.ChangeType( VT_BSTR ); // 转换为字符串
CComBSTR bstr( v_1.bstrVal );
bstr.AppendBSTR( v_2.bstrVal ); //字符串连接
pVal->vt = VT_BSTR;
pVal->bstrVal = bstr.Detach(); //给出参赋值
}
return S_OK;
}
Upper方法无需修改。

2、双接口模型的3种调用方式回顾
双接口(dual) 结构示意图
在讲解双接口模型时,我们总结过有3种调用双接口中方法的手段:
(A)通过vtable直接调用的方式(第1、2、3次实验的根本调用原理,效率最高)
(B)早绑定方式(编译型语言通过IDispatch调用方法的途径,效率不高)
(C)迟绑定方式(脚本语言调用自动化组件的途径,效率最低)
在这3种方式中,(C)方式上次实验已试过。

本次实验将关注(A)和(B)方式。

3、通过vtable直接调用方法
编写客户程序调用Add和Upper(如:计算20+30和20.5+30.3 ;将hello world转换成大写状态)并显示调用结果。

该调用方式就是把自动化组件当作普通的COM组件去调用。

我们已经练习过3次了,请同学们参照文档,独立思考完成,需要说明的是:
1、可使用原始的接口指针或智能指针进行编程(这里请使用#import方式的智能指针,再次练习下这种vc下最简便的调用方式)
2、注意参数类型是VARIANT型;所以在调用方法前应定义好VARIANT型的参数,可使用基本的VARIANT型,如:
VARIANT v1; //定义一个VARIANT型对象
v1.vt=…;//指明该VARIANT型对象的类型,如VT_I4,VT_BSTR…
v1.lVal=20; //给该VARIANT型对象赋值,注意lVal(整数)dblVal(小数)….,若是字符串则需要使用api函数SysAllocString,如v.bstrVal = SysAllocString(L"xxx")
3、由于在调用Upper方法后,返回的字符串是BSTR型的,所以显示调用结果前,需
要将该Unicode型的字符串转换为普通的字符串。

可使用ConvertBSTRToString,如char *p=_com_util::ConvertBSTRToString(vs.bstrVal) 注意:为了能使用该函数,必须加上头文件#include "comutil.h"并且在Project Setting --Link--Library Modules中加入comsupp.lib库文件。

4、通过IDispatch间接调用方法(早绑定)
同样编写客户程序调用Add和Upper(如:计算20+30和20.5+30.3 ;将hello world 转换成大写状态)并显示调用结果。

通过该客户程序的编写,我们可以对IDispatch有更深刻、更清晰的认识。

该调用方式揭示了具体如何通过IDispatch访问方法或属性。

请同学们参照文档,独立思考完成,需要说明的是:
1、可使用原始的接口指针或智能指针进行编程(这里请使用原始的接口指针。

选取的原则:简单应用时用智能指针合适,而涉及原理性的应用(底层)时用原始接口指针比较合适)。

2、通过IDispatch间接调用方法Add的例子(如:计算20+30):
int main(int argc, char* argv[])
{
//COM的初始化
//获取CLSID
//定义IDispatch 接口指针
//创建自动化对象并返回IDispatch 接口指针
CComBSTR BSFunName(L"Add"); // 准备取得Add 函数的序号DispID,为了能使用CComBSTR,别忘了头文件#include "atlbase.h"
DISPID dispID; // 定义一个DISPID序号对象
hResult = pIDisp->GetIDsOfNames( // 根据函数名,取得DISPID
IID_NULL,
&BSFunName, // 函数名
1, // BSFunName中的元素个数
LOCALE_SYSTEM_DEFAULT, // 使用系统默认的语言环境
&dispID ); // 返回值DISPID
if (FAILED(hResult))
{
printf("GetIDsOfNames failed!\n");
return -2;
}
VARIANT v[2]; // 定义Add(20,30) 方法所需要的参数
v[0].vt = VT_I4; v[0].lVal = 30; // 第二个参数,整数2
v[1].vt = VT_I4; v[1].lVal = 20; // 第一个参数,整数1
DISPPARAMS dispParams = { v, NULL, 2, 0 }; // 把参数包装在这个结构中,2表示现在数组里面有几个元素
VARIANT vResult; // 方法返回的计算结果
hResult = pIDisp->Invoke( // 调用Invoke方法
dispID, // 指定dispID
IID_NULL,
LOCALE_SYSTEM_DEFAULT, // 使用系统默认的语言环境
DISPATCH_METHOD, // 调用的是方法,不是属性
&dispParams, // 参数
&vResult, // 返回值
NULL, // 不考虑异常处理
NULL); // 不考虑错误处理
if (FAILED(hResult))
{
printf("Invoke failed!\n");
return -2;
}
printf("1 + 2 = %ld\n",vResult.lVal); //显示结果
……
……
}
3、结合教材,务必看懂以上原理性调用代码,自行完成20.5+30.3和hello world转换成大写状态的功能。

相关文档
最新文档