INFO: メッセージを MSG 複合ファイルに保存する

概要

この記事には、メッセージを複合ドキュメントに保存する方法、具体的には、.msg ファイル形式をサポートするすべてのクライアントが読み取り可能な.msg ファイルを示すコードが含まれています。

詳細

次の関数は、有効なメッセージ オブジェクトを in パラメーターとして受け取り、そのプロパティを使用してメッセージの複製を作成し、.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で失敗する可能性があります。 これは、構造化されたストレージとストリームに関する既知の問題が原因です。 構造化ストレージに保存されているメッセージに新しい添付ファイルまたは受信者が追加されるたびに、新しいルート ストレージ ファイルが開きます。 これらのファイルは、トランザクションが完了するまで閉じません。 オペレーティング システムでは、同時に開いているルート ストレージ ファイルの数に制限があるため、既知の回避策はありません。