This C# code is in a .NET 4.5 ComVisible assembly:
C# Code
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("22341223-9264-12AB-C1B4-B4F112014C31")]
public interface IComWithTask
{
void LongExecutionMethod(double x);
void LongExecutionMethodAsync(double x);
}
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[Guid("23844123-9274-12CB-C1F4-B4F1521E4F33")]
public interface IComWithTaskEvents
{
void OnLongExecutionMethodComplete(double x);
}
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IComWithTaskEvents))]
[Guid("E4F27AA4-1932-2196-1234-121CF2722C42")]
[ProgId("ComWithTask")]
public class ComWithTask : IComWithTask
{
[ComVisible(false)]
public delegate void LongExecutionMethodComplete(double x);
public event LongExecutionMethodComplete OnLongExecutionMethodComplete;
public void LongExecutionMethod(double x)
{
if (OnLongExecutionMethodComplete != null)
{
OnLongExecutionMethodComplete(x * x);
}
}
public void LongExecutionMethodAsync(double x)
{
Task.Factory.StartNew(state =>
{
var onLongExecutionMethodComplete = OnLongExecutionMethodComplete;
if (onLongExecutionMethodComplete != null)
{
onLongExecutionMethodComplete(x * x);
}
}, null);
}
}
From Excel 2010 32bit VBA, I’ve got the following behavior:
VBA Code
Private WithEvents oComWithTask As ComWithTask
Public Sub Class_Initialize()
Set oComWithTask = New ComWithTask
End Sub
Public Sub LongExecutionMethod()
' Works as expected
Call oComWithTask.LongExecutionMethod(2)
End Sub
Public Sub LongExecutionMethodAsync()
' Does NOT work!
Call oComWithTask.LongExecutionMethodAsync(3)
End Sub
Private Sub oComWithTask_OnLongExecutionMethodComplete(ByVal x As Double)
MsgBox x
End Sub
I am aware that I am spinning a thread inside .NET when calling LongExecutionMethodAsync, and I am aware that office applications are single threaded.
I did find a great literature on calling COM components from .NET in a multithreaded way, but couldn’t find any resource that goes the other way around, i.e. VBA calling a multithreaded .NET wrapped with COM method.
Any thoughts on how to make
LongExecutionMethodAsyncwork with
multithreading and could you point me to any related resource on this
subject?
Also, do you have other suggestions for triggering async events in VBA?
The code above is working as expected, the problem was the life span of the object in VBA which was dying before the raise of the event.