C#调用Delphi加密DLL返回字符串时出现访问违规问题求助
错误原因
- 你在导出函数的参数中使用了Delphi专有的
AnsiString类型,该类型的内存布局、生命周期管理都是Delphi runtime私有的,C#互操作封送器无法正确识别,参数传递阶段就会触发内存访问错误,这是你函数入口断点还没触发就崩溃的核心原因。 - Delphi侧
Output参数错误添加了var修饰符:var PAnsiChar等价于指向字符指针的二级指针,而C#传入的StringBuilder封送后是一级字符指针,参数类型不匹配。 - 导出函数未显式指定调用约定,Delphi默认调用约定为
register,C#平台调用默认约定为stdcall,约定不一致会导致栈内存失衡。
修复方案
Delphi侧代码修改
// 所有参数使用标准C兼容类型,显式指定stdcall调用约定 procedure Encrypt(const Source: PAnsiChar; const Key: PAnsiChar; OutPut: PAnsiChar; const OutputLength: Integer); stdcall; var EncryptedString, EncodedString: AnsiString; begin // 内部逻辑依然可以用AnsiString,仅需把输入的PAnsiChar做转换即可 EncryptedString := Crypt(AnsiString(Source), AnsiString(Key)); EncodedString := Encode(EncryptedString); if Length(EncodedString) <= OutputLength then System.AnsiStrings.StrPCopy(Output, EncodedString); end; exports Encrypt;
C#侧代码修改
// 显式指定调用约定匹配Delphi侧的stdcall [DllImport("AsmEncrypt.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] public static extern void Encrypt(string password, string key, StringBuilder output, int outputlength); // 调用前请确保StringBuilder初始化了足够的容量,容量需要大于加密输出的最大可能长度 // 示例:StringBuilder str = new StringBuilder(512); Encrypt(credentials.Password, myKey, str, str.Capacity);
额外校验点
- 确保Delphi编译DLL的目标平台(x86/x64)和C#项目的目标平台完全一致,不要使用Any CPU配置。
- 不需要引入
ShareMem单元,该方案中输出内存由C#侧的StringBuilder分配,不存在跨运行时内存释放的问题。
内容的提问来源于stack exchange,提问作者Matt Baech
相关产品推荐
相关产品推荐

