WIN32汇编-开发记事本语音阅读工具
WIN32汇编开发记事本语音阅读工具
一、 引言
Windows系统具有风格一致的华丽图形用户界面、丰富的API函数、设备无关性、多任务等特点而广泛流行。
Win32汇编支持32位Windows API函数的调用,拥有很多高级语言的语法和运算符,编译后的程序执行效率高,占微量系统资源,短小精练,因此WIN32汇编语言非常适合记事本语音阅读工具这类软件的开发。
二、设计思路
汇编语言没有类的概念,只能采用传统的结构化方法进行设计。按软件实现的功能分为以下几个模块:
1、 记事本内容读取
2、 语音阅读文本
3、 消息循环处理
4、 程序的启动与退出
程序开发的难点是前两个模块,笔者进行如下设计:
1、 如何获取记事本内容。首先获取记事本的窗口句柄,然后获得记事本的文本子窗口句柄,最后向子窗口发送WM_GETTEXT消息取得记事本所打开的文本内容。
2、 如何实现语音阅读文本。采用微软的TTS语音引擎实现文本转语音功能, TTS基于COM,因此开发需要使用Microsoft SpeechSDK,直接调用SAPI实现语音朗读,Microsoft SpeechSDK没有相应的汇编语言INC头文件,必须将C的头文件翻译成汇编格式,直接写在代码内,另外COM对象函数遵循严格顺序,不能随意调换列表中函数位置。
该软件人机界面简单,资源文件使用用记事本直接手动编写,读者也可使用VC自带的资源编辑工具编写。
三、代码实现:
(一)程序代码
;程序名:记事本语音阅读工具
;作者:刘兴
;文件名:readtext.asm
;汇编中的注释采用“;”表示,笔者在关健代码上注释其含义。
;汇编中一行代码写不下,用“\”表示续行
;####################################################################
;指定编译选项
.486
.model flat, stdcall
option casemap :none
;####################################################################
;指定使用的头文件
include windows.inc
include user32.inc
include kernel32.inc
include gdi32.inc
include masm32.inc
include ole32.inc
;笔者的MASM32 Version 9.0安装在d盘
include d:\masm32\com\include\oaidl.inc
;####################################################################
;指定使用的库文件
includelib user32.lib
includelib kernel32.lib
includelib gdi32.lib
includelib masm32.lib
includelib ole32.lib
;####################################################################
;汇编期常量定义
IDC_OK equ 101
IDC_MIN equ 102
IDC_EXIT equ 103
FLAG_PLAY equ 1
FLAG_PAUSE equ 2
FLAG_RESUME equ 3
FLAG_STOP equ 0
SPF_ASYNC equ 1;sapi.h中定义
DIALOG_MAIN equ 1
;####################################################################
;定义ISpVoice的虚函数接口表结构
;接口表由sapi.h取得,将ISpVoiceVtbl的定义改成汇编格式
ISpVoice STRUCT DWORD
QueryInterface comethod3 ?
AddRefcomethod1 ?
Release comethod1 ?
SetNotifySink comethod2 ?
SetNotifyWindowMessage comethod5 ?
SetNotifyCallbackFunction comethod4 ?
SetNotifyCallbackInterface comethod4 ?
SetNotifyWin32Event comethod1 ?
WaitForNotifyEvent comethod1 ?
GetNotifyEventHandle comethod1 ?
SetInterest comethod3 ?
GetEvents comethod4 ?
GetInfo comethod2 ?
SetOutput comethod3 ?
GetOutputObjectToken comethod2 ?
GetOutputStream comethod2 ?
Pause comethod1 ?
Resume comethod1 ?
SetVoice comethod2 ?
GetVoice comethod2 ?
Speak comethod4 ?
SpeakStream comethod4 ?
GetStatus comethod3 ?
Skip comethod4 ?
SetPriority comethod2 ?
GetPriority comethod2 ?
SetAlertBoundary comethod2 ?
GetAlertBoundary comethod2 ?
SetRate comethod2 ?
GetRate comethod2 ?
SetVolume comethod2 ?
GetVolume comethod2 ?
WaitUntilDone comethod2 ?
SetSyncSpeakTimeout comethod2 ?
GetSyncSpeakTimeout comethod2 ?
SpeakCompleteEvent comethod1 ?
IsUISupported comethod5 ?
DisplayUI comethod6 ?
ISpVoice ENDS
;####################################################################
;未初始化数据段
.data?
hWinMain DWORD ?
CommandLine DWORD ?
hInstance DWORD ?
showrect RECT <>
ppVoice DWORD ?
;####################################################################
;已初始化数据段
.data
sznoteclass db "Notepad",0
szplay db "开始",0
szresume db "继续",0
szpause db"暂停",0
szbuffer dw 2000 dup(?)
szmscap db "错误",0
dwflag dd FLAG_STOP;当前的工作状态:停止、开始、暂停、继续
;SpVoice对象的CLSIDT和IID定义,在SDK的相关头文件可以找到
CLSID_SpVoiceGUID<96749377H,3391H,11D2H,\
<9EH,0E3H,00H,0C0H,4FH,79H,73H,96H>>
IID_ISpVoice GUID<6C44DF74H,72B9H,4992H,\
<0A1H,0ECH,0EFH,99H,6EH,04H,22H,0D4H>>
szerrtext db "错误号:"
szerrtextno db 20 dup(?),0
;####################################################################
;函数声明
_speaktext proto :DWORD,:DWORD
;####################################################################
;下面是代码段
.code
;#############################################################
;读取并语音朗读记事本内容函数
;函数主要参数说明 @dwflag:标志参数
_readtext proc @dwflag:DWORD
local hwnd:DWORD
invokeFindWindow,addr sznoteclass,NULL
movhwnd,eax;得到记事本窗口句柄
invokeGetWindow,hwnd,GW_CHILD
movhwnd,eax;得到文本子窗口句柄
;获取文本内容
invoke SendMessage,hwnd,WM_GETTEXT,2000,addr szbuffer
;调用子函数实现文本转语音
invoke _speaktext,addr szbuffer,@dwflag
ret
_readtext endp
;###################################################################
;取得COM接口错误号函数
;根据错误号在SDK的winerror.h中查出错误类型
_geterrno proc szerrhex:DWORD,pszerrtext:DWORD
push eax
invokedw2hex,szerrhex,pszerrtext
pop eax
ret
_geterrno endp
;####################################################################
;窗口过程处理函数
_ProcMain proc uses ebx edx hWnd,uMsg,wParam,lParam
.if uMsg==WM_COMMAND
moveax,wParam
movzxeax,ax
.if eax==IDC_EXIT ;程序退出,释放ppVoice对象
mov eax,ppVoice
movedx,[eax]
invoke(ISpVoice PTR[edx]).Release,ppVoice
callCoUninitialize
invoke EndDialog,hWnd,NULL
.elseif eax==IDC_OK
;通过dwflag变量变化实现开始、停止、暂停功能
;转换,调用SetDlgItemText实现按钮文字的更新
.if dwflag==FLAG_STOP
mov dwflag,FLAG_PLAY
invoke SetDlgItemText,hWnd,IDC_OK,addrszpause .elseif dwflag==FLAG_PAUSE
mov dwflag,FLAG_RESUME
invoke SetDlgItemText,hWnd,IDC_OK,addr szpause
.elseif dwflag==FLAG_RESUME||dwflag==FLAG_PLAY
mov dwflag,FLAG_PAUSE
invoke SetDlgItemText,hWnd,IDC_OK,addrszresume .endif
invoke _readtext,dwflag;调用读取并朗读记事本子函数
.elseif eax==IDC_MIN
invoke ShowWindow,hWnd,SW_MINIMIZE;最小化窗口
.endif
.elseif uMsg==WM_INITDIALOG
;初始化pVoice对象
invoke CoInitialize,NULL
invoke CoCreateInstance,addr CLSID_SpVoice,NULL,CLSCTX_ALL,\
addr IID_ISpVoice,addr ppVoice
.IF_FAILED;如果失败,取得错误号并释放资源
invoke_geterrno,eax,addr szerrtextno
invokeMessageBox,NULL,addr szerrtext,\
addr szmscap,MB_ICONERROR
call CoUninitialize
.endif
;设置语音库为默认语音
mov eax,ppVoice
movedx,[eax]
invoke (ISpVoice PTR[edx]).SetVoice,ppVoice,NULL
;设置语速
mov eax,ppVoice
movedx,[eax]
invoke(ISpVoice PTR[edx]).SetRate,ppVoice,3
.IF_FAILED
invoke _geterrno,eax,addr szerrtextno
invoke MessageBox,NULL,addr szerrtext,addr szmscap,\
MB_ICONERROR
.endif
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
_ProcMain endp
;####################################################################
;文本转语音子函数
;函数主要参数说明:pszspeakansi:文本地址,@dwflag:标志参数
_speaktext proc uses edx ebxpszspeakansi:DWORD,@dwflag:DWORD
.data
szspeaktextdw 2000 dup(?);要朗读的文本
.code
;将文本转换成宽字符型,一个字符用16位表示,因为可能存在中文字符
invoke lstrlen,pszspeakansi
mov ebx,eax
invokeMultiByteToWideChar,CP_ACP,MB_PRECOMPOSED,\
pszspeakansi,-1,addr szspeaktext,ebx
mov eax,ppVoice
mov edx,[eax]
.if@dwflag==FLAG_PLAY ;播放
invoke (ISpVoice PTR[edx]).Speak,ppVoice,\
addr szspeaktext,SPF_ASYNC,NULL
.elseif@dwflag==FLAG_PAUSE ;暂停
invoke (ISpVoicePTR[edx]).Pause,ppVoice
.elseif @dwflag==FLAG_RESUME ;继续
invoke (ISpVoicePTR[edx]).Resume,ppVoice .endif
.IF_FAILED
invoke _geterrno,eax,addr szerrtextno
invoke MessageBox,NULL,addr szerrtext,\
addr szmscap,MB_ICONERROR
.endif
ret
_speaktext endp
;####################################################################
;主窗口消息循环
_WinMain proc hInst:DWORD,hPrevInst:DWORD,CmdLine:DWORD,CmdShow:DWORD
;显示模态对话框
invoke DialogBoxParam,hInst,DIALOG_MAIN,\
NULL,addr _ProcMain,NULL
ret
_WinMain endp
;####################################################################
start:
;程序的入口,控制程序的启动与退出
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke GetCommandLine
mov CommandLine, eax
invoke _WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT
invoke ExitProcess,eax;退出程序
;####################################################################
;指定入口地址
end start
(二)资源文件
//文件名:readtext.rc
#include <resource.h>
#define IDC_OK 101
#define IDC_MIN 102
#define IDC_EXIT 103
#define DIALOG_MAIN 1
///////////////////////////////////////////////////////////////////////定义图标文件
IDR_MAINFRAME ICON DISCARDABLE "readtext.ico"
/////////////////////////////////////////////////////////////////////
//定义对话框
DIALOG_MAIN DIALOG 0, 0, 320, 50
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION
CAPTION "记事本语音阅读器(程序:刘兴)"
FONT 9, "宋体"
//定义子窗口控件
BEGIN
//子窗口总共三个按钮
PUSHBUTTON "开始",IDC_OK,10,20,50,14
PUSHBUTTON "最小化",IDC_MIN,110,20,50,14
PUSHBUTTON "退出",IDC_EXIT,210,20,50,14
END
四、编译生成可执行文件
笔者使用MASM32 Version 9.0做为开发和编译工具,此工具可以在http://www.movsd.com/下载。
编译命令:
ml /c /coff readtext.asm
rc readtext.rc
link /subsystem:windows readtext.obj readtext.res
五、程序运行环境要求
该程序要求WINDOWS操作系统安装了Microsoft Speech SDK,并将中文语音设为默认语音库。
上一篇: Elephantbird介绍
下一篇: PE文件格式一览
推荐阅读