【问题标题】:WIndows MAPI unicode issueWINDOWS MAPI Unicode 问题
【发布时间】:2012-03-30 12:49:50
【问题描述】:

在我看来,MAPI(Windows Mail API)与 UTF8 有问题(或者我做错了什么)。

代码示例:

HMODULE m_hLib = LoadLibraryA("MAPI32.DLL");
if (m_hLib == NULL)
    return SEND_MAIL_CANCELED;
LPMAPISENDMAIL SendMail;
SendMail = (LPMAPISENDMAIL) GetProcAddress(m_hLib, "MAPISendMail");
if (!SendMail)
    return;

MapiFileDesc fileDesc;
ZeroMemory(&fileDesc, sizeof(fileDesc));
fileDesc.nPosition = (ULONG) -1;
fileDesc.lpszPathName = (LPSTR) filePath.toUtf8();
fileDesc.lpszFileName = (LPSTR) fileName.toUtf8();

MapiRecipDesc recipientData;
ZeroMemory(&recipientData, sizeof(recipientData));
recipientData.lpszName = (LPSTR) recipient.toUtf8();
recipientData.ulRecipClass = MAPI_TO;

MapiMessage message;
ZeroMemory(&message, sizeof(message));
message.ulReserved = CP_UTF8;
message.lpszSubject = (LPSTR) title.toUtf8();
message.nFileCount = 1;
message.lpFiles = &fileDesc;
message.nRecipCount = 1;
message.lpRecips = &recipientData;

int nError = SendMail(0, NULL, &message, MAPI_LOGON_UI | MAPI_DIALOG, 0);

titlefilePathfileNamerecipient 都是 std::strings。据我所知,UTF8 与 ASCII 兼容(也以 NULL 结尾),所以它的字符串可以毫无问题地保存这样的值。

我正在通过这种方式从 wstring 转换为 UTF8:

int requiredSize = WideCharToMultiByte(CP_UTF8, 0, data.c_str(), -1, 0, 0, 0, 0);
if(requiredSize > 0)
{
    std::vector<char> buffer(requiredSize);
    WideCharToMultiByte(CP_UTF8, 0, data.c_str(), -1, &buffer[0], requiredSize, 0, 0);
    this->container.append(buffer.begin(), buffer.end() - 1);
}

container 是一个std::string 对象。

【问题讨论】:

  • 这里的实际问题是什么?您期望会发生什么,而您会得到什么?

标签: windows winapi unicode mapi


【解决方案1】:

MAPISendMail() 不支持 UTF-8,只支持 Ansi。如果您需要发送 Unicode 数据,您必须在 Windows 7 及更早版本上使用MAPISendMailHelper(),或在 Windows 8 及更高版本上使用MAPISendMailW()。这在MAPISendMail() documentation中有明确说明。

附带说明,当您将 cchWideChar 参数设置为 -1 时,WideCharToMultiByte() 包含空终止符。因此,您正在编码并将该空终止符包含在您的 container 数据中。您应该将 cchWideChar 设置为字符串的实际长度,以完全避免空终止符:

int requiredSize = WideCharToMultiByte(CP_UTF8, 0, data.c_str(), data.length(), 0, 0, 0, 0); 
if (requiredSize > 0) 
{ 
    std::vector<char> buffer(requiredSize); 
    WideCharToMultiByte(CP_UTF8, 0, data.c_str(), data.length(), &buffer[0], requiredSize, 0, 0); 
    container.append(buffer.begin(), buffer.end()); 
} 

http://msdn.microsoft.com/en-us/library/windows/desktop/dd296721.aspx 上,它声明“在 Windows 7 和更早版本:使用 MAPISendMailHelper 发送消息”,但在 http://msdn.microsoft.com/en-us/library/windows/desktop/hh802867.aspx 的底部,它声明“最低支持”是 Windows 8。似乎是相互矛盾的信息,因此不清楚是否MAPISendMailHelper 确实适用于 Windows 7 及更早版本。

【讨论】:

  • MAPISendMailHelper 在 Windows 7 Service Pack 1 上不存在。我使用 depends.exe 来检索 mapi32.dll 的导出函数。 mapi32.dll 不导出 MAPISendMailHelper。
  • MAPISendMailHelper 未从任何 dll 导出;它在最新的 Windows SDK 中作为代码提供。它在“MapiUnicodeHelp.h”文件中。
  • 在 Win7 和更早版本下,MAPISendMailHelper() 只是将 Unicode 结构转换为 ANSI 结构并调用 MapiSendMail() 而不是 MapiSendMailW()。换句话说,它不支持 Unicode MAPI,除非底层 MAPI 提供程序支持(即 Win8 MAPI)。它的唯一目的是简化客户端代码——您不必根据 Windows 版本构建不同的结构和调用不同的函数。
  • 顺便提一下,所有代码都可以在 MapiUnicodeHelp.h 中查看。 MAPISendMailHelper() 不是 DLL 导出,而是 #included 到您的项目中的代码。
  • 实际上 MAPISendMail() 在 Windows 7 上确实使用了 UTF8,但您必须在 HKEY_LOCAL_MACHINE\SOFTWARE\Clients\Mail\YourAppName 下添加一个注册表项 DWORD SupportUTF8(通常为值 1)。如果添加,它将把MAPISendMail()ULONG ulReserved设置为CP_UTF8,你可以使用MultiByteToWideChar转换成宽字符。
猜你喜欢
  • 2011-11-15
  • 1970-01-01
  • 1970-01-01
  • 2013-07-23
  • 2013-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多