如何审核我的Windows应用程序以获得正确的Unicode处理

How can I audit my Windows application for correct Unicode handling?

本文关键字:Unicode 处理 我的 何审核 Windows 应用程序      更新时间:2023-10-16

我不能使用预打包的Unicode字符串库,如ICU,因为它们将二进制文件的大小放大到了疯狂的程度(这是一个200k的程序;ICU是16MB+!)。

我已经对所有内容使用了内置的wchar_t字符串类型,但我想确保在对字符串进行迭代或类似的事情方面不会做任何愚蠢的事情。

有没有像Fuzzers这样的工具是为了安全而不是为了Unicode?也就是说,在我的代码中抛出基本多语言平面之外的字符,并确保事情像UTF-16一样得到正确处理?

(哦,很明显,跨平台的解决方案是可行的,尽管大多数跨平台的东西都必须同时支持UTF-8和UTF-16)

EDIT:还要注意一些比UTF-16代理项对不那么明显的东西,比如重音符号!

错误答案

使用WM_UNICHAR,它可以处理UTF-32,并可以处理Unicode补充平面字符。

虽然这几乎是真的,但完全的真相看起来是这样的:

  1. WM_UNICHAR是为ANSI Windows设计的接收Unicode字符的黑客。创建一个Unicode窗口,您将永远不会收到它
  2. 创建一个ANSI窗口,您会惊讶地发现它仍然没有按预期工作。问题是,当创建窗口时,您会收到一个带有0xffffWM_UNICHAR,对此必须返回1(默认窗口过程将返回0)。如果不这样做,你就再也看不到WM_UNICHAR了。干得好,官方文件没有告诉你
  3. 由于神秘的原因,在不支持WM_UNICHAR的系统上运行程序(比如我的Windows 7 64系统),即使你做得正确,它仍然无法工作

理论上的正确答案

没有什么需要审计或注意的。

使用定义的UNICODE编译,或者使用";CCD_ 9";函数,并使用WM_CHAR,就好像这是最自然的事情一样。就是这样。这确实是最自然。

WM_CHAR使用UTF-16(除非它不使用,例如在Windows 2000下)。当然,单个UTF-16字符不能表示BMP之外的代码点,但这不是问题,因为您只需获得两个包含代理对的WM_CHAR消息。它对你的应用程序是完全透明的,你不需要做任何特别的事情。任何接受宽字符串的Windows API函数也会很高兴地接受这些代理
唯一需要注意的是,现在字符串的字符长度(显然)不再只是16位单词的数量。但无论如何,一开始这是一个错误的假设。

可悲的事实

事实上,在许多(大多数?所有?)系统上,您只会得到一条WM_CHAR消息,其中wParam包含密钥代码的低16位。这对BMP中的任何东西都很好,但在其他方面都很糟糕。

我已经通过使用Alt键盘代码和创建自定义键盘布局来验证这一点,该布局在BMP之外生成代码点。在任何一种情况下,都只接收单个WM_CHAR,其中包含字符的低16位。上面的16位被简单地丢弃。

为了使您的程序能够100%正确地使用Unicode,您显然必须使用输入法管理器(ImmGetCompositionStringW),这是一个麻烦且文档记录不好的问题。就我个人而言,这仅仅意味着:;好吧,拧螺丝";。但是,如果你有兴趣做到100%正确,可以查看任何使用Scintilla(链接到行)的编辑器的源代码,它可以做到这一点,并且非常完美。

需要检查的一些事项:

  • 确保不是处理WM_CHAR而是处理WM_UNICHAR:

    WM_UNICHAR消息与WM_CHAR相同,只是它使用了UTF-32。它被设计为向ANSI窗口发送或发布Unicode字符,并且它可以处理Unicode补充平面字符

  • 不要假设第i个字符位于索引i。显然不是,如果你碰巧用这个事实来把绳子掰成两半,那么你可能会把它搞砸。

  • 不要仅仅因为字符数组的长度为N就告诉用户(在状态栏或其他地方)用户有N个字符。