none
When to call MAPIUninitialize after an asynchronous IMAPIForm::DoVerb? RRS feed

  • Question

  • Hi,

    I'm using Extended MAPI to send an email via outlook from my application.

    Now I use IMAPIFormMgr::LoadForm and IMAPIForm::DoVerb to show the composing UI and send the mail.

    When the work is done, I want to call MAPIUninitialize to uninitialize.


    But after IMAPIForm::DoVerb returned, there is still some work going on asynchronously and I don't know when it will end.

    If I call MAPIUninitialize right after IMAPIForm::DoVerb, there will be an IMAPISession object leaked.

    If I Sleep for about five seconds and then call MAPIUninitialize, the IMAPISession object's ref count will be zero and the object is released successfully.


    I've tried IMAPIViewAdviseSink::OnShutdown and IMAPIViewAdviseSink::OnSubmitted, but all failed.

    I've looked at OOM, it looks like using OOM will be difficult to bypass the Outlook security issue.

    RDO sounds fine but it is too big for my application.

    So now the only option is Extended MAPI.

    Any suggestion will be appreciated.

    Friday, July 4, 2014 9:57 AM

Answers

  • Doing this on a separate thread is nothing but asking for trouble... The MAPI form is implemented by outlook.exe, and all calls are marshaled to the main Outlook thread anyway, just like all OOM calls.

    There is no advantage doing this on a separate thread.


    Dmitry Streblechenko (MVP)
    http://www.dimastr.com/redemption
    Redemption - what the Outlook
    Object Model should have been
    Version 5.5 is now available!

    • Marked as answer by uni_gauldoth Monday, July 7, 2014 1:48 AM
    Saturday, July 5, 2014 4:35 PM

All replies

  • Hello,

    The MAPIUninitialize method should be called when you are done with Extended MAPI. Here is what MSDN states:

    A client application calls the MAPIUninitialize function to end its interaction with MAPI, begun with a call to the MAPIInitialize function. After MAPIUninitialize is called, no other MAPI calls can be made by the client.

    > I'm using Extended MAPI to send an email via outlook from my application.

    The reasonable questions is: Why do you need to use Extended MAPI in that case?

    > I've looked at OOM, it looks like using OOM will be difficult to bypass the Outlook security issue.

    There is a commercial component which can suppress any security warnings in Outlook. You can read more about this and possible ways of solving such issues on the Outlook "Object Model Guard" Security Issues for Developers page.

    Do you develop a COM add-in or a standalone application?


    Friday, July 4, 2014 10:09 AM
  • Thanks for those information, I will check them to see if they could solve my problem.

    I'm developing a standalone application, just want to add a "send via attachment" thing.
    I understood MAPIUninitialize should be called after all Extended MAPI works are done, but I don't know when those work are done because IMAPIForm::DoVerb is doing asynchronous works.
    Friday, July 4, 2014 10:33 AM
  • In that case automating Outlook will be a better solution.
    Friday, July 4, 2014 11:46 AM
  • What is wrong with your implementation of IMAPIFormViewer::OnShutdown? Is it ever getting called?

    Why not initialize MAPI when your app starts up and call MAPIUninitialize when it exits? This way you are no dependent on any callback (which you cannot use to call MAPIUninitialize anyway since MAPI system is still running)?


    Dmitry Streblechenko (MVP)
    http://www.dimastr.com/redemption
    Redemption - what the Outlook
    Object Model should have been
    Version 5.5 is now available!

    Friday, July 4, 2014 6:44 PM
  • Hi Eugene,

    I will try automating outlook, just wrote a simple automation wrapper in c++.


    Hi Dmitry,

    IMAPIFormViewer::OnShutdown(IMAPIViewAdviseSink::OnShutdown) has been called, but I tried to call MAPIUninitialize right after IMAPIFormViewer::OnShutdown is called, the IMAPISession object still leaks at this moment. If I Sleep() for 5 seconds or more in IMAPIFormViewer::OnShutdown, things goes fine.

    It looks like something is still using the session object.

    The sending thread may be different every time, so I call MAPIInitialize and MAPIUninitialize every time I want to send a mail.

    Only calling MAPIUninitialize when my app exits may solve this problem.

    But if the user exit my app right after he sent a mail, then something bad may happen, or may not.

    I will have a try tomorrow.

    Thanks for all your helps.

    Saturday, July 5, 2014 2:07 PM
  • Doing this on a separate thread is nothing but asking for trouble... The MAPI form is implemented by outlook.exe, and all calls are marshaled to the main Outlook thread anyway, just like all OOM calls.

    There is no advantage doing this on a separate thread.


    Dmitry Streblechenko (MVP)
    http://www.dimastr.com/redemption
    Redemption - what the Outlook
    Object Model should have been
    Version 5.5 is now available!

    • Marked as answer by uni_gauldoth Monday, July 7, 2014 1:48 AM
    Saturday, July 5, 2014 4:35 PM
  • I just wrote a function called "MAPISendMailSimple" to wrap those operations. My colleague may call this function when they need to send a mail.

    It may be difficult to force all the user of "MAPISendMailSimple" to call this function from the same thread when they want to send a mail.

    Is it safe to call MAPIInitialize only one time on the main thread, when other operations happened on other threads?

    Sunday, July 6, 2014 3:44 AM
  • No, you must call MAPIInitialize on each thread.

    Since you are displaying the form in a separate thread, why not do that modally?


    Dmitry Streblechenko (MVP)
    http://www.dimastr.com/redemption
    Redemption - what the Outlook
    Object Model should have been
    Version 5.5 is now available!

    Sunday, July 6, 2014 7:01 AM
  • Yes, the form is displayed modally.

    Event after the modal form is closed, I still need to wait some seconds to call MAPIUninitialize.

    I noticed when Outlook is running, there will not be such problem. It only happens when outlook is not running.

    I wrote following code to wait until IMAPISession's ref count changed to 1, and then do those uninitialization works. When Outlook is not running, it will stuck for about 5 seconds and then quit.

    if(lpMapiSession) { while(true) { lpMapiSession->AddRef(); ULONG curRefCount = lpMapiSession->Release(); if(curRefCount == 1) { break; } Sleep(100); } HRESULT hResult = lpMapiSession->Logoff(0,0,0); if(hResult != S_OK) { } ULONG refCount = lpMapiSession->Release(); assert(refCount == 0); lpMapiSession = 0; }

    MAPIUninitialize();



    Sunday, July 6, 2014 7:34 AM
  • I tried MAPISendMail, there is also such problems.

    Maybe I should just wait some seconds because I don't reuse the session.

    Sunday, July 6, 2014 8:30 AM
  • Did you have a chance to use the Outlook object model instead?
    Sunday, July 6, 2014 10:25 AM
  • Hi Eugene,

    I could adapt the code to use Outlook Object Model.

    OOM is much more simpler. I will study OOM from now on, if it meets my requirements, I will adapt my code to use OOM.

    Sunday, July 6, 2014 1:39 PM