0%

CSharp调用C++ dll

C#中动态加载C++ DLL文件

在C#中动态加载C++ DLL(动态链接库)可以通过几种方式实现。下面我将介绍最常用的方法:

1. 使用DllImport特性(静态加载)

这是最常见的方式,虽然不是完全动态的,但值得了解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
using System;
using System.Runtime.InteropServices;

class Program
{
// 声明DLL中的函数
[DllImport("YourCppDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int YourCppFunction(int param1, string param2);

static void Main()
{
// 调用DLL中的函数
int result = YourCppFunction(123, "test");
Console.WriteLine($"Result: {result}");
}
}

2. 使用LoadLibrary和GetProcAddress(真正动态加载)

如果你想在运行时决定加载哪个DLL,可以使用Windows API:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
using System;
using System.Runtime.InteropServices;

class Program
{
// 导入Windows API函数
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LoadLibrary(string dllToLoad);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool FreeLibrary(IntPtr hModule);

// 定义委托类型匹配C++函数签名
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int YourCppFunctionDelegate(int param1, string param2);

static void Main()
{
IntPtr pDll = LoadLibrary(@"YourCppDll.dll");
if (pDll == IntPtr.Zero)
{
Console.WriteLine("Failed to load DLL");
return;
}

IntPtr pAddressOfFunctionToCall = GetProcAddress(pDll, "YourCppFunction");
if (pAddressOfFunctionToCall == IntPtr.Zero)
{
Console.WriteLine("Failed to find function");
FreeLibrary(pDll);
return;
}

// 将函数指针转换为委托
YourCppFunctionDelegate yourFunction = Marshal.GetDelegateForFunctionPointer<YourCppFunctionDelegate>(pAddressOfFunctionToCall);

// 调用函数
int result = yourFunction(123, "test");
Console.WriteLine($"Result: {result}");

// 释放DLL
FreeLibrary(pDll);
}
}

3. 使用COM Interop(如果DLL是COM组件)

如果C++ DLL是COM组件,可以使用COM互操作:

1
2
3
Type comType = Type.GetTypeFromProgID("YourCOMComponent.YourClass");
dynamic comObject = Activator.CreateInstance(comType);
comObject.YourMethod(123, "test");

注意事项

  1. 调用约定:确保C#端和C++端的调用约定一致(通常C++使用__cdecl__stdcall)。

  2. 数据类型映射:注意C++和C#之间的数据类型转换,特别是字符串和指针类型。

  3. 32/64位兼容性:确保DLL和应用程序的平台架构一致(同为x86或x64)。

  4. DLL位置:DLL文件需要放在应用程序可找到的路径(如exe所在目录或系统PATH中)。

  5. 内存管理:如果DLL分配内存,确保有相应的释放机制,避免内存泄漏。

  6. 异常处理:C++异常不能直接传递到C#,需要在C++端捕获并转换为错误码。