none
Automating Word 2007 from VB.Net RRS feed

  • Question

  • Hi,

    I'm trying to automate Word 2007 from VB.Net (VS2010) and I'm hitting a couple of problems. Firstly, the first time I try to connect to word in every session of the application, it fails with error 429 - Cannot create ActiveX component. Code as below:

            Dim appWord As Microsoft.Office.Interop.Word.Application

            On Error Resume Next

            appWord = GetObject(, "Word.Application")

            If Err.Number <> 0 Then

                appWord = CreateObject("Word.Application")

                If Err.Number <> 0 Then

                    MsgBox("An error has occurred - please notify the Help Desk." & vbNewLine & vbNewLine & "[" & Err.Number & "] - " & Err.Description, MsgBoxStyle.Exclamation, gstrAppName)

                    On Error GoTo 0

                Exit Sub

                End If

            End If

    Am I doing something wrong there? Second and subsequent attempts work OK.

    Also, When I insert a table into the document and then add text to the cells of the table, the text actually goes into a completely unrelated table immediately before the newly inserted table:

            Dim docWord As Microsoft.Office.Interop.Word.Document = appWord.Documents.Open(gstrDocTemplateRoot & mastrFileName(dlbDocumentTemplate.SelectedIndex))
    
            Dim objTable1 As Microsoft.Office.Interop.Word.Table = docWord.Tables.Add(docWord.Bookmarks("PRODUCTS").Range, 2, 2)
            objTable1.Cell(1, 1).Range.Text = "Cell 1, 1"
            objTable1.Cell(1, 2).Range.Text = "Cell 1, 2"
            objTable1.Cell(2, 1).Range.Text = "Data cell 1"
            objTable1.Cell(2, 2).Range.Text = "Data cell 2"
            objTable1.Rows(1).Range.Font.Bold = True
    
            Dim objTable2 As Microsoft.Office.Interop.Word.Table = docWord.Tables.Add(docWord.Bookmarks("PRODUCTS").Range, 2, 2)
            objTable2.Cell(1, 1).Range.Text = "Cell 2, 1"
            objTable2.Cell(1, 2).Range.Text = "Cell 2, 2"
            objTable2.Cell(2, 1).Range.Text = "Data cell 2.1"
            objTable2.Cell(2, 2).Range.Text = "Data cell 2.2"
            objTable2.Rows(1).Range.Font.Bold = True

    While the second table is inserted into the first cell of the first table.

    Am I just doing this all wrong? The code basically came from various MS sites, so I was hoping it would be pretty straightforward.

    Thanks in advance,

    Tony.


    • Edited by Tony Spratt Monday, January 14, 2013 3:56 PM
    Monday, January 14, 2013 3:56 PM

Answers

  • Hi Tony

    It's much better to post totally unrelated questions in separate threads - you'll get more and better responses that way as one person may not have answers for all questions...

    Re the Tables: Before we can make any suggestions we'd have to know where that bookmark is located. For the second table it's almost certainly inside the first cell of the first table. Difficult to say what's going on with the creation of the first table, though...

    Re the first question: what line of code is triggering the error?

    GetObject does not work the same in .NET as in VBA. If Word isn't actually already running then you will get an error - unlike in VBA, GetObject won't start a new instance of Word if it isn't already running. So you need to check the Processes running in Windows whether Word is already running and, if it's not, first start Word. See this article for code that checks whether an application is already running. It's in C# but you should be able to figure out the Namespace and methods/properties:
      http://blogs.msdn.com/b/andreww/archive/2008/11/30/starting-or-connecting-to-office-apps.aspx


    Cindy Meister, VSTO/Word MVP, my blog

    • Marked as answer by Tony Spratt Tuesday, January 15, 2013 11:30 AM
    Monday, January 14, 2013 10:04 PM
    Moderator

