C++基础开发之DLL开发的导出函数与C#导入函数参数类型对齐

前言

在C++中,通过DLL导出函数,通常使用__declspec(dllexport)修饰符。在C#中,通过DllImport来导入C++ DLL中的函数。确保参数类型在C++和C#之间正确对齐非常重要,在 C++ 开发 DLL 提供给 C# 使用的过程中,导出函数的参数类型可以包括多种。以下是一些常见的参数类型,以及每种类型的示例,同时提供了相应的 C# DllImport 函数的编写方式。

基础类型对照

C++ 数据类型C# 数据类型
intint
unsigned intuint
shortshort
unsigned shortushort
longlong
unsigned longulong
floatfloat
doubledouble
charchar
unsigned charbyte
wchar_tchar (UTF-16)
boolbool
voidvoid
int*IntPtr
unsigned int*IntPtr
double*IntPtr
char*string (or IntPtr for raw memory)
const char*string (or IntPtr for raw memory)
structstruct (with [StructLayout] if needed)
HANDLEIntPtr

处理案例

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总结

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dotnet研习社

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值