ATL早期提供了宏A2W,W2A进行编码转换,但是该组宏存在以下缺点:
1、默认认为转换前的参数(A2W)、转换后的结果(W2A)的编码是ANSI;
2、转换后结果保存在栈上。
该组宏无法满足我们从UTF8、UCS2之间的互相转换,并且有可能导致栈溢出。鉴于此,当我发现可以用CA2W/CW2A这两组宏进行转码时,内心欢喜。该组宏的构造函数可以指定代码页,同时转换后的结果保存在堆上。查看源码可知,该组宏内部是通过这两个API实现转码的:
WideCharToMultiByte,MultiByteToWideChar。这两个API在调用时必须指定结果缓冲区的长度,因此,正常的做法是调用两次API。第一次调用获取所需长度,第二次调用进行真正的转码。但是CA2W/CW2A只调用了一次,在调用前预测结果缓冲区的长度。对于CA2W,结果缓冲区的长度等于输入参数的长度;对于CW2A,结果缓冲区的长度等于输入参数的长度的两倍。由于UCS2编码的字符串的字符数,必然小于其他编码的字符串的字节数,所以CA2W分配的缓冲区足够大,调用MultiByteToWideChar必然成功。然而,CW2A内部预测的缓冲区长度只在目标字符串的编码为ANSI时才成立。对于UTF8编码的目标字符串,其字符数有可能等于输入长度的3倍、6倍。针对这种情况,CW2A对WideCharToMultiByte的调用可能由于缓冲区长度不足而失败,从而导致ATL抛出异常。
所以,大家使用CW2A进行字符编码转换时,切记:目标编码的字符串长度必须小于输入参数的2倍。