INFORMAÇÕES: Guardar mensagem no ficheiro composto MSG
Resumo
Este artigo contém código que demonstra como guardar uma mensagem num documento composto, especificamente um ficheiro de .msg que é legível por qualquer cliente que suporte o formato de ficheiro .msg.
Mais informações
A função abaixo utiliza um objeto de mensagem válido como um parâmetro in e utiliza as respetivas propriedades para criar um duplicado da mensagem e guardá-la num ficheiro composto com o formato .msg. A linha de assunto da mensagem é utilizada como o nome de ficheiro do novo ficheiro.
Nota
Os carateres especiais na linha de assunto do parâmetro in desta função podem causar resultados inesperados. Embora o código possa ser escrito para evitar carateres especiais na linha do assunto, não é alemão para o tópico e esse código é intencionalmente deixado de fora.
#define INITGUID
#include <objbase.h>
#define USES_IID_IMessage
#include <mapix.h>
#include <mapitags.h>
#include <mapidefs.h>
#include <mapiutil.h>
#include <mapiguid.h>
#include <imessage.h>
// {00020D0B-0000-0000-C000-000000000046}
DEFINE_GUID(CLSID_MailMessage,
0x00020D0B,
0x0000, 0x0000, 0xC0, 0x00, 0x0, 0x00, 0x0, 0x00, 0x00, 0x46);
HRESULT SaveToMSG ( LPMESSAGE pMessage )
{
HRESULT hRes = S_OK;
LPSPropValue pSubject = NULL;
LPSTORAGE pStorage = NULL;
LPMSGSESS pMsgSession = NULL;
LPMESSAGE pIMsg = NULL;
SizedSPropTagArray ( 7, excludeTags );
char szPath[_MAX_PATH];
char strAttachmentFile[_MAX_PATH];
LPWSTR lpWideCharStr = NULL;
ULONG cbStrSize = 0L;
// create the file name in the directory where "TMP" is defined
// with subject as the filename and ".msg" extension.
// get temp file directory
GetTempPath(_MAX_PATH, szPath);
// get subject line of message to copy. This will be used as the
// new file name.
HrGetOneProp( pMessage, PR_SUBJECT, &pSubject );
// fuse path, subject, and suffix into one string
strcpy ( strAttachmentFile, szPath );
strcat ( strAttachmentFile, pSubject->Value.lpszA );
strcat ( strAttachmentFile, ".msg");
// get memory allocation function
LPMALLOC pMalloc = MAPIGetDefaultMalloc();
// Convert new file name to WideChar
cbStrSize = MultiByteToWideChar (CP_ACP,
MB_PRECOMPOSED,
strAttachmentFile,
-1, lpWideCharStr, 0);
MAPIAllocateBuffer ( cbStrSize * sizeof(WCHAR),
(LPVOID *)&lpWideCharStr );
MultiByteToWideChar (CP_ACP,
MB_PRECOMPOSED,
strAttachmentFile,
-1, lpWideCharStr, cbStrSize );
// create compound file
hRes = ::StgCreateDocfile(lpWideCharStr,
STGM_READWRITE |
STGM_TRANSACTED |
STGM_CREATE, 0, &pStorage);
// Open an IMessage session.
hRes = ::OpenIMsgSession(pMalloc, 0, &pMsgSession);
// Open an IMessage interface on an IStorage object
hRes = ::OpenIMsgOnIStg(pMsgSession,
MAPIAllocateBuffer,
MAPIAllocateMore,
MAPIFreeBuffer,
pMalloc,
NULL,
pStorage,
NULL, 0, 0, &pIMsg);
// write the CLSID to the IStorage instance - pStorage. This will
// only work with clients that support this compound document type
// as the storage medium. If the client does not support
// CLSID_MailMessage as the compound document, you will have to use
// the CLSID that it does support.
hRes = WriteClassStg(pStorage, CLSID_MailMessage );
// Specify properties to exclude in the copy operation. These are
// the properties that Exchange excludes to save bits and time.
// Should not be necessary to exclude these, but speeds the process
// when a lot of messages are being copied.
excludeTags.cValues = 7;
excludeTags.aulPropTag[0] = PR_ACCESS;
excludeTags.aulPropTag[1] = PR_BODY;
excludeTags.aulPropTag[2] = PR_RTF_SYNC_BODY_COUNT;
excludeTags.aulPropTag[3] = PR_RTF_SYNC_BODY_CRC;
excludeTags.aulPropTag[4] = PR_RTF_SYNC_BODY_TAG;
excludeTags.aulPropTag[5] = PR_RTF_SYNC_PREFIX_COUNT;
excludeTags.aulPropTag[6] = PR_RTF_SYNC_TRAILING_COUNT;
// copy message properties to IMessage object opened on top of
// IStorage.
hRes = pMessage->CopyTo(0, NULL,
(LPSPropTagArray)&excludeTags,
NULL, NULL,
(LPIID)&IID_IMessage,
pIMsg, 0, NULL );
// save changes to IMessage object.
pIMsg -> SaveChanges ( KEEP_OPEN_READWRITE );
// save changes in storage of new doc file
hRes = pStorage -> Commit(STGC_DEFAULT);
// free objects and clean up memory
MAPIFreeBuffer ( lpWideCharStr );
pStorage->Release();
pIMsg->Release();
CloseIMsgSession ( pMsgSession );
pStorage = NULL;
pIMsg = NULL;
pMsgSession = NULL;
lpWideCharStr = NULL;
return hRes;
}
Todas as versões do Outlook e do Exchange Client suportam CLSID_MailMessage como o documento composto. A única razão para utilizar um CLSID diferente é suportar outros clientes que utilizam um CLISD diferente quando escreve mensagens no armazenamento estruturado.
Ao guardar mensagens com um grande número de destinatários ou anexos, é possível que a operação CopyTo falhe com MAPI_E_NOT_ENOUGH_MEMORY. Isto deve-se a um problema conhecido com armazenamento estruturado e fluxos. Sempre que um novo anexo ou destinatário é adicionado à mensagem que está a ser guardada no armazenamento estruturado, é aberto um novo Ficheiro de Armazenamento de Raiz. Estes ficheiros não são fechados até que a transação seja concluída. Uma vez que o sistema operativo impõe um limite ao número de ficheiros de armazenamento de raiz abertos simultaneamente, não existe uma solução conhecida.
Comentários
https://aka.ms/ContentUserFeedback.
Brevemente: Ao longo de 2024, vamos descontinuar progressivamente o GitHub Issues como mecanismo de feedback para conteúdos e substituí-lo por um novo sistema de feedback. Para obter mais informações, veja:Submeter e ver comentários