cocos2d 中UserDefault在windows平台下的路径问题
2016-03-29 16:35
423 查看
在使用cocos2dx c++开发项目时,通常使用cocos自带的UserDefault来存储一些项目所用到的一些配置信息:如游戏的音量,游戏的闯关数等...
但是windows平台下,测试发现如果用户的帐户名使用是中文,在启动程序时会报错,导致程序无法运行。经过排查,把问题定位到CCFileUtils-win32.cpp的FileUtilsWin32::getWritablePath函数中:
这里可以看到作者在使用
来把路径定位到帐户下的APPData目录,而CSIDL_LOCAL_APPDATA这个宏的解释是:
#define CSIDL_LOCAL_APPDATA 0x001c // <user name>\Local Settings\Applicaiton Data (non roaming)
微软在解释SHGetFolderPath时,说明了用法:
SHGetFolderPathW (Unicode)
and SHGetFolderPathA (ANSI)
由于ANSI的兼容性不好,很多情况会导致中文乱码,所以这里需要修改SHGetFolderPathW来将字符集转成unicode,这样比较好用。
修改过后:
这样就解决了中文目录下使用userDefault造成的程序崩溃问题。
但是windows平台下,测试发现如果用户的帐户名使用是中文,在启动程序时会报错,导致程序无法运行。经过排查,把问题定位到CCFileUtils-win32.cpp的FileUtilsWin32::getWritablePath函数中:
string FileUtilsWin32::getWritablePath() const { // Get full path of executable, e.g. c:\Program Files (x86)\My Game Folder\MyGame.exe char full_path[CC_MAX_PATH + 1]; ::GetModuleFileNameA(nullptr, full_path, CC_MAX_PATH + 1); // Debug app uses executable directory; Non-debug app uses local app data directory //#ifndef _DEBUG // Get filename of executable only, e.g. MyGame.exe char *base_name = strrchr(full_path, '\\'); if(base_name) { char app_data_path[CC_MAX_PATH + 1]; // Get local app data directory, e.g. C:\Documents and Settings\username\Local Settings\Application Data if (SUCCEEDED(SHGetFolderPathA(nullptr, CSIDL_LOCAL_APPDATA, nullptr, SHGFP_TYPE_CURRENT, app_data_path))) { string ret((char*)app_data_path); // Adding executable filename, e.g. C:\Documents and Settings\username\Local Settings\Application Data\MyGame.exe ret += base_name; // Remove ".exe" extension, e.g. C:\Documents and Settings\username\Local Settings\Application Data\MyGame ret = ret.substr(0, ret.rfind(".")); ret += "\\"; // Create directory if (SUCCEEDED(SHCreateDirectoryExA(nullptr, ret.c_str(), nullptr))) { return convertPathFormatToUnixStyle(ret); } } } //#endif // not defined _DEBUG // If fetching of local app data directory fails, use the executable one string ret((char*)full_path); // remove xxx.exe ret = ret.substr(0, ret.rfind("\\") + 1); ret = convertPathFormatToUnixStyle(ret); return ret; }
这里可以看到作者在使用
SUCCEEDED(SHGetFolderPathA(nullptr, CSIDL_LOCAL_APPDATA, nullptr, SHGFP_TYPE_CURRENT, app_data_path))这个函数时,目的是想通过
CSIDL_LOCAL_APPDATA
来把路径定位到帐户下的APPData目录,而CSIDL_LOCAL_APPDATA这个宏的解释是:
#define CSIDL_LOCAL_APPDATA 0x001c // <user name>\Local Settings\Applicaiton Data (non roaming)
微软在解释SHGetFolderPath时,说明了用法:
SHGetFolderPathW (Unicode)
and SHGetFolderPathA (ANSI)
由于ANSI的兼容性不好,很多情况会导致中文乱码,所以这里需要修改SHGetFolderPathW来将字符集转成unicode,这样比较好用。
修改过后:
string FileUtilsWin32::getWritablePath() const { // Get full path of executable, e.g. c:\Program Files (x86)\My Game Folder\MyGame.exe char full_path[CC_MAX_PATH + 1]; ::GetModuleFileNameA(nullptr, full_path, CC_MAX_PATH + 1); // Debug app uses executable directory; Non-debug app uses local app data directory //#ifndef _DEBUG // Get filename of executable only, e.g. MyGame.exe char *base_name = strrchr(full_path, '\\'); if(base_name) { // Get local app data directory, e.g. C:\Documents and Settings\username\Local Settings\Application Data WCHAR utf16Path[CC_MAX_PATH + 1] = { 0 }; if(SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_LOCAL_APPDATA, nullptr, SHGFP_TYPE_CURRENT, utf16Path))) { char utf8_path[1024 + 2] = { 0 }; WideCharToMultiByte(CP_UTF8, 0, utf16Path, CC_MAX_PATH + 1, utf8_path, 1024 + 2, NULL, NULL); string ret((char*)utf8_path); // Adding executable filename, e.g. C:\Documents and Settings\username\Local Settings\Application Data\MyGame.exe ret += base_name; // Remove ".exe" extension, e.g. C:\Documents and Settings\username\Local Settings\Application Data\MyGame ret = ret.substr(0, ret.rfind(".")); ret += "\\"; // Create directory if (SUCCEEDED(SHCreateDirectoryExA(nullptr, ret.c_str(), nullptr))) { return convertPathFormatToUnixStyle(ret); } } } //#endif // not defined _DEBUG // If fetching of local app data directory fails, use the executable one string ret((char*)full_path); // remove xxx.exe ret = ret.substr(0, ret.rfind("\\") + 1); ret = convertPathFormatToUnixStyle(ret); return ret; }
这样就解决了中文目录下使用userDefault造成的程序崩溃问题。
相关文章推荐
- 我是运营,我没有假期
- 每个 Linux 游戏玩家都绝不想要的恼人体验
- 在 Fedora 上使用 Steam play 和 Proton 来玩 Windows 游戏
- Steam 让我们在 Linux 上玩 Windows 的游戏更加容易
- 如何使用 Steam Play 在 Linux 上玩仅限 Windows 的游戏
- 新一代iPad适配应用之游戏篇
- VB实现的《QQ美女找茬游戏》作弊器实例
- C#实现洗牌游戏实例
- C#实现的算24点游戏算法实例分析
- C#实现简单的井字游戏实例
- C++编写简单的打靶游戏
- C++实现基于控制台界面的吃豆子游戏
- 纯javascript实现的小游戏《Flappy Pig》实例
- 基于javascript实现句子翻牌网页版小游戏
- JavaScript实现俄罗斯方块游戏过程分析及源码分享
- JS小游戏之仙剑翻牌源码详解
- JS小游戏之宇宙战机源码详解
- Android基本游戏循环实例分析
- JavaScript游戏之优化篇
- js实现俄罗斯方块小游戏分享