今天看windows mobile的document关于MAPI这部分,在网上google了下,结果找到这篇,它不是winmobile的,而是普通的PC,不过MAPI的东西在这两个环境下思路大体相同,转了下面充数。原文发在csdn上。

一、概述

---- 本文主要讲述如何使用Visual C++用MAPI编写E-mail程序。MAPI是包含在Windows之中的,因此不需要安装其他额外的部件。MAPI有以下三种形式:

·       SMAPI,Simple MAPI,简单的MAPI

·       CMC,Common Messaging Calls,一般通讯调用

·       完整的MAPI

---- SMAPI和CMC都包含在完整的MAPI中,当用户想执行一些高级操作,比如编写自己的E-mail服务器的时候,必须使用完整的MAPI。本文主要阐述如何编写能够收发电子邮件的程序,因此使用SMAPI就足够了。

二、编写电子邮件程序

3-1 初始化MAPI

---- 要使用MAPI,必须首先对它进行初始化。初始化包括以下三个步骤:

1.    装载MAPI32.DLL动态链接库

2.    找到想要调用的MAPI函数地址

3.    登录到电子邮件对象

3-1-1 装载MAPI32.DLL

---- 要装载MAPI,用户必须程序运行时动态的装载一个动态链接库。LoadLibrary函数提供了此功能,它定位一个动态链接库,并返回HINSTANCE局柄(需要保存该句柄)。

LoadLibrary的语法如下:

LoadLibrary ( lpLibFileName );

其中lpLibFileName为LPCTSTR结构变量,

是所要调用的库的路径和名称。

程序示例:

// 调用MAPI32.DLL并计算函数地址

HINSTANCE hInstMail;

hInstMail = ::LoadLibrary ( “MAPI32.DLL” );

if ( hInstMail == NULL )

{

// 错误处理

// 受篇幅限制,下面的错误处理部分省略

}

3-1-2 确定函数地址

---- 由于MAPI32.DLL是被动态装载的,因此不知道所要调用的函数地址,也就不能一开始就调用它们,而要通过函数名获得函数的地址,并在动态链接库中查找每一个函数并核实。因此首先必须为这些函数声明指针

程序示例:

// 为MAPI32.DLL中的函数声明函数指针

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,PSTR 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);

---- 为了决定每一个函数的地址,必须为每一个函数调用GetProcAddress。

GetProcAddress的语法为:

GetProcAddress (hModule, lpProcName);

其中,hModule为HMODULE结构,是所调用DLL模块的句柄;

lpProcName为LPCSTR结构,是函数名称。

程序示例:

// 找到MAPI32.DLL函数的地址,并将它们保存在函数指针变量里

