VC++编写电子邮件程序 第二篇 也是用simple mapi
一、概述
---- 本文主要講述如何使用Visual C++用MAPI編寫E-mail程序。MAPI是包含在Windows之中的,
因此不需要安裝其他額外的部件。MAPI有以下三種形式:
SMAPI,Simple MAPI,簡單的MAPI
CMC,Common Messaging Calls,一般通訊調(diào)用
完整的MAPI
---- SMAPI和CMC都包含在完整的MAPI中,當用戶想執(zhí)行一些高級操作,比如編寫自己的E-mail服務(wù)器的時候,
必須使用完整的MAPI。本文主要闡述如何編寫能夠收發(fā)電子郵件的程序,因此使用SMAPI就足夠了。
二、編寫電子郵件程序
3-1 初始化MAPI
---- 要使用MAPI,必須首先對它進行初始化。初始化包括以下三個步驟:
裝載MAPI32.DLL動態(tài)鏈接庫
找到想要調(diào)用的MAPI函數(shù)地址
登錄到電子郵件對象
3-1-1 裝載MAPI32.DLL
---- 要裝載MAPI,用戶必須程序運行時動態(tài)的裝載一個動態(tài)鏈接庫。LoadLibrary函數(shù)提供了此功能,
它定位一個動態(tài)鏈接庫,并返回HINSTANCE局柄(需要保存該句柄)。
LoadLibrary的語法如下:
LoadLibrary ( lpLibFileName );
其中l(wèi)pLibFileName為LPCTSTR結(jié)構(gòu)變量,
是所要調(diào)用的庫的路徑和名稱。
程序示例:
// 調(diào)用MAPI32.DLL并計算函數(shù)地址
HINSTANCE hInstMail;
hInstMail = ::LoadLibrary ( “MAPI32.DLL” );
if ( hInstMail == NULL )
{
// 錯誤處理
// 受篇幅限制,下面的錯誤處理部分省略
}
3-1-2 確定函數(shù)地址
---- 由于MAPI32.DLL是被動態(tài)裝載的,因此不知道所要調(diào)用的函數(shù)地址,也就不能一開始就調(diào)用它們,
而要通過函數(shù)名獲得函數(shù)的地址,并在動態(tài)鏈接庫中查找每一個函數(shù)并核實。因此首先必須為這些函數(shù)聲明指針
程序示例:
// 為MAPI32.DLL中的函數(shù)聲明函數(shù)指針
ULONG (PASCAL *lpfnMAPISendMail) (LHANDLE lhSession,
ULONG ulUIParam, lpMapiMessage lpMessage,
FLAGS flFlags, ULONG ulReserved);
ULONG (PASCAL *lpfnMAPIResolveName) (LHANDLE lhSession,
ULONG ulUIParam, LPTSTR lpszName,
FLAGS ulFlags, ULONG ulReserved,
lpMapiRecipDesc FAR *lppRecip);
ULONG (FAR PASCAL *lpfnMAPILogon)(ULONG ulUIParam,
LPSTR lpszProfileName, LPSTR lpszPassword,
FLAGS flFlags, ULONG ulReserved,
LPLHANDLE lplhSession);
ULONG (FAR PASCAL *lpfnMAPILogoff)(LHANDLE lhSession,
ULONG ulUIParam, FLAGS flFlags,
ULONG ulReserved);
ULONG (FAR PASCAL *lpfnMAPIFreeBuffer)(LPVOID lpBuffer);
ULONG (FAR PASCAL *lpfnMAPIAddress)(LHANDLE lhSession,
ULONG ulUIParam, LPSTR lpszCaption,
ULONG nEditFields, LPSTR lpszLabels,
ULONG nRecips, lpMapiRecipDesc lpRecips,
FLAGS flFlags, ULONG ulReserved,
LPULONG lpnNewRecips,
lpMapiRecipDesc FAR *lppNewRecips);
ULONG (FAR PASCAL *lpfnMAPIFindNext)(LHANDLE lhSession,
ULONG ulUIParam, LPSTR lpszMessageType,
LPSTR lpszSeedMessageID, FLAGS flFlags,
ULONG ulReserved, LPSTR lpszMessageID);
ULONG (FAR PASCAL *lpfnMAPIReadMail)(LHANDLE lhSession,
ULONG ulUIParam, LPSTR lpszMessageID,
FLAGS flFlags, ULONG ulReserved,
lpMapiMessage FAR *lppMessage);
---- 為了決定每一個函數(shù)的地址,必須為每一個函數(shù)調(diào)用GetProcAddress。
GetProcAddress的語法為:
GetProcAddress (hModule, lpProcName);
其中,hModule為HMODULE結(jié)構(gòu),是所調(diào)用DLL模塊的句柄;
lpProcName為LPCSTR結(jié)構(gòu),是函數(shù)名稱。
程序示例:
// 找到MAPI32.DLL函數(shù)的地址,并將它們保存在函數(shù)指針變量里
(FARPROC&) lpfnMAPISendMail = GetProcAddress(hInstMail,
“MAPISendMail”);
(FARPROC&) lpfnMAPIResolveName = GetProcAddress(
hInstMail, “MAPIResolveName”);
(FARPROC&) lpfnMAPILogon = GetProcAddress(hInstMail,
“MAPILogon”);
(FARPROC&) lpfnMAPILogoff = GetProcAddress(hInstMail,
“MAPILogoff”);
(FARPROC&) lpfnMAPIFreeBuffer = GetProcAddress(
hInstMail, “MAPIFreeBuffer”);
(FARPROC&) lpfnMAPIAddress = GetProcAddress(hInstMail,
“MAPIAddress”);
(FARPROC&) lpfnMAPIFindNext = GetProcAddress(hInstMail,
“MAPIFindNext”);
(FARPROC&) lpfnMAPIReadMail = GetProcAddress(hInstMail,
“MAPIReadMail”);
3-1-3 登錄到電子郵件對象
---- 用戶必須在電子郵件系統(tǒng)中登錄,才能實現(xiàn)MAPI的各種功能。MAPI提供了登錄的三種選擇:
登錄到一個已經(jīng)存在的對象。
登錄到一個新對象,用編程的方法確定解釋新信息。
使用對話框提示用戶登錄。
---- 我們通常選擇登錄到一個已經(jīng)存在的電子郵件對象,因為網(wǎng)絡(luò)合作用戶通常會保持自己的
電子郵件程序處于激活狀態(tài)。登錄通常使用MAPI提供的函數(shù)lpfnMAPILogon。
lpfnMAPILogon的語法為:
lpfnMAPILogon (lpszProfileName, lpszPassword, flFlags,
ulReserved, lplhSession );
---- 其中,lpszProfileName指向一個256字符以內(nèi)的登錄名稱,lpszPassword指向密碼,它們均
為LPTSTR結(jié)構(gòu)。flFlags為FLAGS結(jié)構(gòu),其值詳見表1。ulReserved必須為0。lplhSession為輸出SMAPI的句柄。
表1:lpfnMAPILogon函數(shù)中flFlags的值
值 意義
MAPI_FORCE_DOWNLOAD
在函數(shù)調(diào)用返回之前下載用戶的所有郵件。
如果MAPI_FORCE_DOWNLOAD沒有被設(shè)置,
那么信件能夠在函數(shù)調(diào)用返回后在后臺被下載。
MAPI_NEW_SESSION 建立一個新會話,
而不是獲得環(huán)境的共享會話。如果MAPI_NEW_SESSION沒有被設(shè)置,
MAPILogon使用現(xiàn)有的共享會話。
MAPI_LOGON_UI 顯示一個登錄對話框來提示用戶輸入登錄信息。
例如Outlook檢查用戶電子郵件時便是如此。
MAPI_PASSWORD_UI MAPILogon只允許用戶輸入電子郵件的密碼,
而不許改動賬號。
程序示例:
LHANDLE lhSession;
ULONG lResult = lpfnMAPILogon(0, NULL, NULL, 0, 0,
&lhSession);
if (lResult != SUCCESS_SUCCESS)
//SUCCESS_SUCCESS在MAPI.H中被定義
{
// 錯誤處理
}
3-2 閱讀電子郵件
---- MAPIFindNext和MAPIReadMail使用與閱讀E-mail的兩個基本函數(shù)。MAPIFindNext用于定位第一
封或下一封電子郵件并返回標識號,MAPIReadMail返回以該標識號為基礎(chǔ)的電子郵件的內(nèi)容。另外,
一個常用的函數(shù)是MAPIFreeBuffer,用于釋放內(nèi)存。
3-2-1 定位到第一封信
---- 要找到第一封信,需要使用MAPIFindNext函數(shù),其函數(shù)聲明如下:
ULONG FAR PASCAL MAPIFindNext(LHANDLE lhSession,
ULONG ulUIParam, LPTSTR lpszMessageType,
LPTSTR lpszSeedMessageID, FLAGS flFlags,
ULONG ulReserved, LPTSTR lpszMessageID )
---- 其中,lhSession為提交SMAPI的會話句柄 ;ulUIParam為父窗體的句柄;lpszMessageType
指向一個字符串,用來鑒別郵件類型,并加以查找;lpszSeedMessageID為指向起始信息ID的指針,
其值為0時,MAPIFindNext獲得第一封電子郵件;flFlags的值見表2;ulReserved必須為0;
lpszMessageID為輸出值,它是指向信息ID地址的指針。
---- 表2:MAPIFindNext函數(shù)中flFlags的值
值 意義
MAPI_GUARANTEE_FIFO 按郵件發(fā)送的時間順序接受電子郵件。
MAPI_LONG_MSGID 返回信件標識符可達512字符。
MAPI_UNREAD_ONLY 只列舉沒有閱讀過的電子郵件。
程序示例:
// 找到第一條沒有閱讀的電子郵件
char pMessageID [513];
ULONG lResult = lpfnMAPIFindNext(lhSession, NULL, NULL,
NULL, MAPI_LONG_MSGID | MAPI_UNREAD_ONLY,
0, pMessageID);
3-2-2 閱讀信息
當信件ID被獲取后,就可以調(diào)用MAPIReadMail
閱讀實際的E-mail信息了。MAPIReadMail的函數(shù)聲明如下:
ULONG FAR PASCAL MAPIReadMail(LHANDLE lhSession,
ULONG ulUIParam, LPTSTR lpszMessageID,
FLAGS flFlags, ULONG ulReserved,
lpMapiMessage FAR * lppMessage);
其中,lppMessage為指向MapiMessage的指針;
除flFlags外的其他參數(shù)與lpfnFindNext函數(shù)的同名參數(shù)意義相同,
flFlags參數(shù)的值見表3:
表3:MAPIReadMail函數(shù)中flFlags的值:
值 意義
MAPI_BODY_AS_FILE 將郵件信息寫到一個臨時文件中,
并且將它作為第一個附件添加到附件列表中。
MAPI_ENVELOPE_ONLY 只讀取郵件標題。
MAPI_PEEK 讀完郵件之后不把它標記為“已讀”。
MAPI_SUPPRESS_ATTACH MAPIReadMail函數(shù)不拷貝附件,
但是將郵件文本寫入MapiMessage結(jié)構(gòu)中。
程序示例:
// 讀取電子郵件
long nFlags = MAPI_SUPPRESS_ATTACH;
if (!bMarkAsRead)
nFlags = nFlags | MAPI_PEEK;
lResult = lpfnMAPIReadMail(lhSession, NULL, pMessageID,
nFlags, 0, &pMessage);
if (lResult != SUCCESS_SUCCESS);
return false;
如果調(diào)用成功,就可以訪問MapiMessage結(jié)構(gòu)了(使用pMessage):
pMessage- >ulReserved:0
pMessage- >lpszSubject:郵件標題
pMessage- >lpszNoteText:郵件信息
pMessage- >lpszMessageType:郵件類型
pMessage- >DateReceived:接收時間
pMessage- >lpszConversationID:郵件所屬的會話線程ID
pMessage- >flFlags:其值見表4
表4:MapiMessage結(jié)構(gòu)中的flFlags
值 意義
MAPI_RECEIPT_REQUESTED 接收通知被申請。
客戶端應(yīng)用程序在發(fā)送消息時設(shè)置該項。
MAPI_SENT 郵件已被發(fā)送。
MAPI_UNREAD 郵件是“未讀”狀態(tài)。
pMessage- >lpOriginator:指向MapiRecipDesc結(jié)構(gòu),包含發(fā)件人信息。
pMessage- >nRecipCount:信件者數(shù)目。
pMessage- >lpRecips:指向MapiRecipDesc結(jié)構(gòu)數(shù)組,包含接收者信息。
pMessage- >nFileCount:附件數(shù)量。
pMessage- >lpFiles:指向MapiFileDesc結(jié)構(gòu)數(shù)組,
每一個結(jié)構(gòu)包含一個文件附件。
3-2-3 釋放內(nèi)存
---- 在訪問另一條信件以前應(yīng)當釋放內(nèi)存,否則會出現(xiàn)內(nèi)存泄漏。
程序示例:
// 釋放內(nèi)存
lpfnMAPIFreeBuffer(pMessage);
3-2-4 定位到下一條信件
定位到下一條信件依然使用MAPIFindNext函數(shù),
該函數(shù)聲明及參數(shù)意義詳見3-2-1節(jié)。下面示范如何定位到下一條信件。 程序示例:
// 定位到下一條沒有閱讀的信件
ULONG lResult = lpfnMAPIFindNext(lhSession, NULL, NULL,
pMessageID, MAPI_LONG_MSGID|MAPI_UNREAD_ONLY,
0, pMessageID);
3-3 發(fā)送電子郵件
---- 發(fā)送電子郵件的一般步驟:
---- 1. 建立MapiMessage結(jié)構(gòu)對象
---- 2. 調(diào)用MAPIResolveName使發(fā)送者名稱合法
---- 3. 添加附件
---- 4. 調(diào)用MAPISendMail發(fā)送電子郵件
---- 5. 調(diào)用MAPIFreeBuffer釋放內(nèi)存
---- 下面詳細分別詳細闡述。
3-3-1 建立MapiMessage結(jié)構(gòu)對象
---- 對于MapiMessage結(jié)構(gòu),3-2-2節(jié)已經(jīng)做過介紹,下面一步步介紹如何設(shè)置其中的值:
---- 1. 為MapiMessage對象分配內(nèi)存:
MapiMessage message;
Memset(&message, 0, sizeof(message));
---- 2. 將ulReserved設(shè)置為0:
message.ulReserved = 0;
---- 3. 設(shè)置信息類型指針lpszMessageType,可以為NULL:
message.lpszMessageType = NULL;
---- 4. 設(shè)置信件標題(lpszSubject):
char subject[512];
strcpy(subject, sSubject);
message.lpszSubject = subject;
---- 5. 設(shè)置信件內(nèi)容:
char text[5000];
strcpy(text, sMessage);
message.lpszNoteText = text;
---- 6. 設(shè)置flFlags標識,詳見3-2-2節(jié)中表4:
message.flFlags = MAPI_SENT;
---- 7. 用一個指向MapiRecipDesc結(jié)構(gòu)的指針設(shè)置發(fā)送者信息(lpOriginator),或?qū)⑵湓O(shè)置為NULL:
message.lpOriginator = NULL;
---- 8. 設(shè)置接收者數(shù)目(nRecipCount),可以是1或更多:
message.nRecipCount = 1;
---- 9. 設(shè)置接收者信息(lpRecips),詳見3-3-2節(jié)
---- 10. 設(shè)置附件數(shù)量(nFileCount)
---- 11. 設(shè)置附件信息,詳見3-3-3節(jié)
b3-3-2 正確設(shè)置接收者信息
---- 設(shè)置接收者信息時,應(yīng)當使用MAPIResolveName函數(shù)來為MapiRecipDesc結(jié)構(gòu)對象分配內(nèi)存,
并返回一個指針,該指針將被保存在MapiMessage結(jié)構(gòu)的lpRecips中。MAPIResolveName的函數(shù)聲明如下:
ULONG FAR PASCAL MAPIResolveName(LHANDLE lhSession,
ULONG ulUIParam, LPTSTR lpszName,
FLAGS flFlags, ULONG ulReserved,
lpMapiRecipDesc FAR * lppRecip )
---- 其中l(wèi)ppRecip即為前面提到的返回的指針。除flFlags外其余參數(shù)與前幾個函數(shù)意義相同。
flFlags的值詳見表5。
表5:MAPIResolveName中flFlags的值
值 意義
MAPI_AB_NOMODIFY 對話框為只讀。如果MAPI_DIALOG被設(shè)置,
那么該項將被忽略。
MAPI_DIALOG 顯示一個名稱解決方案的對話框
MAPI_LOGON_UI 如果需要的話,將會顯示儀個對話框讓用戶登錄
MAPI_NEW_SESSION 新建一個會話
程序示例:
char recipient[512];
strcpy(recipient, sTo);
lResult = lpfnMAPIResolveName(lhSession, 0, recipient,
0, 0, &message.lpRecips);
3-3-3 添加附件
---- 下面的程序示例將演示如何在電子郵件中包含附件。
只有一點需要說明:MapiFileDesc結(jié)構(gòu)中flFlags的值,詳見表6。
表6:MapiFileDesc結(jié)構(gòu)中flFlags的值
值 意義
MAPI_OLE 附件是OLE對象。
MAPI_OLE_STATIC 附件是靜態(tài)OLE對象。
0 附件將被視為數(shù)據(jù)文件
程序示例:
// 設(shè)置附件信息
CString sPath, sFileName;
MapiFileDesc FileInfo;
char path[512];
char filename[512];
if (sAttachment == “”)
message.nFileCount = 0;
else
{
int nPos = sAttachment.ReverseFind(‘\\');
if (nPos == -1)
{
sPath = sAttachment;
}
else
{
sPath = sAttachment;
sFilename = sAttachment.Mid(nPos +1);
}
strcpy(path, sPath);
strcpy(filename, sFilename);
message.nFileCount = 1;
FileInfo.ulReserved = 0;
FileInfo.flFlags = 0;
FileInfo.nPosition = sMessage.GetLength() –1;
FileInfo.lpszPathName = path;
FileInfo.lpszFileName = filename;
FileInfo.lpFileType = NULL;
message.lpFiles = & m_FileInfo;
}
3-3-4 發(fā)送電子郵件
---- 使用MAPISendMail發(fā)送電子郵件,其聲明如下:
ULONG FAR PASCAL MAPISendMail (LHANDLE lhSession,
ULONG ulUIParam, lpMapiMessage lpMessage,
FLAGS flFlags, ULONG ulReserved )
---- 其中,flFlags的允許值為MAPI_DIALOG、MAPI_LOGON_UI和MAPI_NEW_SESSION,
其意義與前幾個函數(shù)中同名標識意義相同。
程序示例:
lResult = lpfnMAPISendMail(0, 0, &m_message, 0, 0);
3-3-5 釋放內(nèi)存
程序示例:
lpfnMAPIFreeBuffer(m_message.lpRecips);
四、小結(jié)
---- 本文比較具體的介紹并演示了編寫一個電子郵件程序的核心部分,
如果讀者要編寫電子郵件程序,還需要進行的處理:
---- 1. 加上錯誤處理代碼。受篇幅限制,本文的程序示例中只有兩處為錯誤處理留空,
比較它們的異同。電子郵件程序是非常容易出錯的,因此除這兩處外要在主要函數(shù)
調(diào)用完成后都加上錯誤處理,或使用try throw catch塊處理例外。
---- 2. 加上UI處理。
---- 另外,本文所闡述的方法比較簡單易行,事實上,有關(guān)電子郵件的程序遠比這復(fù)雜得多,
因此讀者若需要編寫一個功能強大的電子郵件程序,需要精通MAPI和SMTP/POP3等協(xié)議;
如果讀者要編寫一個電子郵件服務(wù)器,那么不妨在精通MAPI和SMTP/POP3之后,
閱讀一些有關(guān)Exchange Server的資料
總結(jié)
以上是生活随笔為你收集整理的VC++编写电子邮件程序 第二篇 也是用simple mapi的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql数据库存放视频路径_学习怎样把
- 下一篇: BusinessSkinForm VCL