当前位置: 首页 > news >正文

第2章,[标签 Win32] :编写兼容多字节字符集和 Unicode 字符集的 Windows 程序

专栏导航

上一篇:第2章 :宽字符库函数

回到目录

下一篇:无

本节前言

在前面几节,我们讲解了 Unicode 字符集,Unicode 函数库。

本节的内容,如果想要学会,你需要了解这些知识。

请确保你已经掌握了已经文章链接的内容。

参考课节:第2章 :Unicode 由来简述

参考参考课节:第2章 :char 数据类型与 Unicode 字符

课节:第2章 :宽字符库函数

确保你已学会了上面的几节的内容以后,再来接着往下学习。

一.    如何让程序兼容多字节字符集与 Unicode 字符集

多字节字符集,我们也可以将其称之为 ASCII 字符集。而 Unicode 字符集,则是一种宽字符集了。

有时候,我们在编写程序的时候,会希望,既编写出能够适用于 ASCII 字符集的程序,又能够编写出适用于 Unicode 字符集的程序来。

它的难度并不高。我们只需要针对同一个程序编写两个版本。第一个版本使用 ASCII 字符集,第二个版本使用 Unicode 字符集。

说起来容易,而实际去做的时候,问题也来了。假定,我对 ASCII 字符集的程序作了一点改动。接下来,Unicode 字符集的程序,也会需要作出相同的改动。如果程序完全是自己写的,这个还好。

可是,许多的程序,它是由一个公司的多个员工来完成的,甚至是由不同的公司,各自书写某些个模块,协同配合,来完成一个软件的。这种情况下,谁知道各自版本分别作了什么改动?如何确保 ASCII 字符集与 Unicode 字符集版本的程序保持协同变化呢?

我们经常使用电脑的话,会知道,某一款软件,可能时不时地会升级。酷狗音乐,百度网盘,是不是都是隔一段时间就升级?

如果我们针对酷狗音乐,同时写出 ASCII 字符集版本与 Unicode 字符集版本的程序,那么,这种升级工作,这种协调配合工作,会是相当地有难度的。

为了达到说,编写的某一个程序,既能够产生多字节字符集的版本,又能够产生 Unicode 字符集的版本,我们可以换一个思路。那就是,我们只编写一套代码。然后呢,在某一种参数设置之下,它会编译出多字节字符集的版本,而在另一个参数设置之下,它会产生 Unicode 字符集版本的程序来。

如此一来,似乎,协调配合的成本,就好多了。

就这么办。

二.    头文件准备

为了编写兼容版程序,你需要在程序中包含 Tchar.h 头文件。当然了,前提是,必须首先包含 Windows.h 头文件。

这样一来,头文件方面的代码如下。

#include <Windows.h>
#include <Tchar.h>

Tchar.h 头文件,它并不是 ANSI C 标准的一部分,所以其中定义的每一个函数和宏都有一个下划线前缀。

Tchar.h 头文件为那些需要字符串参数的普通运行库函数提供了一系列的通用函数名称与数据类型,例如 _tprintf 和 _tcslen 。所谓的通用是说,它里面的函数名与数据类型,既可以指 Unicode 版本,也可以指多字节字符集版本。

至于说,究竟是指的哪一种版本,要靠是否定义了 _UNICODE 标识符。

三.    _UNICODE 标识符的作用

本分节,我们的前提是,假定你已经在程序的开头的头文件包含部分,包含了 Tchar.h 头文件。在这一前提之下,我们来讨论 _UNICODE 标识符的作用。

(一)_tcslen

如果 _UNICODE 标识符被定义了,则 _tcslen 就被定义为 wcslen 。

#define _tcslen wcslen

如果 _UNICODE 标识符没有被定义,则 _tcslen 就被定义为 strlen 。

#define _tcslen strlen

(二)TCHAR 数据类型

如果 _UNICODE 标识符被定义了,则 TCHAR 就是 wchar_t 。

typedef wchar_t TCHAR;

如果 _UNICODE 标识符没有被定义,则 TCHAR 就是 char 。

typedef char TCHAR;

(三)__T,_T,_TEXT,__TEXT 与 TEXT 宏

先来看 __T 宏的定义。

如果 _UNICODE 标识符被定义了,则以如下方式定义 __T 宏。

#define __T(x)     L##x

这是一个有趣的语法。在基础的 C/C++ 之中,你可能并未学习过它。那一对井号被称为【令牌粘贴】,它使得字母 L 与宏参数 x 拼接在一起。

举例来说,对于 __T("Pink") 宏,它的含义是,将 L 与宏参数 "Pink" 拼接在一起,形成的东西就是 L"Pink" 。

再比如,对于 __T("Study") 宏,它的含义是,将 L 与宏参数 "Study" 拼接在一起,形成的东西就是 L"Study" 。

如果 _UNICODE 标识符没有被定义,则以如下方式定义 __T 宏。

#define __T(x)    x

