I wrote these rules out while debugging a crash in another MS product:
- All threads which use MAPI must call MAPIInitialize before doing any MAPI.
- All threads which use MAPI must call MAPIUninitialize before ending.
- No thread should ever call MAPIUninitialize if it didn’t already call MAPIInitialize.
- 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:
- MAPI just can’t work on a thread that hasn’t been initialized. All MAPI calls will fail.
- Memory leak.
- 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.
- 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.