(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 登录到电子邮件对象

---- 用户必须在电子邮件系统中登录,才能实现MAPI的各种功能。MAPI提供了登录的三种选择:

·       登录到一个已经存在的对象。

·       登录到一个新对象,用编程的方法确定解释新信息。

·       使用对话框提示用户登录。

---- 我们通常选择登录到一个已经存在的电子邮件对象,因为网络合作用户通常会保持自己的电子邮件程序处于激活状态。登录通常使用MAPI提供的函数lpfnMAPILogon。

lpfnMAPILogon的语法为:

lpfnMAPILogon (lpszProfileName, lpszPassword, flFlags,

ulReserved, lplhSession );

---- 其中,lpszProfileName指向一个256字符以内的登录名称,lpszPassword指向密码,它们均为LPTSTR结构。flFlags 为FLAGS结构,其值详见表1。ulReserved必须为0。lplhSession为输出SMAPI的句柄。

表1:lpfnMAPILogon函数中flFlags的值

值      意义

MAPI_FORCE_DOWNLOAD    在函数调用返回之前下载用户的所有邮件。

如果MAPI_FORCE_DOWNLOAD没有被设置,

那么信件能够在函数调用返回后在后台被下载。

MAPI_NEW_SESSION       建立一个新会话,

而不是获得环境的共享会话。如果MAPI_NEW_SESSION没有被设置,

MAPILogon使用现有的共享会话。

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的两个基本函数。MAPIFindNext用于定位第一封或下一封电子邮件并返回标识号,MAPIReadMail返回以该标识号为基础的电子邮件的内容。另外,一个常用的函数是MAPIFreeBuffer,用于释放内存。

3-2-1 定位到第一封信

---- 要找到第一封信,需要使用MAPIFindNext函数,其函数声明如下:

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函数中flFlags的值

值      意义

MAPI_GUARANTEE_FIFO    按邮件发送的时间顺序接受电子邮件。

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被获取后,就可以调用MAPIReadMail

阅读实际的E-mail信息了。MAPIReadMail的函数声明如下:

ULONG FAR PASCAL MAPIReadMail(LHANDLE lhSession,

ULONG ulUIParam, LPTSTR lpszMessageID,

FLAGS flFlags, ULONG ulReserved,

lpMapiMessage FAR * lppMessage);

其中,lppMessage为指向MapiMessage的指针;

除flFlags外的其他参数与lpfnFindNext函数的同名参数意义相同,

flFlags参数的值见表3:

表3:MAPIReadMail函数中flFlags的值:

值      意义

MAPI_BODY_AS_FILE      将邮件信息写到一个临时文件中,

并且将它作为第一个附件添加到附件列表中。

MAPI_ENVELOPE_ONLY     只读取邮件标题。

MAPI_PEEK      读完邮件之后不把它标记为“已读”。

MAPI_SUPPRESS_ATTACH   MAPIReadMail函数不拷贝附件,

但是将邮件文本写入MapiMessage结构中。

程序示例:

// 读取电子邮件

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;

如果调用成功,就可以访问MapiMessage结构了(使用pMessage):

pMessage- >ulReserved:0

pMessage- >lpszSubject:邮件标题

pMessage- >lpszNoteText:邮件信息

pMessage- >lpszMessageType:邮件类型

pMessage- >DateReceived:接收时间

pMessage- >lpszConversationID:邮件所属的会话线程ID

pMessage- >flFlags:其值见表4

表4:MapiMessage结构中的flFlags

值      意义

MAPI_RECEIPT_REQUESTED 接收通知被申请。

客户端应用程序在发送消息时设置该项。

MAPI_SENT      邮件已被发送。

MAPI_UNREAD    邮件是“未读”状态。

pMessage- >lpOriginator:指向MapiRecipDesc结构,包含发件人信息。

pMessage- >nRecipCount:信件者数目。

pMessage- >lpRecips:指向MapiRecipDesc结构数组,包含接收者信息。

pMessage- >nFileCount:附件数量。

pMessage- >lpFiles:指向MapiFileDesc结构数组,

每一个结构包含一个文件附件。

3-2-3 释放内存

---- 在访问另一条信件以前应当释放内存,否则会出现内存泄漏。

程序示例:

// 释放内存

lpfnMAPIFreeBuffer(pMessage);

3-2-4 定位到下一条信件

定位到下一条信件依然使用MAPIFindNext函数,

该函数声明及参数意义详见3-2-1节。下面示范如何定位到下一条信件。

程序示例:

// 定位到下一条没有阅读的信件

ULONG lResult = lpfnMAPIFindNext(lhSession, NULL, NULL,

pMessageID, MAPI_LONG_MSGID|MAPI_UNREAD_ONLY,

0, pMessageID);

3-3 发送电子邮件

---- 发送电子邮件的一般步骤:

---- 1. 建立MapiMessage结构对象

---- 2. 调用MAPIResolveName使发送者名称合法

---- 3. 添加附件

---- 4. 调用MAPISendMail发送电子邮件

---- 5. 调用MAPIFreeBuffer释放内存

---- 下面详细分别详细阐述。

3-3-1 建立MapiMessage结构对象

---- 对于MapiMessage结构,3-2-2节已经做过介绍,下面一步步介绍如何设置其中的值:

---- 1. 为MapiMessage对象分配内存:

MapiMessage message;

Memset(&message, 0, sizeof(message));

---- 2. 将ulReserved设置为0:

message.ulReserved = 0;

---- 3. 设置信息类型指针lpszMessageType,可以为NULL:

message.lpszMessageType = NULL;

---- 4. 设置信件标题(lpszSubject):

char subject[512];

strcpy(subject, sSubject);

message.lpszSubject = subject;

---- 5. 设置信件内容:

char text[5000];

strcpy(text, sMessage);

message.lpszNoteText = text;

---- 6. 设置flFlags标识,详见3-2-2节中表4:

message.flFlags = MAPI_SENT;

---- 7. 用一个指向MapiRecipDesc结构的指针设置发送者信息(lpOriginator),或将其设置为NULL:

message.lpOriginator = NULL;

---- 8. 设置接收者数目(nRecipCount),可以是1或更多:

message.nRecipCount = 1;

---- 9. 设置接收者信息(lpRecips),详见3-3-2节

---- 10. 设置附件数量(nFileCount)

---- 11. 设置附件信息,详见3-3-3节

b3-3-2 正确设置接收者信息

---- 设置接收者信息时,应当使用MAPIResolveName函数来为MapiRecipDesc结构对象分配内存,并返回一个指针,该指针将被保存在MapiMessage结构的lpRecips中。MAPIResolveName的函数声明如下:

ULONG FAR PASCAL MAPIResolveName(LHANDLE lhSession,

ULONG ulUIParam, LPTSTR lpszName,

FLAGS flFlags, ULONG ulReserved,

lpMapiRecipDesc FAR * lppRecip )

---- 其中lppRecip即为前面提到的返回的指针。除flFlags外其余参数与前几个函数意义相同。flFlags的值详见表5。

表5:MAPIResolveName中flFlags的值

值      意义

MAPI_AB_NOMODIFY       对话框为只读。如果MAPI_DIALOG被设置,

那么该项将被忽略。

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结构中flFlags的值,详见表6。

表6:MapiFileDesc结构中flFlags的值

值      意义

MAPI_OLE       附件是OLE对象。

MAPI_OLE_STATIC 附件是静态OLE对象。

0       附件将被视为数据文件

程序示例:

// 设置附件信息

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 发送电子邮件

---- 使用MAPISendMail发送电子邮件,其声明如下:

ULONG FAR PASCAL MAPISendMail (LHANDLE lhSession,

ULONG ulUIParam, lpMapiMessage lpMessage,

FLAGS flFlags, ULONG ulReserved )

---- 其中,flFlags的允许值为MAPI_DIALOG、MAPI_LOGON_UI和MAPI_NEW_SESSION,其意义与前几个函数中同名标识意义相同。

程序示例:

lResult = lpfnMAPISendMail(0, 0, &m_message, 0, 0);

3-3-5 释放内存

程序示例:

lpfnMAPIFreeBuffer(m_message.lpRecips);

四、小结

---- 本文比较具体的介绍并演示了编写一个电子邮件程序的核心部分,如果读者要编写电子邮件程序,还需要进行的处理:

---- 1. 加上错误处理代码。受篇幅限制,本文的程序示例中只有两处为错误处理留空,比较它们的异同。电子邮件程序是非常容易出错的,因此除这两处外要在主要函数调用完成后都加上错误处理,或使用try throw catch块处理例外。

---- 2. 加上UI处理。

---- 另外,本文所阐述的方法比较简单易行,事实上,有关电子邮件的程序远比这复杂得多,因此读者若需要编写一个功能强大的电子邮件程序,需要精通MAPI和 SMTP/POP3等协议;如果读者要编写一个电子邮件服务器,那么不妨在精通MAPI和SMTP/POP3之后,阅读一些有关Exchange Server的资料

利用MAPI实现邮件收发(VC++)相关推荐

  1. 利用MAPI实现电子邮件功能

    利用MAPI实现电子邮件功能 在VB.VC中进行面向Internet的开发应用,是近期许多程序员关注的热点. 随着办公自动化应用软件水平的提高和Intranet的流行,越来越多的办公自动化系统中都采用 ...

  2. VS2008下利用#pragma comment屏蔽VC/VS生成的exe程序的CMD窗口

    2016-6-1日注:此种方法并不适用于VS2012,在VS2012中屏蔽CMD的方法可以见博文:VS2012及VS系列怎样屏蔽CMD窗口~_昊虹图像算法-CSDN博客_vs 不打开cmd 有时候我们 ...

  3. 利用cheat engine以及VC编写游戏修改器

    cheat engine的介绍已经完毕了,下面就是怎么使用它的问题,这里写一个稍微有意思一点的,也有实际用途的话题,就是来编写自己的游戏修改器. 这篇文章参考了http://www.pediy.com ...

  4. 利用JMail组件快速构建邮件程序

    当你需要在VC程序中提供邮件支持功能的时候,你有许多种选择: 1)根据SMTP,POP3,MIME等协议从零开始实现.这要求熟悉RFC 821,RFC 822,RFC 1123, RFC 1652, ...

  5. VC中JMail组件的应用(上)

    当你需要在VC程序中提供邮件支持功能的时候,你有许多种选择: 1)根据SMTP,POP3,MIME等协议从零开始实现.这要求熟悉RFC 821,RFC 822,RFC 1123, RFC 1652, ...

  6. CE MAPI实例讲解 --- IMAPIAdviseSink的一个例子(四)

    AdviseSink 对于我们了解系统SMS以及OUTLOOK的消息运作有很大帮助,我们可以挂接到SMS.OUTLOOK的Message Store上,看看在做某些操作时,系统到底对Message做了 ...

  7. VS2012及VS系列怎样屏蔽CMD窗口~

    以前我写过一篇博文,是关于VS2008屏蔽CMD窗口的,详见VS2008下利用#pragma comment屏蔽VC/VS生成的exe程序的CMD窗口_昊虹图像算法-CSDN博客 但那种方法对VS20 ...

  8. GCC和MSVC的INITIALIZER的实现

    熟悉linux内核编程的应该知道内核模块有一个宏叫 module_init,当内核模块被静态编译到内核后,会在内核init阶段调用每个被module_init声明过的函数.这是如何实现的呢?其实是用到 ...

  9. 源码免杀处理的技巧与tips

    2019独角兽企业重金招聘Python工程师标准>>> 首先,要了解编译中MAP的利用:     第一步设置VC编译环境生成Map文件. 在 VC 中,点击菜单"Proje ...

