• Sign in
 
  •  
  • MSDN Blogs
  • Microsoft Blog Images
  • More ...

  • Blog Home
  • About
  • Email Blog Author
  • Share this
  • RSS for posts
  • Atom
  • RSS for comments
  • CDO (25)
  • Code Snippet (43)
  • Custom Providers (17)
  • Debugging (7)
  • DevMsgTeam (301)
  • Documentation (109)
  • DST (8)
  • EWS (7)
  • Exchange (109)
  • Gotchas (97)
  • Hotfix (28)
  • MAPI (240)
  • MAPI Download (54)
  • MFCMAPI (101)
  • MSDN (59)
  • Non Dev (11)
  • OOM (17)
  • Outlook (171)
  • Outlook 2007 Auxiliary Reference (45)
  • Outlook Integration API (12)
  • Protocol Docs (20)
  • PST/OST (23)
  • Referrals (8)
  • Vista (12)
  • WrapPST (18)
Links:
  • Download MFCMAPI
  • MFCMAPI on Facebook
  • Troubleshooting Outlook Crashes
  • Office Update Center
  • Developer Messaging Team Blog
This site is provided "AS IS" with no warranties, and confers no rights. Use of included code samples are subject to the terms specified in the Terms of Use.
Archives
  • May 2013 (3)
  • April 2013 (1)
  • March 2013 (2)
  • February 2013 (2)
  • January 2013 (2)
  • December 2012 (4)
  • November 2012 (2)
  • October 2012 (2)
  • September 2012 (1)
  • August 2012 (3)
  • June 2012 (2)
  • May 2012 (1)
  • April 2012 (3)
  • March 2012 (3)
  • February 2012 (3)
  • January 2012 (1)
  • December 2011 (3)
  • November 2011 (1)
  • October 2011 (3)
  • September 2011 (1)
  • August 2011 (1)
  • July 2011 (4)
  • June 2011 (3)
  • May 2011 (3)
  • April 2011 (3)
  • March 2011 (5)
  • February 2011 (1)
  • January 2011 (2)
  • December 2010 (1)
  • November 2010 (4)
  • October 2010 (1)
  • September 2010 (3)
  • August 2010 (5)
  • July 2010 (3)
  • June 2010 (3)
  • May 2010 (1)
  • April 2010 (3)
  • March 2010 (3)
  • February 2010 (3)
  • January 2010 (2)
  • December 2009 (3)
  • November 2009 (5)
  • October 2009 (4)
  • September 2009 (5)
  • August 2009 (5)
  • July 2009 (11)
  • June 2009 (6)
  • May 2009 (5)
  • April 2009 (3)
  • March 2009 (18)
  • February 2009 (10)
  • January 2009 (3)
  • December 2008 (2)
  • November 2008 (2)
  • October 2008 (5)
  • September 2008 (4)
  • August 2008 (10)
  • July 2008 (6)
  • June 2008 (8)
  • May 2008 (2)
  • April 2008 (4)
  • March 2008 (2)
  • February 2008 (2)
  • January 2008 (5)
  • December 2007 (3)
  • November 2007 (2)
  • October 2007 (3)
  • September 2007 (1)
  • August 2007 (4)
  • July 2007 (5)
  • June 2007 (3)
  • May 2007 (4)
  • April 2007 (1)
  • March 2007 (6)
  • February 2007 (3)
  • January 2007 (2)
  • December 2006 (4)
  • November 2006 (3)
  • October 2006 (1)
  • August 2006 (1)
  • June 2006 (5)
  • May 2006 (5)
  • December 2005 (1)
  • November 2005 (4)
  • October 2005 (2)
  • September 2005 (1)
  • April 2005 (3)
  • December 2004 (2)
  • September 2004 (2)
  • August 2004 (3)
  • July 2004 (3)

MAPI Multithreading Rules

MSDN Blogs > SGriffin's MAPI Internals > MAPI Multithreading Rules

MAPI Multithreading Rules

Stephen Griffin - MSFT
24 Sep 2004 2:53 PM
  • Comments 34

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.
  • 34 Comments