All replies

  • Hi Tony

    It's much better to post totally unrelated questions in separate threads - you'll get more and better responses that way as one person may not have answers for all questions...

    Re the Tables: Before we can make any suggestions we'd have to know where that bookmark is located. For the second table it's almost certainly inside the first cell of the first table. Difficult to say what's going on with the creation of the first table, though...

    Re the first question: what line of code is triggering the error?

    GetObject does not work the same in .NET as in VBA. If Word isn't actually already running then you will get an error - unlike in VBA, GetObject won't start a new instance of Word if it isn't already running. So you need to check the Processes running in Windows whether Word is already running and, if it's not, first start Word. See this article for code that checks whether an application is already running. It's in C# but you should be able to figure out the Namespace and methods/properties:
      http://blogs.msdn.com/b/andreww/archive/2008/11/30/starting-or-connecting-to-office-apps.aspx


    Cindy Meister, VSTO/Word MVP, my blog

    • Marked as answer by Tony Spratt Tuesday, January 15, 2013 11:30 AM
    Monday, January 14, 2013 10:04 PM
    Moderator
  • Hi Tony,

    Thank you for posting in the MSDN Forum.

    For your 1st request, I think you can try the code below. My project is an console application, you can pick the code from Sub Main() and use it in your own project.

    Imports Word = Microsoft.Office.Interop.Word
    Module Module1
    
        Sub Main()
            Dim wdApp As Word.Application
    
            Try
                wdApp = System.Runtime.InteropServices.Marshal.GetActiveObject("Word.Application")
            Catch ex As Exception
    
            End Try
    
            If wdApp Is Nothing Then
                wdApp = New Word.Application()
                wdApp.Visible = True
                'wdApp.Documents.Add()
            End If
    
        End Sub
    
    End Module

    For your 2nd question, you can answer Cindy's question first.

    Hope it helps.

    Best regards,


    Quist Zhang [MSFT]
    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.

    Tuesday, January 15, 2013 7:23 AM
    Moderator
  • Hi Quist Zhang

    Did you test your code with no instance of Word already running?

    VB.NET's GetObject actually calls GetActiveObject, in the background, and GetActiveObject should throw an error if there's no instance of Word already running... Unless you're using a really old version of the .NET Framework, where it worked differently (such as Andrew Whitechapel was using when he wrote the blog article five years ago). See for example the EXAMPLE discussion in this article: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.getactiveobject.aspx


    Cindy Meister, VSTO/Word MVP, my blog

    Tuesday, January 15, 2013 8:16 AM
    Moderator
  • Try-catch statement handles exceptions. 

    Tuesday, January 15, 2013 8:42 AM
  • Hi Cindy,

    Thank you for your last reply.

    I've closed all my documents and look into task manager for sure.

    GetActiveObject did throw an error when I put the code

    wdApp = System.Runtime.InteropServices.Marshal.GetActiveObject("Word.Application")

    out of Try... Catch.. block which is the handlers for different exceptions.

    Later I've tried Try...Catch... seen in the page you've provided and managed to create an new instance if GetActiveObject failed.

    The code works fine and I think the logic is basically the same with Tony's.

    Best regards,


    Quist Zhang [MSFT]
    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.

    Tuesday, January 15, 2013 8:47 AM
    Moderator
  • Hi Quist Zhang

    Yes, Try..Catch will work, but the difference between using error handling for something like this in .NET versus the old COM error-handling that Tony is using is that you get a noticeable performance hit - the code runs more slowly.

    .NET philosophy posits that error handling should be used to catch "unexpected" problems, but it should not be used for "code branching" unless there's absolutely no alternative. That's why .NET code should, for example, test whether a variable Is Nothing (=null in C#) rather than use Try...Catch when it's not certain whether an object could be assigned to the variable. This approach can also be used in this instance, if you prefer it to checking running processes.

    Code samples:

        Private Sub btnGetActiveObject_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGetActiveObject.Click
            Dim oApp As Object
            Dim xlApp As Excel.Application
            Dim appName As String = "Excel.Application"
    
            oApp = System.Runtime.InteropServices.Marshal.GetActiveObject(appName)
            If Not oApp Is Nothing Then
                xlApp = CType(oApp, Excel.Application)
                MessageBox.Show(xlApp.ActiveWindow.Caption)
            End If
            xlApp = Nothing
        End Sub
    
        Private Sub btnCheckProcesses_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
            Handles btnCheckProcesses.Click
    
            Dim WordApp As Word.Application
            Dim appName As String = "Word.Application"
            Dim wdProcesses() As System.Diagnostics.Process = _
              System.Diagnostics.Process.GetProcessesByName("winword")
            Dim wdprocess As System.Diagnostics.Process
            For Each wdprocess In wdProcesses
                System.Diagnostics.Debug.Print(wdprocess.MainWindowTitle)
                System.Diagnostics.Debug.Print(wdprocess.StartInfo.Arguments.Length.ToString())
            Next
            If wdProcesses.Length > 0 Then
                WordApp = System.Runtime.InteropServices.Marshal.GetActiveObject(appName)
            Else
                WordApp = New Word.Application
            End If
            If Not WordApp Is Nothing Then
                WordApp.Visible = True
                WordApp.Activate()
                MessageBox.Show(WordApp.ActiveWindow.Caption)
                WordApp = Nothing
            End If
        End Sub


    Cindy Meister, VSTO/Word MVP, my blog

    Tuesday, January 15, 2013 8:58 AM
    Moderator
  • Hi Cindy,

    Thank you very much for your last reply.

    The code above is great. I have to say that I've learned a ton today.

    I'll read through the 2 pages you've provided above.

    Thanks again.


    Quist Zhang [MSFT]
    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.

    Tuesday, January 15, 2013 9:26 AM
    Moderator
  • Hi Tony

    It's much better to post totally unrelated questions in separate threads - you'll get more and better responses that way as one person may not have answers for all questions...

    Re the Tables: Before we can make any suggestions we'd have to know where that bookmark is located. For the second table it's almost certainly inside the first cell of the first table. Difficult to say what's going on with the creation of the first table, though...

    Re the first question: what line of code is triggering the error?

    GetObject does not work the same in .NET as in VBA. If Word isn't actually already running then you will get an error - unlike in VBA, GetObject won't start a new instance of Word if it isn't already running. So you need to check the Processes running in Windows whether Word is already running and, if it's not, first start Word. See this article for code that checks whether an application is already running. It's in C# but you should be able to figure out the Namespace and methods/properties:
      http://blogs.msdn.com/b/andreww/archive/2008/11/30/starting-or-connecting-to-office-apps.aspx


    Cindy Meister, VSTO/Word MVP, my blog

    Cindy,

    Thanks very much for your help - I think I've got it all sorted now. Yes, I should have separated the two questions but I'm afraid that as they were consecutive in the code, I got a bit carried away and treated them as the same problem. Anyway, the first problem was easily sorted out - I mixed late binding object creating with early binding code - a schoolboy error, there.

    As for the problem with the tables, your comment got me thinking and I replaced the one bookmark with two - one for each table - and bookmarked the actual paragraph marks, rather than the empty area before them. This has the tables put in the right place and the paragraph mark removed, which gives me the formatting I actually wanted. How the text for the first insterted table came to be in a completely unrelated table earlier in the document I will never be able to work out, but happily that problem vanished with the new bookmark placement.

    Thanks again - help is always much appreciated.

    Tony.

    Tuesday, January 15, 2013 11:35 AM