INFO:將訊息儲存至 MSG 複合檔案
摘要
本文包含的程式代碼示範如何將訊息儲存至複合檔,特別是支援.msg檔格式的任何用戶端可讀取的.msg檔案。
其他相關資訊
下列函式會在 參數中使用有效的訊息物件做為 ,並使用其屬性來建立訊息的復本,並使用.msg格式將它儲存至複合檔。 訊息的主旨行會做為新檔案的檔名。
注意事項
此函式中 in 參數之 主旨行中的特殊字元可能會導致非預期的結果。 雖然程式代碼可以撰寫以避免主旨行中的特殊字元,但它不會與主題產生關聯,而且會刻意排除這類程序代碼。
#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;
}
所有版本的 Outlook 和 Exchange 用戶端支援CLSID_MailMessage作為複合檔。 使用不同 CLSID 的唯一原因是,當您將訊息寫入結構化記憶體時,支援使用不同 CLISD 的其他用戶端。
儲存具有大量收件者或附件的郵件時,CopyTo 作業可能會因為MAPI_E_NOT_ENOUGH_MEMORY而失敗。 這是因為結構化記憶體和數據流的已知問題。 每次將新的附件或收件者新增至儲存在結構化記憶體中的訊息時,就會開啟新的根記憶體檔案。 在交易完成之前,不會關閉這些檔案。 由於操作系統會限制同時開啟的根記憶體檔案數目,因此沒有已知的因應措施。