图4-4展示了一个自定义接口。自定义接口总是从接口IUnknown派生。IUnknwon是所有COM接口的基础接口,定义了三个方法:AddRef、Release和QueryInterface。跟着这些方法之后的是指向接口ICourseManagement所包含方法(GetCourse、SetCourse和GetCustomerControl)的
指针。
这种接口的特点在于这是调用方法最快的途径,但是它会受限于
编程语言,接口定义必须在编译时可见。
脚本客户端(比如VBScript和JavaScript)无法使用这些接口,而Visual Basic 6编写的客户端可以使用这种接口
脚本客户端不能处理自定义接口,它们只能使用调度接口。一个调度接口是一个
IDispatch接口的实现,它可以被
脚本客户端理解,所以在编译时不需要知道接口的内存布局。
图4-5展示了IDispatch接口的功能。除了IUnknown的方法外,一个IDispatch接口定义了四个方法。第三个和第四个是最有意思的方法:GetIDsOfNames和Invoke。GetIDsOfNames会被
客户端最先调用以得到一个方法名对应的ID。比如,客户端传入方法名“GetCourse”后将在返回值中得到其ID 0x60020000。这个方法的标号或者调度ID将会被传入到IDispath的Invoke方法,以调用GetCourse这个方法。Invoke方法然后就会使用另一个映射表来根据调度ID得到方法入口,这样这个方法就可以被调用。
你可以想象到这会比自定义接口慢。从方法名获得其ID,以及通过ID调用方法的这些映射机制是需要花时间的。而且除了这种映射机制,还有数据转换的过程。Invoke仅接受一个参数,这个参数内包含的参数需要通过转换才能用来调用目标方法。
自定义接口可以提供最佳的性能,而调度接口可以被脚本客户端调用。为了两全其美,微软设计出了双重接口。双重接口从IDispatch接口派生,但是添加了一些新的方法到vtable中(见图4-6)。只知道IDispatch的
客户端可以使用它的GetIDsOfNames和Invoke方法来得到和访问那些方法
指针,但是可以访问自定义接口的客户端也可以直接使用它们。