MASM32写的Windows COM访问函数

这个是以前沉迷于MASM32的时候写的,现在我已经很少写汇编语言,但为了让这个代码对沉迷于MASM32的朋友有帮助,就特地写了个例子代码,例子代码调用SAPI的COM对象,让它说句话。

有兴趣的朋友可以拿去研究,我打算过两天写一篇详细的文章来讲解一下。这个例子代码有那么几个字总让我感觉不爽,但我又故意要这么写,这不自己坑自己么。。。。

函数导出三个函数:

;调用对象的函数表,offs是函数表偏移,例如要调用第二个函数,偏移就是1*4.
OleInvoke proto c pInterface:dword,offs:dword,cArg:dword,Arg:vararg
;自动化IDispatch的调用函数,传入函数名和参数列表即可以调用,详情可以参考例子。
IDispatchInvoke proto c pIDispatch:DWORD,pszFuncName:DWORD,pVarRet:DWORD,numArgs:DWORD,args:VARARG
;设置、取得对象属性函数。
IDispatchPutGetProperty proto c pIDispatch:DWORD,put0_get1:DWORD,pszPropertyname:DWORD,pVarRet:DWORD,dwVType:DWORD,dwData:DWORD

三个函数具体实现如下:

;调用对象的函数表,offs是函数表偏移,例如要调用第二个函数,偏移就是1*4.
OleInvoke proc c pInterface:dword,offs:dword,cArg:dword,Arg:vararg

	mov ecx,cArg
	.while ecx>=1
		dec ecx
		mov eax,dword ptr [Arg+ecx*4]
		push eax
	.endw

	mov eax,pInterface
	mov edx,[eax]
	push pInterface
	mov eax,offs
	call dword ptr [edx+eax]
	ret
OleInvoke endp

;自动化IDispatch的调用函数,传入函数名和参数列表即可以调用,详情可以参考例子。
IDispatchInvoke proc c uses esi edi ebx pIDispatch:DWORD,pszFuncName:DWORD,pVarRet:DWORD,numArgs:DWORD,args:VARARG ;vartype1,value1,vartype2,value2
		local hMem:DWORD,tmpMem[128]:BYTE,dispid:DWORD,pointer:DWORD
		local dp:DISPPARAMS
		.data
		IDI_IID_NULL	GUID	{000000000h,00000h,00000h,{000h,000h,000h,000h,000h,000h,000h,000h}}
		.code
		;getidsofnames
		invoke MultiByteToWideChar,CP_ACP,0,pszFuncName,-1,addr tmpMem,128
		lea eax,tmpMem
		mov pointer,eax
		invoke OleInvoke,pIDispatch,20,5,offset IDI_IID_NULL,addr pointer,1,0,addr dispid
		mov eax,numArgs
		inc eax
		imul eax,sizeof VARIANT
		invoke GlobalAlloc,GPTR,eax
		mov hMem,eax
		;init params
		invoke RtlZeroMemory,addr dp,sizeof DISPPARAMS
		.if numArgs>0
			mov eax,sizeof VARIANT
			imul eax,numArgs

			mov esi,hMem
			lea edi,args
			mov eax,numArgs
			shl eax,3 ;numArgs*4*2
			sub eax,8
			add edi,eax
			assume esi:ptr VARIANT
			mov ebx,0
			.while ebx<numArgs
				mov eax,[edi]
				mov [esi].vt,ax
				mov eax,[edi][4]
				mov [esi].lVal,eax
				mov eax,numArgs
				mov dp.cArgs,eax
				mov eax,hMem
				mov dp.rgvarg,eax
				add esi,sizeof VARIANT
				sub edi,8
				inc ebx
			.endw
			assume esi:nothing

		.else
			mov dp.rgvarg,0
			mov dp.cArgs,0
		.endif
		invoke OleInvoke,pIDispatch,24,8,dispid,offset IDI_IID_NULL,0,1,addr dp,pVarRet,0,0
		invoke GlobalFree,hMem
ret
IDispatchInvoke endp

