这段时间,我在学习vc。以前一直是在用C#和Java的,最近发现MFC还是有一定的用处的,所以就利用暑假这段时间来学习一下。但是光看书没有用,几 个月之前,我用C#实现了一个飞信发短信的接口。所以这次,以学习MFC为目的,写了一个MFC版的飞信发短信接口。开发工具用的是Visual studio 2005。
其中用到了MFC中的众多功能,如Socket、CString类的使用、Winnet、加密(hash)、ATl提供的正则表达式库和调用Dom解析 xml等等。最后,我将该接口做成了一个MFC dll,从而也学习了MFC dll的制作和使用。编译的时候采用默认的Unicode编码。另外,其中还涉及到编码的转换等等。在处理字符串的时候基本都用CString,不知道这 种习惯好不好。
接口中只提供一个CFetion类,其中提供3个函数,功能主要登陆、发送短信和登出,相当简单,一看就明白。由于其中调用了Com,所以调用的时候需要进行Com的初始化工作。下面是一个使用的例子:
#include "Fetion.h"
#pragma comment(lib, "MFCFetionSDK.lib")
CoInitialize(NULL);
CFetion fetion(_T("你的手机号"), _T("你的密码"));
fetion.Login();
fetion.SendSMSToPhone(_T("好友手机号"), _T("要发送的消息。"));
fetion.Logout();
CoUninitialize();
速度方面,我测试一下,还是相当快的,占的内存也非常的少。
关于飞信协议方面,还是采用MD5进行加密的,改成SHA1也相当简单。在我之前的文章中,我讲到一些关键技术的实现方法。由于刚刚初学MFC,其中肯定写得很烂,所以代码先不提供了。如果有需要,可以发邮件给我。mailto:ssdut@126.com。
下面说一下,我解决的几个关键性的问题,也方便刚初学MFC的朋友。
1、如何导出MFC类?
这个问题折磨了我很久,vs2005中新建一个MFC dll的时候会产生一个.def文件,用来导出函数,但我上网查了好多资料,都没有实现用.def导出类。网上有说可以生成map文件后,通过查看其中的 信息导出类中的函数。我嫌麻烦,最后通过AFX_CLASS_EXPORT进行导出的。导入用AFX_CLASS_IMPORT。
2、如何用afxinet.h访问https
飞信在登录的时候用到https,好像我试了一下http同样是可行的,但是我觉得不够安全,所以选择使用https。但是这和C#中一样,访问 https的是有会出现证书的问题。网上资料很少,可能是我找资料的方法不对,最后在一个国外网站上找到一个solution。
AfxParseURL(url, type, server, param, port);
connection = session.GetHttpConnection(server, port);
if(type == 4107)
{
file = connection->OpenRequest(CHttpConnection::HTTP_VERB_GET, param, NULL, 1, NULL, NULL, INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID);
}
3、编码转换和hash的计算
编码转换用的Windows api中的WideCharToMultiByte和MultiByteToWideChar。而hash用的是#include <wincrypt.h>。下面是我用到的工具类。
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
#pragma once
// CUtils
#pragma region 编码CodePage表
enum CodePages
{
IBM037 = 37 ,
IBM437 = 437 ,
IBM500 = 500 ,
ASMO_708 = 708 ,
DOS_720 = 720 ,
ibm737 = 737 ,
ibm775 = 775 ,
ibm850 = 850 ,
ibm852 = 852 ,
IBM855 = 855 ,
ibm857 = 857 ,
IBM00858 = 858 ,
IBM860 = 860 ,
ibm861 = 861 ,
DOS_862 = 862 ,
IBM863 = 863 ,
IBM864 = 864 ,
IBM865 = 865 ,
cp866 = 866 ,
ibm869 = 869 ,
IBM870 = 870 ,
windows_874 = 874 ,
cp875 = 875 ,
shift_jis = 932 ,
gb2312 = 936 ,
ks_c_5601_1987 = 949 ,
big5 = 950 ,
IBM1026 = 1026 ,
IBM01047 = 1047 ,
IBM01140 = 1140 ,
IBM01141 = 1141 ,
IBM01142 = 1142 ,
IBM01143 = 1143 ,
IBM01144 = 1144 ,
IBM01145 = 1145 ,
IBM01146 = 1146 ,
IBM01147 = 1147 ,
IBM01148 = 1148 ,
IBM01149 = 1149 ,
utf_16 = 1200 ,
unicodeFFFE = 1201 ,
windows_1250 = 1250 ,
windows_1251 = 1251 ,
Windows_1252 = 1252 ,
windows_1253 = 1253 ,
windows_1254 = 1254 ,
windows_1255 = 1255 ,
windows_1256 = 1256 ,
windows_1257 = 1257 ,
windows_1258 = 1258 ,
Johab = 1361 ,
macintosh = 10000 ,
x_mac_japanese = 10001 ,
x_mac_chinesetrad = 10002 ,
x_mac_korean = 10003 ,
x_mac_arabic = 10004 ,
x_mac_hebrew = 10005 ,
x_mac_greek = 10006 ,
x_mac_cyrillic = 10007 ,
x_mac_chinesesimp = 10008 ,
x_mac_romanian = 10010 ,
x_mac_ukrainian = 10017 ,
x_mac_thai = 10021 ,
x_mac_ce = 10029 ,
x_mac_icelandic = 10079 ,
x_mac_turkish = 10081 ,
x_mac_croatian = 10082 ,
utf_32 = 12000 ,
utf_32BE = 12001 ,
x_Chinese_CNS = 20000 ,
x_cp20001 = 20001 ,
x_Chinese_Eten = 20002 ,
x_cp20003 = 20003 ,
x_cp20004 = 20004 ,
x_cp20005 = 20005 ,
x_IA5 = 20105 ,
x_IA5_German = 20106 ,
x_IA5_Swedish = 20107 ,
x_IA5_Norwegian = 20108 ,
us_ascii = 20127 ,
x_cp20261 = 20261 ,
x_cp20269 = 20269 ,
IBM273 = 20273 ,
IBM277 = 20277 ,
IBM278 = 20278 ,
IBM280 = 20280 ,
IBM284 = 20284 ,
IBM285 = 20285 ,
IBM290 = 20290 ,
IBM297 = 20297 ,
IBM420 = 20420 ,
IBM423 = 20423 ,
IBM424 = 20424 ,
x_EBCDIC_KoreanExtended = 20833 ,
IBM_Thai = 20838 ,
koi8_r = 20866 ,
IBM871 = 20871 ,
IBM880 = 20880 ,
IBM905 = 20905 ,
IBM00924 = 20924 ,
EUC_JP = 20932 ,
x_cp20936 = 20936 ,
x_cp20949 = 20949 ,
cp1025 = 21025 ,
koi8_u = 21866 ,
iso_8859_1 = 28591 ,
iso_8859_2 = 28592 ,
iso_8859_3 = 28593 ,
iso_8859_4 = 28594 ,
iso_8859_5 = 28595 ,
iso_8859_6 = 28596 ,
iso_8859_7 = 28597 ,
iso_8859_8 = 28598 ,
iso_8859_9 = 28599 ,
iso_8859_13 = 28603 ,
iso_8859_15 = 28605 ,
x_Europa = 29001 ,
iso_8859_8_i = 38598 ,
iso_2022_jp = 50220 ,
csISO2022JP = 50221 ,
iso_2022_kr = 50225 ,
x_cp50227 = 50227 ,
euc_jp = 51932 ,
EUC_CN = 51936 ,
euc_kr = 51949 ,
hz_gb_2312 = 52936 ,
GB18030 = 54936 ,
x_iscii_de = 57002 ,
x_iscii_be = 57003 ,
x_iscii_ta = 57004 ,
x_iscii_te = 57005 ,
x_iscii_as = 57006 ,
x_iscii_or = 57007 ,
x_iscii_ka = 57008 ,
x_iscii_ma = 57009 ,
x_iscii_gu = 57010 ,
x_iscii_pa = 57011 ,
utf_7 = 65000 ,
utf_8 = 65001
};
#pragma endregion
class CUtils : public CObject
{
public :
CUtils();
virtual ~ CUtils();
static void UnicodeToOther( const CStringW & src, CStringA & result, CodePages codePage);
static void OtherToUnicode( const CStringA & src, CStringW & result, CodePages codePage);
static void EncodingConvert( const CStringA & src, CodePages srcCodePage, CStringA & result, CodePages resultCodePage);
static CStringA ComputeHash( const CStringA & pbData, UINT algId);
};
CUtils::CUtils()
{
}
CUtils:: ~ CUtils()
{
}
void CUtils::UnicodeToOther( const CStringW & src, CStringA & result, CodePages codePage)
{
int n = WideCharToMultiByte(codePage, 0 , src.GetString(), - 1 , 0 , 0 , 0 , 0 );
WideCharToMultiByte(codePage, 0 , src.GetString(), - 1 , result.GetBuffer(n), n, 0 , 0 );
result.ReleaseBuffer();
}
void CUtils::OtherToUnicode( const CStringA & src, CStringW & result, CodePages codePage)
{
int n = MultiByteToWideChar(codePage, 0 , src.GetString(), - 1 , NULL, 0 );
MultiByteToWideChar(codePage, 0 , src.GetString(), - 1 , result.GetBuffer(n), n);
result.ReleaseBuffer();
}
void CUtils::EncodingConvert( const CStringA & src, CodePages srcCodePage, CStringA & result, CodePages resultCodePage)
{
CStringW buffer;
OtherToUnicode(src, buffer, srcCodePage);
UnicodeToOther(buffer, result, resultCodePage);
}
CStringA CUtils::ComputeHash( const CStringA & pbData, UINT algId)
{
HCRYPTPROV hProv;
CryptAcquireContext( & hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
HCRYPTHASH hHash;
// Alg Id:CALG_MD5,CALG_SHA
CryptCreateHash(hProv, algId, 0 , 0 , & hHash);
CryptHashData(hHash, ( const BYTE * )pbData.GetString(), pbData.GetLength(), 0 );
CStringA pbOutHash;
DWORD dwHashLen;
DWORD dwLen = sizeof (dwHashLen);
CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE * )( & dwHashLen), & dwLen, 0 );
dwLen = dwHashLen;
CryptGetHashParam(hHash, HP_HASHVAL, (BYTE * )pbOutHash.GetBufferSetLength(dwLen), & dwLen, 0 );
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0 );
return pbOutHash;
}
其中用到的都是CString,Unicode用的是CStringW,多字节的用的是CStringA。这好像在VC6中只有CString,并不分 什么CStringA和CStringW。所以这不适合在VC6中使用。 那个Codepages是我从C#中找过来的,竟然发现一个重复的,我直接做删 除处理,也不知道对不对,但我知道utf-8是对的。
4、关于头文件的问题
我的dll中Fetion.dll中远不只这三个函数,还有很多私有函数和私有成员。我在提供Fetion.h中都删除了,开始发现删除之后不好用了, 后来我把其中要到的指针成员改成普通的对象就好用了。但是在debug的版本的时候,告诉我fetion对象被破坏了,不知道怎么回事。幸好在 release版本中,一切正常。
5、关于飞信
飞信的协议分析,我是借助别人的成果,我自己没有去抓包分析,也没有去反编译,和我写的C#版本一样,是通过看别人用php版本,翻译过来的。
总结
通过这个简单的小例子,基本对MFC的非窗体使用有了一个了解,会运用各种东西来处理自己想要的效果。对于窗体编程,我的经验不是很多。我也编写了一个小例子,一个隐藏和现实窗口的小程序。在以后的文章中介绍。
dll和例子:
MFCFetionSDK.rar
由于好多人发邮件给我要源代码,所以在此提供源代码的下载:mfcfetion.rar
转载请保持文章的完整性,并注明出处。
作者:
小橋流水
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
另外一个飞信实现例子开源