如何使用delphi-reliant插件基础结构在C#上为程序编写dll插件

时间:2019-06-27 06:36:25

标签: c# delphi interface dllexport

奇怪的是,我想在c#上为在Delphi上编写的程序编写一个插件(对于非CIS用户,请下载Master https://westbyte.com/dm/或Internet Download Accelerator https://westbyte.com/ida/)。我知道,很奇怪。程序开发人员提供了用Delphi编写的模板插件,我现在尝试使用Unmanaged Exports库(DllExport)在c#上重写模板插件,但到目前为止还没有运气。

在Delphi插件模板的代码下面,它按预期运行。

程序代码

library dm_delphi_plugin;

uses
  System.SysUtils, System.Classes, DMPluginIntf in 'DMPluginIntf.pas', dmtest_pluginImpl in 'dmtest_pluginImpl.pas';

{$R *.res}

function RegisterPlugIn: IDMPlugIn; stdcall;
begin
  try
    Result := TDMTestPlugIn.Create;
  except
    Result := nil;
  end;
end;

exports RegisterPlugIn;

begin
end.

接口定义

unit DMPluginIntf;

interface

type
  IDMInterface = interface(IUnknown)
    ['{B412B405-0578-4B99-BB06-368CDA0B2F8C}']
    function DoAction(action: WideString; parameters: WideString)
      : WideString; stdcall;
  end;

  IDMPlugIn = interface(IUnknown)
    ['{959CD0D3-83FD-40F7-A75A-E5C6500B58DF}']
    function getID: WideString; stdcall;
    function GetName: WideString; stdcall;
    function GetVersion: WideString; stdcall;
    function GetDescription(language: WideString): WideString; stdcall;
    function GetEmail: WideString; stdcall;
    function GetHomepage: WideString; stdcall;
    function GetCopyright: WideString; stdcall;
    function GetMinAppVersion: WideString; stdcall;
    procedure PluginInit(_IDmInterface: IDMInterface); stdcall;
    procedure PluginConfigure(params: WideString); stdcall;
    procedure BeforeUnload; stdcall;
    function EventRaised(eventType: WideString; eventData: WideString)
      : WideString; stdcall;
    property ID: WideString read getID;
  end;

implementation
end.

类实现

unit dmtest_pluginImpl;

interface

uses DMPluginIntf, Classes, Vcl.Dialogs;

const
  myPluginID = '{5857F431-C0D8-487C-9A4E-9C2E5A9005FA}';
  myPluginName = 'DM Delphi Template Plugin';
  myPluginVersion = '0.1.1.1';
  myPluginEmail = 'e@mail.com';
  myPluginHomePage = 'https://google.com/';
  myPluginCopyRight = chr(169) + '2019 Developer';
  myMinNeedAppVersion = '6.17.1';
  myPluginDescription = 'Test Plug-in for show how create plugins for DM';

type
  TDMTestPlugIn = class(TInterfacedObject, IDMPlugIn)
  private
    myIDmInterface: IDmInterface;
  protected

  public
    function getID: WideString; stdcall;
    function GetName: WideString; stdcall;
    function GetVersion: WideString; stdcall;
    function GetDescription(language: WideString): WideString; stdcall;
    function GetEmail: WideString; stdcall;
    function GetHomepage: WideString; stdcall;
    function GetCopyright: WideString; stdcall;
    function GetMinAppVersion: WideString; stdcall;
    procedure PluginInit(_IDmInterface: IDmInterface); stdcall;
    procedure PluginConfigure(params: WideString); stdcall;
    procedure BeforeUnload; stdcall;
    function EventRaised(eventType: WideString; eventData: WideString)
      : WideString; stdcall;
    property ID: WideString read getID;
  end;

implementation

function TDMTestPlugIn.GetName: WideString;
begin
  Result := myPluginName;
end;

function TDMTestPlugIn.GetVersion: WideString;
begin
  Result := myPluginVersion;
end;

function TDMTestPlugIn.GetDescription(language: WideString): WideString;
begin
  { code is simplified }
  Result := myPluginDescription;
end;

function TDMTestPlugIn.getID: WideString; stdcall;
begin
  Result := myPluginID;
end;

procedure TDMTestPlugIn.PluginInit(_IDmInterface: IDmInterface);
begin
  myIDmInterface := _IDmInterface;
end;

procedure TDMTestPlugIn.BeforeUnload;
begin
  myIDmInterface := nil;
end;

procedure TDMTestPlugIn.PluginConfigure(params: WideString);
begin
  ShowMessage('Showing config form');
  myIDmInterface.DoAction('AddingURL',
    '<url>http://www.westbyte.com/plugin</url> <sectionslimit>2</sectionslimit>');
end;

function TDMTestPlugIn.EventRaised(eventType: WideString; eventData: WideString)
  : WideString;
begin
  if eventType = 'dm_download_added' then
    ShowMessage('Added ID=' + eventData);
end;

function TDMTestPlugIn.GetEmail: WideString;
begin
  Result := myPluginEmail;
end;

function TDMTestPlugIn.GetHomepage: WideString;
begin
  Result := myPluginHomePage;
end;

