Platform SDK: Exchange Server

Implementing Thread-Safe Objects

With objects that are returned from interface method calls directly, it is the service provider's responsibility to ensure thread-safety. With callback objects, it is the client's responsibility. A service provider implements a thread-safe object by serializing access to shared data within the object, ensuring that one thread does not inadvertently replace the work of another thread. A service provider can implement serialized access to data in three ways:

A client can implement a thread-safe notification callback by calling the MAPI HrThisThreadAdviseSink utility, which transforms a non-thread-safe advise sink into a thread-safe one. (There is no such utility at this time for progress callbacks.) A client can choose to use the MAPI thread-safe progress object or create one manually.

A thread-safe object may or may not be thread-aware. A thread-aware object maintains a separate context for every thread that is using it. Service providers are not required to support thread-awareness in their thread-safe objects, although supporting thread-awareness is useful in some situations. Two MAPI tables always provide their own context by definition. A single table used on more than one thread does not and should not provide a unique context.

A client can choose between receiving notifications on the same thread that was used for the MAPIInitialize call, on the same thread that was used for the Advise call, or on a separate thread owned by MAPI. To ensure that notifications arrive on the same thread used to call MAPIInitialize, a client calls MAPIInitialize and passes zero in the ulFlags member of the MAPIINIT_0 structure. Notifications are then delivered during the main message loop.

To receive notifications on the MAPI-owned thread, a client calls MAPIInitialize with the ulFlags member of the MAPIINIT_0 structure set to MAPI_MULTITHREAD_NOTIFY. The Advise call is made with the client's advise sink object rather than a wrapped version.

To ensure that notifications arrive on the same thread that was used to call Advise, a client calls HrThisThreadAdviseSink and passes the newly created wrapped advise sink to Advise rather than the original advise sink. MAPIInitialize can be called with either flag value.