56
自自自 自自自 (Automation) (Automation) 自自自 http://www.icst.pku.edu.cn/ CompCourse/

自动化 (Automation)

  • Upload
    kalani

  • View
    121

  • Download
    0

Embed Size (px)

DESCRIPTION

自动化 (Automation). 潘爱民 http://www.icst.pku.edu.cn/CompCourse/. 内容. 自动化基础 自动化对象实现 自动化对象应用 自动化编程. 自动化产生与发展. 弱类型的高级语言 ( 比如 Visual Basic) 如何使用 COM ? VBA( 或 VBScript) 自动化与 COM 的关系 自动化的广泛应用. 几个概念. 自动化对象 实现了 IDispatch 接口的 COM 对象 属性和方法 ODL( 对象描述语言 ) 类型库 自动化兼容的数据类型. - PowerPoint PPT Presentation

Citation preview

Page 1: 自动化 (Automation)

自动化自动化 (Automation)(Automation)

潘爱民

http://www.icst.pku.edu.cn/CompCourse/

Page 2: 自动化 (Automation)

内容内容自动化基础自动化对象实现自动化对象应用自动化编程

Page 3: 自动化 (Automation)

自动化产生与发展自动化产生与发展弱类型的高级语言 ( 比如 Visual Basic)

如何使用 COM ?

VBA( 或 VBScript)

自动化与 COM 的关系

自动化的广泛应用

Page 4: 自动化 (Automation)

几个概念几个概念自动化对象– 实现了 IDispatch 接口的 COM 对象

属性和方法ODL( 对象描述语言 )类型库自动化兼容的数据类型

Page 5: 自动化 (Automation)

属性属性 (property)(property) 和方法和方法 (method)(method)

自动化对象的两个基本特性,都具有符号化的名字,用 DISPID 来标识

属性是指自动化对象的数据特征– 属性可以由索引,索引可以是整数,也可以是其他

类型

方法是指自动化对象所提供的功能服务– 方法比属性要灵活得多,可以包含参数

Page 6: 自动化 (Automation)

类型库类型库 (typelib)(typelib)

类型信息是客户程序与组件对象之间通讯的基础

IDL 和 ODL– 接口类型信息使用 interface 或 dispinterface 关键

字描述– 对象类型信息使用 coclass 关键字描述

library 关键字描述库信息– 一个组件程序中的所有对象放在一个 ODL 文件中,

并用 library 关键字描述库信息 工具 MIDL :从 ODL(IDL) 编译成 TLB 文件

Page 7: 自动化 (Automation)

ODLODL 描述举例描述举例

未完未完

Page 8: 自动化 (Automation)

ODLODL 描述举例描述举例 ((续续 ))

Page 9: 自动化 (Automation)

另一个另一个 ODLODL 接口例子接口例子

Page 10: 自动化 (Automation)

IDispatchIDispatch 接口接口

Page 11: 自动化 (Automation)

分发分发 ID(DISPID)ID(DISPID) 整数, 0 和负数有特殊含义

自动化接口通过分发 ID 管理方法和属性

保留的分发 ID及其含义分发 ID 值 说明

DISPID_VALUE 0接口的缺省成员,如果在客户程序中不指定属性或方法,则用此缺省成员。

DISPID_UNKNOWN -1在 GetIDsOfNames 函数中返回此值表明相应的成员或参数名没有找到分发 ID。

DISPID_PROPERTYPUT -3 在属性设置函数中指示一个接收值的参数。DISPID_NEWENUM -4 集合对象的_NewEnum方法。

DISPID_EVALUATE -5对象的 Evaluate方法,在控制器的脚本语言中可以用方括号[]来表示。

DISPID_CONSTRUCTOR -6 表示具有与构造函数相同功能的方法。DISPID_DESTRUCTOR -7 表示具有与析构函数相同功能的方法。

Page 12: 自动化 (Automation)

客户与自动化对象交互示意图客户与自动化对象交互示意图

客户程序

自动化对象

IPointQueryInterfaceAddRefReleaseGetTypeInfoCountGetTypeInfoGetIDsOfNamesInvoke

vtable

get_xset_xget_yset_yMoveTo

Page 13: 自动化 (Automation)

IDispatch::InvokeIDispatch::Invoke

参数 dispIdMember 指定 DISPID 参数 lcid 指定本地化标识 参数 wFlags 指示调用类型

– DISPATCH_METHOD 、 DISPATCH_PROPERTYGET 、DISPATCH_PROPERTYPUT 、 DISPATCH_PROPERTYPUTREF

