升级vs2008后,区域设置不正常导致路径转换失败的问题
繁体版本更新vs2008版本后,有玩家来报客户端启动不正常的问题,经沟通和调查,发现重现的环境是这样的
1. 玩家区域设置使用英文
2. 玩家客户端目录含有繁体字符
而如果是vs6的版本,启动是正常的
调试发现,在使用CShockwaveFlash类,设置flash路径的时候就产生了问题。
vs6
VC98\MFC\SRC\OLEDISP2.CPP
COleDispatchDriver::InvokeHelperV
#if !defined(_UNICODE) && !defined(OLE2ANSI)
case VT_BSTRA:
{
LPCSTR lpsz = va_arg(argList, LPSTR);
pArg->bstrVal = ::SysAllocString(T2COLE(lpsz)); // Line 252
if (lpsz != NULL && pArg->bstrVal == NULL)
AfxThrowMemoryException();
pArg->vt = VT_BSTR;
}
break;
#endif
}
T2COLE 在默认未定义 _CONVERSION_USES_THREAD_LOCALE 的情况下,使用的是CP_ACP来做转换的
vs2008
VC\atlmfc\src\mfc\oledisp2.cpp
COleDispatchDriver::InvokeHelperV
#if !defined(_UNICODE)
case VT_BSTRA:
{
LPCSTR lpsz = va_arg(argList, LPSTR);
CStringW strMBToUnicode(lpsz); // Line 286
pArg->bstrVal = ::SysAllocString(static_cast<LPCWSTR>(strMBToUnicode));
if (lpsz != NULL && pArg->bstrVal == NULL)
AfxThrowMemoryException();
pArg->vt = VT_BSTR;
}
break;
#endif
CStringW strMBToUnicode(lpsz);
使用的acp
inline UINT WINAPI _AtlGetConversionACP() throw()
{
#ifdef _CONVERSION_DONT_USE_THREAD_LOCALE
return CP_ACP;
#else
return CP_THREAD_ACP;
#endif
}
在默认未定义_CONVERSION_DONT_USE_THREAD_LOCALE的情况下,使用的是CP_THREAD_ACP。
MSDN提到了这个变化
http://msdn.microsoft.com/en-us/library/w1sc4t4k%28VS.80%29.aspx
ATL and MFC Changes: ATL 7.0 and MFC 7.0
String Conversions
In versions of ATL up to and including ATL 3.0 in Visual C++ 6.0, string conversions using the macros in atlconv.h were always performed using the ANSI code page of the system (CP_ACP). Starting with ATL 7.0 in Visual C++ .NET, string conversions are performed using the default ANSI code page of the current thread, unless _CONVERSION_DONT_USE_THREAD_LOCALE is defined, in which case the ANSI code page of the system is used as before.
在区域设置使用英文的情况下,表现就会产生和vs6不一样的效果。注意,区域设置(Dxdiag中看到的语言版本),决定了默认的CP_THREAD_ACP,但CP_ACP,取决于系统设置,在区域设置高级里面,用于匹配非Unicode程序的版本
参: Setting the user and system locales
http://mihai-nita.net/2005/06/11/setting-the-user-and-system-locales/
解决方法是,在程序的开始出调用
SetThreadLocale(LOCALE_SYSTEM_DEFAULT);
参考资料:
1. http://msdn.microsoft.com/en-us/library/w1sc4t4k(VS.80).aspx
1. http://connect.microsoft.com/VisualStudio/feedback/details/100887/conversion-dont-use-thread-locale-does-not-work
3. http://blogs.msdn.com/b/michkap/archive/2007/05/28/2960411.aspx
4. http://mihai-nita.net/2005/06/11/setting-the-user-and-system-locales/
5. http://blogs.msdn.com/b/shawnste/archive/2011/11/09/user-locale-system-locale-ui-language-language-profile-amp-all-that.aspx
6. http://blog.donews.com/me1105/archive/2010/11/26/49.aspx
7. http://www.microsoftfaqs.com/Articles/14842531/Problems_with_garbage_characters_in_Chinese_Win7_under_VS2008
繁体版本更新vs2008版本后,有玩家来报客户端启动不正常的问题,经沟通和调查,发现重现的环境是这样的
1. 玩家区域设置使用英文
2. 玩家客户端目录含有繁体字符
而如果是vs6的版本,启动是正常的
调试发现,在使用CShockwaveFlash类,设置flash路径的时候就产生了问题。
vs6
VC98\MFC\SRC\OLEDISP2.CPP
COleDispatchDriver::InvokeHelperV
#if !defined(_UNICODE) && !defined(OLE2ANSI)
case VT_BSTRA:
{
LPCSTR lpsz = va_arg(argList, LPSTR);
pArg->bstrVal = ::SysAllocString(T2COLE(lpsz)); // Line 252
if (lpsz != NULL && pArg->bstrVal == NULL)
AfxThrowMemoryException();
pArg->vt = VT_BSTR;
}
break;
#endif
}
T2COLE 在默认未定义 _CONVERSION_USES_THREAD_LOCALE 的情况下,使用的是CP_ACP来做转换的
vs2008
VC\atlmfc\src\mfc\oledisp2.cpp
COleDispatchDriver::InvokeHelperV
#if !defined(_UNICODE)
case VT_BSTRA:
{
LPCSTR lpsz = va_arg(argList, LPSTR);
CStringW strMBToUnicode(lpsz); // Line 286
pArg->bstrVal = ::SysAllocString(static_cast<LPCWSTR>(strMBToUnicode));
if (lpsz != NULL && pArg->bstrVal == NULL)
AfxThrowMemoryException();
pArg->vt = VT_BSTR;
}
break;
#endif
CStringW strMBToUnicode(lpsz);
使用的acp
inline UINT WINAPI _AtlGetConversionACP() throw()
{
#ifdef _CONVERSION_DONT_USE_THREAD_LOCALE
return CP_ACP;
#else
return CP_THREAD_ACP;
#endif
}
在默认未定义_CONVERSION_DONT_USE_THREAD_LOCALE的情况下,使用的是CP_THREAD_ACP。
MSDN提到了这个变化
http://msdn.microsoft.com/en-us/library/w1sc4t4k%28VS.80%29.aspx
ATL and MFC Changes: ATL 7.0 and MFC 7.0
String Conversions
In versions of ATL up to and including ATL 3.0 in Visual C++ 6.0, string conversions using the macros in atlconv.h were always performed using the ANSI code page of the system (CP_ACP). Starting with ATL 7.0 in Visual C++ .NET, string conversions are performed using the default ANSI code page of the current thread, unless _CONVERSION_DONT_USE_THREAD_LOCALE is defined, in which case the ANSI code page of the system is used as before.
在区域设置使用英文的情况下,表现就会产生和vs6不一样的效果。注意,区域设置(Dxdiag中看到的语言版本),决定了默认的CP_THREAD_ACP,但CP_ACP,取决于系统设置,在区域设置高级里面,用于匹配非Unicode程序的版本
参: Setting the user and system locales
http://mihai-nita.net/2005/06/11/setting-the-user-and-system-locales/
解决方法是,在程序的开始出调用
SetThreadLocale(LOCALE_SYSTEM_DEFAULT);
参考资料:
1. http://msdn.microsoft.com/en-us/library/w1sc4t4k(VS.80).aspx
1. http://connect.microsoft.com/VisualStudio/feedback/details/100887/conversion-dont-use-thread-locale-does-not-work
3. http://blogs.msdn.com/b/michkap/archive/2007/05/28/2960411.aspx
4. http://mihai-nita.net/2005/06/11/setting-the-user-and-system-locales/
5. http://blogs.msdn.com/b/shawnste/archive/2011/11/09/user-locale-system-locale-ui-language-language-profile-amp-all-that.aspx
6. http://blog.donews.com/me1105/archive/2010/11/26/49.aspx
7. http://www.microsoftfaqs.com/Articles/14842531/Problems_with_garbage_characters_in_Chinese_Win7_under_VS2008