最新文章

  1. 再次学习基础爬虫,爬取大学排名。
  2. 关于swing的一些看法
  3. 简单删除我的电脑里的wps云文档图标
  4. Android 学习笔记 BroadcastReceiver广播...
  5. 学校的体育设施预订服务系统
  6. 在Spring MVC应用程序中使用Bean Validation 1.1获得更好的错误消息
  7. 正则表达式中的量词(限定符)含义的准确理解
  8. 正三角形的外接圆面积
  9. java 随机生成图,Java中的快速实值随机生成器
  10. Replace Type Code with Subclasses(以子类取代类型码)
  11. 输出亲朋字符串(信息学奥赛一本通-T1133)
  12. python中iskeydown什么函数_isKeyDown不能在Java中工作
  13. jenkins vue 打包特别慢_Jenkins 自动化部署
  14. RFC2544吞吐量测试详细步骤-MiniSMB-HurricaneII软件操作演示
  15. 企业邮箱怎么写加密邮件,企业邮箱支持吗?
  16. UVM 中的消息机制
  17. 以下不是python语言合法变量_违法行为的客体是指法律所保护的而为违法行为所侵害的:()...
  18. 【嵌入式Linux驱动入门】二、上手Hello驱动,了解驱动开发流程
  19. C++ 神奇的头文件
  20. IN指令和OUT指令

热门文章

  1. 干式离合器与湿式离合器有什么区别(转载)
  2. Unity自定义材质自发光烘焙设置工具
  3. DES算法实现S盒替换
  4. Kubernetes 高可用集群部署
  5. www.etiger.vip 1612题 高斯求和
  6. docker启动nginx及问题处理
  7. python通过Tkinter库实现的一个简单的文本编辑器源码
  8. 修改共享计算机主机名,怎么修改计算机的主机名,和所在的工作组
  9. 转载: centos mysql5.7 安装
  10. 损失函数-MSE-CEE