MAPI Multithreading Rules

I wrote these rules out while debugging a crash in another MS product:

  1. All threads which use MAPI must call MAPIInitialize before doing any MAPI.
  2. All threads which use MAPI must call MAPIUninitialize before ending.
  3. No thread should ever call MAPIUninitialize if it didn't already call MAPIInitialize.
  4. If MAPI_MULTITHREAD_NOTIFICATIONS is not used, the first thread to call MAPIInitialize should live longer than all other MAPI threads and should be the last to call MAPIUninitialize.

I won't name the app, but it violated all 4 rules.

Known consequences of violating these rules:

  1. MAPI just can't work on a thread that hasn't been initialized. All MAPI calls will fail.
  2. Memory leak.
  3. Either a crash or 'mysterious' errors. Thread A initializes MAPI and starts doing some work. Thread B then calls MAPIUninitialize. If no other thread has initialized MAPI, then MAPI assumes everyone is done with it and cleans up. Depending on the timing, thread A will either crash or start getting failures in MAPI calls.
  4. When MAPI_MULTITHREAD_NOTIFICATIONS is not used, MAPI assumes it can tie the notification thread to the thread on which MAPIInitialize was first called. When this thread goes away, a pointer kept by the notification thread is invalidated, leading to a crash the next time we process a notification.