Link to home
Start Free TrialLog in
Avatar of Ted Palmer
Ted PalmerFlag for United States of America

asked on

Microsoft Automation of MS-Word 2007 using VB.NET 2008 programming COMException

Hello EE Experts,

I am very suprised to see so few answered questions on the topic of Microsoft Automation of MS-Word using Visual Basic .NET (2008 in this case) programming there are on EE. The word "Automation" has a very special meaning in this context. So much benefit can be had in businesses of all sizes for the production of documents that are specific to the recipient -- not just junk mail. That is what my VB.NET 2008 program does. Produce documents for attorneys that have data inserted in them by the MS-Word Mail Merge process, but I am having a problem. After the document is produced and saved, I display the file name in a DataGrid that the user can click on to select and click on a  button to "open" the MS-Word document. This opens the document in MS-Word using MS-Word as what Microsoft calls an "Automation Server".

The problem that I am having is this. Early in the start up of the program I declare an object reference variable to point to an instance of MS-Word, and instantiate an instance of MS-Word using MS-Automation techniques. No big deal. Here is the code that works:

     Public go_wrdApp As Microsoft.Office.Interop.Word.Application
     go_wrdApp = CreateObject("Word.Application")

So now go_wrdApp is an object reference variable that points to an instance of the MS-Word.program (an Automation Server)

Using Microsoft "Automation" technique -- Each of the Microsoft Office program components can be a Microsoft "Automation Server" -- I can run the mail merge process and save each MS-Word document generated into a file to be opened later as described above. The problem occurs when the user closes the MS-Word application frame after looking at a documet by clicking on the red 'X' in the upper right corner of the application frame. This closes the whole instance of MS-Word -- not just the document that was being viewed in the application program.

So now, at a later time, when the same user attempts to look at another MS-Word document using the technique described above with the DataGrid, instead of opening the document in MS-Word the VB.NET 2008 program throws a COMException with the message "RPC server is unavailable" because the object reference variable go_wrdApp was left pointing at a MS-Word program object (Automation Server) that no longer exists because the user clicked on the little red 'X' in the upper right corner of the application frame instead of just closing only the document.

Is there a way that I can test "go_wrdApp" object reference variable to be sure that it is pointing at an instance of MS-Word program object that is really there?

"If Not IsNothing(go_wrdApp) Then" doesn't work.

Oh! I believe the reference to RPC in the error message means "Remote Procedure Call".

Thanks,
Ted Palmer
SOLUTION
Avatar of Meir Rivkin
Meir Rivkin
Flag of Israel image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Ted Palmer

ASKER

Sedgwick,

Actually without intending to, I am already doing that twick. Except the Try/Catch block has a lot of source code in it and I didn't think of it as a twick at the time. But that doesn't mean that I can't create a small Try/Catch block just for that purpose. In another function I am already testing the error message returned for "RPC server is unavailable". If it tests true, I execute go_wrdApp = CreateObject("Word.Application") as you suggested. So I am coping with the issue already. I was just looking for something a little less convoluted. It appears that the method you suggest is probably the lease convoluted method there is. I'll try that later today. Unless somebody suggests a simpler method, you have the solution and the points.

Thank you for your help.

Ted Palmer
i know its not the best way of handling this issue but for me it saved alot of time and worked on the spot.
cheers
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
CodeCruiser:

This looks more like what I was looking for. I just finished an SEO webinar and I have to run for an appointment. So I may not get to experiment with this suggestion till tomorrow, but you can be sure that I am going to try this.

Thank you so much,

Ted Palmer
CodeCruiser:

I tried you suggestion and this is what I got. I'm adding a screen shot image of a stack trace and some code. The code first.

From the Logon_clicked event in the form Logon screen:

                    '2013-01-16 Ted Palmer
                    'Changed late binding to early binding per Experts-Exchange.
                    'go_wrdApp = CreateObject("Word.Application")
                    go_wrdApp = New Microsoft.Office.Interop.Word.Application()

From the PrintWord_Clicked event in a different form (screen):

        go_wrdApp = Marshal.GetActiveObject("Word.Application")

        '***** Debug Code -- Save 2013-01-14 by Ted Palmer
        If Not IsNothing(go_wrdApp) Then
            'Debug Code -- Save 2013-01-14 by Ted Palmer
            MessageBox.Show("go_wrdApp exists", _
            "AutoSubrogate® Debug Message:", MessageBoxButtons.OK, MessageBoxIcon.Stop)
            GoTo Exit_Point
        Else
            'Debug Code -- Save 2013-01-14 by Ted Palmer
            MessageBox.Show("go_wrdApp does NOT exists", _
            "AutoSubrogate® Debug Message:", MessageBoxButtons.OK, MessageBoxIcon.Stop)
            GoTo Exit_Point
        End If
MarshalDotGetActiveObject.JPG
CodeCruser:

I tried your suggestion and this is what I got. I attached a screen shot of an error message screen from the general exception handler at the end of the Try/Catch for this block of code.

You can see in the first line of the stack trace that it referes to the Marshal.GetActiveObject("Word.Application"). I  have the "go_wrdApp = New Microsoft.Office.Interop.Word.Application()" statement in a different class. I didn't get an error message about  putting this statement in a different class to create the MS-Word program object.

Do I need to import this "System.Runtime.InteropServices" in the class where I do the "New" statement? I already added the import where I do the Marshal statement because I got a fatal error message requiring it.

The CLR message was "Operation unavailable".

Thanks for your help,

Ted Palmer
MarshalDotGetActiveObject.JPG
I don't know why that error is generated.

>go_wrdApp = New Microsoft.Office.Interop.Word.Application()

This is creating a new word instance anyway. In the class, you just declare the object (I don't know it needs to be in a separate class), then use marshal to get an existing instance and only create new instance if there is no existing instance.
CodeCruser:

OK! I'll try that. Just FYI -- I may have to change this concept but the 'go_' in go_wrdApp stands for Global Object. It was my intent that I instantiate this program object at logon and make it available throughout the whole application program. I thought it would save some time not having to new up a MS-Word object everytime it was needed, but I have learned since the amount of time saved is trivial. I can be flexible.

Thanks for your help.

Ted Palmer
CodeCruser & sedgwick:

I was able to instantiate the MS-Word program object as described by CodeCruser both ways:

By moving the "go_wrdApp = New Microsoft.Office.Interop.Word.Application()" into the same class where I was testing the object reference variable with "If Not IsNothing(go_wrdApp) Then" and after adding the import statement to the place from where I was originally instantiating it. But now that I have it instantiated I am having trouble Disposing of it. I guess I'm just not as good of OOP programmer as I thought I am. Anyway trying to reconcile this better method with what I already have in place that basicly works is taking way too much of my time. So I am going to have to split the points, and use sedgwick's method for now as an expediency.

Maybe next time I can start off doing it the better way in the beginning and not have problems disposing of the object when I am finished with it.

Thank you both for your help.

Ted Palmer
Thank you both. I appreciate your patience.

Ted Palmer