none
Trace memory leak for Outlook Word Editor part RRS feed

  • Question

  • Dear All,

    I'm novice in Outlook Programming.

    I am developing an application based on .NET 2.0. I'm using Outlook  library (Interop.Outlook.dll v 9.1.0.0 )and Word library (Microsoft.Office.Interop.Word.dll v 12.0...) for office automation. I am testing it on Outlook (OL) 2003 with email editor set to Word (default).

    What does Office automation code do?

    Open Outlook application's New Mail Message window. Uses word editor to set the body of the email using Word library. And whenever user closes the message window, all type of COM objects are released with trying to set each type's RCW to 0.

    Here are the code snippets:

    // NAMESPACES
    using Outlook;
    using Word = Microsoft.Office.Interop.Word;
    
    // CLASS LEVEL VARIABLES
    
            // Outlook variables
            private _Application _olApplication;
            private NameSpace _olNameSpace;
            private MailItem _olMailItem;
            private Attachments _olAttachments;
            private Attachment _olAttachment;
            private Inspector _olInspector;
            private ItemEvents_10_Event _olItemEvents10;
    
            // Winword variables
            private Word._Application _wordApplication;
            private Word.Windows _wordWindows;
            private Word.Window _wordWindow;
            private Word.Document _wordDocument;
            private Word.InlineShapes _wordInlineShapes;
            private Word.InlineShape _wordInlineShape;
            private Word.Selection _wordSelection;
    
    // IN SOME FUNCTION THE FOLLOWING CODE
    _olApplication = new Outlook.Application();
                    _olNameSpace = _olApplication.GetNamespace("MAPI");
                    _olNameSpace.Logon(Type.Missing, Type.Missing, false, true);
    
                    _olMailItem = _olApplication.CreateItem(OlItemType.olMailItem) as MailItem;
                    if (_olMailItem == null) return;
    
                    _olItemEvents10 = _olMailItem;
                    _olItemEvents10.Close += mailItem_Close;
    
    // I SUSPECT MEMORY LEAKAGE IN FOLLOWING CODE
    // Variable 'filePath' points to some existing .jpg image
    
                _olInspector = _olMailItem.GetInspector;
    
                if (_olInspector.IsWordMail())
                {
                    _wordDocument = (Word.Document)_olInspector.WordEditor;
                    _wordApplication = _wordDocument.Application;
    
                    _wordWindows = _wordDocument.Windows;
                    _wordWindow = _wordWindows[1];
    
                    _wordSelection = _wordWindow.Selection;
                    _wordSelection.InsertBreak(Word.WdBreakType.wdLineBreak);
                    _wordSelection.InsertBreak(Word.WdBreakType.wdLineBreak);
    
                    _wordInlineShapes = _wordSelection.InlineShapes;
                    _wordInlineShape = _wordInlineShapes.AddPicture(filePath, true, true, Type.Missing);
    
                    _olMailItem.Display(false);
                    File.Delete(filePath);
                }
                else
                {
                    _olMailItem.HTMLBody = String.Format("<body><br/><br/><img src=\"{0}\"><br/></body>", filePath);
                    _olMailItem.Display(false);
                }

    As per my research on COM objects, memory leakage occurs for negligience of following points:

    1. I had not used double dots(.) for any part in COM code.

    2. I had kept record of each COM object in variable so that they can be relased later.

    3. The parameters are passed with either some value or Type.Missing. No empty parameters.

    Here is the code used for mailItem_Close :

    private void mailItem_Close(ref bool cancel)
            {
                try
                {
                    if (_wordDocument != null)
                    {
                        Marshal.FinalReleaseComObject(_wordWindows);
                        Marshal.FinalReleaseComObject(_wordWindow);
                        Marshal.FinalReleaseComObject(_wordSelection);
                        Marshal.FinalReleaseComObject(_wordInlineShapes);
                        Marshal.FinalReleaseComObject(_wordInlineShape);
                        Marshal.FinalReleaseComObject(_wordDocument);
                        _wordApplication.Quit(false, Type.Missing, Type.Missing);
                        Marshal.FinalReleaseComObject(_wordApplication);
                    }
    
                    if (_olApplication != null)
                    {
                        _olItemEvents10.Close -= mailItem_Close;
                        Marshal.FinalReleaseComObject(_olItemEvents10);
                        Marshal.FinalReleaseComObject(_olInspector);
                        Marshal.FinalReleaseComObject(_olMailItem);
                        Marshal.FinalReleaseComObject(_olNameSpace);
                        _olApplication.Quit();
                        Marshal.FinalReleaseComObject(_olApplication);
                    }
    
                    if (_olAttachments == null) return;
                    Marshal.FinalReleaseComObject(_olAttachments);
                    Marshal.FinalReleaseComObject(_olAttachment);
                }
                catch (Exception exc)
                {
                    Utility.WriteError(exc);
                    MessageBox.Show("An error occured while clearing resources. Please try again.\n\n *An entry of error had been made in log file. Consult your vendor for further assistance.",
                                    "Error - While resource clearance!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                finally
                {
                    _wordWindows = null;
                    _wordWindow = null;
                    _wordSelection = null;
                    _wordInlineShapes = null;
                    _wordInlineShape = null;
                    _wordDocument = null;
    
                    _olItemEvents10 = null;
                    _olInspector = null;
                    _olAttachments = null;
                    _olAttachment = null;
                    _olMailItem = null;
                    _olNameSpace = null;
                    _olApplication = null;
    
                    // First pass to release .Net objects
                    // Second pass to release COM objects associated with .Net objects.
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                }
            }

    Some points to be noticed:

    1. When application launches Outlook (OUTLOOK.EXE), together it also launches WINWORD.EXE.

    2. The New Mail Message window show Untitled message but if I check Help from menu bar. There it show menu option About Microsoft Office Word instead of About Microsoft Office Outlook. So that mean somehow Word is being used for creating email message.

    3. If I close the New Mail Message window, the WINWORD.EXE gets closed. And it doesn't show in Task Manager processes. But OUTLOOK.EXE still there.

    4. If launch application again, a new instance of OUTLOOK.EXE appears in Task Manager. So that mean closing the New Mail Message window releases WINWORD.EXE. But the interesting point to be noted here that it also call mailItem_Close which was meant to be executed when mailItem closes from Outlook. So I think there is some sort of layering working.

    5. When application launch and uses word editor, the Outlook show security prompt dialog box. I suspect this dialog box to be the culprit. And I'm unable to trace it or release it. What you think?

    Need your help/suggestion/advice/hint (be it any):

    Please check code. Might I have something in code that sounds bad. Or might be you are having nice ideas to solve it out. The last idea that came to my mind to solve this problem was to kill the OUTLOOK.EXE instance generated from my application. But how to trace that specific instance ?



    Vikram Singh Saini


    Saturday, February 2, 2013 5:36 PM

Answers

  • Ad 5 - you can answer this yourself - if your code is able to close outlook just fine without word as mail editor and security popop should show for you regardless of this (because you are somewehre accessing protected property or method) then this security prompt cannot be the reason for this. If you want to double check you can always install free MS antyvir solution (called MSE or something like that) and verify again.

    as for main problem - i think you are not showing us your full code as i see there attchments variables that are not used anywhere. And even without that - order of releaseing objects is wrong - first release attachments and call to Quit and release of Application should be last.

    Sunday, February 3, 2013 6:10 AM
  • for your problem regarding lingering processes, please repeat steps with sending mail from word _after_ you have disabled all third party plugins in both word and outlook - those processes should not stay in memory.
    Sunday, February 3, 2013 1:44 PM

All replies

  • Ad 1. it should be so - if mail is using word editor in outlook 2003 it meant that external word process is launched and used as editor

    ad 2. this is side effect of above

    ad 3. this is fine, although i would not call Word's Application quit method - you do not get hold of word's application object to do anything so it is not your responsibility to release it

    ad 4. this is main problem, you are not releaseing eveything from outlook process. I would suggest starting with simplest scenatio that exposes this problem, so see if your code works properly (outlook process exists) if you do not use word as email editor, so you stay clear in OOM space. If so, then apparently you are not releasing something. If not let us know.

    Ad 5 security prompt you will get unless you have up to date anti virus scanner, execute your code from add-in or vba, or use redemption

    Saturday, February 2, 2013 7:07 PM
  • Hi,

    Thanks for prompt response.

    For ad 3. : I am quitting it because the code in :

    if (_olInspector.IsWordMail()) {

    }

    is responsible for making Outlook to be in memory (tested).

    For ad 4. : I used simple scenario. Tested code when word was not email editor, all works smooth. No traces left behind. 

    As you said, "I am not releasing something". I am unable to found that something and so I shared code with you all. Might you can found that point.

    For ad 5. : I understand reason for such behavior and no complain for that part. But the point is: Can this security dialog box making Outlook instance to be in memory?


    Vikram Singh Saini (Freelancer on Elance)

    Sunday, February 3, 2013 2:58 AM
  • I noticed a suspecting behavior of Word 2003 (Professional). I was trying to email some document from Word by steps:

    Open Word 2003 --> File --> New --> E-mail message

    These steps open WINWORD.EXE and OUTLOOK.EXE. And both process appear in task manager. However if I close Word, the WINWORD.EXE process should get removed from Processes (as expected).

    But "NO". This not happen. Both of the processes of Word and Outlook still exists. I tried repeating steps many times resulting in many instances of Word & Outook. Thus confirming that Office suite is unable to release COM resources itself.

    Can anyone confirm this as bug? If yes, then I think my code has no mistake. Because I am facing this problem in word editor part only.



    Vikram Singh Saini (Freelancer on Elance)

    Sunday, February 3, 2013 6:06 AM
  • Ad 5 - you can answer this yourself - if your code is able to close outlook just fine without word as mail editor and security popop should show for you regardless of this (because you are somewehre accessing protected property or method) then this security prompt cannot be the reason for this. If you want to double check you can always install free MS antyvir solution (called MSE or something like that) and verify again.

    as for main problem - i think you are not showing us your full code as i see there attchments variables that are not used anywhere. And even without that - order of releaseing objects is wrong - first release attachments and call to Quit and release of Application should be last.

    Sunday, February 3, 2013 6:10 AM
  • Hi,

    Thanks for sharing valuable information till far.

    attachments variable are used for setting email body for 2007 OL.

    // In some function
    _olAttachments = _olMailItem.Attachments;
                _olAttachment = _olAttachments.Add(filePath, OlAttachmentType.olEmbeddeditem, null, "ZSNIP Screenshot");
                _olMailItem.HTMLBody = String.Format("<body><br/><br/><img src=\"cid:{0}\"><br/></body>", _olAttachment.FileName);
                _olMailItem.Display(false);

    I changed order of releasing objects, first releasing attachments and call to Quit and release of Application last.

    // Release of Outlook objects
                    if (_olItemEvents10 != null)
                    {
                        _olItemEvents10.Close -= mailItem_Close;
                        Marshal.FinalReleaseComObject(_olItemEvents10);
                    }
                    if (_olInspector != null) Marshal.FinalReleaseComObject(_olInspector);
                    if (_olMailItem != null) Marshal.FinalReleaseComObject(_olMailItem);
                    if (_olNameSpace != null) Marshal.FinalReleaseComObject(_olNameSpace);
                    if (_olAttachments != null) Marshal.FinalReleaseComObject(_olAttachments);
                    if (_olAttachment != null) Marshal.FinalReleaseComObject(_olAttachment);
                    _olApplication.Quit();
                    if (_olApplication != null) Marshal.FinalReleaseComObject(_olApplication);
    Please let me know if there is any thing I should do for releasing the instance of Outlook.


    Vikram Singh Saini (Freelancer on Elance)

    Sunday, February 3, 2013 12:15 PM
  • for your problem regarding lingering processes, please repeat steps with sending mail from word _after_ you have disabled all third party plugins in both word and outlook - those processes should not stay in memory.
    Sunday, February 3, 2013 1:44 PM
  • Dear DamianD,

    I want to say you big "THANKS" for all your efforts guiding me to the best and easy to implement solution.

    Yes! I disabled all add ins (from both word and outlook). Though I didn't installed but they still existed.

    I disabled them via registry editing from link: How to find and disable Outlook 2003 Add-ins and plugins


    Vikram Singh Saini (Freelancer on Elance)

    Sunday, February 3, 2013 2:33 PM
  • If you use WordMail with Outlook 2003 it opens an instance of Word when you open an email if Word was not already running as a subclassed process of Outlook. That behavior is expected. If there is at least one email open it will keep the subclassed Word process open also.

    --
    Ken Slovak
    [MVP-Outlook]
    http://www.slovaktech.com
    Author: Professional Programming Outlook 2007
    "Vikram Singh Saini" <=?utf-8?B?VmlrcmFtIFNpbmdoIFNhaW5p?=> wrote in message news:b365963d-9126-4c74-8f7e-9ef06474aefc...

    I noticed a suspecting behavior of Word 2003 (Professional). I was trying to email some document from Word by steps:

    Open Word 2003 --> File --> New --> E-mail message

    These steps open WINWORD.EXE and OUTLOOK.EXE. And both process appear in task manager. However if I close Word, the WINWORD.EXE process should get removed from Processes (as expected).

    But "NO". This not happen. Both of the processes of Word and Outlook still exists. I tried repeating steps many times resulting in many instances of Word & Outook. Thus confirming that Office suite is unable to release COM resources itself.

    Can anyone confirm this as bug? If yes, then I think my code has no mistake. Because I am facing this problem in word editor part only.



    Vikram Singh Saini (Freelancer on Elance)


    Ken Slovak MVP - Outlook
    Monday, February 4, 2013 4:56 PM
    Moderator