参数 pDispParams– 包括调用的参数数组、参数的 DISPID 数组、数组中参数个数等

信息 参数 pVarResult 保存返回值信息 参数 pExcepInfo 保存异常信息 参数 puArgErr 错误参数的索引值

Page 14: 自动化 (Automation)

自动化兼容的数据类型自动化兼容的数据类型 ((一一 ))

Page 15: 自动化 (Automation)

自动化兼容的数据类型自动化兼容的数据类型 ((二二 ))

Page 16: 自动化 (Automation)

自动化兼容的数据类型自动化兼容的数据类型 ((三三 ))

布尔型 VARIANT_BOOLtypedef short VARIANT_BOOL;/* 0 == FALSE, -1 == TRUE */

货币类型 CYtypedef struct tagCY

{unsigned long Lo;long Hi;

} CY; 日期类型 DATE

– 浮点数,整数部分表示自 1899 年 12 月 30 日以来的天数,小数部分为时间值

Page 17: 自动化 (Automation)

BasicBasic 字符串类型字符串类型 BSTRBSTR

OLE 提供了一组 API 函数处理 BSTR :– SysAllocString 、 SysAllocStringLen 、 SysFre

eString 、 SysReAllocString 、 SysReAllocStringLen 以及 SysStringLen 等

count …… \0

4字节长度值 字符串,其长度等于指定的值 以 0结尾

LPTSTR psz

Page 18: 自动化 (Automation)

SAFEARRAYSAFEARRAY 类型类型

OLE 也提供了一套 API 函数用来处理 SAFEARRAY 结构

Page 19: 自动化 (Automation)

自动化数据类型的转换自动化数据类型的转换 Invoke 函数的数据类型转换能力为弱数据类

型开发环境提供了极大的便利

OLE 提供了两个类型转换函数: VariantChangeType 和 VariantChangeTypeEx

OLE 也提供了一组专门的类型转换函数 Var<type>From<type> ,比如 VarR4FromI2 、 VarUI2FromDisp 等

Page 20: 自动化 (Automation)

属性和方法调用的参数传递属性和方法调用的参数传递 Invoke 函数的参数 pDispParams

typedef struct tagDISPPARAMS

{

VARIANTARG *rgvarg; // 参数数组 DISPID *rgdispidNamedArgs; // 参数的分发 ID 数组 UINT cArgs; // 数组中参数个数 UINT cNamedArgs; // 命名参数个数} DISPPARAMS;

Page 21: 自动化 (Automation)

参数顺序参数顺序 在 rgvarg 数组中,参数的顺序与客户程序中

调用的参数左右顺序刚好相反比如:

Object.Method(arg1, arg2, arg3)

对应 Invoke 函数的 pDispParams 参数的 DISPPARAMS 结构中, cArgs 为 3 ,表明方法调用有 3 个参数, rgarg 数组的成员分别为:arg3 对应 rgvarg[0] 、 arg2 对应 rgvarg[1] 、arg1 对应 rgvarg[2] 。

Page 22: 自动化 (Automation)

可选参数可选参数 ODL 文件中,可以把方法的参数标记为可选的

(optional)

可选参数也会出现在 DISPPARAMS 结构中

如果 vt 域为 VT_ERROR 并且 scode 域为 DISP_E_PARAMNOTFOUND ,则此参数为可选参数

Page 23: 自动化 (Automation)

命名参数命名参数 (named argument)(named argument)

DISPPARAMS 结构的 cNamedArgs 成员指定了在 rgarg 数组中命名参数的个数

命名参数可以不受次序约束比如:

rgdispidNamedArgs

dog pig elephant 3

id (0) id (1) id (2)

rgvarg

0 1 2 3

cArgs=4

cNamedArgs=3

Page 24: 自动化 (Automation)

IDispatchExIDispatchEx 接口接口派生于 IDispatch

IDispatchEx 接口最主要的特性是增加了对成员的管理,尤其是动态增加和删除成员的特性

Page 25: 自动化 (Automation)

IDispatchExIDispatchEx 接口使用例子接口使用例子cmd1.CommandText = "AuthorsByYearBorn"cmd1.CommandType = adCmdStoredProccmd1.Name = "AuthorsSP"cmd1.ActiveConnection = Cn

Private Sub RunSPButton_Click()Cn.authorsSP 1947, 1948, rsEnd Sub

Page 26: 自动化 (Automation)

自动化对象实现:自动化对象实现: GetTypeInfoCounGetTypeInfoCountt 类型库支持– 首先把本接口所在的 idl 文件编译成 tlb 文件,以便

利用 COM 提供的类型库功能实现本接口的类型支持

STDMETHODIMP CImpIDispatch::GetTypeInfoCount(UINT *pctInfo)

{ *pctInfo=1; //Because we have implemented GetType

Info member. return NOERROR;}

Page 27: 自动化 (Automation)

自动化对象实现:自动化对象实现: GetTypeInfoGetTypeInfo

Page 28: 自动化 (Automation)

GetIDsOfNamesGetIDsOfNames 实现实现HRESULT GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames,

UINT cNames, LCID lcid, DISPID *rgDispId)

