none
Application hangs when executing Documents.Open(ref filename) method and handling Application.DocumentOpen event RRS feed

  • Question

  • I've created a user control (windows form application) to get an instance of Word (either active or new), and provide a button to open documents into that instance using a file dialog picker.

    The form contains 2 buttons, 1 for getting the word instance and another for opening a document. It also contains a list box for displaying the open documents, and an openfiledialog control to provide the means for selecting documents to open.

    I am handling the Application.DocumentOpen event in order to populate the listbox...

        m_wordApp.DocumentOpen += new msoWord.ApplicationEvents4_DocumentOpenEventHandler(m_wordApp_DocumentOpen);

    I am determining when i need to reinvoke my method that populates the listbox to ensure that access to the control is on the same thread that created it....

        private void AddDocument(string name)
        {
            try
            {
                if (m_documentsListBox.InvokeRequired && m_documentsListBox.IsHandleCreated&&!m_documentsListBox.IsDisposed)
                {
                    this.Invoke(m_AddDocument, new object[] { name });
                    return;
                }

                if (!m_documentsListBox.Items.Contains(name))
                    m_documentsListBox.Items.Add(name);
            }
            catch (Exception ex)
            {
            }
        }

    Im not using 2 dots, and i believe i am releasing any COM objects correctly.

    Why does the application hang on either the line of code the opens the document ...
      WordDoc = m_wordDocs.Open(ref fileName);
    or the line that reinvokes the AddDocument() method...
      this.Invoke(m_AddDocument, new object[] { name });

    somewhere along the line i think i must be having a thread issue, because the hang only happens if i choose to open a document using the button, rather than from within Word directly.

    full code below...

    ----------------------------------------------------------------------------------------------------------

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;

    using System.Runtime.InteropServices;

    //  use these for the core office & word references
    using msoWord = Microsoft.Office.Interop.Word;


    namespace MCDevNET.Office.Word.TestUIControls
    {
        public partial class OpenWordDocument : Form
        {
            public OpenWordDocument()
            {
                InitializeComponent();

                m_openWordButton.Click += new EventHandler(buttonOpenWordApp_Click);
                m_openDocumentButton.Click += new EventHandler(buttonOpenDocument_Click);

                m_AddDocument = new UpdateListControl(AddDocument);
            }

            #region Form: control eventHandlers

            void buttonOpenWordApp_Click(object sender, EventArgs e)
            {
                try
                {
                    if (!IsValid(m_wordApp))
                        WordApp = GetInstance();
                    AddAllDocuments();
                }
                catch (Exception ex)
                {
                }
            }

            void buttonOpenDocument_Click(object sender, EventArgs e)
            {
                OpenWordDoc();
            }

            public delegate void UpdateListControl(string name);
            private UpdateListControl m_AddDocument;

        private void AddDocument(string name)
        {
            try
            {
                if (m_documentsListBox.InvokeRequired && m_documentsListBox.IsHandleCreated&&!m_documentsListBox.IsDisposed)
                {
                    this.Invoke(m_AddDocument, new object[] { name });
                    return;
                }

                if (!m_documentsListBox.Items.Contains(name))
                    m_documentsListBox.Items.Add(name);
            }
            catch (Exception ex)
            {
            }
        }

            private void AddAllDocuments()
            {
                try
                {
                    m_documentsListBox.Items.Clear();
                    if (m_wordDocs != null)
                    {
                        for (int i = 1; i <= m_wordDocs.Count; i++)
                            AddDocument(m_wordDocs[i].Name);
                    }
                }
                catch (Exception ex)
                {
                }
            }

            #endregion


            #region Word: properties & eventhandlers

            private msoWord.Document m_wordDoc;
            public msoWord.Document WordDoc
            {
                get { return m_wordDoc; }
                private set
                {
                    try
                    {
                        if (m_wordDoc != value)
                        {
                            ReleaseCOMObject(m_wordDoc);
                            m_wordDoc = value;
                        }
                    }
                    catch (Exception ex)
                    {
                    }
                }
            }

            private msoWord.Documents m_wordDocs;
            public msoWord.Documents WordDocs
            {
                get { return m_wordDocs; }
                private set
                {
                    try
                    {
                        if (m_wordDocs != value)
                        {
                            ReleaseCOMObject(m_wordDocs);
                            m_wordDocs = value;
                        }
                    }
                    catch (Exception ex)
                    {
                    }
                }
            }

            private msoWord.Application m_wordApp;
            public msoWord.Application WordApp
            {
                get { return m_wordApp; }
                set
                {
                    try
                    {
                        if (m_wordApp != value)
                        {
                            if (m_wordApp != null)
                            {
                                m_wordApp.DocumentOpen -= new msoWord.ApplicationEvents4_DocumentOpenEventHandler(m_wordApp_DocumentOpen);
                                ReleaseCOMObject(m_wordApp);
                            }

                            m_wordApp = value;

                            if (IsValid(m_wordApp))
                            {
        m_wordApp.DocumentOpen += new msoWord.ApplicationEvents4_DocumentOpenEventHandler(m_wordApp_DocumentOpen);
                                WordDocs = m_wordApp.Documents;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                    }
                }
            }

            void m_wordApp_DocumentOpen(msoWord.Document doc)
            {
                try
                {
                    string name = doc.Name;
                    AddDocument(name);
                }
                catch (Exception ex)
                {
                }
                finally
                {
                    ReleaseCOMObject(doc);
                    doc = null;
                }
            }

            private msoWord.Application GetInstance()
            {
                msoWord.Application app = null;
                try
                {
                    app = (msoWord.Application)Marshal.GetActiveObject("Word.Application");
                }
                catch (Exception ex)
                {
                    if (app == null)
                        app = new msoWord.Application();
                }
                finally
                {
                    if (IsValid(app))
                    {
                        app.Visible = true;
                        app.Activate();
                    }
                }
                return app;
            }

            private void OpenWordDoc()
            {
                try
                {
                    m_openFileDialog.AddExtension = true;
                    m_openFileDialog.Filter = "All Word (*.docx; *.docm; *.doc; *.dotx; *.dotm; *.dot)|*.docx;*.docm;*.doc;*.dotx;*.dotm;*.dot|Word Documents (*.docx)|*.docx|Word Macro-Enabled Documents (*.docm)|*.docm|Word 97-2003 Documents (*.doc)|*.doc|All Word Templates (*.dotx; *.dotm; *.dot)|*.dotx;*.dotm;*.dot|Word Templates (*.dotx)|*.dotx|Word Macro-Enabled Templates (*.dotm)|*.dotm)";
                    m_openFileDialog.FilterIndex = 1;
                    m_openFileDialog.Multiselect = false;
                    m_openFileDialog.Title = "Open Word Document";

                    if (m_openFileDialog.ShowDialog() == DialogResult.OK)
                    {
                        object fileName = m_openFileDialog.FileName;
                        WordDoc = m_wordDocs.Open(ref fileName);
                    }
                }
                catch (Exception ex)
                {
                }
            }

            private bool IsValid(msoWord.Application app)
            {
                try
                {
                    if (app != null)
                    {
                        string name = app.Caption;
                        return true;
                    }
                }
                catch (Exception ex)
                {
                }
                return false;
            }
            #endregion

            private void ReleaseCOMObject(object comObject)
            {
                try
                {
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                    GC.Collect();
                    GC.WaitForPendingFinalizers();

                    if (comObject != null && Marshal.IsComObject(comObject))
                        Marshal.ReleaseComObject(comObject);

                }
                catch (Exception ex)
                {
                }
            }
        }
    }

    namespace MCDevNET.Office.Word.TestUIControls
    {
        partial class OpenWordDocument
        {
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.IContainer components = null;

            /// <summary>
            /// Clean up any resources being used.
            /// </summary>
            /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }

            #region Windows Form Designer generated code

            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                this.m_documentsListBox = new System.Windows.Forms.ListBox();
                this.m_openDocumentButton = new System.Windows.Forms.Button();
                this.m_openWordButton = new System.Windows.Forms.Button();
                this.m_openFileDialog = new System.Windows.Forms.OpenFileDialog();
                this.SuspendLayout();
                // 
                // lb_Documents
                // 
                this.m_documentsListBox.FormattingEnabled = true;
                this.m_documentsListBox.Location = new System.Drawing.Point(12, 41);
                this.m_documentsListBox.Name = "lb_Documents";
                this.m_documentsListBox.Size = new System.Drawing.Size(156, 134);
                this.m_documentsListBox.TabIndex = 8;
                // 
                // m_openDocumentButton
                // 
                this.m_openDocumentButton.Location = new System.Drawing.Point(93, 12);
                this.m_openDocumentButton.Name = "m_openDocumentButton";
                this.m_openDocumentButton.Size = new System.Drawing.Size(75, 23);
                this.m_openDocumentButton.TabIndex = 7;
                this.m_openDocumentButton.Text = "Doc";
                this.m_openDocumentButton.UseVisualStyleBackColor = true;
                // 
                // m_openWordButton
                // 
                this.m_openWordButton.Location = new System.Drawing.Point(12, 12);
                this.m_openWordButton.Name = "m_openWordButton";
                this.m_openWordButton.Size = new System.Drawing.Size(75, 23);
                this.m_openWordButton.TabIndex = 6;
                this.m_openWordButton.Text = "Word";
                this.m_openWordButton.UseVisualStyleBackColor = true;
                // 
                // m_openFileDialog
                // 
                this.m_openFileDialog.FileName = "openFileDialog1";
                // 
                // OpenWordDocument
                // 
                this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                this.ClientSize = new System.Drawing.Size(182, 184);
                this.Controls.Add(this.m_documentsListBox);
                this.Controls.Add(this.m_openDocumentButton);
                this.Controls.Add(this.m_openWordButton);
                this.Name = "OpenWordDocument";
                this.Text = "OpenWordDocument";
                this.ResumeLayout(false);

            }

            #endregion

            private System.Windows.Forms.ListBox m_documentsListBox;
            private System.Windows.Forms.Button m_openDocumentButton;
            private System.Windows.Forms.Button m_openWordButton;
            private System.Windows.Forms.OpenFileDialog m_openFileDialog;
        }
    }

    Tuesday, May 14, 2013 10:01 AM

