INFO: Salvar mensagem no arquivo composto MSG
Resumo
Este artigo contém um código que demonstra como salvar uma mensagem em um documento composto, especificamente um arquivo .msg que é legível por qualquer cliente que dê suporte ao formato de arquivo .msg.
Mais informações
A função abaixo usa um objeto de mensagem válido como um parâmetro in e usa suas propriedades para criar uma duplicata da mensagem e salvá-la em um arquivo composto usando o formato .msg. A linha de assunto da mensagem é usada como o nome do arquivo do novo arquivo.
Observação
Caracteres especiais na linha de assunto do parâmetro in dessa função podem causar resultados inesperados. Embora o código possa ser escrito para evitar caracteres especiais na linha de assunto, ele 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 suporte ao Cliente do Exchange CLSID_MailMessage como o documento composto. O único motivo para usar um CLSID diferente é dar suporte a outros clientes que usam um CLISD diferente ao gravar mensagens no armazenamento estruturado.
Ao salvar 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. Isso ocorre devido a um problema conhecido com armazenamento e fluxos estruturados. Sempre que um novo anexo ou destinatário é adicionado à mensagem que está sendo salva no armazenamento estruturado, um novo Arquivo de Armazenamento Raiz é aberto. Esses arquivos não serão fechados até que a transação seja concluída. Como o sistema operacional impõe um limite ao número de arquivos de armazenamento raiz abertos simultaneamente, não há solução alternativa conhecida.
Comentários
https://aka.ms/ContentUserFeedback.
Em breve: Ao longo de 2024, eliminaremos os problemas do GitHub como o mecanismo de comentários para conteúdo e o substituiremos por um novo sistema de comentários. Para obter mais informações, consulteEnviar e exibir comentários de