VC9中ATL的atlconv.h中A2W_CP和W2A_CP的Bug

来源:互联网 发布:巨人网络球球大作战 编辑:程序博客网 时间:2024/04/19 16:26

 

VC9中ATL的atlconv.h有Bug,请大家注意一下,这些问题网上也能搜索到:http://blog.csdn.net/BalonFan/archive/2009/04/24/4108985.aspx,但它对EX系列的转换宏理解错了。

我这里澄清一下:
W2A_CP转换宏,allocate分配的空间大小不对(它原来只固定乘2),但当cp为UTF8时,是有可能一个汉字转换出3个字符的,所以在某些情况下,会导致转换失败。
另外还需要注意的点是,这两个转换宏默认是在栈上分配内存的,所以如果要转换的内容比较大,或在调用栈中使用过多的转换,会导致堆栈溢出。
VC9中增加了EX系列,比较漂亮地解决了此问题(兼顾效率和安全),它的原理是根据欲分配空间的大小,只有小于1024才使用栈分配,否则使用堆分配。虽然当在调用栈上使用字符转换过多时还会出现溢出,但已经大大减少了溢出的可能,而且它也有溢出检查。

下面是它原来的定义:
#define A2W_CP(lpa, cp) (/
((_lpa = lpa) == NULL) ? NULL : (/
_convert = (lstrlenA(_lpa)+1),/
(INT_MAX/2<_convert)? NULL : /
ATLA2WHELPER((LPWSTR) alloca(_convert*sizeof(WCHAR)), _lpa, _convert, (cp))))

#define W2A_CP(lpw, cp) (/
((_lpw = lpw) == NULL) ? NULL : (/
(_convert = (lstrlenW(_lpw)+1), /
(_convert>INT_MAX/2) ? NULL : /
ATLW2AHELPER((LPSTR) alloca(_convert*sizeof(WCHAR)), _lpw, _convert*sizeof(WCHAR), (cp)))))       // 乘2是不够的,如果是UTF8,需要 *3/2

#define A2W_CP_EX(lpa, nChars, cp) (/
((_lpa_ex = lpa) == NULL) ? NULL : (/
_convert_ex = (lstrlenA(_lpa_ex)+1),/
FAILED(::ATL::AtlMultiply(&_convert_ex, _convert_ex, static_cast<int>(sizeof(WCHAR)))) ? NULL : /       // 这里只固定乘2
ATLA2WHELPER(/
(LPWSTR)_ATL_SAFE_ALLOCA(_convert_ex, _ATL_SAFE_ALLOCA_DEF_THRESHOLD), /
_lpa_ex, /
_convert_ex / sizeof(WCHAR), /
(cp))))

#define W2A_CP_EX(lpw, nChars, cp) (/
((_lpw_ex = lpw) == NULL) ? NULL : (/
_convert_ex = (lstrlenW(_lpw_ex)+1),/
FAILED(::ATL::AtlMultiply(&_convert_ex, _convert_ex, static_cast<int>(sizeof(WCHAR)))) ? NULL : /       // 这里只固定乘2
ATLW2AHELPER(/
(LPSTR)_ATL_SAFE_ALLOCA(_convert_ex, _ATL_SAFE_ALLOCA_DEF_THRESHOLD), /
_lpw_ex, /
_convert_ex, /
(cp))))

我在Coding/office/app/include/base.h头文件中已经重新定义了这两个宏,如下:

//////////////////////////////////////////////////////////////////////////
// 编码转换相关,VC6和VC9的都有Bug,这里自己写

#undef USES_CONVERSION
#undef A2W
#undef W2A
#undef A2W_CP
#undef W2A_CP
#undef A2W_CP_EX
#undef W2A_CP_EX

#define Z_A2W_CP_EX(lpa, nChars, cp) (/
((_lpa_ex = lpa) == NULL) ? NULL : (/
_convert_ex = (::MultiByteToWideChar(cp, 0, _lpa_ex, (int)(strlen(_lpa_ex)), NULL, 0) + 1), /
        FAILED(::ATL::AtlMultiply(&_convert_ex, _convert_ex, static_cast<int>(sizeof(WCHAR)))) ? NULL : /
ATLA2WHELPER(/
(LPWSTR)_ATL_SAFE_ALLOCA(_convert_ex, _ATL_SAFE_ALLOCA_DEF_THRESHOLD), /
_lpa_ex, /
_convert_ex, /
(cp))))

#define Z_W2A_CP_EX(lpw, nChars, cp) (/
((_lpw_ex = lpw) == NULL) ? NULL : (/
_convert_ex = (::WideCharToMultiByte(cp, 0, _lpw_ex, (int)(wcslen(_lpw_ex)), NULL, 0, NULL, NULL) + 1), /
ATLW2AHELPER(/
(LPSTR)_ATL_SAFE_ALLOCA(_convert_ex, _ATL_SAFE_ALLOCA_DEF_THRESHOLD), /
_lpw_ex, /
_convert_ex, /
(cp))))

// 强制使用安全版本
#define USES_CONVERSIONUSES_CONVERSION_EX
#define A2W(lpa)A2W_EX(lpa, 0)
#define W2A(lpw)W2A_EX(lpw, 0)
#define A2W_CP_EX(lpa, cp)Z_A2W_CP_EX(lpa, 0, cp)
#define W2A_CP_EX(lpw, cp)Z_W2A_CP_EX(lpw, 0, cp)
#define A2W_CP(lpa, cp)A2W_CP_EX(lpa, cp)
#define W2A_CP(lpw, cp)W2A_CP_EX(lpw, cp)

#define A2W_UTF8(lpa)A2W_CP_EX(lpa, CP_UTF8)
#define W2A_UTF8(lpw)W2A_CP_EX(lpw, CP_UTF8)

inline BSTR A2BSTR_CP(LPCSTR lpa, UINT cp)
{
USES_CONVERSION;
return CComBSTR(A2W_CP_EX(lpa, cp)).Detach();
}

inline BSTR A2BSTR_UTF8(LPCSTR lpa)
{
return A2BSTR_CP(lpa, CP_UTF8);
}

原创粉丝点击