;设置、取得对象属性函数。
IDispatchPutGetProperty proc c pIDispatch:DWORD,put0_get1:DWORD,pszPropertyname:DWORD,pVarRet:DWORD,dwVType:DWORD,dwData:DWORD
		local hMem:DWORD,tmpMem[128]:BYTE,dispid:DWORD,pointer:DWORD
		local dp:DISPPARAMS,wflag:DWORD,vt:VARIANT,dispidparam:DWORD
		.data
		IDI2_IID_NULL	GUID	{000000000h,00000h,00000h,{000h,000h,000h,000h,000h,000h,000h,000h}}
		.code
		.if put0_get1==1
			mov wflag,2
		.else
			mov wflag,4
		.endif
		;getidsofnames
		invoke MultiByteToWideChar,CP_ACP,0,pszPropertyname,-1,addr tmpMem,128
		lea eax,tmpMem
		mov pointer,eax
		invoke OleInvoke,pIDispatch,20,5,offset IDI2_IID_NULL,addr pointer,1,0,addr dispid
		mov eax,dwVType
		mov vt.vt,ax
		mov eax,dwData
		mov vt.lVal,eax
		.if wflag==4
			mov dispidparam,-3 ;DISPID_PROPERTYPUT=-3
			mov dp.cArgs,1
			lea eax,vt
			mov dp.rgvarg,eax
			lea eax,dispidparam
			mov dp.rgdispidNamedArgs,eax
			mov dp.cNamedArgs,1

		.else
			mov dp.cArgs,0
			mov dp.rgvarg,0
			mov dp.rgdispidNamedArgs,0
			mov dp.cNamedArgs,0
		.endif

		invoke OleInvoke,pIDispatch,24,8,dispid,offset IDI2_IID_NULL,0,wflag,addr dp,pVarRet,0,0
		invoke GlobalFree,hMem
ret
IDispatchPutGetProperty endp

例子代码如下:

comment~
;汇编访问COM示例
;By Hoverlees  me[at]hoverlees.com  http://www.hoverlees.com
;此示例调用微软SAPI的Speak组件,使其朗读文字
~
.386
.model flat,stdcall
option casemap:none

include		windows.inc
include		gdi32.inc
includelib	gdi32.lib
include		user32.inc
includelib	user32.lib
include		kernel32.inc
includelib	kernel32.lib
include 		ole32.inc
includelib	ole32.lib
include		macro.asm
include		oleaut32.inc
includelib	oleaut32.lib
include		../hdisp.inc
includelib	../hdisp.lib

.data?
	hInstance		dd ?

.data
	WSTR	progid,"SAPI.SpVoice"

.const
	IID_IDispatch	GUID {00020400h,0000h,0000h,{0C0h,00h,00h,00h,00h,00h,00h,46h}} ;定义IID_IDispatch

.code

start:
		invoke GetModuleHandle,NULL
		mov hInstance,eax
		call main
		invoke ExitProcess,NULL
main proc
		local sguid:GUID
		local speaker:DWORD
		local vret:VARIANT
		local tempBuf[255]
		local bstr:DWORD
		invoke CoInitialize,NULL
		;创建Speaker对象
		invoke CLSIDFromProgID,addr progid,addr sguid
		.if eax!=S_OK
			invoke MessageBox,0,CTXT("找不到对象"),0,0
		.endif
		invoke CoCreateInstance,addr sguid,NULL,CLSCTX_INPROC_SERVER,addr IID_IDispatch,addr speaker
		.if eax!=S_OK
			invoke MessageBox,0,CTXT("无法创建对象"),0,0
		.endif

		;调用speak
		invoke MultiByteToWideChar,CP_ACP,0,CTXT("Hello world! 一般Win7支持中文朗读。你好世界。"),-1,addr tempBuf,255
		invoke SysAllocString,addr tempBuf
		mov bstr,eax
		invoke IDispatchInvoke,speaker,CTXT("Speak"),addr vret,1,VT_BSTR,bstr
		invoke SysFreeString,bstr

		invoke MultiByteToWideChar,CP_ACP,0,CTXT("找不到对象啊找不到,无法创建对象啊无法创建,伤不起啊伤不起,伤不起啊啊啊啊啊啊啊啊"),-1,addr tempBuf,255
		invoke SysAllocString,addr tempBuf
		mov bstr,eax
		invoke IDispatchInvoke,speaker,CTXT("Speak"),addr vret,1,VT_BSTR,bstr
		invoke SysFreeString,bstr

		;释放对象
		invoke OleInvoke,speaker,2*4,0  ;speaker->Release();
		invoke CoUninitialize
ret
main    endp
end start

上面这些文件都可以从这里下载,里面有一个LIB文件可以直接链接到你的应用程序中,注意要32位的才行哦。

Leave a comment

Your email address will not be published. Required fields are marked *