Word Interop - System.InvalidOperationException in System.Windows.Forms.dll

Context:

Microsoft Visual Studio 2005 Version 8.0.50727.42 

Microsoft .NET Framework Version 2.0.50727

Word 2003 Interop


Problem:

I am trying to recreate the "AmbiguousMember" example from p. 31 of Whitechapel's "MS .NET Development for MS Office" using VB instead of VC#.

This involves implementing an event handler for the Word Quit event. In the event handler, I need to toggle the Enabled state of two buttons. This causes the following error:

A first chance exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll

The code behind the Form1 form is shown below. Form1 has two buttons: Button1 "Run Word"; Button2 "Quit Word". The event handler is intended to clean up if the user quits the Word application, and reset the buttons.

A net search indicates a known source of this error involves use of "MTA" apartment threading model instead of "STA". I can't figure out how the threading model is set in my VB project.

I dunno why this post is doublespaced.


Imports Word = Microsoft.Office.Interop.Word

Public Class Form1

Private wd As Word.Application

Public wdEvents4 As Word.ApplicationEvents4_Event

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

wd = New Word.Application

wd.Visible = True

wdEvents4 = CType(wd, Word.ApplicationEvents4_Event)

AddHandler wdEvents4.Quit, AddressOf Me.quitHandler

Button2.Enabled = True

Button1.Enabled = False

End Sub

Private Sub Button2_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button2.Click

RemoveHandler wdEvents4.Quit, AddressOf Me.quitHandler

wd.Quit()

wd = Nothing

Button1.Enabled = True

Button2.Enabled = False

GC.Collect()

GC.WaitForPendingFinalizers()

GC.Collect()

GC.WaitForPendingFinalizers()

End Sub

Private Sub quitHandler()

Debug.Print("In wdEvents4_Quit")

wd = Nothing

Button1.Enabled = True

Button2.Enabled = False

End Sub

End Class

 

 

 



Answer this question

Word Interop - System.InvalidOperationException in System.Windows.Forms.dll

  • RostaB

    Update

    OK, here is a solution. As described in this article , if I use the "Invoke" method on the Button1 and Button2 calls in the quitHandler, it works.

    In quitHandler, replace

    Button1.Enabled = True

    with

    Button1.Invoke(CType(AddressOf Button1Enable, MethodInvoker))

    where Button1Enable is just

    Private Sub Button1Enable()

    Button1.Enabled = True

    End Sub

    Likewise for Button2.


  • ntsoo

    Here is some additional information. When I catch the exception that occurs in the quitHandler, the message text says

    A first chance exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll

    Cross-thread operation not valid: Control 'Button1' accessed from a thread other than the thread it was created on.

    So this does appear to be related to a threading model issue. I tried to fix it by

    1) Adding a sub main with <STAThread()> attribute in my Form1 class as follows

    <STAThread()> _

    Public Shared Sub Main()

    Application.EnableVisualStyles()

    Application.Run(New Form1())

    End Sub

    2) In the Application Properties (Application tab), I unchecked the "Enable application framework" button so that I could change the Startup object to "Sub Main".

    I still get the same error.

     

     

     


  • mshvw

    Update

    1) I looked at properties of the CurrentThread inside the Button1_Click and quitHandler methods. The thread executing Button1_Click is already set to ApartmentState.STA. There was no need for me to add the Sub Main and STAThread attribute. This puzzles me because I have seen in a half dozen places that managed threads are started MTA. There are, however, some hits on STA being required for System.Windows.Forms apps, so something is happening behind the scenes to make it STA.

    2) The caller of quitHandler, who I assume is the Runtime Callable Wrapper (RCW) around my wdEvents4 ref, is running MTA. I guess this means it thinks it can execute anything it finds in there without marshaling, and when it tries to I get the exception.

    3) Setting the MTAThread attribute on Sub Main does not help. I think I'm hitting the System.Windows.Forms STA issue there.

    Perhaps if I had some way of starting the RCW as STA, then when it calls the quitHandler the runtime will handle the marshaling

    This is obviously just a learning exercise for me, but would appreciate any ideas.


  • Word Interop - System.InvalidOperationException in System.Windows.Forms.dll