第一种方法,由于自动化对象知道自己所有的方法和属性以及它们的分发 ID ,所以它可以利用这些知识提供 GetIDsOfNames 服务

第二种方法,利用自动化接口的类型信息对象实现 GetIDsOfNames 函数。调用 ITypeInfo::GetIDsOfNames 函数

HRESULT GetIDsOfNames(LPOLESTR *rgszNames,UINT cNames, MEMBERID *pMemId);

或者 OLE 的封装函数 DispGetIDsOfNames

Page 29: 自动化 (Automation)

ITypeLibITypeLib 和和 ITypeInfoITypeInfo 接口接口 COM 实现的 typelib 对象– LoadRegTypeLib ,通过注册表– LoadTypeLib– 通过 ITypeLib 接口操纵 typelib 对象– 第三方语言通过 typelib 支持 COM

typeinfo 对象– 类型库中的类型对象,例如接口、结构、对象– 通过 ITypeInfo 接口操纵 typeinfo 对象

Page 30: 自动化 (Automation)

InvokeInvoke 函数实现函数实现第一种方法适合于比较简单的情形, Inv

oke 函数负责所有的成员处理,包括参数提取、转换等等,然后根据成员分发 ID 的不同,执行不同的分支

第二种方法也要用到类型库信息对象 ITypeInfo 接口指针。

Page 31: 自动化 (Automation)

类型库与自动化对象之间的关系类型库与自动化对象之间的关系

客户程序

(控制器)

自动化对象

……

GetTypeInfoCount

GetTypeInfo

GetIDsOfNames

Invoke

DIPoint类型信息

对象

ITypeInfo

get_xset_xget_yset_yMoveTo

TLB文件

MIDL工具头文件

ODL文件

IPoint

Page 32: 自动化 (Automation)

MIDLMIDL 生成的头文件中接口定生成的头文件中接口定义义

Page 33: 自动化 (Automation)

InvokeInvoke 函数实现举例函数实现举例

Page 34: 自动化 (Automation)

InvokeInvoke 函数调用过程中的异常处理函数调用过程中的异常处理((一一 ))

异常信息由 EXCEPINFO 结构定义

Page 35: 自动化 (Automation)

InvokeInvoke 函数调用过程中的异常处理函数调用过程中的异常处理((二二 ))

异常信息– Invoke 函数直接填充– 或者通过回调函数由客户控制填充信息

如果用类型库实现 Invoke 函数,那么有两种支持异常的办法:– 通过中间变量传递异常信息– 使用 OLE 提供的错误对象

Page 36: 自动化 (Automation)

多语种——本地化多语种——本地化LCID(LocaleID 或者 locale identifier)

函数参数。 LCID被定义为一个 32位的整数。

参看Winnt.h

Page 37: 自动化 (Automation)

用聚合方式实现自动化对象用聚合方式实现自动化对象CreateStdDispatch 函数创建内部聚合

对象

需要类型库

不支持多语种

Page 38: 自动化 (Automation)

自动化对象应用自动化对象应用双接口 (dual interface)迟绑定和早绑定自动化集合对象以 IDispatch作为出接口 *自动化控制器

Page 39: 自动化 (Automation)

dual interfacedual interface

一个接口,既有 IDispatch 接口的灵活性,又有 vtable 接口的效率

从 IDispatch 接口派生– 使用自动化兼容的数据类型

通过 vtable 可以访问属性和方法

Page 40: 自动化 (Automation)

双接口结构图双接口结构图

客户程序

(控制器)

自动化对象

IPoint (双接口)

类型信息

对象

ITypeInfo

QueryInterfaceAddRefReleaseGetTypeInfoCountGetTypeInfoGetIDsOfNamesInvokeget_xset_xget_yset_yMoveTo

TLB文件

MIDL工具头文件

ODL文件

vtable

Page 41: 自动化 (Automation)

双接口定义双接口定义

Page 42: 自动化 (Automation)

