Discussing the nuts and bolts of software development

Thursday, July 24, 2008

 

Outlook Entry IDs Made Easy

When developing for Outlook you will quickly realize that there's more than one way of doing things. For example, take a look at the number of APIs for interacting with Outlook:That doesn't even include the six libraries included in the Outlook 2003 Integration API or the excellent 3rd-party Redemption library. I'm positive there are others. Usually you won't use all these APIs in the same project. However, if you want to do anything significant in Outlook, you'll need to use the OOM and MAPI libraries.

It's important to understand the relationship between MAPI and the OOM:When you work with these APIs, you'll hit on the problem of linking them together. Outlook Entry IDs are a good example. Entry IDs uniquely identify most objects in the OOM and MAPI. Being very flexible, Entry IDs can take many shape or form and can cause headaches when you try to handle them.

At its simplest, an Entry ID is a variable length byte buffer, sometimes represented with a simple byte array. In MAPI, most Entry IDs are represented by the ENTRYID structure:

mapidefs.h

typedef struct { 
BYTE abFlags[4];
BYTE ab[MAPI_DIM];
} ENTRYID, FAR *LPENTRYID;
This structure usually comes wrapped in the SBinary structure.

mapidefs.h

typedef struct _SBinary { 
ULONG cb;
LPBYTE lpb;
} SBinary, FAR *LPSBinary;
In the Outlook Object Model things take a turn for the worst:Is your head spinning? Mine was.

I solved the problem by creating a class (yet another format!) to facilitate manipulation of all these formats:
class EntryId
{
public:
EntryId(EntryId const& entryId);

// All explicit so that it's always clear what we are doing.
explicit EntryId(BSTR const* str, bool hexEncoded = true);
explicit EntryId(SBinary const* binary);
explicit EntryId(SAFEARRAY const* array);
explicit EntryId(unsigned long count, unsigned char const* bytes);

// Again, no implicit conversion
CComBSTR toString(bool hexEncoded = true) const;
CComSafeArray toSafeArray() const;
std::vector toByteArray() const;
// ... add more as you need them

// TODO: Add more custom helper functions.
bool isLongTermId() const;

// TODO: Add comparison operators for convenience and ordered
// container support (such as std::map keys). When comparing
// Entry Ids, remember you need to use the
// IMAPISupport::CompareEntryIDs method.

private:
std::vector<unsigned char> m_buffer;
}
Now whenever I get an Entry ID in any format, the first thing I do is convert it to an EntryId instance. This adds many convenient functionalities:

Labels: , ,


Comments: Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?