The Fifth MAPI Multithreading Rule


We had an issue recently where DDE broadcasts were being blocked on a system. The customer noticed that the problem happened after they called MAPIInitialize on their worker thread. Our investigation gives us a chance to add a 5th rule to the MAPI Multithreading Rules I wrote about a few years ago:

5. The first thread to initialize MAPI must pump messages.

To understand this, first we need to know a bit about DDE. Turns out, Raymond wrote about it a couple times already, so I don’t need to rehash that. The second thing to know is that MAPI uses a hidden window for idle processing. If you dig around a bit, you might even find the window, named “WMS Idle”. MAPI only needs one of these per process, so it’s created on the first thread to initialize MAPI. And as we know, any thread with a window on it must pump messages.

In the customer’s case, they were pumping on the main thread, but not on the MAPI worker thread. Once they inserted message pumping into the MAPI worker thread, DDE was no longer blocked. Alternatively, they could have called HrDispatchNotifications, which is a simple way to pump messages, or called MAPIInitialize on the main thread.

Comments (2)

  1. Dmitry P says:

    Hello,

    First of all I want to thank you about having that blog which already helped me a lot.

    Recently I’ve faced with a problem and need some advise on using MAPI.

    I have a COM object which initializes MAPI and subscribes to the fnevNewMail notification event of a store. There is a thread pool, and all worker threads ofc initialize MAPI as well, and performs copying messages from one mailbox to another. Thus I get message ID from the event and pass it to worker thread to copy it. It works fine, but then I start spamming mailbox with messages every second. After 4 hours working thread crashes with 0xC0000005 code which is access violation.

    After logging every operation to a file I found that all pointers are correct and this reproduces only when a lot of messages arrive and significant amount of time has passed.

    COM works fairy simple and I’m using smart pointers to avoid memory leaks. It opens session, opens storage, subscribes to events and then passes IMAPISession pointer to the working thread, where on every new message message store and folders are opened and message is being copied.

    My question here: is it safe to keep session opened very long time, or should I log on every time when message arrives in a worker thread. I’m trying to make a small app to reproduce it, but I will appreciate if you can give me a direction where I start looking at.

    Thank you.

  2. Stephen Griffin says:

    Nothing in your description sounds inherently wrong. I suggest opening a case so we can analyze a crash dump of the problem. In fact, prior to opening a case, you should take a look at the stack of the crash and make sure you’re not the one causing the AV.