说到TCHAR,大家应该是不陌生。
TCHAR简介
为什么会有TCHAR,因为C++支持两种字符集,如下:
- ANSI字符集:Multi-Byte Character
- Unicode字符集:Unicode Character
VS2008中字符集设置:
右键工程-“Properties”-“Configuration Properties”-“General”-“Character Set”。
微软baba为了统一这两套编码,所以有了TCHAR这个怪咖,通过条件编译(_UNICODE
宏和UNICODE
宏)控制实际使用的字符集。
TCHAR详细信息
-
Use Unicode Character Set,其定义如下:
typedef WCHAR TCHAR, *PTCHAR
其中WCHAR的定义为:typedef wchar_t WCHAR
-
Use Multi-Byte Character Set,其定义如下:
typedef char TCHAR, *PTCHAR
已知char类型长度为1个字节,而wchar_t类型长度为2个字节;
那么可知,TCHAR类型在Multi-Byte字符集下占1个字节,在Unicode字符集下占2个字节。
同一个TCAHR类型的数组变量在不同字符集下,长度是不同的。
TCHAR ptszArray[10];
- 在Unicode字符集下,长度为20个字节
- 在Multi-Byte字符集下,长度为10个字节
问题
扯了这么多闲话,说说正事
这次问题牵涉到一个dll和exe,大致情况如下:
dll:Unicode字符集
exe:Multi-Byte字符集
exe加载dll后通过一个获取函数列表接口获取所有函数指针,该接口的参数为一个函数指针结构体,大致如下:
typedef struct BLKFUNLISTTAG
{
TCHAR m_ptszDevName[10];
Fun1 m_pFun1;
Fun2 m_pFun2;
}BlkFunList, *pBlkFunList;
dll和exe中都是使用TCHAR数组,导致在dll中明明结构体中的2个函数指针已经被赋值;但是运行到exe后,却发现2个函数指针的值全为零。WTF!!!
后来经过分析,是TCHAR捣的鬼。
在dll中TCHAR实际上是wchar_t,则m_ptszDevName[10]的长度为20个字节,而到了exe后,TCHAR实际上是char,其长度为10个字节。
假如DevName为"HID",由于dll为Unicode字符集,则其内存信息如下:
\x00\x68\x00\x69\x00\x64\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
exe里拿到上面这段内存地址,会按照char类型去解析。则只会取前面10个字节的数据:
\x00\x68\x00\x69\x00\x64\x00\x00\x00\x00
剩余的10个字节就会覆盖结构体后面的两个函数指针成员,最终导致2个函数指针的值为0。
哎,想想都觉得可怕。
解决方案
为了不影响dll和exe中现有代码,所以只是将exe中结构体定义中的m_ptszDevName的类型由TCHAR改为WCHAR。