使用[UnmanagedCallersOnly]返回结构体时遇__cdecl语法编译错误
问题解决:返回结构体时cl.exe编译报错的修复方案
核心问题原因
返回自定义结构体时编译报错,本质是C#结构体内存布局未明确、调用约定不匹配,导致DNNE生成的C++包装代码出现语法错误,触发cl.exe返回代码2。
具体修复步骤
1. 给C#结构体添加显式内存布局属性
Delphi和C#的结构体内存布局必须严格一致,否则不仅编译会出问题,运行时也会出现数据错乱。给ReturnTest结构体添加StructLayout属性:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct ReturnTest { public int code; public IntPtr txt; }
LayoutKind.Sequential保证成员按声明顺序排列,和Delphi的record默认布局一致CharSet.Unicode匹配BSTR的Unicode编码格式
2. 给导出函数显式指定调用约定
[UnmanagedCallersOnly]默认调用约定为Cdecl,但需要显式声明避免DNNE生成代码时出现歧义:
[UnmanagedCallersOnly(CallingConvention = CallingConvention.Cdecl)] public static ReturnTest TestFunction() { ReturnTest returnTest = new ReturnTest(); returnTest.code = 1337; returnTest.txt = Marshal.StringToBSTR("a b c d q ¥ K xyz"); return returnTest; }
如果Delphi端使用stdcall调用约定,只需把CallingConvention.Cdecl改成CallingConvention.StdCall即可。
3. 确保DNNE配置正确
- 确认项目目标框架为.NET 5或更高版本(
[UnmanagedCallersOnly]从.NET 5开始支持) - 检查DNNE生成的C++包装文件,确保结构体声明位于函数之前,且调用约定语法正确(比如
__cdecl修饰符位置正确)
4. Delphi端匹配结构体定义
Delphi端必须定义和C#完全一致的record,同时注意BSTR的内存释放:
type ReturnTest = record code: Integer; txt: PWideChar; end; // 调用示例 procedure CallTestFunction; var Result: ReturnTest; S: WideString; begin Result := TestFunction; S := Result.txt; SysFreeString(Result.txt); // 必须释放BSTR,避免内存泄漏 end;
内容的提问来源于stack exchange,提问作者White
相关产品推荐
相关产品推荐

