2009-04-30 37 views
4

我正在为不支持Unicode字符串但支持多字节ANSI字符串的库的PInvoke包装器。在调查图书馆的FxCop报告时,我注意到正在使用的字符串编组有一些有趣的副作用。 PInvoke方法使用“最佳拟合”映射来创建单字节ANSI字符串。为了说明,这是一个方法,看起来像:如何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函数,我是否可以更改签名以期望IntPtr为我在非托管内存中创建的字符串?看起来,这仍然存在许多当前实现的问题(它仍然可能需要删除或替换字符),所以我不确定这是否有所改进。我错过了另一种编组方法吗?

回答

6

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

也许你正在转换为UTF-8。虽然WideCharToMultiByte支持这一点,但我不认为P/Invoke会这样做,因为无法采用UTF-8作为系统范围的ANSI代码页。此时,您会考虑将字符串作为IntPtr来代替,但如果您这样做,则不妨使用受管理的Encoding类来执行转换,而不是WideCharToMultiByte

+0

我看你是对的;我在当前代码页之外进行了字符测试,并且无法想象任何实际上可以在我的代码页中工作的多字节字符。我在摸索着试着找到一个代码页/字符组合,我可以把它放到函数中来获得一些信心,但我认为你是对的。 – OwenP 2009-04-30 19:13:30

+0

我想出了如何测试它:我使用了一个用于日文本地化的XP的映像,并设置了一些名称由大量日文字符组成的资源。这在日本机器上效果很好,但是在英文机器上失败了。 我会*喜欢*的行为就好像我使用Unicode一样,但从您的解释和实验中我发现这是不可能的,而且我已经越来越接近它了。我只需等待库的维护者实现Unicode支持。 – OwenP 2009-04-30 22:10:47

1

这是我找到的最好的方法来实现这一点。而不是作为一个字符串编组,编组为字符[]。将责任置于pinvoke函数API的调用者上,以最合适的方式转换为字节数组。很可能通过使用Text.Encoding类之一。

0

如果你最终不得不手动调用WideCharToMultiByte,我会摆脱p/invoke,并在C++/CLI包装函数中使用WideCharToMultiByte手动编组。与C#相比,托管C++在这些互操作场景中要好得多。

虽然,如果这是您唯一的p/invoke,它可能不值得。

相关问题