function TDMTestPlugIn.GetCopyright: WideString;
begin
  Result := myPluginCopyRight;
end;

function TDMTestPlugIn.GetMinAppVersion: WideString;
begin
  Result := myMinNeedAppVersion;
end;

end.

在我的C#实现下面,这与我期望的不一样。 RegisterPlugIn在程序加载时调用了一次,但之后没有任何反应。从测试插件中,我确定了要调用的下一个函数是getID()(该程序似乎未使用属性ID)。

接口定义

namespace dm_csharp_plugin
{
    [ComImport]
    [ComVisible(true)]
    [Guid("B412B405-0578-4B99-BB06-368CDA0B2F8C"),
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IDMInterface
    {
        string DoAction([MarshalAs(UnmanagedType.BStr)]string action, [MarshalAs(UnmanagedType.BStr)]string parameters);
    }

    [ComVisible(true)]
    [Guid("959CD0D3-83FD-40F7-A75A-E5C6500B58DF")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    interface IDMPlugin
    {
        [return: MarshalAs(UnmanagedType.BStr)]
        string getID();

        [return: MarshalAs(UnmanagedType.BStr)]
        string GetName();

        [return: MarshalAs(UnmanagedType.BStr)]
        string GetVersion();

        [return: MarshalAs(UnmanagedType.BStr)]
        string GetDescription([MarshalAs(UnmanagedType.BStr)]string language);

        [return: MarshalAs(UnmanagedType.BStr)]
        string GetEmail();

        [return: MarshalAs(UnmanagedType.BStr)]
        string GetHomepage();

        [return: MarshalAs(UnmanagedType.BStr)]
        string GetCopyright();

        [return: MarshalAs(UnmanagedType.BStr)]
        string GetMinAppVersion();

        void PluginInit([MarshalAs(UnmanagedType.Interface)]IDMInterface _IDmInterface);

        void PluginConfigure();

        void BeforeUnload();

        [return: MarshalAs(UnmanagedType.BStr)]
        string EventRaised([MarshalAs(UnmanagedType.BStr)]string eventType, [MarshalAs(UnmanagedType.BStr)]string eventData);

        string ID { [return: MarshalAs(UnmanagedType.BStr)]get; }
    }
}

类实现

namespace dm_csharp_plugin
{
    public class Win32MsgBox
    {
        [DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "MessageBox")]
        private static extern int _MessageBox(IntPtr hWnd, String text, String caption, uint type);

        public static void MessageBox(string text, string caption)
        {
            _MessageBox(new IntPtr(0), text, caption, 0);
        }
    }

    public class DMCSharpPlugin : Object, IDMPlugin
    {
        [return: MarshalAs(UnmanagedType.BStr)]
        public string GetCopyright()
        {
            return "";
        }

        [return: MarshalAs(UnmanagedType.BStr)]
        public string GetDescription(string language)
        {
            return "";
        }

        [return: MarshalAs(UnmanagedType.BStr)]
        public string GetEmail()
        {
            return "";
        }

        [return: MarshalAs(UnmanagedType.BStr)]
        public string GetHomepage()
        {
            return "";
        }

        [return: MarshalAs(UnmanagedType.BStr)]
        public string getID()
        {
            Win32MsgBox.MessageBox("getID()", "Method called");
            return "{5857F431-C0D8-487C-9A4E-9C2E5A9005FA}";
        }

        [return: MarshalAs(UnmanagedType.BStr)]
        public string GetMinAppVersion()
        {
            return "6.17.1";
        }

        [return: MarshalAs(UnmanagedType.BStr)]
        public string GetName()
        {
            return "";
        }

        [return: MarshalAs(UnmanagedType.BStr)]
        public string GetVersion()
        {
            return "";
        }

        public void PluginInit([MarshalAs(UnmanagedType.Interface)]IDMInterface dmInstance) { }

        public void PluginConfigure() { }

        [return: MarshalAs(UnmanagedType.BStr)]
        public string EventRaised([MarshalAs(UnmanagedType.BStr)]string eventType, [MarshalAs(UnmanagedType.BStr)]string eventData)
        {
            return "";
        }

        public void BeforeUnload() { }

        public string ID
        {
            [return: MarshalAs(UnmanagedType.BStr)]
            get
            {
                Win32MsgBox.MessageBox("ID property readed", "Method called");

                return "";
            }
        }

    }

    public static class Exports
    {
        [DllExport]
        [return: MarshalAs(UnmanagedType.Interface)]
        public static DMCSharpPlugin RegisterPlugIn()
        {
            Win32MsgBox.MessageBox("RegisterPlugIn begin", "Hello Dialog");
            return new DMCSharpPlugin();
        }
    }
}

我还尝试将RegisterPlugIn重写为一个过程,但是没有运气:

        [DllExport(CallingConvention = CallingConvention.StdCall)]
        public static void RegisterPlugIn([MarshalAs(UnmanagedType.Interface)] out DMCSharpPlugin result)
        {
            result = new DMCSharpPlugin();
        }

我想我在RegisterPlugIn函数返回参数或接口声明的某个地方弄错了,但是不知道还要检查什么。

在编写此插件时,我将提供任何建议和帮助。

0 个答案:

没有答案