迟绑定和早绑定迟绑定和早绑定早绑定 (early binding)– compile time ,利用 typelib– vtable binding , dispid binding– 一般用于编译环境,例如 VB 、 VC 等,以及 VBA ,效率高

迟绑定 (late binding)– runtime– dispid binding– 可以用于脚本环境,例如 ASP 等,灵活性

Page 43: 自动化 (Automation)

早绑定早绑定例如,在 VB 中,开发时刻检查类型信

Page 44: 自动化 (Automation)

自动化集合对象自动化集合对象集合对象也是自动化对象,但要求:– 1 作为一组同类对象 ( 或数值 ) 的容器对象,它必须提供枚举这些成员的方法

– 2 它必须支持 Add 、 Remove 和 Item 方法以及 Count 属性

索引值可以是整数,也可以是其他类型 利用标准属性或方法 _NewEnum 提供“ for

…each” 语法结构的枚举特性集合对象的命名

Page 45: 自动化 (Automation)

对象层次模型示意图对象层次模型示意图

Page 46: 自动化 (Automation)

对象层次模型对象层次模型object hierarchy 或 object modelApplication 对象,全局对象,可创建大多数对象都是不可创建的层次之间的关联–集合与元素的关系,通过枚举器访问– 属性关系,下级对象是上级对象的一个属性

Page 47: 自动化 (Automation)

自动化控制器自动化控制器 (automation controller)(automation controller)

自动化控制器也是一个 COM 客户,功能强大的自动化控制器往往考虑以下特性:– 对象创建机制。– 对象析构机制。– 如何连接到一个已经在运行的自动化对象。– 如何访问自动化对象的属性。– 如何调用自动化对象的方法。– 提供事件处理机制。– 从一个接口转移到另一个接口上。– 向用户提供 UI 形式的对象类型信息。

VB 、 VBScript 等

Page 48: 自动化 (Automation)

脚本技术:脚本技术:应用系统、脚本引擎和脚本文件三者关系应用系统、脚本引擎和脚本文件三者关系

应用系统

(宿主程序)脚本引擎

脚本文件

通过脚本控制应用

创建引擎

装入脚本文件

启动引擎、终止引擎

Page 49: 自动化 (Automation)

脚本技术脚本技术

7. 事件通知

IActiveScriptSite

3. 装入脚本文件

应用系统Script

脚本引擎

脚本文件

名字项对

应的对象IDispatch

IConnectionPointContainer

IActiveScriptParse接口

2. 创建引擎对象

4. 加入名字项

6. 获取名字项信息

8. 调用对象的属性和方法

1. 创建必要的受控对象

IActiveScript接口

5. 启动引擎,运行脚本

与对象有

关的脚本

Page 50: 自动化 (Automation)

自动化对象的自动化对象的 marshalingmarshaling Universal marshaler

– CLSID : {00020424-0000-0000-C000-000000000046} – 只要接口中的数据类型是自动化兼容的,就可以使用。接口可以不是自

动化接口– 在描述接口时,加上属性 oleautomation 或者 dual

注册:[HKCR\Interface\<interface-iid>]

@="IMyInterface" [HKCR\Interface\ <interface-iid>\ProxyStubClsid32]

@="{00020424-0000-0000-C000-000000000046}" [HKCR\Interface\ <interface-iid>\ProxyStubClsid]

@="{00020424-0000-0000-C000-000000000046}“[HKCR\Interface\ <interface-iid>\TypeLib]

@=" <typelib-id>“Version="1.0"

Page 51: 自动化 (Automation)

Universal marshalerUniversal marshaler 示意图示意图

类型库

接口存根接口代理客户调用

目标对象

类型库

Page 52: 自动化 (Automation)

在在 Visual BasicVisual Basic 中使用自动化对象中使用自动化对象((一一 ))

Page 53: 自动化 (Automation)

在在 Visual BasicVisual Basic 中使用自动化对象中使用自动化对象((二二 ))

Dim PointObject As New PointComp.PointObj

PointObject.x = 100

PointObject.y = 100

……

PointObject.MoveTo(200, 150)

对象浏览器

Page 54: 自动化 (Automation)

例子程序例子程序 ((一一 ))

程序 1—— 具有计算器功能的自动化对象

Page 55: 自动化 (Automation)

例子程序例子程序 ((二二 ))

程序 2—— 自动化客户程序

Page 56: 自动化 (Automation)

例子程序例子程序 ((三三 ))程序程序 3——3—— 在在 ExcelExcel 中使用计算器对中使用计算器对

象象