在MFC里面用了一下iniparser类,发现功能不健全,又重新封装了一下,删除了上一篇日志。
MFC和boost的兼容性很烂,我为了省事专门给CString做了重载和特化。
头文件(VS一直不支持export关键字,非常蛋疼):
1 /************************************************************************/ 2 /* Instruction: CIniParser类主要是封装了boost::property_tree::ini_parser中的几个 3 函数,用来操纵ini配置文件。ini文件用于比较简单的程序配置,因此该类被写成了单例。 4 在C++11下,该类是线程安全的,否则不是。 5 Note: 由于该类只和STL及boost打交道,因此使用了STL命名规范。注意property_tree会抛出异常, 6 这里需要捕获异常,并返回错误码。 7 */ 8 /************************************************************************/ 9 #ifndef CTI_SDK_USING_MFC_INI_PARSER_H 10 #define CTI_SDK_USING_MFC_INI_PARSER_H 11 12 #include <string> 13 #include <map> 14 #include <memory> 15 #include <boost/property_tree/ptree.hpp> 16 #include <boost/property_tree/ini_parser.hpp> 17 //模板实现所需 18 #include <boost/property_tree/exceptions.hpp> 19 #include <boost/lexical_cast.hpp> 20 21 class CIniParser : 22 private boost::noncopyable 23 { 24 public: 25 enum IniErrNo 26 { 27 kNoErr=0, 28 kNotFound=1, 29 kNotModified=2, 30 kCanNotCreateFile=3, 31 kOtherErr=10 32 }; 33 static CIniParser& GetInstance( //获得单例 34 const std::wstring& full_filename=L"config.ini");//文件的相对/绝对路径+文件名 35 36 ~CIniParser(void){} 37 template<typename T> 38 int Get(const std::wstring& section_name,const std::wstring& property_name, 39 T *result)const; 40 template<typename T> 41 int Put(const std::wstring& section_name,const std::wstring& property_name, 42 const T& value); 43 int PutMaps(const std::wstring& section_name, 44 const std::map<std::wstring,std::wstring>& property_value_map); 45 //#ifdef _MFC_VER 46 // //为方便使用,提供CString接口 47 template<typename T> 48 int Get(const CString& secitonName,const CString& propertyName, 49 T* result)const; 50 //CString非标准,lexical_cast会失败,因此需要特化 51 template<> 52 int Get<CString>(const CString& secitonName,const CString& propertyName, 53 CString* result)const; 54 template<typename T> 55 int Put(const CString& sectionName,const CString& propertyName, 56 const T& value); 57 template<> 58 int Put<CString>(const CString& sectionName,const CString& propertyName, 59 const CString& value); 60 int PutMaps(const CString& sectionName, 61 const std::map<CString,CString>& propertyValueMap); 62 //#endif //!_MFC_VER 63 64 private: 65 CIniParser(const std::wstring& full_filename); 66 std::string filename_; 67 boost::property_tree::wptree pt_; 68 }; 69 70 //模板函数的实现,由于VS不支持export关键字,模板函数只能定义在头文件中(考虑写在另一个文件,然后include) 71 72 template<typename T> 73 int CIniParser::Get(const std::wstring& section_name, 74 const std::wstring& property_name, 75 T *result)const 76 { 77 std::wstring node(section_name+L"."+property_name); 78 try 79 { 80 *result=pt_.get<T>(node); 81 }catch(boost::property_tree::ptree_bad_data& e) 82 { 83 std::cout<<e.data<std::string>()<<std::endl; 84 return CIniParser::kNotFound; 85 }catch(boost::property_tree::ptree_bad_path& e) 86 { 87 std::cout<<e.what()<<std::endl; 88 return CIniParser::kCanNotCreateFile; 89 } 90 catch(...) 91 { 92 return CIniParser::kOtherErr; 93 } 94 return 0; 95 } 96 97 template<typename T> 98 int CIniParser::Get(const CString& secitonName, 99 const CString& propertyName, 100 T *result)const 101 { 102 return Get(wstring(secitonName.GetString()),propertyName.GetString(),result); 103 } 104 105 template<> 106 int CIniParser::Get<CString>(const CString& secitonName,const CString& propertyName, 107 CString* result)const 108 { 109 std::wstring temp; 110 int err=Get(std::wstring(secitonName.GetString()), 111 propertyName.GetString(), 112 &temp); 113 *result=temp.c_str(); 114 return err; 115 } 116 template<typename T> 117 int CIniParser::Put(const std::wstring& section_name, 118 const std::wstring& property_name, 119 const T& value) 120 { 121 std::wstring node(section_name+L"."+property_name); 122 int err=0; 123 try 124 { 125 pt_.put(node,value); 126 write_ini(filename_,pt_); 127 } 128 catch(boost::property_tree::ptree_bad_data& e) 129 { 130 err=CIniParser::kNotModified; 131 std::wcout<<e.data<std::wstring>()<<std::endl; 132 } 133 catch(boost::property_tree::ini_parser_error& e) 134 { 135 err=CIniParser::kNotModified; 136 std::cout<<"Line "<<e.line() 137 <<", file name: "<<e.filename() 138 <<", message: "<<e.message() 139 <<std::endl; 140 } 141 catch(...) 142 { 143 return CIniParser::kOtherErr; 144 } 145 return err; 146 } 147 template<typename T> 148 int CIniParser::Put(const CString& sectionName,const CString& propertyName, 149 const T& value) 150 { 151 return Put(wstring(sectionName.GetString()),propertyName.GetString(),value); 152 } 153 154 template<> 155 int CIniParser::Put<CString>(const CString& sectionName,const CString& propertyName, 156 const CString& value) 157 { 158 //指定实例函数 159 return Put(std::wstring(sectionName.GetString()) 160 ,propertyName.GetString(),value.GetString()); 161 } 162 163 #endif // !CTI_SDK_USING_MFC_INI_PASER_H
实现文件:
1 #include "IniParser.h" 2 #include <fstream> 3 #include <boost/property_tree/exceptions.hpp> 4 #include <boost/lexical_cast.hpp> 5 #include "tools.h" 6 using namespace std; 7 using namespace boost::property_tree; 8 using namespace boost; 9 10 //Warn: 这种方法在C++11前是行不通的!可以使用boost::call_once完成 11 CIniParser& CIniParser::GetInstance(const std::wstring& full_filename) 12 { 13 static CIniParser instance(full_filename); 14 return instance; 15 } 16 17 18 int CIniParser::PutMaps(const std::wstring& section_name, 19 const std::map<std::wstring,std::wstring>& property_value_map) 20 { 21 int err=0; 22 for(auto pairs:property_value_map) 23 { 24 try 25 { 26 pt_.put(section_name+L"."+pairs.first,pairs.second); 27 } 28 catch(ptree_bad_data& e) 29 { 30 err=CIniParser::kNotModified; 31 wcout<<L"write error:"<<e.data<wstring>()<<endl; 32 } 33 } 34 try 35 { 36 write_ini(filename_,pt_); 37 } 38 catch(ini_parser_error& e) 39 { 40 err=CIniParser::kNotModified; 41 cout<<"Line "<<e.line() 42 <<", file name: "<<e.filename() 43 <<", message: "<<e.message() 44 <<endl; 45 } 46 return err; 47 } 48 49 int CIniParser::PutMaps( const CString& sectionName, 50 const std::map<CString,CString>& propertyValueMap ) 51 { 52 map<wstring,wstring> temp_map; 53 for(auto pairs:propertyValueMap) 54 { 55 temp_map[pairs.first.GetString()]=pairs.second.GetString(); 56 } 57 return PutMaps(sectionName.GetString(),temp_map); 58 } 59 60 CIniParser::CIniParser( const std::wstring& full_filename) 61 { 62 wstring_to_string(full_filename,&filename_); 63 wfstream file(filename_,ios::in); 64 if (!file) 65 { 66 file.clear(); 67 file.open(filename_,ios::out); 68 //这里可能抛出异常 69 assert(file); 70 file.close(); 71 } 72 read_ini(filename_,pt_); 73 }
使用的工具函数:
1 /************************************************************************/ 2 /* Instruction: 本文件主要包含了一些自己常用的工具函数,方便其他函数引用 3 */ 4 /************************************************************************/ 5 #ifndef CTI_SDK_USING_MFC_TOOLS_H 6 #define CTI_SDK_USING_MFC_TOOLS_H 7 #include <string> 8 //UNICODE转换辅助函数 9 //仅供内部使用 10 static int ANSIToUnicode(const char *src,int srcCount,wchar_t *dest,int destCount); 11 static int UnicodeToANSI(const wchar_t *src,int srcCount,char *dest,int destCount); 12 //for MFC only 13 #if defined(_MFC_VER) 14 int CStringAToCStringW(const CStringA& src,CStringW *dest); 15 int CStringWToCStringA(const CStringW& src,CStringA *dest); 16 CString GetIPFromDWORD(const DWORD& dw); 17 DWORD MakeIPToDWORD(const CString& ip); 18 #endif 19 //只涉及标准库,使用STL命名约定 20 int string_to_wstring(const std::string& src,std::wstring *dest); 21 int wstring_to_string(const std::wstring& src,std::string *dest); 22 23 int GetUniqueName(const TCHAR *prefix,TCHAR *out,int outCount); 24 #endif // !CTI_SDK_USING_MFC_TOOLS_H
实现:
1 #include "tools.h" 2 #include <boost/lexical_cast.hpp> 3 4 using namespace std; 5 using namespace boost; 6 7 int ANSIToUnicode(const char *src,int srcCount,wchar_t *dest,int destCount) 8 { 9 assert(src && dest); 10 assert(destCount >= srcCount); 11 #ifdef WIN32 12 #include <stringapiset.h> 13 int err=MultiByteToWideChar(CP_ACP,0,src,-1,dest,destCount*sizeof(dest[0])); 14 if (err==0) 15 { 16 err=static_cast<int>(GetLastError()); 17 } 18 else 19 { 20 err=0; 21 } 22 return err; 23 #else 24 setlocale(LC_ALL,""); 25 int err=mbstowcs(dest,src,destCount*sizeof(dest[0])); 26 setlocale(LC_ALL,"C"); 27 return err; 28 #endif // WIN32 29 } 30 int UnicodeToANSI(const wchar_t *src,int srcCount,char *dest,int destCount) 31 { 32 assert(src && dest); 33 assert(destCount >= srcCount); 34 #ifdef WIN32 35 int err=WideCharToMultiByte(CP_ACP,0,src,-1,dest,destCount,NULL,NULL); 36 if (err==0) 37 { 38 err=static_cast<int>(GetLastError()); 39 } 40 else 41 { 42 err=0; 43 } 44 return err; 45 #else 46 setlocale(LC_ALL,""); 47 int err=wcstombs(dest,src,destCount); 48 setlocale(LC_ALL,"C"); 49 return err; 50 #endif 51 } 52 int CStringAToCStringW(const CStringA& src,CStringW *dest) 53 { 54 int length; 55 #ifdef WIN32 56 length=MultiByteToWideChar(CP_ACP,0,src,-1,NULL,0)+1; 57 #else 58 length=mbstowcs(NULL,src,0)+1; 59 #endif // WIN32 60 wchar_t *destbuffer=new wchar_t[length]; 61 int err=ANSIToUnicode(src,src.GetLength(),destbuffer,length); 62 dest->Format(L"%s",destbuffer); 63 delete[] destbuffer; 64 return err; 65 } 66 int CStringWToCStringA(const CStringW& src,CStringA *dest) 67 { 68 int length; 69 #ifdef WIN32 70 length=WideCharToMultiByte(CP_ACP,0,src,-1,NULL,0,NULL,NULL)+1; 71 #else 72 length=wcstombs(NULL,src,0)*2+1; 73 #endif // WIN32 74 char *destbuffer=new char[length]; 75 int err=UnicodeToANSI(src,src.GetLength(),destbuffer,length); 76 dest->Format("%s",destbuffer); 77 delete[] destbuffer; 78 return err; 79 } 80 //TODO: 应该先实现标准的,再使用非标准的调用标准,这里懒得修改了 81 int string_to_wstring(const string& src,wstring *dest) 82 { 83 CStringW destbuffer; 84 int err=CStringAToCStringW(src.c_str(),&destbuffer); 85 dest->assign(destbuffer.GetString()); 86 destbuffer.ReleaseBuffer(); 87 return err; 88 } 89 int wstring_to_string(const wstring& src,string *dest) 90 { 91 CStringA destbuffer; 92 int err=CStringWToCStringA(src.c_str(),&destbuffer); 93 dest->assign(destbuffer.GetString()); 94 destbuffer.ReleaseBuffer(); 95 return err; 96 } 97 98 //TODO: 完善错误处理 99 int GetUniqueName(const TCHAR *prefix,TCHAR *out,int outCount) 100 { 101 int errcode=0; 102 TCHAR tszTemplate[MAX_PATH]={0}; 103 errcode=_tcscat_s(tszTemplate,MAX_PATH*sizeof(TCHAR),_T("XXXXXX")); 104 assert(outCount >= _countof(tszTemplate)); 105 errcode=_tmktemp_s(tszTemplate); 106 errcode=_tcscpy_s(out,outCount*sizeof(TCHAR),tszTemplate); 107 return errcode; 108 } 109 110 CString GetIPFromDWORD( const DWORD& dw ) 111 { 112 WORD hw=HIWORD(dw); 113 WORD lw=LOWORD(dw); 114 BYTE ip1stSection=HIBYTE(hw); 115 BYTE ip2ndSection=LOBYTE(hw); 116 BYTE ip3rdSection=HIBYTE(lw); 117 BYTE ip4thSection=LOBYTE(lw); 118 CString result; 119 result.Format(_T("%d.%d.%d.%d"),ip1stSection,ip2ndSection,ip3rdSection, 120 ip4thSection); 121 return result; 122 } 123 124 DWORD MakeIPToDWORD( const CString& ip ) 125 { 126 CString ipSections[4]; 127 CString temp; 128 int pos=0,i=0; 129 temp=ip.Tokenize(_T("."),pos); 130 while (temp!=_T("")) 131 { 132 VERIFY(i<4); 133 ipSections[i++]=temp; 134 temp=ip.Tokenize(_T("."),pos); 135 } 136 BYTE ip1stSection=_ttoi(ipSections[0].GetString()); 137 BYTE ip2ndSection=_ttoi(ipSections[1].GetString()); 138 BYTE ip3rdSection=_ttoi(ipSections[2].GetString()); 139 BYTE ip4thSection=_ttoi(ipSections[3].GetString()); 140 //注意高低位顺序 141 WORD hw=MAKEWORD(ip2ndSection,ip1stSection); 142 WORD lw=MAKEWORD(ip4thSection,ip3rdSection); 143 DWORD result=MAKELONG(lw,hw); 144 145 return result; 146 }
这几天写MFC程序,感觉最麻烦的就是unicode和ansi的转换。
C++最令人的讨厌的特性之一就是不缺省支持unicode,最讨厌的特性之二是没有好的GUI框架。
如果可以的话,还是直接用Qt最简单。C++的哲学确实偏向学院派,不管是ace,boost还是poco,甚至stl,单独拿出来学习,感觉都很惊艳,
但是在工业项目中间使用,就感觉各种别扭……