Creating a New Interprocess (IPC) Message Class

Structured messages can be sent and read between programs, or between programs and users. By using MAPI properties to structure message content, you avoid writing code to parse message text or a binary attachment.

Design Tasks

  1. Decide whether yours is an interpersonal messaging (IPM) application or a type of interprocess communication (IPC) application. There is an enormous variety of applications; following is a basic list of types and examples. For more information about IPM applications, see Creating a New Interpersonal (IPM) Message Class.

    Logically, person-to-person applications, machine-to-person applications, and applications that post to public forums should be designated IPM, while person-to-machine and machine-to-machine applications are IPC message classes. The only real difference is that IPM messages in a message store are visible to messaging clients, while IPC messages usually are not. Anything that requires a person to respond must use an IPM message class. Applications involving a more complex pattern including people and machines often involve a mix of IPM and IPC messages.

  2. Decide whether to use Simple MAPI, CMC, MAPI, or the Active Messaging Library. See Selecting a Client Interface.
  3. Decide whether your application can use the same profile as the messaging client or whether you must create one. See Creating and Configuring a Profile.
  4. Choose the message class name, beginning it with IPM. or IPC. according to the guidelines established previously.
  5. Define properties specific to the message class. Decide whether to use named properties or properties from the 0x6800-0x7fff range. See About Property Identifiers and Named Properties. Properties that contain e-mail addresses should be stored in a special way to provide for translation when changing messaging domains. See Sending Across Messaging Domains.

    One difference between IPM and IPC applications is that machines are much less tolerant of variations in message format than people are. Compatibility with messaging clients that can view only message text is often required for IPM applications, but IPC applications typically use MAPI properties to structure information in their messages and require MAPI everywhere. Nevertheless, for machine-to-person applications it may be necessary to duplicate some or all of the properties in the message text for compatibility with messaging clients that can view only message text.

  6. Define the commands — called "verbs" in MAPI — specific to your message class, and choose which standard verbs to implement.
  7. Decide how to handle sent messages and reports. It is usually not appropriate for IPC applications to save outbound messages in the IPM Sent Items folder, but the application may need to save outbound messages in a hidden folder for tracking purposes. See Hidden Folders.

Implementation Tasks

  1. Load the selected interface DLL and the entry points you will need. See one of the following topics, depending upon which interface you have selected.
  2. Log on to MAPI. IPM message classes should use the messaging client's session if available. IPC applications may need to use a specific profile they've created themselves.
  3. For MAPI only, access the default message store. See Opening a Folder.
  4. Create folders and receive folder mappings for your message class. For an IPC application the folders should be children of the message store's root folder, not of the IPM subtree. Include receive folder mappings for reports associated with your message class, if necessary. These steps can only be done using MAPI; if you have chosen a different interface, you can still write this code using MAPI and put it in your installation program.
    1. Open the root folder by calling the IMsgStore::OpenEntry method with a null entry identifier.
    2. Call the IMAPIFolder::CreateFolder method to create the folder.
    3. Call the IMsgStore::SetReceiveFolder method to establish a receive folder mapping for your message class. Several message classes can use the same receive folder; when processing incoming messages, you can restrict the folder's contents table on the PR_MESSAGE_CLASS property to isolate the messages you're interested in.
    4. Locate your folder. The most efficient way to find your folder once you've created it is a receive folder mapping. Even if you don't intend for the folder to receive messages, you can map it to a string that is not used as a message class. Named properties on the store object — the most obvious alternative — are not always supported by message store providers, and MAPI does not define a range of message store properties for application use.
  5. Open the send and receive folders for your message class.
    1. Call the IMsgStore::GetReceiveFolder method.
    2. Pass the entry identifier returned to the IMsgStore::OpenEntry method.

      To open the Outbox (send folder) for IPM only:

    3. Call the message store's IMAPIProp::GetProps method to retrieve the PR_IPM_OUTBOX_ENTRYID property.
    4. Pass the entry identifier to the IMsgStore::OpenEntry method.
  6. Send outgoing messages.

    Remember to handle the disposition of submitted messages. IPM message classes should honor common IPM client options for disposition of sent messages and the message store's PR_IPM_SENTMAIL_ENTRYID property.

  7. Handle incoming messages.
    1. Open the contents table on the receive folder, using the IMAPIContainer::GetContentsTable method.
    2. Register for notification of new mail, using the IMsgStore::Advise method, the fnevNewMail event, and a null entry identifier. Do this before retrieving any messages to avoid a race condition that would result in missing messages.
    3. Create a property restriction to match PR_MESSAGE_CLASS with your message class and apply it to the contents table by calling IMAPITable::Restrict. Consider also limiting your contents table view to unread messages by creating a bitmask restriction with the MSGFLAG_UNREAD flag as the mask for the PR_MESSAGE_FLAGS property. See About Restrictions.
    4. Retrieve all the messages from the table, using the HrQueryAllRows function or the IMAPITable::QueryRows method, and process them.
    5. Rely on new mail notifications to advise you of further incoming messages. Your notification handler should check the lpszMessageClass member of the NEWMAIL_NOTIFICATION structure and ignore any messages that are not of your class.
  8. For each user of your application, make the .EXE file and any auxiliary files available.

About Sample Source Code

See the following topic:

Sample Timecard Application