用汇编语言访问com对象[三]
2008-03-26 19:42
211 查看
大量的细节使得Com看上去很复杂,但是使用起来却很简单。最难的部分就是理解里面的数据结构,尽管COM是语言无关的,但是他借用了很多c++的术语来描述自己。
为了能使用某个对象的com接口函数,你必须首先要从类厂中创建这个对象,并且让他来返回接口指针。这个过程被CoCreateInstance这个API函数完成。当你使用完接口时,要调用Release方法。一个COM对象可以看作是一个服务,调用com的应用程序就是他的客户端。
在调用com接口函数之前,你需要了解接口是什么,一个com接口就是一个函数指针表,我们还是从IUnknown接口开始,如果你创建了一个组件导出了IUnknown接口,那么你就有了一个全功能的com对象。IUnknown有三个基本的几口方法,既然所有的接口都是从它派生出来,那么我们一定要记住,一个接口实际上就是一个函数指针成员组成的结构体。
例如:
IUnknown STRUCT DWORD
; IUnknown methods
IUnknown_QueryInterface QueryInterface_Pointer ?
IUnknown_AddRef AddRef_Pointer ?
IUnknown_Release Release_Pointer ?
IUnknown ENDS
它只有12个字节长,它具有3个DWORD指针来指向实际的实现函数。对于虚函数表,你一定听说过,这些指针定义如下,因此我们可以让masm在编译我们的调用时进行一些类型检查。
QueryInterface_Pointer typedef ptr QueryInterface_Proto
AddRef_Pointer typedef ptr AddRef_Proto
Release_Pointer typedef ptr Release_Proto
最后我们定义我们的函数如下:
QueryInterface_Proto typedef PROTO :DWORD, :DWORD, :DWORD
AddRef_Pointer typedef PROTO :DWORD
Release_Pointer typedef PROTO :DWORD
为了保持masm32松散的类型检查一致,函数参数都定义为dword
定义接口是一个相当大的编辑就是,masm不支持前向引用。因此,我们不得不颠倒一下定义的顺序。先定义函数头,再定义函数指针,最后定义接口。实际上在使用接口时,你需要一个指向它的指针。
CoCreateInstance函数能用来直接返回一个接口指针。它实际上指向了拥有接口的对象。这个结构看上去如图所示:
这个结构里有大量的间接访问,使用宏可以简化它。
当客户端调用COM库创建com组件时,它传进了一个地址用于存放对象指针。这个就是我们所说的ppv. 从c++的角度来讲,叫做指向指针的指针,void类型代表无类型。它保存了另一个指针pv的地址。pv指向了虚函数表。
例如:我们使用CoCreateInstance函数成功的返回了一个接口指针ppv,我们想看下它是否支持其他的接口,我们可以调用QueryInterface方法。用c++的方法描述QueryInterface如下:
(HRESULT) SomeObject::QueryInterface (this:pObject, IID:pGUID, ppv2:pInterface)
用汇编写法如下:
; get pointer to the object
mov eax, ppv
; and use it to find the interface structure
mov edx, [eax]
; push the function parameters onto the stack
push OFFSET ppv2
push OFFSET IID_ISomeOtherInterface
push dword ppv
; and then call that method
call dword ptr [edx + 0]
使用invoke调用简化如下:
; get pointer to the object
mov eax, ppv
; and use it to find the interface structure
mov edx, [eax]
; and then call that method
invoke (IUnknown PTR [edx]).IUnknown_QueryInterface, ppv,
ADDR IID_SomeOtherInterface, ADDR ppv_new
注意IUnknown PTR [edx]这个类型转换,是让编译器知道使用哪个结构来得到QueryInterface函数在虚表中的正确偏移。其中有一个模糊的地方,注意我修改了函数名字为"IUnknown_QueryInterface",这个名字修饰时必要的。当你有一个大的com工程,有许多相似的接口,你就会遇到麻烦。不同的接口对应不同的方法表示,是非常有效的。
coinvoke 宏,这个宏定义在oaidl.inc文件中。使用它,可以进一步简化com调用。
;---------------------------------------------------------------------
; coinvoke MACRO
;
;
; pInterface pointer to a specific interface instance
; Interface the Interface's struct typedef
; Function which function or method of the interface to perform
; args all required arguments
; (type, kind and count determined by the function)
;
coinvoke MACRO pInterface:REQ, Interface:REQ, Function:REQ, args:VARARG
LOCAL istatement, arg
FOR arg, <args> ;; run thru args to see if edx is lurking in there
IFIDNI <&arg>, <edx>
.ERR <edx is not allowed as a coinvoke parameter>
ENDIF
ENDM
istatement CATSTR <invoke (Interface PTR[edx]).&Interface>,<_>,<&Function, pInterface>
IFNB <args> ;; add the list of parameter arguments if any
istatement CATSTR istatement, <, >, <&args>
ENDIF
mov edx, pInterface
mov edx, [edx]
istatement
ENDM
;---------------------------------------------------------------------
因此,前面的QueryInterface方法调用就可以简化成:
coinvoke ppv ,IUnknown, QueryInterface, ADDR IID_SomeOtherInterface,
ADDR ppnew
注意这里名字修饰是隐藏在宏中处理的。
为了能使用某个对象的com接口函数,你必须首先要从类厂中创建这个对象,并且让他来返回接口指针。这个过程被CoCreateInstance这个API函数完成。当你使用完接口时,要调用Release方法。一个COM对象可以看作是一个服务,调用com的应用程序就是他的客户端。
在调用com接口函数之前,你需要了解接口是什么,一个com接口就是一个函数指针表,我们还是从IUnknown接口开始,如果你创建了一个组件导出了IUnknown接口,那么你就有了一个全功能的com对象。IUnknown有三个基本的几口方法,既然所有的接口都是从它派生出来,那么我们一定要记住,一个接口实际上就是一个函数指针成员组成的结构体。
例如:
IUnknown STRUCT DWORD
; IUnknown methods
IUnknown_QueryInterface QueryInterface_Pointer ?
IUnknown_AddRef AddRef_Pointer ?
IUnknown_Release Release_Pointer ?
IUnknown ENDS
它只有12个字节长,它具有3个DWORD指针来指向实际的实现函数。对于虚函数表,你一定听说过,这些指针定义如下,因此我们可以让masm在编译我们的调用时进行一些类型检查。
QueryInterface_Pointer typedef ptr QueryInterface_Proto
AddRef_Pointer typedef ptr AddRef_Proto
Release_Pointer typedef ptr Release_Proto
最后我们定义我们的函数如下:
QueryInterface_Proto typedef PROTO :DWORD, :DWORD, :DWORD
AddRef_Pointer typedef PROTO :DWORD
Release_Pointer typedef PROTO :DWORD
为了保持masm32松散的类型检查一致,函数参数都定义为dword
定义接口是一个相当大的编辑就是,masm不支持前向引用。因此,我们不得不颠倒一下定义的顺序。先定义函数头,再定义函数指针,最后定义接口。实际上在使用接口时,你需要一个指向它的指针。
CoCreateInstance函数能用来直接返回一个接口指针。它实际上指向了拥有接口的对象。这个结构看上去如图所示:
这个结构里有大量的间接访问,使用宏可以简化它。
当客户端调用COM库创建com组件时,它传进了一个地址用于存放对象指针。这个就是我们所说的ppv. 从c++的角度来讲,叫做指向指针的指针,void类型代表无类型。它保存了另一个指针pv的地址。pv指向了虚函数表。
例如:我们使用CoCreateInstance函数成功的返回了一个接口指针ppv,我们想看下它是否支持其他的接口,我们可以调用QueryInterface方法。用c++的方法描述QueryInterface如下:
(HRESULT) SomeObject::QueryInterface (this:pObject, IID:pGUID, ppv2:pInterface)
用汇编写法如下:
; get pointer to the object
mov eax, ppv
; and use it to find the interface structure
mov edx, [eax]
; push the function parameters onto the stack
push OFFSET ppv2
push OFFSET IID_ISomeOtherInterface
push dword ppv
; and then call that method
call dword ptr [edx + 0]
使用invoke调用简化如下:
; get pointer to the object
mov eax, ppv
; and use it to find the interface structure
mov edx, [eax]
; and then call that method
invoke (IUnknown PTR [edx]).IUnknown_QueryInterface, ppv,
ADDR IID_SomeOtherInterface, ADDR ppv_new
注意IUnknown PTR [edx]这个类型转换,是让编译器知道使用哪个结构来得到QueryInterface函数在虚表中的正确偏移。其中有一个模糊的地方,注意我修改了函数名字为"IUnknown_QueryInterface",这个名字修饰时必要的。当你有一个大的com工程,有许多相似的接口,你就会遇到麻烦。不同的接口对应不同的方法表示,是非常有效的。
coinvoke 宏,这个宏定义在oaidl.inc文件中。使用它,可以进一步简化com调用。
;---------------------------------------------------------------------
; coinvoke MACRO
;
;
; pInterface pointer to a specific interface instance
; Interface the Interface's struct typedef
; Function which function or method of the interface to perform
; args all required arguments
; (type, kind and count determined by the function)
;
coinvoke MACRO pInterface:REQ, Interface:REQ, Function:REQ, args:VARARG
LOCAL istatement, arg
FOR arg, <args> ;; run thru args to see if edx is lurking in there
IFIDNI <&arg>, <edx>
.ERR <edx is not allowed as a coinvoke parameter>
ENDIF
ENDM
istatement CATSTR <invoke (Interface PTR[edx]).&Interface>,<_>,<&Function, pInterface>
IFNB <args> ;; add the list of parameter arguments if any
istatement CATSTR istatement, <, >, <&args>
ENDIF
mov edx, pInterface
mov edx, [edx]
istatement
ENDM
;---------------------------------------------------------------------
因此,前面的QueryInterface方法调用就可以简化成:
coinvoke ppv ,IUnknown, QueryInterface, ADDR IID_SomeOtherInterface,
ADDR ppnew
注意这里名字修饰是隐藏在宏中处理的。
相关文章推荐
- 寄存器(内存访问)07 - 零基础入门学习汇编语言19
- 汇编语言-第三章 寄存器(内存访问)
- 汇编语言--寄存器(内存访问)
- 汇编语言(王爽)第三章 寄存器(内存访问)
- [置顶] [汇编语言学习笔记][第三章寄存器(内存访问)]
- 寄存器(内存访问)02 - 零基础入门学习汇编语言14
- 寄存器(内存访问)03 - 零基础入门学习汇编语言15
- 寄存器(内存访问)04 - 零基础入门学习汇编语言16
- 【汇编语言笔记】 内存访问、汇编语言程序常用格式
- 汇编语言:第三章 寄存器(内存访问)
- 汇编语言寄存器内存访问笔记
- 王爽<汇编语言>实验14 访问CMOS RAM 解答(详细注释)
- 汇编语言(王爽)--实验7寻址方式在结构化数据访问中的应用
- 汇编语言(王爽)--实验14 访问CMOS RAM
- 汇编语言笔记03-寄存器(内存访问)
- 寄存器(内存访问)02 - 零基础入门学习汇编语言14
- 寄存器(内存访问)03 - 零基础入门学习汇编语言15
- 寄存器(内存访问)04 - 零基础入门学习汇编语言16
- 用汇编语言写的一个模仿IE访问网站数据包的程序片段
- 汇编语言 实验14 访问CMOS RAM