2012-03-30 4 views
3

Мне кажется, что MAPI (Windows Mail API) имеет проблемы с UTF8 (или, может быть, я сделал что-то не так).WIndows MAPI unicode issue

Пример кода:

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

title, filePath, fileName и recipient все std::string s. Насколько я знаю, UTF8 совместим с ASCII (также NULL завершен), поэтому его строка может содержать такие значения без каких-либо проблем.

Я преобразование в UTF8 из wstring таким образом:

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 объекта.

+0

Каков фактический вопрос здесь? Что вы ожидаете, и что вы получаете вместо этого? –

ответ

8

MAPISendMail() не поддерживает UTF-8, только Ansi. Если вам нужно отправить данные Unicode, вы должны использовать MAPISendMailHelper() в Windows 7 и более ранних версиях, или MAPISendMailW() в Windows 8 и более поздних версиях. Это четко указано в MAPISendMail() documentation.

На боковой ноте WideCharToMultiByte() содержит нулевой ограничитель, когда вы устанавливаете параметр cchWideChar равным -1. Таким образом, вы кодируете и включаете этот нулевой ограничитель в свои данные 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 и ранее.

+1

MAPISendMailHelper не существует в Windows 7 Service Pack 1. Я использовал файл depend.exe для извлечения экспортированных функций mapi32.dll. MAPISendMailHelper не экспортируется mapi32.dll. –

+4

MAPISendMailHelper не экспортируется из любой DLL; он поставляется в виде кода в последнем пакете Windows SDK. Он находится в файле «MapiUnicodeHelp.h». – Swythan

+0

В Win7 и ранее MAPISendMailHelper() просто преобразует структуры Unicode в структуры ANSI и вызывает MapiSendMail() вместо MapiSendMailW(). Другими словами, он не поддерживает Unicode MAPI, если только основной поставщик MAPI не выполняет (I.e., Win8 MAPI). Его единственная цель - упростить клиентский код - вам не нужно создавать разные структуры и вызывать разные функции в зависимости от версии Windows. – chrisd