As I explained in comment above I had wrong interface search in registry for NewAsyncCallbackTest.INewCallback instead of INewCallback and I have also used NewAsyncCallbackTest.INewCallback in VBA so I thought I miss INewCallback.
So as @Hans Passant said: nothing wrong with C# Code: NewAsyncTaskRunner.cs. Used attribute InterfaceIsIDispatch. DLL is properly registered.
So the correct approach in VBA:
class module TaskRunnerEventHandler
Option Compare Database
Option Explicit
Implements INewCallback
Private Sub INewCallback_OnTaskCompleted(ByVal result As String)
Debug.Print result
End Sub
Usage module
Option Compare Database
Option Explicit
Dim obj As Object
Dim CallbackHandler As CallbackHandler
Sub StartTask(taskParam As String)
Set CallbackHandler = New CallbackHandler
Set obj = CreateObject("NewAsyncCallbackTest.NewAsyncTaskRunner")
obj.RunAsyncTask taskParam, CallbackHandler
End Sub
Sub TestMultipleTasks()
Dim i As Integer
' Loop ten times to check multiple tasks
For i = 1 To 10
StartTask "Task " & i
Sleep 100
Debug.Print "Task " & i & " is running asynchronously!"
Next i
End Sub
But I'm also curious to use [ComSourceInterfaces] attribute as @Hans Passant mentioned as standard approach in VBA but I'm doing some wrong...
ITaskRunnerEvents.cs
using System;
using System.Runtime.InteropServices;
namespace ComEventTest
{
[ComVisible(true)]
[Guid("c8614250-4291-4fb0-8b45-4aa305b0c595")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ITaskRunnerEvents
{
void OnTaskCompleted(string result);
}
}
TaskRunner.cs
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace ComEventTest
{
[ComVisible(true)]
[Guid("ac9de195-73e8-44ae-8cf1-d8f110421923")]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(ITaskRunnerEvents))]
public class TaskRunner
{
// Declare the delegate for the event
public delegate void TaskCompletedEventHandler(string result);
// Declare the event
public event TaskCompletedEventHandler OnTaskCompleted;
// Method to start the async task
public void RunTask(string input)
{
Task.Run(async () =>
{
await Task.Delay(5000); // Simulate work
OnTaskCompleted?.Invoke($"Task completed with input: {input}");
});
}
}
}
VBA Side:
ClassModule TaskRunnerEventHandler
Option Compare Database
Option Explicit
Public WithEvents taskRunner As ComEventTest.taskRunner
Private Sub taskRunner_OnTaskCompleted(ByVal result As String)
MsgBox result
End Sub
Public Sub InitializeTaskRunner()
Set taskRunner = New ComEventTest.taskRunner
End Sub
Usage module
Sub TestTaskRunner()
Set eventHandler = New TaskRunnerEventHandler
eventHandler.InitializeTaskRunner
eventHandler.taskRunner.RunTask "Test Input"
End Sub
I have a problem here: eventHandler.taskRunner.RunTask "Test Input" err: Method or data member not found