这个是以前沉迷于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位的才行哦。