调用dll文件阅读文本
-
- 帖子: 40
- 注册时间: 2009-02-23 15:52
调用dll文件阅读文本
我用的XP,已经安装了中英文语音阅读库,手里有个dll文件SpeechText.dll
在命令行中执行 :ec libcall("SpeechText", "MT_SpeechText", "VIM speak"), 可以发出语音,但是VIM随即崩溃。有什么办法可以让它不崩溃?
在命令行中执行 :ec libcall("SpeechText", "MT_SpeechText", "VIM speak"), 可以发出语音,但是VIM随即崩溃。有什么办法可以让它不崩溃?
-
- 帖子: 40
- 注册时间: 2009-02-23 15:52
Re: 调用dll文件阅读文本
查看了帮助,里面说“函数必须只能接受单个参数,或者是字符指针,或者是长整数,而且必须返回字符指针或者 NULL”。查看了一下源代码,该函数返回bool值。谁能帮我改一下并编译成dll文件?这个我不会
代码: 全选
#include <windows.h>
#include <sapi.h>
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "sapi.lib")
ISpVoice * gpVoice = NULL;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
if (FAILED(CoInitialize(NULL))) {
return FALSE;
}
if (FAILED(CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&gpVoice))) {
return FALSE;
}
if (!gpVoice) return FALSE;
break;
case DLL_PROCESS_DETACH:
/*
if (gpVoice) gpVoice->Release();
*/
gpVoice = NULL;
CoUninitialize();
break;
default:
break;
}
return TRUE;
}
BOOL WINAPI MT_SpeechText(char const * text, BOOL async)
{
WCHAR * msg;
BOOL ret;
int len;
DWORD dwFlags;
len = strlen(text) + 1;
msg = new WCHAR[len];
MultiByteToWideChar(CP_ACP, 0, text, len, msg, len);
if (async) {
dwFlags = SPF_ASYNC;
} else {
dwFlags = SPF_DEFAULT;
}
if (FAILED(gpVoice->Speak(msg, dwFlags, NULL))) {
ret = FALSE;
} else {
ret = TRUE;
}
delete msg;
return ret;
}
- 自由建客
- 帖子: 13468
- 注册时间: 2008-07-30 23:21
- 系统: Debian stable AMD64
Re: 调用dll文件阅读文本
libcall() 接受的输入参数不是长整数,而是 int。返回值是 char*。
更微妙的是,这个 char* 指向的那片区域很可能是非法的。
更微妙的是,这个 char* 指向的那片区域很可能是非法的。
-
- 帖子: 40
- 注册时间: 2009-02-23 15:52
Re: 调用dll文件阅读文本
我输入的参数是字符串,而且运行成功,只是返回bool值引起崩溃。如果修改MT_SpeechText函数,让其返回NULL,应该就不会崩溃了吧?自由建客 写了:libcall() 接受的输入参数不是长整数,而是 int。返回值是 char*。
更微妙的是,这个 char* 指向的那片区域很可能是非法的。
- lilydjwg
- 论坛版主
- 帖子: 4258
- 注册时间: 2009-04-11 23:46
- 系统: Arch Linux
- 联系:
Re: 调用dll文件阅读文本
不会 cl.exe。你要是给 gcc 能读的源码我直接在 Linux 上就能给你编译了。lh-n 写了:查看了帮助,里面说“函数必须只能接受单个参数,或者是字符指针,或者是长整数,而且必须返回字符指针或者 NULL”。查看了一下源代码,该函数返回bool值。谁能帮我改一下并编译成dll文件?这个我不会
-
- 帖子: 36
- 注册时间: 2010-09-23 13:47
Re: 调用dll文件阅读文本
以前写过几个给 libcall() 调用的DLL,粗略看了一下:
1. 如果 DLL 的函数返回数值类型,在 Vim 脚本里要用 libcallnr() 而不是 libcall() 。
2. 应该是出错的主要原因:DLL 的函数必须是 C 调用约定(具体见 :h libcall())。WINAPI 宏其实就是指定函数是 pascal 调用约定。调用约定不一样,函数返回后堆栈会被破坏,导致程序杯具。解决方法就是把 WINAPI 改成 __cdecl 。(如果使用纯C编译,可以直接把 WINAPI 删掉,但是看你代码里有 new 和 delete ,应该是按 C++ 编译的)
3. MT_SpeechText() 有两个参数,但是 Vim 的 libcall() 和 libcallnr() 只能传 1 个参数。如果你想让第二个参数起作用,另外写两个函数,分别调用 MT_SpeechText(text, TRUE) 和 MT_SpeechText(text, FALSE) ,然后从 Vim 脚本里根据需要调用这两个函数就 OK 了。
1. 如果 DLL 的函数返回数值类型,在 Vim 脚本里要用 libcallnr() 而不是 libcall() 。
2. 应该是出错的主要原因:DLL 的函数必须是 C 调用约定(具体见 :h libcall())。WINAPI 宏其实就是指定函数是 pascal 调用约定。调用约定不一样,函数返回后堆栈会被破坏,导致程序杯具。解决方法就是把 WINAPI 改成 __cdecl 。(如果使用纯C编译,可以直接把 WINAPI 删掉,但是看你代码里有 new 和 delete ,应该是按 C++ 编译的)
3. MT_SpeechText() 有两个参数,但是 Vim 的 libcall() 和 libcallnr() 只能传 1 个参数。如果你想让第二个参数起作用,另外写两个函数,分别调用 MT_SpeechText(text, TRUE) 和 MT_SpeechText(text, FALSE) ,然后从 Vim 脚本里根据需要调用这两个函数就 OK 了。
- 自由建客
- 帖子: 13468
- 注册时间: 2008-07-30 23:21
- 系统: Debian stable AMD64
Re: 调用dll文件阅读文本
我没说输入不能是字符串,只是纠正你说的长整数的想法,它不支持 int 之外的整数类型。lh-n 写了:我输入的参数是字符串,而且运行成功,只是返回bool值引起崩溃。如果修改MT_SpeechText函数,让其返回NULL,应该就不会崩溃了吧?自由建客 写了:libcall() 接受的输入参数不是长整数,而是 int。返回值是 char*。
更微妙的是,这个 char* 指向的那片区域很可能是非法的。
libcallnr() 返回类型为 int,可直接用于你的 BOOL。
-
- 帖子: 40
- 注册时间: 2009-02-23 15:52
Re: 调用dll文件阅读文本
你好,谢谢你的分析。这个代码不是我写的,C++我也是才学了个皮毛,电脑上也没有C++编译器,你能帮我改一下源代码并编译成dll吗?wz520 写了:以前写过几个给 libcall() 调用的DLL,粗略看了一下:
1. 如果 DLL 的函数返回数值类型,在 Vim 脚本里要用 libcallnr() 而不是 libcall() 。
2. 应该是出错的主要原因:DLL 的函数必须是 C 调用约定(具体见 :h libcall())。WINAPI 宏其实就是指定函数是 pascal 调用约定。调用约定不一样,函数返回后堆栈会被破坏,导致程序杯具。解决方法就是把 WINAPI 改成 __cdecl 。(如果使用纯C编译,可以直接把 WINAPI 删掉,但是看你代码里有 new 和 delete ,应该是按 C++ 编译的)
3. MT_SpeechText() 有两个参数,但是 Vim 的 libcall() 和 libcallnr() 只能传 1 个参数。如果你想让第二个参数起作用,另外写两个函数,分别调用 MT_SpeechText(text, TRUE) 和 MT_SpeechText(text, FALSE) ,然后从 Vim 脚本里根据需要调用这两个函数就 OK 了。
-
- 帖子: 40
- 注册时间: 2009-02-23 15:52
Re: 调用dll文件阅读文本
谢谢你,我用libcallnr()也是一样的崩溃。自由建客 写了:我没说输入不能是字符串,只是纠正你说的长整数的想法,它不支持 int 之外的整数类型。lh-n 写了:我输入的参数是字符串,而且运行成功,只是返回bool值引起崩溃。如果修改MT_SpeechText函数,让其返回NULL,应该就不会崩溃了吧?自由建客 写了:libcall() 接受的输入参数不是长整数,而是 int。返回值是 char*。
更微妙的是,这个 char* 指向的那片区域很可能是非法的。
libcallnr() 返回类型为 int,可直接用于你的 BOOL。
- lilydjwg
- 论坛版主
- 帖子: 4258
- 注册时间: 2009-04-11 23:46
- 系统: Arch Linux
- 联系:
Re: 调用dll文件阅读文本
给我 sapi 的头文件和库文件,我试试能不能帮你编译一个。
-
- 帖子: 40
- 注册时间: 2009-02-23 15:52
Re: 调用dll文件阅读文本
不好意思,我没有也不懂那些东西lilydjwg 写了:给我 sapi 的头文件和库文件,我试试能不能帮你编译一个。

