Introduction to MAPI in Pocket PC 2002 C++ Applications, Part 2

 

Microsoft Corporation

June 2002

Summary: This article picks up where the first article on MAPI (messaging application programming interface) left off. Part 1 introduced you to initializing MAPI and sending mail using the MAPI functions and/or the CVOMAPI classes. This second article in the three-part MAPI series covers reading messages and using message stores other than the default (ActiveSync) message store. Part 3 covers attachments, advanced message properties, and notification sinks. (3 printed pages)

Applies to:
   Microsoft® Windows® Powered Pocket PC 2002
   Microsoft eMbedded Visual C++ version 3.0
   Pocket PC 2002 SDK
   VOMAPI classes from Virtual Office Systems Web site (a free download)

Gotchas

As mentioned in Part 1 of the MAPI series, there are many elements of MAPI that are not fully implemented on the Pocket PC 2002 MAPI, such as the address book and most query filters.

Languages supported

Any language supported by Microsoft® eMbedded Visual C++® 3.0. Screenshots in U.S. English.

Contents

MAPI Message Stores
Reading Folder Contents
Reading Message Contents
Conclusion
Further Reading

MAPI Message Stores

The default message store (Microsoft® ActiveSync®) is present by default, but additional message stores can be added by the user (through Inbox or another e-mail application) or from the installation of a MAPI Service Provider. Wherever additional message stores come from, they are all treated identically by MAPI from an application perspective. The steps below are encapsulated in the CVOMAPI::SetMessageStore() method. To choose a different message store:

  1. Get an interface pointer to the Message Stores table by calling the GetMsgStoresTable method of your IMAPISession interface. In the sample code this is done in the CVOMAPI::Logon() method.
  2. Use the SetColumns method of the Message Stores table, specifying at least PR_DISPLAY_NAME and PR_ENTRYID as column types.
  3. Query the rows in the Message Stores table using the IMAPITable::QueryRows() method.
  4. For each row returned, check the value of the PR_DISPLAY_NAME column against the name of the Message Store you want to use. When you find it, open it using the IMAPISession::OpenMsgStore() method, passing the message store's ENTRYID.

Reading Folder Contents

Each Message Store contains one or more folders. Some folders have unique identifiers defined to make finding the folders easier. In particular, the "Inbox" has the identifier PR_CE_IPM_INBOX_ENTRYID. The "Outbox" has the identifier PR_CE_IPM_DRAFTS_ENTRYID (defined in CEMAPI.H). Figure 1 shows the MAPI2 sample project's "Send Mail" dialog, and Figure 2 shows the MAPI2 sample project's "Unread Mail" dialog. Note that the body of the message is not read until the message is selected in the list box.


Figure 1. Send Mail dialog in sample project MAPI2


Figure 2. Read Unread Mail dialog in sample project MAPI2

To obtain the contents of a folder, you must first obtain an interface pointer to the folder itself using the LPMDB::OpenEntry() method. For detailed examples refer to the CVOMAPI::GetInBoxFolder() and CVOMAPI::GetOutBoxFolder() methods in the sample project. The basic steps are:

  1. Call the IMsgStore::GetProps() method of the Message Store object to retrieve the ENTRYID of the folder you want. The property tag passed to this method will identify which folder you want.
  2. Call the IMsgStore::OpenEntry() method of the Message Store object to retrieve an interface pointer to the folder.
  3. Call the IMAPIFolder::GetContentsTable() method to get an interface pointer to the table of contents for the folder.
  4. Prepare an SpropTagArray containing the properties of the messages you want to retrieve in your summary view. In general this will not contain the body or attachments for the messages, as those are too large usually to be desired in a summary view.
  5. Call the IMAPITable::SetColumns() method with the SpropTagArray defined above.
  6. Call the IMAPITable::QueryRows() method to retrieve the requested columns for each message in the folder. In this way you can retrieve the ENTRYID for each message, as shown in the sample project, in the CVOMAPI::GetNewMessages() method.

Reading Message Contents

Once you have the ENTRYID for a message, you can obtain the IMAPIMessage interface pointer to the message and work with it directly. This allows you to read and set the properties of the message, as well as send the message (as shown in the first article in this series). The sample project contains a class named CVOMAPIMessage, which encapsulates some of the basic attributes of a message so that you can see how the properties are obtained. Additional property tags are defined in CEMAPI.H and can be obtained in the same manner.

One property in particular merits special attention: The PR_BODY property needs to be read as a stream of data in blocks, instead of as a simple property such as PR_SUBJECT, for example. To obtain the body of the message:

  1. Call the IMAPIMessage::OpenProperty() method, passing IID_IStream as the desired interface type. This will get you an IStream interface pointer for the property.
  2. Repeatedly call the IStream::Read() method to read the entire property in chunks of data.
  3. Compile the chunks of data into a single property. The sample project shows how to do this in the CVOMAPIMessage::GetBody() method.

Conclusion

As you can tell, reading messages is a bit more complex than creating them, but still is not unmanageable once you know the structure of the MAPI objects and how to obtain the correct interface pointers. By using the MAPI interfaces your application can have full access to any message stores, the folders within them, and the messages within the folders.

Further Reading

To learn more, continue on to part three of this three-part series.