@网络老鼠技术小屋

网络老鼠技术小屋-涂飞平的博客空间

发现自己原来写的东西也蛮经典^_^

10 年前 0

今天有个工作涉及了自动化接口,找到很多文档,居然发现很早(2004-11-23)时候自己在01cn.net发表的一个回帖,其中对于IDispatch接口产生原因和工作方式的解释很到位,其中的语言也组织的不错。佩服自己真是太有才了^_^
下面是节选:(原文具体见:http://www.01cn.net/cgi-bin/topic_show.cgi?id=1285)
IDispatch这个接口其实是为VB和脚本语言特别设置的(VB开
始时候是解析执行的,并不是真正的32位原生代码!),对于一个普通接口(除IDispatch外),其实他们是一种内存规范而已,也就是说对于其中的各
个方法的调用,他们都是通过接口指向的vptr来定位的,比如:
IFoo=interface(IUnKnown)
function foo1:HResult;
end;
那么你得到这个接口后,这样调用:IFoo.foo1,而对应的IFoo的地址放在EAX
中,那么它的调用的代码是这样的:
Call [eax+$C],也就是说它是除了IUnKonwn三个标准方法后的一个方法(第四个了)。
在解释型的语言中,构造这种内存不是不可能,但不同的接口就要构造不同的内存架构,很是麻烦,而且效率不会高到哪里去,所以MS想到一个好的办法,就是只
是在内存中构造一种内存结构,然后通过这种结构和接口中函数的方法名称(脚本中正好可以使用函数的名称来调用方法,两全其美!)来调用接口的方法。这就是
IDispatch的由来了,只要对象具有了这个接口(和由这个接口派生的接口),那么它的接口其他方法就可以被请求了(一般叫作双接口),注意:
由IDispatch派生的接口,他们的接口内存结构与IDispatch也是不同的,但前面的几个域是一样的(就象子对象内存布局中包含父对象内存布局
一样的道理!),所以对于他们的访问一样可以采用构造IDispatch内存方式!而无需为这个接口构造完整的内存结构,因为这个结构后面的方法我们并不
打算使用内存地位的方式来请求,而是准备采用下面说的方式来请求!

IDispatch 有4个方法 GetTypeInfoCount,GetTypeInfo,GetIDsOfNames ,Invoke
通过他们可以得到对象接口的各种信息,最后可以通过得到的函数名和函数的代号来用Invoke调用,这样就不要构造那些接口的内存结构而直接访问各个接口了!
但天下没有白吃的午餐,既然MS为了方便只是用一个接口来调用其他的接口,那么中间我们实现IDispatch的时候就要为那些发出请求的软件正确返回我
们内部其他接口的正确信息,很多事情都要我们自己做了,也就IDispatch 接口将部分工作转嫁到我们的身上了^_^(它到省事了)
下面模仿一下脚本型语言的访问方式:
假设一个asp中:
dim v
v=CreateObject("asdsadasd")//构建一个对象,也就是IDispatch内存块,并在内部加载此对象,并且同时请求这个对象的IDispatch接口;
v.foo1//得到方法名称:"foo1",然后通过IDispatch的GetIDsOfNames得到这个函数的ID值,最后就通过Invoke和这个ID值来调用foo1方法了。


过这个分析我们应该知道,要想在ASP中执行的方法(因为它是一种脚本环境),你的接口除了要有自己的方法之外,还必须是从IDispatch接口继承下
来的,这样解析机才会正确的调用,但也应该看到,经过了这么多调度过程,它的效率与直接在内存中接口访问慢很多了(不是一个数量级^_^)

编写评论