Answers

  • After putting it to our resident boffin he threw it into Process Explorer and did a bit of searching on t'internet.

    He came up with the cause being a deadlock between the word event firing and the initial execution of the Documents.open() command.

    The solution he proposed was this...

    new System.Threading.Tasks.Task(() => this.WordDoc = this.m_wordDocs.Open(ref fileName)).Start();
    //WordDoc = m_wordDocs.Open(ref fileName);

    i've implemented this into the code and can confirm that this does indeed provide a fix to the problem.  the word document opens properly and the listbox updates correctly, without any hangs.

    Monday, June 3, 2013 2:45 PM

All replies

  • Hello,

    Thanks for your participation in this forum. I'm trying to involve some senior engineers into this issue and it will take some time. Your patience will be greatly appreciated. Sorry for any inconvenience.

    Best Regards,


    Damon Zheng
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, May 16, 2013 1:55 PM
    Moderator
  • cheers damon, keep me posted.

    have you been able to replicate the problem with my supplied code?

    matt

    Thursday, May 16, 2013 3:58 PM
  • Hello Matt,

    I was able to reproduce the issue. However, because of its complexity your question falls into the paid support category which requires a more in-depth level of support.  If the support engineer determines that the issue is the result of a bug the service request will be a no-charge case and you won't be charged. Please visit the below link to see the various paid support options that are available to better meet your needs. http://support.microsoft.com/default.aspx?id=fh;en-us;offerprophone

    Thanks,
    Ajay

    Thursday, May 23, 2013 8:05 PM
  • thanks ajay

    it's good to know that you have reproduced the issue.  and it's a shame that it's not down to my shoddy coding or any schoolboy errors that have crept in, otherwise you may have been able to locate and fix the problem.

    i shall investigate further on stackoverflow in case somebody there can spot whether or not this is a fault with my understanding or handling of threading and the office COM model.

    If i manage to find any further info on this then i will post back, but sadly the paid support charges are something that i cannot financially cover.

    cheers

    matt 

    Tuesday, May 28, 2013 1:46 PM
  • Hi Matt

    Your code is awfully complex for what should be something fairly simple. Just because Ajay can reproduce the problem using your code doesn't mean the problem isn't in how you coded it...

    One thing that strikes me is your use of ReleaseComObject. It appears to me that you're over-using it. It should be enough to set the object to null before re-assigning something else to the variable.

    Beyond that, I'd try going back to a very simple approach - using the object model directly rather than wrapping it up as you've done - and see if that works at a basic level. If it does, then you'll know that the problem comes from all the layers of wrapping...


    Cindy Meister, VSTO/Word MVP, my blog

    Sunday, June 2, 2013 11:13 AM
    Moderator
  • i hear you cindy.  there's a schoolboy error i made right there in suggesting that it might not be my "shoddy coding"... where i got that notion from, i don't know!?  so, yes, it still could well be my own schoolboy errors.   still  :)

    as for the over-complex solution, i'm just trying to follow correct procedures as i've read on stackoverflow, msdn etc.  when starting to learn c# a coupla years back it was not stated in the easy examples on msdn that you'ld have to do things like reinvoking controls so that they're accessed on the threads that created them.  Nor that i should never use 2 dots programming (ie object.object.property) for fear of creating inaccessable references to COM objects that i could not then release and would kick around in memory until the system ground to a halt. 

    i actually thought that programming for office in the .net framework might actually be relatively straightforward and simpler, but i've since realised that that was actually my first foolhardy assumption.  how wrong i was.  it would now appear that programming COM in the .net environment is even trickier than simply dealing with the odd "dll-hell".

    My understanding now of coding for office/COM is that an RCW needs to be released in several circumstances, and one of those being everytime a COM object is passed between the unmanaged and managed environments whereby it increments the RCW count.  That's what i was trying to achieve here, but any further advice/help with this matter would be greatly appreciated.

    i will however strip out and ignore all the "rubbish" and see how that performs (2 dots or no 2 dots, and to hell with the Marshal class). 

    cheers

    m

    Monday, June 3, 2013 2:38 PM
  • After putting it to our resident boffin he threw it into Process Explorer and did a bit of searching on t'internet.

    He came up with the cause being a deadlock between the word event firing and the initial execution of the Documents.open() command.

    The solution he proposed was this...

    new System.Threading.Tasks.Task(() => this.WordDoc = this.m_wordDocs.Open(ref fileName)).Start();
    //WordDoc = m_wordDocs.Open(ref fileName);

    i've implemented this into the code and can confirm that this does indeed provide a fix to the problem.  the word document opens properly and the listbox updates correctly, without any hangs.

    Monday, June 3, 2013 2:45 PM
  • Hi Matt

    Thanks for researching and reporting back. That's an interesting twist...


    Cindy Meister, VSTO/Word MVP, my blog

    Monday, June 3, 2013 5:45 PM
    Moderator