You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#委托与C函数指针:C DLL在C#中结构体函数绑定问题

解决C#中绑定C DLL带函数指针的结构体问题

首先,你当前的C#结构体定义有个关键问题——直接在结构体里声明delegate类型是不符合非托管交互规则的,C里的函数指针在C#里需要通过声明匹配签名的委托类型,再结合正确的结构体字段定义来对应。下面一步步给你梳理解决方法:

第一步:声明匹配签名的委托类型

C里的函数指针签名是int (*Func)(void*, int*),对应的C#委托需要严格匹配参数、返回值类型,还要指定和C代码一致的调用约定(默认C编译器用cdecl,如果你的DLL用stdcall要对应修改):

// 先定义和C函数指针签名完全匹配的委托,指定调用约定
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public unsafe delegate int Func1Delegate(void* instance, int* data);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public unsafe delegate int Func2Delegate(void* instance, int* data);
// ... 其他函数对应的委托类型

第二步:修正C#结构体定义

结构体里的字段要对应C的函数指针,我们可以直接用上面定义的委托类型(.NET会自动处理委托到非托管函数指针的转换),这样更直观:

[StructLayout(LayoutKind.Sequential)]
public unsafe struct myStructure
{
    // 用我们定义的委托类型,和C结构体的函数指针一一对应
    public Func1Delegate Func1;
    public Func2Delegate Func2;
    // ... 其他函数指针字段
}

第三步:绑定C#函数到结构体

现在你需要把自己的C#实现方法转换成委托实例,赋值给结构体的对应字段:

1. 编写匹配签名的C#实现方法

确保方法的参数、返回值和委托完全一致:

public unsafe int MyFunc1(void* instance, int* data)
{
    // 这里写你的业务逻辑,比如读取传入的data值
    int inputValue = *data;
    Console.WriteLine($"MyFunc1收到数据: {inputValue}");
    // 返回int类型结果给C DLL
    return inputValue + 1;
}

public unsafe int MyFunc2(void* instance, int* data)
{
    // 你的Func2业务实现
    return *data * 2;
}

2. 创建委托实例并赋值给结构体

unsafe
{
    myStructure structInstance = new myStructure();
    // 将C#方法包装成委托实例,赋值给结构体字段
    structInstance.Func1 = new Func1Delegate(MyFunc1);
    structInstance.Func2 = new Func2Delegate(MyFunc2);

    // 现在这个structInstance就可以传递给C DLL的函数了
    // 比如如果DLL有导出函数 void ProcessStruct(myStructure* s);
    // 你可以这样调用:
    // ProcessStruct(&structInstance);
}

关键注意事项

  • 调用约定必须一致:如果你的C DLL用的是stdcall(比如Windows API常用的调用约定),要把UnmanagedFunctionPointer里的CallingConvention改成CallingConvention.StdCall,否则会导致栈溢出或程序崩溃。
  • 避免委托被GC回收:如果C DLL会长期持有这个结构体的引用,要把委托实例存在全局变量里,防止被垃圾回收器回收:
    private static Func1Delegate _keepAliveFunc1;
    private static Func2Delegate _keepAliveFunc2;
    
    // 赋值时保留引用
    _keepAliveFunc1 = new Func1Delegate(MyFunc1);
    structInstance.Func1 = _keepAliveFunc1;
    
  • 开启不安全代码:所有涉及指针的代码都需要在unsafe块中,或者在项目属性→生成选项里勾选"允许不安全代码"。

内容的提问来源于stack exchange,提问作者Denis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:25:18