Are you a world traveler? ZoneTick is a cool utility that'll help you stay in touch over multiple time zones!
 
Accessing Message Attachments  
Nik Okuntseff  MS Exchange Server Programming 

Accessing Message Attachments

How can we access message attachments? Let's suppose we need to save a message attachment as a file. This is how it may be accomplished:

#include <afxwin.h>
#include <edk.h>

int main()
{
    /*
     * Algorithm:
     *  1. Open the message.
     *  2. Open its attachment.
     *  3. Create a file and store PR_ATTACH_DATA_BIN in it.
     */

    // Change if necessary
    char * pszFolder = "@PR_IPM_SUBTREE_ENTRYID\\Drafts";
    char * pszMsgSubject = "Message with Attachment";
 
    HRESULT hr;
    LPMAPISESSION pSession = NULL;

    // Initialize MAPI
    hr = MAPIInitialize(NULL);
    if (FAILED(hr)) throw -1;

    // Obtain MAPI session
    hr = MAPILogonEx(0,    // Handle to parent window
      "MS Exchange Settings", // Profile name
      NULL,   // Password
      MAPI_NEW_SESSION |
      MAPI_EXTENDED |
      MAPI_LOGON_UI, // Logon flags
      &pSession);  // Resulting MAPI session
    if (FAILED(hr)) throw -1;

    // Find default message store
    ULONG cbDefStoreEid = 0;
    LPENTRYID pDefStoreEid = NULL;
    hr = HrMAPIFindDefaultMsgStore(pSession, &cbDefStoreEid, &pDefStoreEid);
    if (FAILED(hr)) throw -1;

    // Open default message store
    LPMDB pDefMsgStore = NULL;
    hr = pSession->OpenMsgStore(0, cbDefStoreEid, pDefStoreEid, NULL,
        MDB_WRITE | MAPI_DEFERRED_ERRORS, &pDefMsgStore);
    if (FAILED(hr)) throw -1;

    // Open the desired folder
    LPMAPIFOLDER pFolder = NULL;
    hr = HrMAPIOpenFolderEx(pDefMsgStore,
       '\\',
       pszFolder,
       &pFolder);
    if (FAILED(hr)) throw -1;

    // Get contents table.
    LPMAPITABLE pContentsTable = NULL;
    hr = pFolder->GetContentsTable(0, &pContentsTable);
    if (FAILED(hr)) throw -1;

    // Get row count
    ULONG ulRows = 0;
    hr = pContentsTable->GetRowCount(0, &ulRows);
    if (FAILED(hr)) throw -1;
    assert(ulRows > 0);

    // Get all rows
    SRowSet * pRowSet = NULL;
    hr = pContentsTable->QueryRows(ulRows, 0, &pRowSet);
    assert(ulRows == pRowSet->cRows);

    // Scan all rows until we have our source message
    SRow row;
    LPUNKNOWN pMsg = NULL;
    ULONG ulObjType = 0;
 
    for (ULONG ul = 0; ul < ulRows; ul++)
    {
        row = pRowSet->aRow[ul];

        for (ULONG ulIndex = 0; ulIndex < row.cValues; ulIndex++)
        {
            if (PR_SUBJECT == row.lpProps[ulIndex].ulPropTag)
            {
                char * pszCurSubject = row.lpProps[ulIndex].Value.lpszA;
                int iRes = memcmp(pszMsgSubject, pszCurSubject, strlen(pszMsgSubject));
                if (0 == iRes)
                {
                    // We have found our message!
 
                    // Get PR_ENTRYID
                    SBinary bin;
                    ZeroMemory(&bin, sizeof(bin));
                    for (ULONG ulNewIndex = 0; ulNewIndex < row.cValues; ulNewIndex++)
                    {
                        if (PR_ENTRYID == row.lpProps[ulNewIndex].ulPropTag)
                        {
                            bin = row.lpProps[ulNewIndex].Value.bin;
                            break;
                        }
                    }
                    assert(bin.cb);
 
                    // Open the message
                    hr = pDefMsgStore->OpenEntry(bin.cb,
                        (LPENTRYID) bin.lpb,
                        NULL,
                        MAPI_BEST_ACCESS,
                        &ulObjType,
                        &pMsg);
                    if (FAILED(hr)) throw -1;
                }
            }
        }
    }
    // At this point we have the message open...

    // Open its attachment
    LPMAPITABLE pAttachTbl = NULL;
    hr = ((LPMESSAGE) pMsg)->GetAttachmentTable(0, &pAttachTbl);
    if (FAILED(hr)) throw -1;

    // Get row count
    hr = pAttachTbl->GetRowCount(0, &ulRows);
    if (FAILED(hr)) throw -1;
    assert(1 == ulRows);

    // Get all rows
    if (pRowSet)
        MAPIFreeBuffer(pRowSet);
    pRowSet = NULL;
    hr = pAttachTbl->QueryRows(ulRows, 0, &pRowSet);
    assert(ulRows == pRowSet->cRows);

    // Get PR_ATTACH_NUM
    row = pRowSet->aRow[0];
    LPATTACH pAttach = NULL;
    ULONG ulAttachNum = 0;
    for (ULONG ulIndex = 0; ulIndex < row.cValues; ulIndex++)
    {
        if (PR_ATTACH_NUM == row.lpProps[ulIndex].ulPropTag)
        {
            // Open the attachment.
            ulAttachNum = row.lpProps[ulIndex].Value.l;
            hr = ((LPMESSAGE) pMsg)->OpenAttach(ulAttachNum,
                 NULL,
                 MAPI_BEST_ACCESS,
                 &pAttach);
            if (FAILED(hr)) throw -1;
            break;
        }
    }
    // At this point we should have the attachment open

    // Get PR_ATTACH_DATA_BIN property
    SPropTagArray tagArray;
    tagArray.cValues = 1;
    tagArray.aulPropTag[0] = PR_ATTACH_DATA_BIN;

    ULONG ulValues = 0;
    LPSPropValue pAttachDataBin = NULL;
    hr = pAttach->GetProps(&tagArray,
       0,
       &ulValues,
       &pAttachDataBin);
    if (FAILED(hr)) throw -1;
    assert(pAttachDataBin);

    // Create a file to write data to
    HANDLE hFile = CreateFile("C:\\AttachData.txt",
        GENERIC_WRITE,
        0,
        NULL,
        OPEN_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
    assert(hFile != INVALID_HANDLE_VALUE);

    // Save data
    DWORD dwBytesWritten = 0;
    BOOL b = WriteFile(hFile, // Handle to the file
      pAttachDataBin->Value.bin.lpb, // Pointer to data to write to file
      pAttachDataBin->Value.bin.cb, // Number of bytes to write
      &dwBytesWritten,    // Number of bytes written
      NULL);       // Pointer to OVERLAPPED structure
    assert(b && (dwBytesWritten == pAttachDataBin->Value.bin.cb));
 
    // Cleanup
    if (hFile)
        CloseHandle(hFile);
    if (pAttachDataBin)
        MAPIFreeBuffer(pAttachDataBin);
    if (pAttach)
        pAttach->Release();
    if (pAttachTbl)
        pAttachTbl->Release();
    if (pMsg)
        pMsg->Release();
    if (pRowSet)
        MAPIFreeBuffer(pRowSet);
    if (pContentsTable)
        pContentsTable->Release();
    if (pFolder)
        pFolder->Release();
    if (pDefMsgStore)
        pDefMsgStore->Release();
    if (pDefStoreEid)
        MAPIFreeBuffer(pDefStoreEid);
    if (pSession)
        pSession->Release();
    ::MAPIUninitialize();
    return 0;
}

The algorithm is straightforward. I assume that the message resides in the Drafts folder, has "Message with Attachment" subject, and in fact contains 1 attachment.
 

[ Contents | Home ]

Send comments and suggestions to niko@wrconsulting.com
Copyright © 1997-1998 by Nik Okuntseff