四. 发送短消息
发送短信是一个相对比较简单的过程,之所以拿出来一节来讨论,是因为我们不仅仅要讨论如何发送短信,还要讨论一个重要的进程,也就是 tmail.exe 进程。简单的讲,这个进程在后台控制着短信和邮件的接收和发送过程,在前台提供一个显示 UI ,供大家对短信进行操作。本文短信发送部分,就是利用 tmail 的短信发送功能实现的,不需要直接使用 AT 命令,这使得我们发送短信部分的代码变得异常简单。
1. tmail.exe 进程
a) 什么是 tmail.exe 进程
tmail.exe 是微软处理消息的核心模块,处理包括短信, outlook 等邮件消息,也包括第三方定制的 MMS 功能模块。为了方便第三方开发,微软定义了一些列的 COM 接口,可以将很多第三方开发的模块集成到 tmail.exe 中,从而扩展了 tmail.exe 的功能。 WM5.0 版本以前的彩信功能,多半是第三方开发者通过实现该 COM 接口提供的。最后我们提到的短信拦截的程序 MapiRule ,本质也是实现了 IMapiClient 接口的 ProcessMessage 方法,然后注册到系统中, tmail 在启动时加载了这个 COM 组件,从而拥有了短信截获的功能。
b) 判断 tmail.exe 进程是否正在运行
很多时候,我们希望能够知道目前 tmail.exe 是否在运行,从而进行后续的操作。比如,发送短信的时候我们要确保 tmail.exe 已经在运行中,否则即便成功发送短信的程序,短信也只会被存在发件箱中,等待 tmail.exe 启动以后才能被发送出去。也有些时候,我们不希望 tmail.exe 运行,比如后面为 tmail.exe 注册 MapiRule 的时候。所以,要想继续本文的内容,首先需要解决 tmail.exe 进程的查找问题,也就是判断 tmail.exe 进程是否正在运行。这部分内容虽然不属于 cemapi 的范畴,但却是必须的基础。
判断 tmail.exe 进程是否在运行的思路是,首先对系统进程、堆、线程做一个快照,然后在快照中遍历所有进程,查找进程名为 tmail.exe 的进程,如果存在则认为 tmail.exe 进程正在运行,否则 tmail.exe 进程不再运行。我直接给出了这部分的源程序,并在上面增加了注释和说明,程序很简单,非常容易理解,您也可以直接复制过去使用,毕竟这不是本文关注的重点。
// 参数为要查找的进程全名,如 :tmail.exe
// 返回 0 则进程不存在,否则返回进程 Id
DWORD FindProcess(CString strProcessName)
{
DWORD dwPid = 0; // 用于保存tmail.exe 的Id
HANDLE hHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); // 为当前系统进程建立快照
DWORD dwId = ::GetCurrentProcessId(); // 当前进程的Id
if (INVALUE_HANDLE_VALUE!=hHandle) // 如果快照建立成功
{
PROCESSENTRY32 stEntry;
stEntry.dwSize = sizeof (PROCESSENTRY32);
if (Process32First(hHandle, &stEntry)) // 在快照中查找一个进程,stEntry 返回进程相关属性和信息
{
do
{
if (wcsstr(stEntry.szExeFile,strProcessName)) // 比较该进程名称是否与strProcessName 相符
{
if (dwId != stEntry.th32ProcessID) // 如果相等,且该进程的Id 与当前进程不相等,则找到strProcessName 对应的进程。
{
dwPid = stEntry.th32ProcessID;
break ;
}
}
}while (Process32Next(hHandle, &stEntry)); // 再快照中查找下一个进程。
}
CloseToolhelp32Snapshot(hHandle); // 释放快照句柄。
}
return dwPid;
}
程序很好理解,需要提醒一下读者的是,使用CreateToolhelp32Snapshot 函数需要包含tlhelp32.h 这个头文件,并且需要添加toolhelp.lib 库文件。
c) 杀掉 tmail.exe 进程
获取到了进程 ID 以后,杀掉这个进程就变得很简单了。代码如下:
DWORD dwPid=FindProcess(_T( “ tmail.exe ” ));
if(0!=dwPid){ // 找到进程
HANDLE hHandle=OpenProcess(PROCESS_TERMINATE,FALSE,dwPid); // 根据进程ID, 获取tmail.exe 的句柄
TerminateProcess(hHandle,0); // 关闭进程
}
d) 启动 tmail.exe 进程
直接调用 CreateProcess 函数就可以启动进程,代码如下:
// 启动tmail.exe 进程
CreateProcess(_T("tmail.exe" ), _T("-RunInBKG" ),NULL, NULL, FALSE, 0, NULL, NULL, NULL, NULL);
命令行参数 – RunInBKG ,表示tmail.exe 后直接在后台运行,避免短信邮件浏览器的出现。另外tmail.exe 还有很多很有用的命令行参数,下面一一列举出来。(这部分内容虽然很多网站都有有介绍,但由于我是在无聊客的文章中最先看到的,所以这里就只注明引用自无聊客的《 MAPI 的一些问题解答 (by 无聊客 ) 》)
-service: 调用类型, MMS 或 SMS
-attach: 添加附件
-subject: 添加 subject
-to: 添加目标地址
2. 利用 tmail.exe 发送一条短消息
前面部分已经详细的讨论过,如何在具体信箱中建立一条短信息了,其实建立了一条短信,就已经完成了短信发送功能中 95% 内容了。这里只介绍一个方法, IMessage::SubmitMessage 方法,用于像 tmail.exe 提交已经创建的短信息,并由 tmail 完成短信发送过程。该方法的定义如下:
HRESULT IMesssage::SubmitMessage(ULONG ulFlag);
返回只用于判断方法是否正确执行。参数列表:
ulFlag :发送标志,可选择的值有 FORCE_SUBMIT 和 0 ,短信应用中一般选择 0 ,我加上了 FORCE_SUBMIT 标志,感觉没什么不同,估计是要用在特定环境中的吧,具体作用大家补充吧。
发送短信的代码与建立消息基本上完全一样,大家可以参考,唯一不同的是要将最后 m_pMsg->SaveChange(0) 这句替换成 m_pMsg->SubjectMessage(0) 即可。
4 . 如何屏蔽掉短信发送后的系统提示信息
每次消息发送后,系统都会出现一个提示框,提示消息已经发送。如果开发我们自己的应用程序,当然不希望每发一次消息,提示框就出来露次脸了,那么如果屏蔽掉短信发送后的系统提示信息呢?其实,这部分也跟 cemapi 没啥关系,但为了文章尽量系统,也把它写在这里吧。
在 Windows (是 PC 端哈)菜单上选择“开始”——“程序”——“ Microsoft Visual Studio 2005 ”——“ Visual Studio Remote Tools ”启动“远程注册表编辑器”,在 HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Inbox 目录下创建一个 Settings 目录,在其中添加一个名为 SMSNoSentMsg 的 DWORD 类型的键,值为 1 。然后重启设备或者仿真器即可。
5 . 源程序
还是等文章写完后,整理好再发吧。