接下来,我们再来看看 _T 与 _TEXT 宏。

#define _T(x)   __T(x)

#define _TEXT(x)   __T(x)

由此可见,_T,__T 和 _TEXT 宏,它们是同义语,你使用哪个都行。并且,想要使用它们,你都需要包含头文件 Tchar.h 。

有两个宏,__TEXT 宏 与 TEXT 宏。它们俩的含义其实也和 _T,__T 和 _TEXT 宏含义相同。但是,使用 TEXT 宏 或者 __TEXT 宏,并不需要包含头文件 Tchar.h 。

我们用下面的代码块来理解 __TEXT 宏与 TEXT 宏。

#ifdef _UNICODE
#define __TEXT(x)  L##x
#else
#define __TEXT(x)  x
#endif#define TEXT(x)  __TEXT(x)

在佩措尔德先生的 Windows 程序设计教材里面,他经常使用的,是 TEXT 宏。在我们的专栏里面,我们可能经常会去使用的,是 _T 宏。

对于 _T,__T,_TEXT,__TEXT 与 TEXT 宏,使用它们的效果是,如果定义了 _UNICODE 标识符,则宏所代表的字符串会被解释为 Unicode 字符串,里面的每一个字符由 Unicode 字符组成,占用两个字节。如果没有定义 _UNICODE 标识符,则宏所代表的字符串会被解释为 ASCII 字符串,里面的每一个字符由 char 型字符组成,占用 1 个字节。

四.    如何设置 _UNICODE 标识符

我们首先给出一个程序示例。代码如下。

#include <Windows.h>
#include <Tchar.h>int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance, PSTR szCndLine,int nCmdShow)
{TCHAR title[] = _T("Happy Win32");TCHAR info[] = _T("Windows API is very interesting !");MessageBox(NULL, info, title, MB_ICONINFORMATION);return 0;
}

想要读懂以上代码,需要你已经掌握本专栏的第一章内容,需要你已经了解了 MessageBox 的用法。

(一)建立 Windsows SDK 解决方案

接下来,请大家新建一个 Windows SDK 解决方案,然后添加一个名为 WinMain.cpp 的源文件。在源文件中,将上面的代码块中的代码,复制过去。

新建 Windows SDK 解决方案的方法如下面的文章链接所示。

课节:MFC 第1章:用 VS2019 编写 WIndows SDK 程序

课节:MFC 第1章:用 VS2010 编写 WIndows SDK 程序

上面的连接,哪个都可以让你学会新建 Windows SDK 解决方案。建议你两个都学会。不过,在本节,以及本专栏里面,我们能用 VS2019 来解决的,都尽量地使用 VS2019 。除非某些程序,用 VS2019 编译会出现问题,我们才转而使用 VS2010 。

建立好了解决方案,添加了源文件并复制好了代码以后,你可以先编译一下这个程序,然后去运行它。

编译的方法是,依次点选【生成】,【生成解决方案】菜单命令。

运行的方法是,依次点选【调试】,【开始执行(不调试)】菜单命令。

运行结果如下。

图1

然后呢,你点击【确定】按钮,关闭这个小程序就可以了。但是呢,VS2019 先不要关闭,我们还有用。

我们接着往下看。

(二)设置 _UNICODE 标识符

请大家依次点选【项目】,【属性】菜单命令,如下图所示。

图2

关于【项目】菜单下面的【属性】菜单项,它的菜单名字会随着 项目的不同而有所不同。如果项目的名字是【me01】,则【属性】菜单项的名字会是【me01 属性】。在这里,由于我在新建 Windows SDK 解决方案的时候,项目名和解决方案名都设置成了【Project1】,所以呢,此处的【属性】菜单项的名字为【Project1 属性】。

点选了【项目】,【属性】菜单命令以后,弹出下图所示的对话框。

图3

在图3 的红色框线所示区域,依次点选【配置属性】,【高级】,结果如下。

图4

在图4 的红色框线所示的部分,可以用来设置字符集。鼠标点击红色框线内部左边的【字符集】字样,右边会出现向下的箭头符号,如下图所示。

图5

单击这个图5 里面的红色框线所示的向下箭头符号,结果如下图所示。

图6

在图6 里面,出现了四个选项。一般地,我们要么选择【使用 Unicode 字符集】,要么选择【使用多字节字符集】。

如果你在图6 所示的下拉列表里面,选择了【使用 Unicode 字符集】,那就相当于给程序定义了 _UNICODE 标识符。如果你选择了【使用多字节字符集】,那就相当于说,程序没有定义 _UNICODE 标识符。

好玩吧?

有一个问题,我们是否可以自己手动地来编写代码,设置 _UNICODE 标识符呢?

从技术上说,似乎可以。不过呢,不推荐你这么做。我能够想到的一个原因是,假如某一个程序里面,它包含好多好多的源文件与头文件,那么,你要如何来维护这个程序,使得所有的地方,都定义了 _UNICODE 标识符或者都没有定义 _UNICODE 标识符呢?

