前言
在C++中,通过DLL导出函数,通常使用__declspec(dllexport)修饰符。在C#中,通过DllImport来导入C++ DLL中的函数。确保参数类型在C++和C#之间正确对齐非常重要,在 C++ 开发 DLL 提供给 C# 使用的过程中,导出函数的参数类型可以包括多种。以下是一些常见的参数类型,以及每种类型的示例,同时提供了相应的 C# DllImport
函数的编写方式。
基础类型对照
C++ 数据类型 | C# 数据类型 |
---|---|
int | int |
unsigned int | uint |
short | short |
unsigned short | ushort |
long | long |
unsigned long | ulong |
float | float |
double | double |
char | char |
unsigned char | byte |
wchar_t | char (UTF-16) |
bool | bool |
void | void |
int* | IntPtr |
unsigned int* | IntPtr |
double* | IntPtr |
char* | string (or IntPtr for raw memory) |
const char* | string (or IntPtr for raw memory) |
struct | struct (with [StructLayout] if needed) |
HANDLE | IntPtr |
处理案例
1. 处理基础类型:
C++ 导出函数:
// YourLibrary.h
#ifndef YOURLIBRARY_H
#define YOURLIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) int AddTwoNumbers(int a, int b);
#ifdef __cplusplus
}
#endif
#endif // YOURLIBRARY_H
C# 导入函数:
// YourCSharpCode.cs
class Program {
[DllImport("YourLibrary.dll")]
public static extern int AddTwoNumbers(int a, int b);
static void Main() {
int result = AddTwoNumbers(3, 4);
Console.WriteLine(result); // 输出 7
}
}
2. 处理指针类型:
C++ 导出函数:
// YourLibrary.h
#ifndef YOURLIBRARY_H
#define YOURLIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) void MultiplyByTwo(int* value);
#ifdef __cplusplus
}
#endif
#endif // YOURLIBRARY_H
C# 导入函数:
// YourCSharpCode.cs
class Program {
[DllImport("YourLibrary.dll")]
public static extern void MultiplyByTwo(ref int value);
static void Main() {
int number = 5;
MultiplyByTwo(ref number);
Console.WriteLine(number); // 输出 10
}
}
3. 处理指针数组:
C++ 导出函数:
// YourLibrary.h
#ifndef YOURLIBRARY_H
#define YOURLIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) void IncrementArray(int* array, int size);
#ifdef __cplusplus
}
#endif
#endif // YOURLIBRARY_H
C# 导入函数:
// YourCSharpCode.cs
class Program {
[DllImport("YourLibrary.dll")]
public static extern void IncrementArray(int[] array, int size);
static void Main() {
int[] numbers = { 1, 2, 3, 4, 5 };
IncrementArray(numbers, numbers.Length);
Console.WriteLine(string.Join(", ", numbers)); // 输出 2, 3, 4, 5, 6
}
}
4. 处理处理结构体:
C++ 导出函数:
// YourLibrary.h
#ifndef YOURLIBRARY_H
#define YOURLIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
struct Point {
int x;
int y;
};
__declspec(dllexport) int CalculateDistance(const Point* p1, const Point* p2);
#ifdef __cplusplus
}
#endif
#endif // YOURLIBRARY_H
C# 导入函数:
// YourCSharpCode.cs
[StructLayout(LayoutKind.Sequential)]
public struct Point {
public int x;
public int y;
}
class Program {
[DllImport("YourLibrary.dll")]
public static extern int CalculateDistance(ref Point p1, ref Point p2);
static void Main() {
Point p1 = new Point { x = 1, y = 2 };
Point p2 = new Point { x = 4, y = 6 };
int distance = CalculateDistance(ref p1, ref p2);
Console.WriteLine(distance); // 输出 5
}
}
5. 处理字符串:
C++ 导出函数:
// YourLibrary.h
#ifndef YOURLIBRARY_H
#define YOURLIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) void ConcatenateStrings(const char* str1, const char* str2, char* result);
#ifdef __cplusplus
}
#endif
#endif // YOURLIBRARY_H
C# 导入函数:
// YourCSharpCode.cs
class Program {
[DllImport("YourLibrary.dll", CharSet = CharSet.Ansi)]
public static extern void ConcatenateStrings(string str1, string str2, StringBuilder result);
static void Main() {
StringBuilder result = new StringBuilder(256);
ConcatenateStrings("Hello", " World", result);
Console.WriteLine(result.ToString()); // 输出 Hello World
}
}
6. 处理回调函数 Callback :
C++ 导出函数:
// YourLibrary.h
#ifndef YOURLIBRARY_H
#define YOURLIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
typedef void(__stdcall *CallbackFunc)(const char* message);
__declspec(dllexport) void SetCallback(CallbackFunc callback);
__declspec(dllexport) void TriggerCallback();
#ifdef __cplusplus
}
#endif
#endif // YOURLIBRARY_H
C# 导入函数:
// YourCSharpCode.cs
class Program {
// 定义回调函数的委托
public delegate void CallbackDelegate(string message);
// 导入设置回调函数的函数
[DllImport("YourLibrary.dll")]
public static extern void SetCallback(CallbackDelegate callback);
// 导入触发回调函数的函数
[DllImport("YourLibrary.dll")]
public static extern void TriggerCallback();
// 回调函数的实现
static void CallbackFunction(string message) {
Console.WriteLine("Callback received: " + message);
}
static void Main() {
// 设置回调函数
SetCallback(CallbackFunction);
// 触发回调函数
TriggerCallback();
}
}
7. 处理结构体数组:
C++ 导出函数:
// YourLibrary.h
#ifndef YOURLIBRARY_H
#define YOURLIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
struct Point {
int x;
int y;
};
__declspec(dllexport) void GetPoints(Point* points, int count);
#ifdef __cplusplus
}
#endif
#endif // YOURLIBRARY_H
C# 导入函数:
// YourCSharpCode.cs
[StructLayout(LayoutKind.Sequential)]
public struct Point {
public int x;
public int y;
}
class Program {
[DllImport("YourLibrary.dll")]
public static extern void GetPoints([Out] Point[] points, int count);
static void Main() {
Point[] points = new Point[3];
GetPoints(points, points.Length);
foreach (var p in points) {
Console.WriteLine($"Point: ({p.x}, {p.y})");
}
}
}
8. 处理枚举:
C++ 导出函数:
// YourLibrary.h
#ifndef YOURLIBRARY_H
#define YOURLIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
enum Color {
Red,
Green,
Blue
};
__declspec(dllexport) void PrintColor(Color color);
#ifdef __cplusplus
}
#endif
#endif // YOURLIBRARY_H
C# 导入函数:
// YourCSharpCode.cs
class Program {
public enum Color {
Red,
Green,
Blue
}
[DllImport("YourLibrary.dll")]
public static extern void PrintColor(Color color);
static void Main() {
PrintColor(Color.Green);
}
}
9. 处理指向指针的指针:
C++ 导出函数:
// YourLibrary.h
#ifndef YOURLIBRARY_H
#define YOURLIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) void GetDoublePointerValue(int** value);
#ifdef __cplusplus
}
#endif
#endif // YOURLIBRARY_H
C# 导入函数:
// YourCSharpCode.cs
class Program {
[DllImport("YourLibrary.dll")]
public static extern void GetDoublePointerValue(out IntPtr value);
static void Main() {
IntPtr result;
GetDoublePointerValue(out result);
int value = Marshal.ReadInt32(result);
Console.WriteLine(value);
// 记得释放内存
Marshal.FreeCoTaskMem(result);
}
}
10. 处理句柄 HANDLE:
C++ 导出函数:
// YourLibrary.h
#ifndef YOURLIBRARY_H
#define YOURLIBRARY_H
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) HANDLE OpenResource();
__declspec(dllexport) void CloseResource(HANDLE resource);
#ifdef __cplusplus
}
#endif
#endif // YOURLIBRARY_H
C# 导入函数:
// YourCSharpCode.cs
class Program {
[DllImport("YourLibrary.dll")]
public static extern IntPtr OpenResource();
[DllImport("YourLibrary.dll")]
public static extern void CloseResource(IntPtr resource);
static void Main() {
IntPtr resource = OpenResource();
// 使用 resource...
// 关闭资源
CloseResource(resource);
}
}
11. 处理结构体中的数组:
C++ 导出函数:
// YourLibrary.h
#ifndef YOURLIBRARY_H
#define YOURLIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
struct Data {
int array[5];
};
__declspec(dllexport) void ModifyData(Data* data);
#ifdef __cplusplus
}
#endif
#endif // YOURLIBRARY_H
C# 导入函数:
// YourCSharpCode.cs
[StructLayout(LayoutKind.Sequential)]
public struct Data {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public int[] array;
}
class Program {
[DllImport("YourLibrary.dll")]
public static extern void ModifyData(ref Data data);
static void Main() {
Data data = new Data { array = new int[5] { 1, 2, 3, 4, 5 } };
ModifyData(ref data);
foreach (var value in data.array) {
Console.WriteLine(value);
}
}
}
12. 处理函数指针:
C++ 导出函数:
// YourLibrary.h
#ifndef YOURLIBRARY_H
#define YOURLIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
typedef int(__stdcall *AddFunction)(int a, int b);
__declspec(dllexport) void SetAddFunction(AddFunction addFunc);
__declspec(dllexport) int InvokeAddFunction(int a, int b);
#ifdef __cplusplus
}
#endif
#endif // YOURLIBRARY_H
C# 导入函数:
// YourCSharpCode.cs
class Program {
// 定义函数指针的委托
public delegate int AddFunctionDelegate(int a, int b);
// 导入设置函数指针的函数
[DllImport("YourLibrary.dll")]
public static extern void SetAddFunction(AddFunctionDelegate addFunc);
// 导入调用函数指针的函数
[DllImport("YourLibrary.dll")]
public static extern int InvokeAddFunction(int a, int b);
static void Main() {
// 设置函数指针
SetAddFunction((a, b) => a + b);
// 调用函数指针
int result = InvokeAddFunction(3, 4);
Console.WriteLine(result); // 输出 7
}
}
13. 处理泛型类型:
C++ 导出函数:
// YourLibrary.h
#ifndef YOURLIBRARY_H
#define YOURLIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
template <typename T>
__declspec(dllexport) T AddGenericValues(T a, T b);
#ifdef __cplusplus
}
#endif
#endif // YOURLIBRARY_H
C# 导入函数:
// YourCSharpCode.cs
class Program {
// 导入泛型函数
[DllImport("YourLibrary.dll")]
public static extern T AddGenericValues<T>(T a, T b);
static void Main() {
// 调用泛型函数
int result = AddGenericValues(3, 4);
Console.WriteLine(result); // 输出 7
double doubleResult = AddGenericValues(1.5, 2.5);
Console.WriteLine(doubleResult); // 输出 4.0
}
}
14. 处理异步操作:
C++ 导出函数:
// YourLibrary.h
#ifndef YOURLIBRARY_H
#define YOURLIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
typedef void(__stdcall *AsyncCallback)(int result);
__declspec(dllexport) void PerformAsyncOperation(AsyncCallback callback);
#ifdef __cplusplus
}
#endif
#endif // YOURLIBRARY_H
C# 导入函数:
// YourCSharpCode.cs
class Program {
// 定义异步回调函数的委托
public delegate void AsyncCallbackDelegate(int result);
// 导入异步操作的函数
[DllImport("YourLibrary.dll")]
public static extern void PerformAsyncOperation(AsyncCallbackDelegate callback);
// 异步回调函数的实现
static void AsyncCallbackFunction(int result) {
Console.WriteLine("Async operation completed with result: " + result);
}
static void Main() {
// 执行异步操作
PerformAsyncOperation(AsyncCallbackFunction);
// 继续执行其他操作...
}
}
这些示例涵盖了更多的情况,包括处理函数指针、泛型类型、异步操作等。根据实际需求,你可能会遇到其他类型的参数和情况,确保在 C# 中使用 DllImport
时,参数类型和传递方式与 C++ 函数中的定义一致。
15. 处理结构体中的指针:
C++ 导出函数:
// YourLibrary.h
#ifndef YOURLIBRARY_H
#define YOURLIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
struct Data {
int* values;
int count;
};
__declspec(dllexport) void ProcessStructWithPointer(Data* data);
#ifdef __cplusplus
}
#endif
#endif // YOURLIBRARY_H
C# 导入函数:
// YourCSharpCode.cs
[StructLayout(LayoutKind.Sequential)]
public struct Data {
public IntPtr values;
public int count;
}
class Program {
// 导入函数
[DllImport("YourLibrary.dll")]
public static extern void ProcessStructWithPointer(ref Data data);
static void Main() {
int[] values = { 1, 2, 3, 4, 5 };
Data data = new Data {
values = Marshal.UnsafeAddrOfPinnedArrayElement(values, 0),
count = values.Length
};
// 调用导入函数
ProcessStructWithPointer(ref data);
}
}
16. 处理 std::string:
C++ 导出函数:
// YourLibrary.h
#ifndef YOURLIBRARY_H
#define YOURLIBRARY_H
#include <string>
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) void ProcessStdString(const std::string& str);
#ifdef __cplusplus
}
#endif
#endif // YOURLIBRARY_H
C# 导入函数:
// YourCSharpCode.cs
class Program {
// 导入函数
[DllImport("YourLibrary.dll", CharSet = CharSet.Ansi)]
public static extern void ProcessStdString(string str);
static void Main() {
// 调用导入函数
ProcessStdString("Hello, C++!");
}
}
17. 处理 const char*:
C++ 导出函数:
// YourLibrary.h
#ifndef YOURLIBRARY_H
#define YOURLIBRARY_H
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) void ProcessConstCharPointer(const char* str);
#ifdef __cplusplus
}
#endif
#endif // YOURLIBRARY_H
C# 导入函数:
// YourCSharpCode.cs
class Program {
// 导入函数
[DllImport("YourLibrary.dll", CharSet = CharSet.Ansi)]
public static extern void ProcessConstCharPointer(string str);
static void Main() {
// 调用导入函数
ProcessConstCharPointer("Hello, C++!");
}
}
未完待续…
欢迎评论区留言补充
注意事项:
-
数据类型对应关系: 确保C++和C#中使用相同的数据类型,例如int,double等。
-
字符集匹配: 字符串的处理可能需要注意字符集匹配,上述示例中使用了CharSet = CharSet.Ansi来指定字符集。
-
函数命名约定: 确保使用相同的函数命名约定,例如__cdecl 或者
__stdcall,在C#中通过CallingConvention指定。 -
函数声明的一致性: 在C#中使用 [DllImport] 时,确保函数声明的一致性,包括参数的数量、类型和顺序。
通过这些对齐措施,可以确保C++ DLL中的导出函数和C#中的导入函数正确匹配,从而实现跨语言的调用。
参考文档
c++创建dll导出函数名称
[C++实现&C#调用] 如何遍历DLL导出函数
c#调用c++的DLL
c#调用c++.dll总结