這段時間,我在學習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:[email protected]。
下面說一下,我解決的幾個關鍵性的問題,也友善剛初學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://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-YWan5SZwcDOxkTY0czYmZmM4czN2czM5EGMkRDN1QzY0UDZz8CX4AzLchDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLzM3Lc9CX6MHc0RHaiojIsJye.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);
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
轉載請保持文章的完整性,并注明出處。
作者:小橋流水