Oxygene Host and Oxygene Hydra Plugin : System.InvalidCastException when calling plugin methods from host

Hi,

I’m looking at migrating my .Net Oxygene plugins from a Delphi host application into a .Net Oxygene host. Should be relatively straight forward, but I run in to a System.InvalidCastException everytime I try to call a method on a plugin.

I have reverted to looking at the ManagedOxygeneHost sample application and trying to load a simple plugin with one interface defined. That also gives me the same issue :-

The only modifications to the sample host application are to add the code file containing the interface definition and call it from method MainForm.lb_Plugins_DoubleClick i.e.

namespace DUF003;

uses
  RemObjects.Hydra.CrossPlatform,
  System.Runtime.InteropServices;

interface
type
	[Guid('37E83B67-4943-43AB-9AF6-EBAF981BF793')]
  	IMessageProcessor = public interface(IHYCrossPlatformInterface)
   	method ProcessMessage(Message: String);
  	end;

implementation

end.

and call the plugin from the double click method with :-

self.fCurrentPlugin := self.moduleManager1.CreateInstance(PluginDescriptor(self.lb_Plugins.SelectedItem));
self.pnl_Host.HostPlugin(self.fCurrentPlugin);

(self.fCurrentPlugin as DUF003.IMessageProcessor).ProcessMessage('BOO !');

As you can see, the module instance loads OK and is hosted in the panel (it just has a simple label with “CAT001 Test” as the caption). The exception occurs on the above line of code, which also occurs in my real world code.

Other points that may be relevant :-

In my real world code, I have looked at the interfaces supported by the plugin and my interfaces are listed i.e. the code below would list the IMessageProcessor interface in a listbox.

var objType: &Type := typeOf(self.CurrentPlugin);

//  Getting interface of specified name
//  using GetField(String) Method
var minterface: array of &Type := objType.GetInterfaces();
for i: Integer := 0 to minterface.Length - 1 do
	listInfo.Items.Add(minterface[i]);

The “Import Plugin Interface” does not seem to work :-

image

If I import the .pas file containing the interface listed above, all I get is a file with the code shown below. I therefore link to the plugin unit containing the interface definition i.e. the file shown above (in the DUF003 namespace).

namespace ManagedHost;

// Imported cross-patform Hydra plugin interfaces
// Some interfaces may not be imported or imported incorrectly due to the following issues:
// [1:1] Unit expected
// 

interface

implementation

end.

I also modified the AssemblyInfo.pas of the host application to include

[assembly: ComVisible(true)]

which I believe is as per the “passing interfaces” documentation.

Can you suggest how to move forward (or supply a very simple host / plugin Oxygene sample that works when calling a method on the plugin) ?

It would be way more effective if you could provide a tetcase (your host and your plugin code). Just replace your actual business logic with dummy code that would return some dummy data.
Send it to support@ so we will keep it private.

Hi Anton,

Here’s a sample solution (DUF.sln), that has two projects (DUF002 - Host and DUF003 - Client).

The host is effectively your managed oxygene host example (recoded as I don’t get a design surface for the form in that application). The client does nothing other than expose the IMessageProcessor interface. I’ve left the compiled DUF003.dll in the debug directory of DUF002 i.e. the host will load DUF*.dll from there.

DUF.zip (159.1 KB)

Hopefully you’ll spot what is causing the problem ?

Hi Anton,

Just checking in to see if you’ve had chance to review the dummy code I sent through ?

Sure

You need to put your IMessageProcessor interface definition into a separate assembly and reference this assembly from both host and plugin projects. Otherwise .NET runtime won’t be able to cast plugin type to its interface type

Yes, of course. Thanks Anton.

Following up on this Anton… Moving the interface to a separate assembly and referencing from there has worked for a .NET plugin in a .NET host.

I do now seem to have the reverse problem - an “interface not supported” issue when using such a .NET plugin in a Delphi host. I’ve modified the sample attached to show how I have implemented this in .NET. I’ve not explicitly tried this plugin in Delphi, but in my production code, I’ve replicated the method of taking the interface into a separate assembly and that results in the “interface not supported” problem.

As I’m looking to migrate a lot of plugins from a Delphi host to a .NET one (over time), I’d like to be a in a position where I can have a plugin that works in both a .NET host and Delphi (which is pretty much the purpose of Hydra, so I must be missing something!). At the moment, I’m only able to define things to work one way or another.

Can you see anything obviously problematic with the attached shared assembly (DUF004) approach which would prevent the plugin method being visible / callable from a Delphi host that had imported the interface ?

DUF II.zip (1.2 MB)

Hello

Here is the sample of a plugin where plugin interface and plugin logic are defined in separate assemblies:
Delphi WPF.zip (14.3 KB)
This plugin can be loaded by the Delphi host application from the Delphi WPF sample.

The only change required to make the plugin work is to mark the interfaces assembly as ComVisible. You need to change code line in the AssemblyInfo.pas file from

[assembly: ComVisible(false)]

to

[assembly: ComVisible(true)]

Regards

Thanks Anton. I’ll take a look in the next day or so and let you know how I get on.

Just to confirm that setting [assembly: ComVisible(true)] worked. In my “DUF” example in the I had set the value in the actual plugin, but NOT in the interface DLL.