I'm creating a .NET component that I want to use to simplify working with an application that supports a COM Automation interface. One of the features of the component is that it will display dialogs to collect information from the user. However, in the workflow that I need to use, the dialog is partially displayed and then it freezes.
I've created a simplified version of what I'm doing using Excel. I'm actually using another application with a COM Automation interface but the problem is a general problem and is reproducible using Excel, which most people should have. Here's a brief description of the various pieces. I'm writing this in Visual Basic but assume the same problem will occurr with C# although I haven't tested that.
.NET Class Library project "MyCmd"
Class MyDef
When an instance of the MyDef class is created, it gets and saves the currently active Excel sheet. It also listens to the SelectionChange event of the Excel Sheet object. In response to the SelectionChange event, it creates an instance of the "MyCmd" class (described below) and fires a custom CommandCreated event, passing the created MyCmd object.
It also supports a public method called ForceEvent which does the same thing as the SelectionChange event. This is used to test the functionality using a different code path.
Imports Microsoft.Office.Interop.Excel
Public Class MyDef
Private WithEvents _sheet As Microsoft.Office.Interop.Excel.Worksheet
Public Event CommandCreated(ByVal command As MyCmd)
Public Sub New()
_sheet = g_app.ActiveSheet
End Sub
Public Sub ForceEvent()
Dim cmd As New MyCmd()
RaiseEvent CommandCreated(cmd)
End Sub
Private Sub _sheet_SelectionChange(Target As Range) Handles _sheet.SelectionChange
Me.ForceEvent()
End Sub
End Class
Class MyCmd
A class that contains a single method that creates a new instance of a dialog and displays it.
Public Class MyCmd
Private _form As Form = Nothing
Public Sub ShowDialog()
If _form Is Nothing Then
_form = New CommandDialog
End If
_form.Visible = True
End Sub
End Class
The dialog I'm testing with is a form (named "CommandDialog") with a couple of buttons and no code behind them. I'm just testing to see if the form is displayed as expected.
Globals Module
I'm also using the code below to connect to Excel and get the Excel Application object. It works as expected.
Public Module Globals
Private _app As Microsoft.Office.Interop.Excel.Application = Nothing
Public Function g_app() As Object
If Not _app Is Nothing Then
Return _app
Else
Try
_app = GetObject(, "Excel.Application")
Catch ex As Exception
MsgBox("Excel must be running")
Return Nothing
End Try
Return _app
End If
End Function
End Module
.NET Class Library project "MyCmd"
I also have another project called "CommandFramework" that is using the MyCmd class library. This second project is a Windows Form App that contains two buttons and an event handler for the CommandCreated event supported by MyDef. The entire code is below.
When the first button is clicked, it creates an instance of the MyDef class, which because of the WithEvent declaration, also sets up an event handler for the CommandCreated event. Clicking the second button calls the ForceEvent method which results in firing the CommandCreated event and displays the dialog. I can also click in a cell in the active Excel sheet and that causes the SelectionChange event to be fired and results in the ForceEvent method to be called. However, in this case, the dialog is only partially displayed and is frozen. The code flow is identical except for the trigger which is either clicking the second button or receiving the Excel SelectionChange event. The second case causes the freeze.
Public Class CommandFramework
Private WithEvents _cmdDef As MyCommand.MyDef = Nothing
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
_cmdDef = New MyCommand.MyDef
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
_cmdDef.ForceEvent()
End Sub
Private Sub cmdDef_CommandCreated(command As MyCommand.MyCmd) Handles _cmdDef.CommandCreated
command.ShowDialog()
End Sub
End Class
Does anyone have any ideas what the cause of the problem is and what a solution might be? My guess is it's some kind of threading issue and there's a deadlock but I don't know enough about that area to even begin diagnosing or trying something else.