我正在为一个不支持Unicode字符串但仍支持多字节ANSI字符串的库的PInvoke包装器工作.在调查关于库的FxCop报告时,我注意到使用的字符串编组有一些有趣的副作用.PInvoke方法使用"最佳拟合"映射来创建单字节ANSI字符串.为了说明,这是一个方法的样子:
[DllImport("thedll.dll", CharSet=CharSet.Ansi)]
public static extern int CreateNewResource(string resourceName);
Run Code Online (Sandbox Code Playgroud)
使用包含非ASCII字符的字符串调用此函数的结果是Windows找到"关闭"字符,通常这看起来最终是"???".如果我们假装'a'是非ASCII字符,那么将"cat"作为参数传递将创建名为"c?t"的资源.
如果我遵循FxCop规则中的指导原则,我最终会得到这样的结果:
[DllImport("thedll.dll", CharSet=CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
public static extern int CreateNewResource([MarshalAs(UnmanagedType.LPStr)] string resourceName);
Run Code Online (Sandbox Code Playgroud)
这引入了行为的变化; 现在当一个字符无法映射时抛出一个异常.这让我很担心,因为这是一个突破性的变化,所以我想尝试将字符串编组为多字节ANSI,但我看不到这样做的方法. UnmanagedType.LPStr被指定为单字节ANSI字符串,LPTStr will be Unicode or ANSI depending on the system, and LPWStr is not what the library expects.
How would I tell PInvoke to marshal the string as a multibyte string? I see there's a WideCharToMultiByte()
UnmanagedType.LPStrLPTStr will be Unicode or ANSI depending on the system, and LPWStr is not what the library expects.
How would I tell PInvoke to marshal the string as a multibyte string? I see there's a WideCharToMultiByte() API function, could I change the signature to expect an IntPtr到我在非托管内存中创建的字符串?看起来这仍然有很多当前实现的问题(它仍然可能需要删除或替换字符),所以我不确定这是否是一个改进.还有另一种编组方法,我错过了吗?
ANSI 是多字节的,ANSI字符串根据系统上当前启用的代码页进行编码.WideCharToMultiByte与P/Invoke的工作方式相同.
也许你所追求的是转换为UTF-8.虽然WideCharToMultiByte支持这一点,但我不认为P/Invoke会这样做,因为不可能采用UTF-8作为系统范围的ANSI代码页.此时你会考虑将字符串作为一个IntPtr代替,尽管如果你这样做,你也可以使用托管Encoding类来进行转换,而不是WideCharToMultiByte.