browser icon
You are using an insecure version of your web browser. Please update your browser!
Using an outdated browser makes your computer unsafe. For a safer, faster, more enjoyable user experience, please update your browser today or try a newer browser.

不要在接口定义中使用 TCHAR 字符串

Posted by on 2009 年 09 月 29 日

你可以任意转载本文,但请在转载后的文章中注明作者和原始链接。
媒体约稿请联系 titilima_AT_163.com(把“_AT_”换成“@”)。

先上个图,July 早期版本的“运行”对话框。

其实在我最初的构想中,这个对话框的提示文字并不是系统默认的文字,而应该是我写上去的——最起码把“Windows”替换成 “July”。
但是我最后放弃了,因为我写上去的字到最后显示出来是乱码。由于 RunFileDlg 这个 API 并没有详细的文档支持,而且其时的我也没有任何逆向的能力,所以干脆把文本参数给了个 NULL,直接用默认提示算球了。
现在回想起来其实是 TCHAR 惹的祸。在当时,我从网上得到的 RunFileDlg 声明是类似这个样子:

1
2
3
4
5
6
7
8
int WINAPI RunFileDlg(
    HWND hwndParent,
    HICON hIcon,
    LPCTSTR pszWorkingDir,
    LPCTSTR pszTitle,
    LPCTSTR pszPrompt,
    DWORD dwFlags
);

我的开发环境是 VC6,工程设置没改过。于是一调用,乱码个球了。因为 RunFileDlg 的字符串参数实际上是 LPCWSTR,而 VC6 默认会把 LPCTSTR 定义为 LPCSTR。

我想,现在该重新审视一下 TCHAR 的意义了。它,以及 LPTSTR、LPCTSTR 都是一个 typedef,而并非一个具体的类型。它会随着编译器是否定义了 UNICODE 宏而指向真正的类型,也就是 WCHAR 或 char。换句话说,TCHAR 的确实现了 Unicode 和 ANSI 编码的兼容,但这种兼容是在源代码一级的,在编译好的 PE 可执行映像中,该是什么还是什么。考虑下面的代码:

1
2
char str[32];
lstrcpy(str, "Hello, World");

我曾见过无数类似的代码,甚至我也这么写过。在 ANSI 的编译环境下,这么写是没问题的,但是如果定义了 UNICODE,那么这段代码就会收到编译错误,因为 lstrcpy 将会被定义成 lstrcpyW,需求的参数类型是 LPWSTR 和 LPCWSTR。
也许你会说:我自己有能力控制我的源代码,知道自己用的是 lstrcpyA 还是 lstrcpyW,你管得着么?
的确,这是你的自由,我也不会干涉你的代码风格,更不会质疑你对代码的控制力。
但是,如果你的代码要提供给别人,而且你提供的只是一个接口;甚至,这个接口跨越了 PE 边界,那你总应该负点责吧?
别让你那含混不清的 TCHAR 给你们双方都带来麻烦。

订阅本站

11 Comments

  • At 2009.09.29 13:42, 李马 said:

    TCHAR 可以在源代码一级达到编码兼容的效果,但如果这个接口跨越了 PE 的边界,这个 TCHAR 就可能会给调用者造成误解。
    如果我提供给你一个 .dll 和一个 .h,而这个 .h 中的接口定义是用 TCHAR 来描述的,那会发生什么事?
    1. 你分别写 A 和 W 的两套代码来测试这个 TCHAR 到底代表 char 还是 WCHAR。这麻烦了你。
    2. 你直接问我这个 TCHAR 代表什么。这麻烦了我们俩。
    所以,何必呢?

    • At 2009.10.23 11:46, stainboy said:

      恩,仔细想了一下,你说的很有道理。呵呵,请无视我的回复吧。谢谢。

      • At 2009.09.29 14:11, antkillerfarm said:

        写的不错!

        • At 2009.09.29 22:43, likunkun said:

          非常同意!

          • At 2010.01.05 17:13, 鲁小兵 said:

            学习了,收藏~~~

            • At 2010.01.09 15:15, starmate said:

              很多地方都说Unicode好,但是我自己还没有亲身体验过,lima能否举例说明一下?
              我自己碰到的情况是,使用printf函数无法输出unicode的中文字符,例如这样:
              wchar_t szBuf[] = L”你好”;
              wprintf(L”%s\n”,szBuf);
              或者用printf输出也不行,但是使用ANSI编码中文就可以输出,是否有什么解决方法可以用printf函数输入unicode的中文呢?
              谢谢

              • At 2010.01.11 09:19, 李马 said:

                至于好处就不多说了,在《Windows 程序设计》的第二章,有很详细的论述。
                至于你所说的 CRT 对 Unicode 中文的支持,可以参考下面的文章:http://blog.csdn.net/fengzhijiaxu/archive/2009/11/18/4829229.aspx

                • At 2010.01.14 09:58, starmate said:

                  你好,我对你提到的文章三种方法,后面两种我不是很懂,就第一种方法来说,即是如下:
                  TCHAR szBuf[MAX_PATH] = _T(“测试test”) ;
                  _tprintf ( _T( “%s\n”), szBuf ) ;
                  依然对中文的显示是有问题的,只能显示问号

                  • At 2010.01.14 10:35, 李马 said:

                    看一下第三种方法,应该是你要的。

                    • At 2010.01.15 09:35, starmate said:

                      谢谢,已经理解^_^

                      • 1 old comments are not displayed. Click to display all comments
                      (Required)
                      (Required, will not be published)