还是谢谢你!
- 自由建客
- 帖子: 13468
- 注册时间: 2008-07-30 23:21
- 系统: Debian stable AMD64
Re: 调用dll文件阅读文本
汗!现在才注意到 MT_SpeechText() 是两个参数。
-
- 帖子: 36
- 注册时间: 2010-09-23 13:47
Re: 调用dll文件阅读文本
搞定了。VC2010 Express 编译。在我的 GVim 7.3.629 上测试有声音,不会崩溃。lh-n 写了: 你好,谢谢你的分析。这个代码不是我写的,C++我也是才学了个皮毛,电脑上也没有C++编译器,你能帮我改一下源代码并编译成dll吗?
另附最终用于编译的源码。
前面也说了,因为 MT_SpeechText() 要两个参数,最好不要从 Vim 脚本里调用,而用 SpeechText() 和 SpeechTextAsync() 代替。具体见压缩包里的源码。
不过,貌似不支持中文,也许是我没装中文语音阅读库。如果你也不行,那么 Vim 命令改成下面这样子试试:
:echo libcall("SpeechText", "SpeechText", iconv("你好", 'utf-8', 'cp936'))
- 附件
-
- SpeechText.zip
- (38.47 KiB) 已下载 92 次
-
- 帖子: 40
- 注册时间: 2009-02-23 15:52
Re: 调用dll文件阅读文本
非常感谢,用你的方法不不但不会崩溃,也可以阅读中文。wz520 写了:搞定了。VC2010 Express 编译。在我的 GVim 7.3.629 上测试有声音,不会崩溃。lh-n 写了: 你好,谢谢你的分析。这个代码不是我写的,C++我也是才学了个皮毛,电脑上也没有C++编译器,你能帮我改一下源代码并编译成dll吗?
另附最终用于编译的源码。
前面也说了,因为 MT_SpeechText() 要两个参数,最好不要从 Vim 脚本里调用,而用 SpeechText() 和 SpeechTextAsync() 代替。具体见压缩包里的源码。
不过,貌似不支持中文,也许是我没装中文语音阅读库。如果你也不行,那么 Vim 命令改成下面这样子试试:
:echo libcall("SpeechText", "SpeechText", iconv("你好", 'utf-8', 'cp936'))
但是还有个问题,该函数只能用一次,第二次用就不会发声了。
----------------------------------------------------------
可能是我的语音引擎的问题,前面用的是Neospeech的引擎,我又试了系统自带的语音引擎没问题。这到底是什么原因呢?
-
- 帖子: 36
- 注册时间: 2010-09-23 13:47
Re: 调用dll文件阅读文本
这我就不知道了,没搞过TTS相关的编程。我只是在你贴的代码的基础上做了很简单的修改,没有改动核心的东西。lh-n 写了:非常感谢,用你的方法不不但不会崩溃,也可以阅读中文。
但是还有个问题,该函数只能用一次,第二次用就不会发声了。
----------------------------------------------------------
可能是我的语音引擎的问题,前面用的是Neospeech的引擎,我又试了系统自带的语音引擎没问题。这到底是什么原因呢?
而且我的系统也只装了自带的引擎,没办法调试 NeoSpeech 的效果。
要么……求个 NeoSpeech 语音库下载,让我试着调试一下?
