Call back events from WPF .Net framework Visual basic plugin to Delphi host application

I have created the WPF VB.net plugin that is hosted by a Delphi 11.3 application. The plugin works, but I’m trying to establish callback events from vb.net to delphi.

Here is my .net Interface

Imports System.Runtime.InteropServices
Imports RemObjects.Hydra.CrossPlatform

Public Delegate Sub NotifyEventHandler(ByVal sender As Object)
<ComVisible(True)>
<Guid("E2FDD28C-19DC-41DF-8D6B-ADCA3104B8A1")>   ' ← Generate a new GUID (see below)
Public Interface ISpeechKitPlugin
	Inherits IHYCrossPlatformInterface


	' Methods that Delphi can call on the plugin (.NET)
	Sub StartSpeech()
	Sub StopSpeech()
	Function GetCurrentText() As String
	Sub SetText(ByVal value As String)

	' Properties (optional - implemented as getter/setter methods)
	Function GetIsActive() As Boolean
	Sub SetIsActive(ByVal value As Boolean)

	' Event setters - Delphi will assign its handlers here
	Sub Set_OnSpeechStarted(ByVal handler As NotifyEventHandler)
	Sub Set_OnSpeechStopped(ByVal handler As NotifyEventHandler)
	Sub Set_OnTextChanged(ByVal handler As NotifyEventHandler)

	' Optional: Method the plugin can call on the host (if host implements it)
	Sub HostCommand(ByVal command As String)

End Interface

Here is the imported interface in delphi. ( I had to define the interface in VB.net as the import from Delphi to vb.net in visual studio 2022 doesn’t seem to exist. I also had to add the NotifyEventHandler type as the hydra tool doesn’t seem to create it.

interface

uses
  Hydra.Core.Interfaces;

type
  NotifyEventHandler = procedure(sender: TObject) of object;

type
  ISpeechKitPlugin = interface;

// Original name: DiaSpeechKitPlugin.ISpeechKitPlugin
ISpeechKitPlugin = interface(IHYCrossPlatformInterface)
['{E2FDD28C-19DC-41DF-8D6B-ADCA3104B8A1}']
	procedure StartSpeech; safecall;
	procedure StopSpeech; safecall;
	function GetCurrentText: WideString; safecall;
	procedure SetText(const value: WideString); safecall;
	function GetIsActive: WordBool; safecall;
	procedure SetIsActive(const value: WordBool); safecall;
	procedure Set_OnSpeechStarted(const handler: NotifyEventHandler); safecall;
	procedure Set_OnSpeechStopped(const handler: NotifyEventHandler); safecall;
	procedure Set_OnTextChanged(const handler: NotifyEventHandler); safecall;
	procedure HostCommand(const command: WideString); safecall;
end;

implementation
end.

In the main Delphi application I define a call back procedure.

procedure OnSpeechStartedHandler(Sender: TObject);

Then Later on in the application I try to use the interface to assign the procedure.

if Supports(fPluginInstance, ISpeechKitPlugin, fSpeechKit) then
begin
  fSpeechKit.StartSpeech;
  fSpeechKit.SetText(‘Hello from Delphi’);
  // Assign event handlers
  fSpeechKit.Set_OnSpeechStarted(OnSpeechStartedHandler);
end;

When the “Set_OnspeechStarted(OnSpeechStartedHandler); is called the application crashes hard. I cannot find an example of a TnotifyEvent callback event in the samples. What is the proper way to implement this? The AI Chat bots have offered varying solutions that don’t work.

Thanks in advance for any help.

Hi,

Delphi objects (TObject) and .NET objects (object) are incompatible. this is a reason why you have crash.

I can suggest to use interfaces instead of objects. check more at Passing Interfaces between Host and Plugins

I have an interface. I posted it in the original message. I’m just not clear how can trigger events in both the VB.Net plugin that call a function in Delphi The interface example I posted has procedures that I call that affect the plugin.

Hi,

Public Delegate Sub NotifyEventHandler(ByVal sender As Object)
NotifyEventHandler = procedure(sender: TObject) of object;

You can’t use NotifyEventHandler type in ISpeechKitPlugin because

How can I structure a basic call back that passes a string or a record type?

Hi,

You can use interfaces like

  IMyInterface= interface
  ['{E2FDD28C-3333-2222-1111-ADCA3104B8A1}']
     function GetValue: string; safecall;
     procedure SetValue(value: string); safecall;
     function GetValue2: string; safecall;
     procedure SetValue2(value: string); safecall;
     procedure DoSomething;safecall;

     property Value: string read GetValue write SetValue;
     property Value2: string read GetValue2 write SetValue2;
  end;
procedure Set_OnSpeechStarted(const handler: IMyInterface); safecall;

so you can read/write string or struct values.


in brief, you create wrapper for your object

Kind of a side question… I’m using VB.net for various reasons. From my VB.net project in visual studio 2022 I don’t have the option to import an interface from Delphi. Maybe i’m not looking in the right place.

Hi,

AFAIR you can import only plugin interfaces.

so you can’t import interfaces from delphi host into .NET plugin and vice versa

It is in the Hydra documentation, Half way down the page.

You can import delphi plugin .pas into .NET host app (.NET Framework only, known issue) and import .net dll into Delphi host.

1 Like

What is the difference between a WPF .Net Core and a WPF .Net framework plugin? I chose .Net framework for my application and it seems to be working, but I maybe .net core would have worked the same.

Hi,

they use different frameworks. this is main difference.