C#调用含嵌套结构体指针的C/C++ DLL时函数指针映射失败问题
解决C#调用C DLL函数指针映射为null的问题
我来帮你排查下问题所在,你的代码里有几个关键错误导致函数指针始终无法正确映射:
1. 委托签名与C函数不匹配
你定义的委托参数和C DLL里的函数签名完全不符,这会导致CLR无法正确绑定函数指针:
- C里的
Close是无参数函数,但你给FP_DLL_TEST_CLOSE加了ref VersionInfo参数 - C里的
RegisterClient接收int id参数,但你给FP_DLL_TEST_RC加了ref VersionInfo参数
2. 错误的内存分配逻辑
你提前手动分配了内存并赋值给dllTest.psItf,但实际上DLL的GetDllTestFP函数是要将自身内部的结构体指针赋值给传入的psFP->psItf,不需要你提前分配内存。
3. 未正确将指针转换为C#结构体
调用GetDllTestFP后,你没有把dllTest.psItf指向的非托管结构体转换为C#的DllTestFPStruct实例,直接使用了之前创建的空结构体,自然所有委托都是null。
修正后的完整C#代码
using System; using System.Runtime.InteropServices; class Program { // 先定义和C结构体匹配的VersionInfo [StructLayout(LayoutKind.Sequential)] public struct VersionInfo { public uint uMajor; public uint uMinor; public uint uMRevision; } // 修正委托签名,完全匹配C函数 [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int FP_DLL_TEST_CLOSE(); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int FP_DLL_TEST_INIT(ref VersionInfo sVersInfo); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int FP_DLL_TEST_RC(int id); [StructLayout(LayoutKind.Sequential)] public struct DllTestFPStruct { public FP_DLL_TEST_CLOSE Close; public FP_DLL_TEST_INIT Init; public FP_DLL_TEST_RC RegisterClient; } [StructLayout(LayoutKind.Sequential)] public struct DllTestMgr { public IntPtr psItf; public int iDummy; } [DllImport("DllTestC.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void GetDllTestFP(ref DllTestMgr ps); static void Main(string[] args) { DllTestMgr dllTest = new DllTestMgr(); // 不需要提前分配内存,直接传入空的Mgr实例 GetDllTestFP(ref dllTest); if (dllTest.psItf == IntPtr.Zero) { Console.WriteLine("Failed to get DLL function pointers!"); return; } // 将非托管指针转换为C#结构体 DllTestFPStruct dllFPs = Marshal.PtrToStructure<DllTestFPStruct>(dllTest.psItf); // 测试调用函数 VersionInfo vInfo = new VersionInfo { uMajor = 1, uMinor = 0, uMRevision = 0 }; dllFPs.Init(ref vInfo); dllFPs.RegisterClient(123); dllFPs.Close(); } }
额外注意事项
- 确保你的DLL是和C#程序同架构编译的(比如x86对应x86,x64对应x64),否则会出现调用失败或者指针错误
- C DLL里的静态函数
Close、Init、RegisterClient没有返回值,但声明的是int类型,最好补充返回值(比如return 0;),避免未定义行为
内容的提问来源于stack exchange,提问作者arash javanmard
相关产品推荐
相关产品推荐

