欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

WIN32汇编-开发记事本语音阅读工具

程序员文章站 2022-04-29 15:13:13
...

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,并将中文语音设为默认语音库。