;---------------------------------------------------------------------
; 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方法调用如下:
DllGetClassObject返回一个IClassFactory接口,这个接口是从IUnknown派生的,另外他还有自己的两个重要的成员函数。
HRESULT CreateInstance(
IUnknown * pUnkOuter, //Pointer to outer object when part of an
// aggregate REFIID riid,
REFIID riid, //Reference to the interface identifier
oid** ppvObject); //Address of output variable that receives
// the interface pointer requested in riid
HRESULT LockServer(BOOL fLock);
//Increments or decrements the lock count
---------------------------------------------------------------------------------------------------------------------On WinTel platforms,
我建一个ATL工程,命名为MyComApp,然后选择“insert a new ATL object“,然后选择“Simple Object”,命名为:MyCom。这样就创建了一个空的IMyCom接口,然后通过右键菜单,我们添加属性SetValue和GetValue,并增加一个RaiseValue方法。然后我们保存退出工程,拷贝MyComApp.idl文件到我的汇编工程目录。
下面就是这个idl文件的内容:
// MyCom.idl : IDL source for MyCom.dll
//
// This file will be processed by the MIDL tool to
// produce the type library (MyCom.tlb) and marshalling code
AddRef_MC proc this_:DWORD
mov eax, this_
inc (MyComObject ptr [eax]).nRefCount
mov eax, (MyComObject ptr [eax]).nRefCount
ret ; note we return the object count
AddRef_MC endp
Release_MC proc this_:DWORD
mov eax, this_
dec (MyComObject ptr [eax]).nRefCount
mov eax, (MyComObject ptr [eax]).nRefCount
.IF (eax == 0)
; the reference count has dropped to zero
; no one holds reference to the object
; so let's delete it
invoke CoTaskMemFree, this_
dec MyCFObject.nRefCount
xor eax, eax ; clear eax (count = 0)
.ENDIF
ret ; note we return the object count
Release_MC endp
; 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
;---------------------------------------------------------------------
; 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
;---------------------------------------------------------------------
.code
start:
; here is where we call the proc with the COM methods
invoke CoInitialize, NULL
invoke CoCreateInstance, ADDR CLSID_MyCom, NULL,
CLSCTX_INPROC_SERVER,
ADDR IID_IMyCom, ADDR ppv