奇怪的是,我想在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
函数返回参数或接口声明的某个地方弄错了,但是不知道还要检查什么。
在编写此插件时,我将提供任何建议和帮助。