Exchange, Outlook, MAPI, Gotchas, DevMsgTeam
Comments
  • Konstantin Root (kroot@fusionone.com)
    1 Oct 2004 5:48 AM
    Will there be any potential problems, if i call MAPIInitialize with MAPI_NO_COINIT flag and initialize thread myself with COINIT_MULTITHREADED?
  • Stephen Griffin
    1 Oct 2004 9:24 AM
    As long as you're handling the CoUninitialize on the other end, no, that should not be a problem.
  • Pete Maclean (pete@maclean.com)
    18 Aug 2005 5:53 PM
    I would add a fifth rule:

    5. The application must run a message loop on a thread that calls MAPIInitialize and MAPIUninitialize. And it is probably wise to make this thread the one that is the first to call MAPIInitialize and last to call MAPIUninitialize.

    I learned of this need the hard way after experiencing a hang in IProfAdmin::DeleteProfile and solving it by having my main thread which runs the message loop call MAPIInitialize.
  • Pete Maclean (pete@maclean.com)
    20 Aug 2005 2:02 PM
    I must amend my fifth rule already -- I overlooked something that now seems rather obvious.

    I wrote, "it is probably wise to make this thread [with the message loop] the one that is the first to call MAPIInitialize and last to call MAPIUninitialize." Actually this is not simply wise but essential.

    The documentation for MAPIInitialize states that, as step 6, the function "Initializes the notification engine, creates its window and..." Experimentation shows that this window is actually created only on the first call to MAPIInitialize from a given process -- which makes some sense. So this window belongs to the thread that makes that first call, and that's the thread that is going to receive its messages and must therefore run a message loop to process them.
  • Hai
    4 Apr 2006 1:29 PM
    I have a couple of more questions :-)

    1. What happens when a first thread calls MAPIInitialize without MAPI_MULTITHREAD_NOTIFICATIONS and a second thread calls MAPIInitialize with MAPI_MULTITHREAD_NOTIFICATIONS? And the other way around? It that the first call made to MAPIInitialize will always win?

    2. If 1 is true, then all subsequent calls made to MAPIInitialize is only for the purpose of AddRef to MAPI subsystem, right? If this is the case, then as long as the first thread lives longer than every other threads, there should be no need to call MAPIInitialize on other threads. Unless MAPI is doing some extra work for each single thread?

    Thanks!
  • Stephen Griffin - MSFT
    4 Apr 2006 1:43 PM
    No - ALL threads that use MAPI must be initialized. MAPI does do per thread work. See consequence 1. As to the first question, I think the first caller will win, but I'm not certain.
  • Hai
    6 Apr 2006 10:31 AM
    Stephen, thanks for the response. However, after applying this rules to my worker threads, I am stuck with some other kinds of problems. Hope that you could clarify some points :)

    In short this is what I am doing: I am writing a service provider, with AddressBook, Transport and MessageStore providers. Worker threads are created at run time to talk to servers. Before I read this blog, there is no MAPIInitialize and MAPIUninitialize pairs in the worker threads, and everything works fine (at least looks like). The consequence 1 above seems not applicable here.

    Then after reading this blog and related MAPI docs in MSDN, I thought "Oops, I am doing something abnormal, maybe it's better to stick to the rules". Thus I added MAPIInitialize and MAPIUninitialize pairs in my worker threads. Everything continues to work fine, UNLESS if one worker thread does not end when the client shutdown. Sometimes when the worker thread stuck in talking to server, its MAPIUninitialize does not get a chance to be called. It looks like because of the missing MAPIUninitialize the MAPI subsystem refuses to shutdown our service providers. For instance, the IABProvider::Shutdown() is not called by MAPI.

    I am wondering, is the service provider supposed to be called in its Shutdown() from MAPI to be notified to call MAPIUninitialize()? Or, is there some other way that the service provider can be told to call MAPIUninitialize() when the client initiates the shutdown process?

    Any information will be appreciated. Thanks!
  • Stephen Griffin - MSFT
    6 Apr 2006 5:29 PM
    Hai - I'm not sure what the point of confusion is. You started conforming to rule 1, but you note that you have problems when you don't conform to rule 2. Here's my suggestion - if you've got operations that may get stuck making calls out to servers, do those on threads that have nothing to do with MAPI. Then you'll be free to do whatever you want with those threads without affecting MAPI's stability.
  • Tusi
    24 Jul 2006 9:20 AM
    What is the situation, if i have a Windows Service and before the message loop i call MAPIInitialize (MULTITHREAD NOTIFICATIONS, NO_COINIT, NT_SERVICE) and after the message loop i call MAPIUninitialize. E.g. the MAPI subsystem will be kept alive as far as my service is alive. Will it be a problem? Since all the threads using the service are working fine with MAPI - until some strange errors appear after a very long run (4-5 days).
  • Stephen Griffin - MSFT
    24 Jul 2006 9:25 AM
    MAPIUnitialize requires the message pump as part of shutting down MAPI.
  • Kevin
    10 Oct 2006 2:55 PM
    Stephen, comments made here are making me confused. Can you clarify where I'm misunderstanding things? Here's my understanding: 1. The first thread to call MAPIInitialize requires a message pump because it creates the hidden notification window. 2. All other threads that subsequently call MAPIInitialize do not require a message pump. 3. All threads also call a corresponding MAPIUninitialize 4. The first thread eventually should call MAPIUnitialize. Because it owns the message pump, it is able to correctly shut down MAPI. Is this right?
  • Stephen Griffin - MSFT
    10 Oct 2006 3:20 PM

    Kevin,

    Mostly right - you'll also want to make sure that first thread is the last one to call MAPIUninitialize.

    Steve

  • Kevin
    10 Oct 2006 3:33 PM
    Stephen, Thanks for the response, that helps a lot. I think it's safe to assume that if we're an Outlook plugin, then Outlook owns the initial MAPIInitialize and last MAPIUninitialize call, right? I might still be out on a limb, but I'm figuring that while it's great to be aware of this behavior, most Outlook plugins that properly init/uninit probably don't have to worry about message pumps... -Kevin
  • Stephen Griffin - MSFT
    10 Oct 2006 3:45 PM

    In that case - yeah - Outlook's thread 0 would be handling the initial init/uninit as well as the message pump.

  • Kevin
    10 Oct 2006 5:01 PM
    Cool, you're awesome, Stephen, and great blog.
Page 1 of 3 (34 items) 123
Leave a Comment
  • Please add 7 and 8 and type the answer here:
  • Post
  • © 2013 Microsoft Corporation.
  • Terms of Use
  • Trademarks
  • Privacy & Cookies
  • Report Abuse
  • 5.6.426.415