如何P调用多字节ANSI字符串? [英] How do I PInvoke a multi-byte ANSI string?

查看:105
本文介绍了如何P调用多字节ANSI字符串?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为一个不支持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函数,我可以更改签名以期望将IntPtr 转换为在非托管内存中创建的字符串吗?看来这仍然具有当前实现所存在的许多问题(可能仍然必须删除或替换字符),所以我不确定这是否有所改善.我还缺少另一种编组方法吗?

解决方案

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

也许您要转换为UTF-8.尽管WideCharToMultiByte支持此功能,但我认为P/Invoke不支持,因为不可能将UTF-8用作系统范围的ANSI代码页.此时,您将考虑将字符串作为IntPtr传递,尽管如果这样做,您也可以使用托管的Encoding类进行转换,而不是使用WideCharToMultiByte. /p>

I'm working on a PInvoke wrapper for a library that does not support Unicode strings, but does support multi-byte ANSI strings. While investigating FxCop reports on the library, I noticed that the string marshaling being used had some interesting side effects. The PInvoke method was using "best fit" mapping to create a single-byte ANSI string. For illustration, this is what one method looked like:

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

The result of calling this function with a string that contains non-ASCII characters is that Windows finds a "close" character, generally this looks like it ends up being "???". If we pretend that 'a' is a non-ASCII character, then passing "cat" as a parameter would create a resource named "c?t".

If I follow the guidelines in the FxCop rule, I end up with something like this:

[DllImport("thedll.dll", CharSet=CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
public static extern int CreateNewResource([MarshalAs(UnmanagedType.LPStr)] string resourceName);

This introduces a change in behavior; now when a character cannot be mapped an exception is thrown. This concerns me because this is a breaking change, so I'd like to try and marshal the strings as multi-byte ANSI but I cannot see a way to do so. UnmanagedType.LPStr is specified to be a single-byte ANSI string, 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 to a string I create in unmanaged memory? It seems like this still has many of the problems that the current implementation has (it still might have to drop or substitute characters), so I'm not sure if this is an improvement. Is there another method of marshaling that I'm missing?

解决方案

ANSI is multi-byte, and ANSI strings are encoded according to the codepage currently enabled on the system. WideCharToMultiByte works the same way as P/Invoke.

Maybe what you're after is conversion to UTF-8. Although WideCharToMultiByte supports this, I don't think P/Invoke does, since it's not possible to adopt UTF-8 as the system-wide ANSI code page. At this point you'd be looking at passing the string as an IntPtr instead, although if you're doing that, you may as well use the managed Encoding class to do the conversion, rather than WideCharToMultiByte.

这篇关于如何P调用多字节ANSI字符串?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