.NET调用Unicode非托管DLL,文件名参数后出现乱码,求原因
问题原因及解决方案
根本原因
非托管DLL中LPCTSTR在Unicode编译环境下等价于const wchar_t*(宽字符字符串),但你的.NET互调用代码里DllImport默认使用ANSI字符集,导致.NET将string转换为ANSI编码的单字节字符串传递给DLL,而DLL却按照宽字符格式解析,因此出现"a"后跟随乱码的情况——宽字符每个字符占2字节,ANSI的"a"是0x61,后续内存中的随机数据被错误当成宽字符的一部分解析。
修复步骤
1. 修正DllImport的字符集
在DllImport属性中显式指定CharSet.Unicode,确保.NET传递宽字符字符串:
[DllImport("SDK.DLL", CharSet = CharSet.Unicode)] public static extern uint ProcessFileAPI(string lpSrcFileName, string lpDstFileName, TProgressProc pgrsproc, IntPtr lpProgProcParam, ref int pbCancel, ref TOptions1 options);
2. 匹配结构体内存对齐
非托管结构体用了#pragma pack(1),对应的.NET结构体需要添加StructLayout属性指定对齐规则,避免内存布局不一致:
[StructLayout(LayoutKind.Sequential, Pack = 1)] public struct TOptions1 { public bool bOption1; public bool bOption2; }
3. 确认回调委托的调用约定
非托管回调LPPROGRESSPROC使用CALLBACK(即stdcall调用约定),.NET委托默认是StdCall,显式标注更稳妥:
[UnmanagedFunctionPointer(CallingConvention.StdCall)] public delegate void TProgressProc(byte btProgress, IntPtr lParam);
修正后的完整互调用代码
using System; using System.Runtime.InteropServices; namespace SDKAPI { [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct TOptions1 { public bool bOption1; public bool bOption2; } [UnmanagedFunctionPointer(CallingConvention.StdCall)] public delegate void TProgressProc(byte btProgress, IntPtr lParam); } namespace SDKAPI.Units { public class SDKAPI { [DllImport("SDK.DLL", CharSet = CharSet.Unicode)] public static extern uint ProcessFileAPI(string lpSrcFileName, string lpDstFileName, TProgressProc pgrsproc, IntPtr lpProgProcParam, ref int pbCancel, ref TOptions1 options); } }
完成上述修改后,字符串参数会以正确的Unicode宽字符形式传递给非托管DLL,乱码问题即可解决。
内容的提问来源于stack exchange,提问作者alancc
相关产品推荐
相关产品推荐

