如何PInvoke多字节ANSI字符串?

时间:2009-04-30 17:37:17

标签: string pinvoke

我正在为一个不支持Unicode字符串但支持多字节ANSI字符串的库的PInvoke包装器工作。在调查关于库的FxCop报告时,我注意到使用的字符串编组有一些有趣的副作用。 PInvoke方法使用“最佳拟合”映射来创建单字节ANSI字符串。为了说明,这就是一种方法:

[DllImport("thedll.dll", CharSet=CharSet.Ansi)]
public static extern int CreateNewResource(string resourceName);

使用包含非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);

这引入了行为的变化;现在当一个字符无法映射时抛出一个异常。这让我很担心,因为这是一个突破性的变化,所以我想尝试将字符串编组为多字节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() API function, could I change the signature to expect an IntPtr?看起来这仍然存在许多当前实现的问题(它仍然可能需要删除或替换字符),所以我不确定这是否是一个改进。还有另一种编组方法,我错过了吗?

3 个答案:

答案 0 :(得分:6)

ANSI 多字节,ANSI字符串根据系统上当前启用的代码页进行编码。 WideCharToMultiByte与P / Invoke的工作方式相同。

也许您所追求的是转换为UTF-8。虽然WideCharToMultiByte支持这一点,但我不认为P / Invoke会这样做,因为不可能采用UTF-8作为系统范围的ANSI代码页。此时您将看到将字符串作为IntPtr传递,但如果您这样做,您也可以使用托管的Encoding类进行转换,而不是{ {1}}。

答案 1 :(得分:1)

这是我发现实现这一目标的最佳方式。而不是作为字符串编组,编组为byte []。将责任放在pinvoke函数API的调用者上,以最合适的方式转换为字节数组。最有可能的方法是使用Text.Encoding类之一。

答案 2 :(得分:0)

如果您最终必须手动调用WideCharToMultiByte,我将摆脱p / invoke并在C ++ / CLI包装函数中使用WideCharToMultiByte手动封送它。托管C ++在这些互操作场景中要比C#好得多。

但是,如果这是你唯一的p / invoke,它可能不值得。