C#调用非托管DLL的两种方式
在开发过程中,我们经常需要调用一些非托管的DLL库,比如用Delphi编写的DLL。本文将介绍两种在C#中调用非托管DLL的方法。
示例DLL
首先,我们有一个Delphi编写的DLL,它导出了一个名为MyFunction
的方法:
delphi
library testDLL;
uses
SysUtils,
Dialogs,
Classes;
{$R *.res}
function MyFunction(param1: Integer): Integer; stdcall;
begin
Result := param1 + 1;
end;
exports
MyFunction;
begin
end.
方式一:直接调用
这是最常见的调用方式,通过DllImport
属性直接导入非托管方法。
csharp
[DllImport("testDLL.dll")]
static extern int MyFunction(int a);
然后,你可以直接调用这个方法:
csharp
int i = MyFunction(123);
方式二:使用本地委托
另一种方法是将非托管方法转换为本地委托。这种方式更灵活,但需要更多的代码。
辅助方法
首先,我们需要一些辅助方法来加载和卸载DLL:
csharp
// 辅助方法:加载DLL
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LoadLibrary(string lpFileName);
// 辅助方法:卸载DLL
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool FreeLibrary(IntPtr hModule);
// 获取方法指针
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
定义委托
接下来,定义一个与DLL中方法参数一致的委托:
csharp
public delegate int MyFunctionDelphiDelegate(int param1);
使用委托调用方法
最后,使用委托来调用非托管方法:
csharp
void run()
{
// 加载DLL
IntPtr dllHandle = LoadLibrary("testDLL.dll");
if (dllHandle == IntPtr.Zero)
{
var err = Marshal.GetHRForLastWin32Error();
}
// 获取方法指针
IntPtr functionPointer = GetProcAddress(dllHandle, "MyFunction");
MyFunctionDelphiDelegate my = (MyFunctionDelphiDelegate)Marshal.GetDelegateForFunctionPointer(functionPointer, typeof(MyFunctionDelphiDelegate));
// 调用方法
int i = my(1);
// 释放DLL
FreeLibrary(dllHandle);
}
注意事项
- 位数一致性:确保你的程序和DLL的位数(32位或64位)保持一致。
- 字符串参数 :Delphi方法中的参数和返回值如果是字符串,不能直接使用
String
类型。需要使用PAnsiChar
或PChar
,并搭配StrNew
使用。 - 返回值 :如果方法返回值为字符串,需要使用
IntPtr
类型,并通过Marshal.PtrToStringAnsi(strIntPtr)
来获取实际的字符串值。
通过这两种方式,你可以灵活地在C#中调用非托管的DLL库,满足不同的开发需求。