MAPI Session Handling

Before you can access any of the MAPI objects or any part of the messaging subsystem, you first need to establish a MAPI session, which is a managed link between a client application and the rest of the MAPI components. After you have initialized and logged into MAPI, you are returned a pointer to an object that implements the IMAPISession interface, which can then be used to access messages, folders, and other objects in the MAPI message stores. You also need to use the IMAPISession interface to log out of MAPI when you have finished using it.

The IMAPISession interface implements the methods described in Table 11.13.

Table 11.13. IMapiSession Methods




Sets up an IMAPIAdviseSink interface that will receive notification events for the session.


Compares two ENTRYID structures to see if they are the same.


Returns an IMAPITable interface for the table. This interface lists the message stores that are installed on the device.


Ends a MAPI session.


Returns an interface for a specific MAPI object based on its ENTRYID.


Returns an IMsgStore interface for a specific message store.


Cancels a notification event sink that was set up with a previous call to IMAPISession::Advise().

To get the pointer to the IMAPISession interface, you cannot simply call into the CoCreateInstance() function to instantiate a new session object. Instead, you must properly initialize MAPI by first calling into the MAPIInitialize() function:

HRESULT MAPIInitialize(LPVOID lpMapiInit);

The lpMapiInit parameter is ignored on the Pocket PC.

After MAPI has been initialized, you need to log on to the messaging subsystem by calling into the MAPILogonEx() function. This will return to you a pointer to the MAPI session interface that you then use to access the rest of the MAPI objects:

HRESULT MAPILogonEx(ULONG ulUIParam, LPTSTR lpszProfileName,
  LPTSTR lpszPassword, FLAGS flFlags,

All of the parameters for MAPILogonEx() are unused, except for the lppSession parameter, which points to the IMAPISession interface pointer when the function returns.

The following code shows how you use MAPILogonEx() to get the pointer to an IMAPISession object:


// Initialize COM
if(FAILED(CoInitializeEx(NULL, 0)))
   return FALSE;

// Initialize and log on to MAPI
IMAPISession *pIMapi = NULL;

if(MAPIInitialize(NULL) != S_OK)
   return FALSE;

if(MAPILogonEx(0, NULL, NULL, 0, &pIMapi) != S_OK) {
   return FALSE;

// MAPI is ready, now do something with it...

When you are finished using MAPI, it is important to remember to properly close the MAPI session in order for the e-mail subsystem to clean up memory and free up any resources that it is using. Before you log off the current session, you should make sure that any MAPI objects that have been instantiated have already called into their IUnknown::Release() method. In addition, any memory allocations made with the MAPIAllocateBuffer() function should be freed by calling into MAPIFreeBuffer().

After you are sure that all of the MAPI objects have been properly cleaned up, you can use the IMAPISession::Logoff() function, which has the following prototype:

HRESULT IMAPISession::Logoff(ULONG ulUIParam, ULONG ulFlags,
   ULONG ulReserved);

On Pocket PC, all of the parameters should be set to 0.

Finally, to free any additional resources, use the MAPIUninitialize() function to end your MAPI session:

HRESULT MAPIUninitialize();

Cleaning up from a MAPI session is relatively straightforward:

// Cleanup
if(pIMapi) {
   pIMapi->Logoff(0, 0, 0);
   pIMapi = NULL;

return TRUE;

Accessing MAPI Objects

Now that you have successfully logged into a MAPI session, you can start working with the various objects in the messaging subsystem. Let's take a quick look at how you can get the interface pointer to a few of the MAPI objects that are described in the remainder of this chapter.

To get the MAPI table of the message stores that have been installed and are available on the device, you can use the following function:

HRESULT IMAPISession::GetMsgStoresTable(ULONG ulFlags,
   LPMAPITABLE *lppTable);

The first parameter, ulFlags, is unused and should be set to 0. The lppTable parameter will point to an IMAPITable interface that contains the list of available message stores.

If you already have the ENTRYID for a particular message store that you want to open, use the IMAPISession::OpenMsgStore() function:

  cbEntryID, LPENTRYID lpEntryID, LPCIID lpInterface, ULONG
   ulFlags, LPMDB *lppMDB);

The ulUIParam, lpInterface, and ulFlags parameters are ignored and should be set to 0. The ENTRYID of the message store that you want to open should be set by the lpEntryID parameter, and the cbEntryID parameter is used to set its size. Finally, the lppMDB parameter will point to the IMsgStore interface when the function returns. If you set the lpEntryID parameter to NULL, the default store (ActiveSync) will be opened.

Finally, to get the interface pointer for any MAPI object that has an ENTRYID, use the IMAPISession::OpenEntry() function:

  lpEntryID, LPCIID lpInterface, ULONG ulFlags, ULONG
  *lpulObjType, LPUNKNOWN *lppUnk);

The first parameter, cbEntryID, should specify the number of bytes of the ENTRYID. The lpEntryID parameter points to the actual ENTRYID that you want to open. The lpInterface parameter is used to point to an interface identifier for the interface that you are trying to open. If this is set to NULL, you will be returned the default interface for the object type (for example, opening a MAPI message object will return an IMessage interface pointer).

When the function returns, the lpUlObjType parameter will point to the object type that was opened. Because this is an optional parameter, it can also be set to NULL if you are not interested in the type information. The last parameter, lppUnk, gets the interface pointer for the ENTRYID that was specified in lpEntryID.

Remember that you need to call into the object's IUnknown::Release() method when you have completed using it.