winapi - WIndows MAPI unicode problem

Indlæg af Hanne Mølgaard Plasc

Problem



Det forekommer mig, at MAPI (Windows Mail API) har problemer med UTF8 (eller måske gjorde jeg noget forkert).


Kodeprøve:


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 og recipient er alle std::string s. Så vidt jeg ved, er UTF8 kompatibel med ASCII (også NULL termineret), så dens streng kan holde sådanne værdier uden problemer.


Jeg konverterer til UTF8 fra wstring på denne måde:


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 er et std::string objekt.

Bedste reference


MAPISendMail() understøtter ikke UTF-8, kun Ansi. Hvis du skal sende Unicode-data, skal du bruge MAPISendMailHelper() på Windows 7 og tidligere eller MAPISendMailW() på Windows 8 og senere. Dette fremgår tydeligt af dokumentationen MAPISendMail(). [19] [20] [21]


På en sidebesked inkluderer WideCharToMultiByte() nullterminatoren, når du indstiller parameteren cchWideChar til -1. Som sådan kodes du og inkluderer den nullterminator i dine container data. Du skal i stedet indstille cchWideChar til den faktiske længde af strengen for at undgå nullterminatoren helt:


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


På http://msdn.microsoft.com/en-us/library/windows/desktop/dd296721.aspx hedder det 'I Windows 7 og tidligere: Brug MAPISendMailHelper til at sende en besked', men nederst på http://msdn .microsoft.com/en-os/library/windows/desktop/hh802867.aspx det hedder 'Minimum understøttet' er Windows 8. Ligner modstridende oplysninger og derfor er det uklart, om MAPISendMailHelper virkelig er til Windows 7 og tidligere. [22] [23]