In my previous article, I described how to read the SMS, MMS, and Emails data from your Windows Mobile device. Now I’m going to tell you how to read the attachments from the emails. I’ll also explain where you can find the attachments to MMS messages.

 

Content

  • Description of IAttach Properties
  • Working with e-mail attachments
  • MMS attachments – short explanation
  • Conclusion
  • Useful links

 

Description of IAttach Properties

Message attachments are one or several additional "blobs" of data, such as a picture, document or sound file attached to the email by a sender. Each individual attachment to a message is supported by the IAttach interface.

Although the IAttach interface has no unique methods, it is derived from the IMAPIProp interface. Below, I describe the properties that are used to configure an attachment.

  • PR_ATTACH_DATA_BIN – it’s the IStream interface, which is used to access the attachment. Property type is PT_BINARY.
  • PR_ATTACH_FILENAME – it’s the display name for the attachment. The type for this property is PT_TSTRING.
  • PR_ATTACH_METHOD – this property must be set to PR_ATTACH_BY_VALUE, it has PT_LONG type.
  • PR_ATTACH_NUM – It’s the number that uniquely identifies the attachment within the message. The type for this property is PT_LONG.
  • PR_ATTACH_SIZE – it’s the size, in bytes, of the attachment and all of the attachment properties. The type for this property is PT_LONG.
  • PR_ENTRYID – it’s the object's entry identifier. The type for property is PT_BINARY.
  • PR_LAST_MODIFICATION_TIME – it’s the last date and time when the object was modified. The type for property is PT_SYSTIME.
  • PR_NULL – it’s a NULL value. The type for property is PT_NULL.
  • PR_OBJECT_TYPE – it’s the type of object. The type for property is PT_LONG.
  • PR_PARENT_ENTRYID – it’s the parent object's entry identifier. The type for property is PT_BINARY.

Working with e-mail attachments

We have already discussed how to open message, so I omit this part.

We have an already opened message. So, let's go ahead and get the  attachments by first getting the attachment table for the message.

HRESULT hr = S_OK;
//check
if(pMsg ==  NULL)
{
    return E_FAIL;
}
IMAPITable *attachmentTable = NULL;
hr = pMsg->GetAttachmentTable(0, &attachmentTable);
if(FAILED(hr)) 
{ 
    return hr;
}

In this example, we query the table for the PR_ATTACH_NUM for the attachment we are interested in.

Then we need to get the properties from the table for the Attachments. For example, we’ll read just three: PR_ATTACH_NUM, PR_ATTACH_SIZE, PR_ATTACH_FILENAME.

SRowSet *pAttachmentRowSet = NULL;
SizedSPropTagArray(3, tableAttachmentColumns) =
{3,{PR_ATTACH_NUM,PR_ATTACH_SIZE,PR_ATTACH_FILENAME}};
attachmentTable->SetColumns((LPSPropTagArray)&tableAttachmentColumns, 0);

Then, in the cycle, we can ask all attachments of the email.

…
hr = attachmentTable->QueryRows(1, 0, &pAttachmentRowSet);
if(pAttachmentRowSet->cRows != 1)
    return E_FAIL;
// Grab the properties from the table entry that you will use to open the attachment stream.
long attachmentNumber = 0;
DWORD attachmentSize = 0;
TCHAR attachmentName[MAX_PATH] = TEXT("\0");
attachmentNumber = pAttachmentRowSet->aRow[0].lpProps[0].Value.l;
attachmentSize = pAttachmentRowSet->aRow[0].lpProps[1].Value.ul;
_tcscpy(attachmentName, pAttachmentRowSet->aRow[0].lpProps[2].
    Value.lpszW);
FreeProws(pAttachmentRowSet);

Using the IMessage::OpenAttach() method with the attachment number, which we found in the query, we can get the IAttach interface pointer.

IAttach *pAttach = NULL;
hr = pMsg->OpenAttach(attachmentNumber, 0, 0, &pAttach);
if(FAILED(hr)) 
{ 
    return hr;
} 

After getting an attach interface, we can get the IStream pointer for the PR_ATTACH_DATA_BIN property.

LPSTREAM AttachmentStream = NULL;
TCHAR filePath[MAX_PATH] = TEXT("\0");
wsprintf(filePath, TEXT("\\%s"), attachmentName);
hr = pAttach->OpenProperty(PR_ATTACH_DATA_BIN, NULL, 0, 0,
    (IUnknown **)&AttachmentStream);

When we have the stream pointer, we can copy it to the file or vector of bytes.

STATSTG stg;
HRESULT hr = pstmBody->Stat(&stg,STATFLAG_NONAME);
if (FAILED(hr))
{
    return hr;
}
unsigned int bodysize = stg.cbSize.LowPart;
if(bodysize == 0)
{
    return hr;
}
unsigned char* bodybuf = new unsigned char[bodysize];
ZeroMemory(bodybuf, bodysize);
ULONG read;
hr = pstmBody->Read(bodybuf, bodysize, &read);
if (FAILED(hr) || bodysize != read)
{
    delete bodybuf; 
    return hr;
}
outBuffer.assign(bodybuf, bodybuf + bodysize);
delete [] bodybuf;

And don’t forget to clean up all resources.

AttachmentStream->Release();
pAttach->Release();
…
attachmentTable->Release()

MMS attachments – short explanation

We cannot read mms attachments in the same way we read the email ones.

The MMS storage will send us an error when we ask for the properties from the attachment table.

IMAPITable *attachmentTable = NULL;
…
hr = attachmentTable->QueryRows(1, 0, &pAttachmentRowSet);
if(FAILED(hr)) 
{ 
    return hr;
}
…

We can find MMS attachments in the raw body of the message. My previous article can tell you about how to read the message body.

…
HRESULT hr = pMsg->OpenProperty (PR_BODY, NULL, STGM_READ, 0, (IUnknown **) &pstmBody);
…

The format of MMS message is SMIL (Synchronized Multimedia Integration Language). We can find the attachments looking through the raw message body.

Parsing of the SMIL body of an MMS massage is beyond the scope of this article.

Conclusion

I hope this article helped you to get to know about:

  • Work with the e-mail attachments
  • The differences between Email and MMS attachments

In this article, I didn’t show how to get the MMS attachments and how to parse SMIL format.

Useful links

SMIL format and MMS:

Download Sample Source (ZIP, 12 KB)

 

Read another Dev Blog article: How to USB debug Windows.

Subscribe to updates