这似乎会很麻烦。

然而,如果你采用 Visual Studio 软件的设置功能,很简单的几个菜单对话框的设置,就可以实现对 _UNICODE 标识符的设置。

我们是在学习写 Windows 程序,那么,既然 Visual Studio 里面提供了简便的方法,那就直接用呗,不必自己单独采用麻烦的方法。

在你新建 Windows SDK 程序以后,默认的字符集选项,应该是【使用 UNICODE 字符集】选项。此处,假定,我们想要将其更改为【使用多字节字符集】,那么,我们需要在图6 中单击选择【使用多字节字符集】选项,选完了以后,结果如下图所示。

图7

然后呢,在图7 的截图界面所在的对话框里面,先点击【应用】,再点击【确定】,如下图所示。

图8

点击了【确定】按钮,软件会回到主界面。

这样一来,程序所用的字符集,我们就设置好了。

简单地小结一下,设置 _UNICODE 标识符,或者说,设置 Windows 程序所使用的字符集的方法为:【项目】,【属性】,【配置属性】,【高级】,【字符集】,单击选择【使用 UNICODE 字符集】或者单击选择【使用多字节字符集】,点击【应用】按钮,点击【确定】按钮。

以上的红色字体所标注的,便是设置字符集的流程。

不过,在我们设置好了字符集以后,原来所编译好的程序所用的字符集,并未更改为我们刚刚设置的字符集。我们想要使刚刚新设置的字符集生效,我们需要重新编译程序。

(三)重新生成解决方案

依次点选【生成】,【生成解决方案】菜单命令,我们就可以重新编译程序了。重新编译的程序,会采用我们刚刚新设置的字符集。

(四)运行新版本程序

接下来,我们来运行一下新程序。

依次点选【调试】,【开始执行(不调试)】菜单命令,以运行新版本的程序。结果如下图所示。

图9

什么嘛?图9 和图1 也没啥不同嘛。

请大家先点击图9 中的【确定】按钮,以关闭程序。

的确是没啥不同。

可是,此时,我们将鼠标停在代码中的 TCHAR 文字的区域里面,VS2019 会弹出一个提示框,如下图所示。

图10

图10 里面,在红色框线所示的位置,它的提示文字是【typedef char TCHAR】。可见,当我们设置好了多字节字符集以后,TCHAR,就等同于 char 了。

接下来,我们按照上面的方法,重新将字符集设置会 UNICODE 字符集,然后重新编译。然后,我们再次将鼠标停在代码中的 TCHAR 标识符的区域里面,又会弹出一个提示框,如下所示。

图11

图11 里面,在红色框线所示的位置,它的提示文字是【typedef WCHAR TCHAR】。可见,当我们设置好了 UNICODE 字符集以后,TCHAR,就等同于 WCHAR 了。

这个 WCHAR,我们前面的章节没有讲。WCHAR,其实就是 wchar_t 。

typedef wchar_t WCHAR;

好了,本节内容,差不多讲完了。

结束语

本节内容,篇幅还是不小的。

希望你能够学好本节内容。多看几遍,我相信,你能够学好的。

专栏导航

上一篇:第2章 :宽字符库函数

回到目录

下一篇:无

相关文章:

  • 自己的网站就可以做app杭州百度seo
  • wordpress根目录没有.htaccess抖音seo代理
  • 高唐网站建设疫情最新情况
  • wordpress 后台攻击优化方法
  • 新手练习做网站哪个网站比较合适在线一键免费生成网页网站
  • 大神自己做的下载音乐的网站产品推广思路
  • 【DevTools浏览器开发者工具反调试之无限Debugger跳过】
  • SpringBoot高校党务系统
  • PyTorch RNN实战:快速上手教程
  • Python 数据分析与可视化 Day 7 - 可视化整合报告实战
  • Python核心可视化库:Matplotlib与Seaborn深度解析
  • request这个包中,get 这个方法里传入的是params ,post这个方法里传入的是data 和 json。这个区别是什么?
  • pscc系统如何部署,怎么更安全更便捷?
  • Linux 怎么恢复sshd.service
  • 结构体数组与Excel表格:数据库世界的理性与感性
  • 超级好用的小软件:geek,卸载软件,2m大小
  • Webpack 核心概念
  • 基于MATLAB的BP神经网络的心电图分类方法应用
  • Web后端基础:Java操作数据库----JDBC
  • 夏至之日,共赴实时 AI 之约:RTE Open Day@AGI Playground 2025 回顾
  • CAS 有什么问题?如何解决这些问题?
  • 《解锁Web游戏潜力:手柄操控的进阶法则》
  • 【nRF52832】【环境搭建 1】【ubuntu下搭建nRF52832开发环境】
  • 2 Studying《BPF.Performance.Tools》1-9
  • AnythingLLM+Ollama搭建本地知识库
  • 【Ansible】Ansible介绍