我正在创建一个 .net WebAPI,以促进从 Delphi 代码逐步迁移到 C#,但我们的代码库非常大,有 150 万多行代码。因此,我们尝试将应用程序分解为可以加载到 C# API 中的小库,然后随着时间的推移逐渐重写功能或服务。我们决定我们的库将导出 3 个常用函数:
Initialize
,Execute
,DisposeStr
。我们创建的所有 dll 都会导出这些函数,以便我们有一个通用的方式与我们的本机代码进行通信。
我的问题是,我将有一个
DelphiEmployeeService.cs
、DelphiWorktimeService.cs
等(可能超过一百次),并且我需要在每个服务包装器的开头有基本相同的行:
[LibraryImport("<DLLNAME>", EntryPoint = "Initialize")]
[return: MarshalAs(UnmanagedType.Bool)]
[UnmanagedCallConv(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
private static partial bool Initialize();
[LibraryImport("<DLLNAME>", EntryPoint = "Execute", StringMarshalling = StringMarshalling.Utf16)]
[UnmanagedCallConv(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
private static partial IntPtr Execute(string parameters);
[LibraryImport("<DLLNAME>", EntryPoint = "DisposeStr")]
[UnmanagedCallConv(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
private static partial void DisposeStr(IntPtr str);
为了解决这个问题,我想创建一个
DelphiImplementation.cs
基类,但我不确定如何让后代注册要加载的 dll 名称...
我想要的是类似的东西
public class DelphiImplementation
{
protected abstract string LibraryName;
[LibraryImport(LibraryName, EntryPoint = "Initialize")]
[return: MarshalAs(UnmanagedType.Bool)]
[UnmanagedCallConv(CallConvs = new Type[] {typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
private static partial bool Initialize();
[LibraryImport(LibraryName, EntryPoint = "Execute", StringMarshalling = StringMarshalling.Utf16)]
[UnmanagedCallConv(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
private static partial IntPtr Execute(string parameters);
[LibraryImport(LibraryName, EntryPoint = "DisposeStr")]
[UnmanagedCallConv(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
private static partial void DisposeStr(IntPtr str);
}
public class EmployeeDelphiService : DelphiImplementation
{
protected override string LibraryName => "Employee.dll"
}
这样的事情可能吗?
NativeLibrary
类动态加载 DLL 并执行函数。从函数指针创建委托并将它们存储在类中以便调用它们应该相当简单。
public class DelphiImplementation
{
protected abstract string LibraryName { get; }
[return: MarshalAs(UnmanagedType.Bool)]
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
protected delegate bool InitializeDelegate();
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
protected delegate IntPtr ExecuteDelegate(string parameters);
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
protected delegate void DisposeStrDelegate(IntPtr str);
private IntPtr Handle { get; } = NativeLibrary.Load(LibraryName);
protected InitializeDelegate Initialize { get; }
protected ExecuteDelegate Execute { get; }
protected InitializeDelegate DisposeStr { get; }
protected DelphiImplementation()
{
Initialize = Marshal.GetDelegateForFunctionPointer<InitializeDelegate>(NativeLibrary.GetExport(Handle, nameof(Initialize)));
Execute = Marshal.GetDelegateForFunctionPointer<ExecuteDelegate>(NativeLibrary.GetExport(Handle, nameof(Execute)));
DisposeStr = Marshal.GetDelegateForFunctionPointer<DisposeStrDelegate>(NativeLibrary.GetExport(Handle, nameof(DisposeStr)));
}
}
您可以简单地做
someImplementation.Initialize()
等