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

时间:2011-06-20 15:42:09

标签: c++ winapi unicode

我无法使用预先打包的Unicode字符串库,例如ICU,因为它们会将二进制文件的大小炸毁到一个疯狂的程度(它是一个200k的程序; ICU是16MB +!)。

我正在使用内置的wchar_t字符串类型,但是我想确保在对字符串进行迭代或类似的事情时我没有做任何愚蠢的事情。

是否有像Fuzzers这样的工具用于安全但是用于Unicode?也就是说,在我的代码中将基本多语言平面之外的字符抛出,并确保以UTF-16正确处理事情?

(哦,显然跨平台解决方案有效,但大多数跨平台的东西都必须支持UTF-8和UTF-16)

编辑:还要注意比UTF-16代理对更不明显的事情 - 像重音符号这样的东西!

2 个答案:

答案 0 :(得分:3)

要检查的一些事项:

  • 请确保您处理WM_CHAR而不是处理WM_UNICHAR

      

    WM_UNICHAR消息与WM_CHAR相同,但它使用UTF-32。它旨在将Unicode字符发送或发布到ANSI窗口,它可以处理Unicode补充平面字符

  • 假设i th 字符位于索引i。它显然不是,如果你碰巧使用这个事实,比如说,将一个字符串分成两半,那么你可能会弄乱它。

  • 请勿告知用户(在状态栏或其他内容中)用户有N个字符,因为字符数组的长度为N.

答案 1 :(得分:2)

错误答案

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

虽然这几乎是真的,但完整的事实如下:

  1. WM_UNICHAR是为ANSI Windows设计的黑客,用于接收Unicode字符。创建一个Unicode窗口,您永远不会收到它。
  2. 创建一个ANSI窗口,您会惊讶地发现仍然无法按预期工作。问题是,当创建窗口时,您会收到一个WM_UNICHAR 0xffff,您必须通过返回1来响应WM_UNICHAR(默认窗口过程将返回0)。如果做不到这一点,你将永远不会再看到WM_UNICHAR。官方文档没有告诉你那个好工作。
  3. 在系统上运行您的程序,出于神秘的原因,不支持UNICODE(例如我的Windows 7 64系统),即使您正确地执行了所有操作,它仍然无效。
  4. 理论上正确答案

    无需审核或注意。

    使用W定义编译,或使用“WM_CHAR”函数显式创建窗口类和窗口,并使用WM_CHAR,就像这是最自然的事情一样做。而已。这确实是最自然的事情。

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

    悲伤的事实

    实际上,在许多(大多数?全部?)系统中,您只需获得一条wParam条消息,WM_CHAR包含密钥代码的低16位。对于BMP中的任何内容来说,这都很好,但其他方面很糟糕。

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

    为了使您的程序能够100%正确地使用Unicode,您必须使用输入法管理器(edittext.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // TODO Auto-generated method stub Value = edittext.getText().toString(); if(Your Condition){ imageview.setimage(R.Drawable.true_image); }else{ imageview.setimage(R.Drawable.false_image); } } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { // TODO Auto-generated method stub } @Override public void afterTextChanged(Editable s) { // TODO Auto-generated method stub } }); } ),这是一个令人讨厌的错误记录。对我个人来说,这只是意味着:“好吧,搞砸了”。但如果您对100%正确感兴趣,请查看使用Scintilla (link to line)的任何编辑器的源代码,这样做并且完美无缺。