四.发送短消息
发送短信是一个相对比较简单的过程,之所以拿出来一节来讨论,是因为我们不仅仅要讨论如何发送短信,还要讨论一个重要的进程,也就是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. 源程序
还是等文章写完后,整理好再发吧。