一個框架基礎的東西,一般也是操作的最基礎的類,比如char、int、bool等,有時出現內存泄露的問題導致錯誤的拋出,但是C++開發有的時候就算是拋出異常,那也是靠經驗來積累才能非常快速准確的找出錯誤所在,這就需要在框架中需要添加日志管理的接口,日志管理的好處就是開發者自身在找異常時提供參考,另一個就是如果用戶操作時出現問題,也可將日志反饋,幫助快速解決問題;總之了為了更好的擴展完善我的框架,我詳細列一下這個基礎服務庫(XPCore)包含內容:
- 雖說sharpui控件庫內封閉好string類,但是不夠滿足需求,我就新定義了xstring類,這個字條串類中,涉及常用的所有操作,比如:查找、去空、大小寫轉換、取指定的字符串、連接、操作符運算、編碼轉換、與其他基礎類間的轉換、刪除、替換等等;頭文件如下:
1 //xstring 常用編碼格式 2 enum XPCORE_API XEncodings 3 { 4 //默認編碼 5 encoding_gb2312=0, 6 //wchar_t 7 encoding_wchart=1, 8 //Unicode 9 encoding_unicode=2, 10 //Unicode 的一種表達形式 11 encoding_utf8=3 12 13 }; 14 15 //自定義字符串類 xstring的最大長度 16 #define _xstring_max_Length_ 4096 17 //自定義字符串類 默認編碼為GB2312,支持與Unicode wchar_t Utf-8轉換 18 class XPCORE_API xstring:implements XPCore::Object 19 { 20 public: 21 xstring(); 22 xstring(const char* value); 23 xstring(const wchar_t* value); 24 xstring(const xstring &other); 25 ~xstring(); 26 27 const char* c_str() const; 28 char* c_str(); 29 30 const wchar_t* w_str() const; 31 wchar_t* w_str(); 32 33 int Lendth() const; 34 bool Empty() const; 35 36 XEncodings Encoding() const; 37 void SetEncoding(int encoding); 38 39 bool StartsWith(const xstring& value) const; 40 bool EndsWith(const xstring& value) const; 41 bool Contains(const xstring& value,int &startIndex) const; 42 bool StartsWith(const char value) const; 43 bool EndsWith(const char value) const; 44 bool Contains(const char value,int &startIndex) const; 45 bool Equals(const xstring& value) const; 46 47 static xstring FromInt(int value); 48 static xstring FromFloat(float value,int numofDigits=10); 49 static xstring FromBool(bool value); 50 51 int ToInt() const; 52 float ToFloat() const; 53 bool ToBool() const; 54 55 int IndexOf(char value, int startIndex) const; 56 int IndexOf(const xstring& value) const; 57 int IndexOf(const xstring& value, int startIndex) const; 58 int IndexOf(char value, int startIndex, int count) const; 59 int IndexOf(const xstring& value, int startIndex, int count) const; 60 61 bool Remove(int startIndex); 62 bool Remove(int startIndex, int count); 63 bool Replace(char oldChar, char newChar); 64 bool Replace(const xstring& oldValue, const xstring& newValue); 65 66 xstring Insert(int startIndex, const xstring& insertValue); 67 68 xstring Substring(int startIndex) const; 69 xstring Substring(int startIndex, int length) const; 70 xstring Substring(int startIndex,int count, char sz) const; 71 72 xstring ToLower(); 73 xstring ToString(); 74 xstring ToUpper(); 75 xstring Trim(); 76 xstring TrimLeft(); 77 xstring TrimRight(); 78 79 bool IsDigital() const; 80 bool IsBool() const; 81 bool IsCharacter() const; 82 83 void Clear(); 84 85 char& operator[](int index); 86 const char& operator[](int index) const; 87 88 xstring operator=(const xstring &other); 89 xstring operator=(const char* val); 90 xstring operator=(const wchar_t* val); 91 xstring operator+(const xstring &other); 92 void operator+=(const xstring &other); 93 bool operator==(const xstring &other); 94 bool operator>(const xstring &other); 95 bool operator<(const xstring &other); 96 ///////////////////////////////////////////////// 97 98 static xstring FromUtf8(const xstring &other); 99 static xstring FromUnicode(const xstring &other); 100 static xstring FromGB2312(const xstring &other); 101 102 xstring ToUtf8(); 103 xstring ToUnicode(); 104 xstring ToGB2312(); 105 protected: 106 char* _ptr; 107 int _encoding; 108 };
- 內嵌了編碼轉換跨平台開源代碼(Iconv,詳細大家可以網上找對應資源),引用頭文件“iconv.h”,定義共有方法:int code_convert(char *from_charset,char *to_charset,char *inbuf,int inlen,char *outbuf,int outlen),實現編碼間轉換,Iconv在轉碼方面還是很強大的,首先跨平台這優勢就不言而喻了,其次方法簡單,就只需要剛才定義的方法就可以如:xstring中定義的ToUtf8方法
xstring xstring::ToUtf8() { char* _out=new char[_xstring_max_Length_]; code_convert("GB2312","UTF-8",_ptr,strlen(_ptr),_out,_xstring_max_Length_); xstring _temStr=_out; _temStr.SetEncoding(XEncodings::encoding_utf8); return _temStr; }
- 常用的宏,如類似接口的定義、釋放內存等等
//******************************************** // Interface.h //主要是宏定義一些關鍵詞,可以形成接口類 //******************************************** #ifndef _XPCOREINTERFACE_H #define _XPCOREINTERFACE_H #define _Interface_ class //繼承接口 #define implements public //聲明接口起始 #define DeclareInterface(name) _Interface_ name { \ public: \ virtual ~name() {}; \ //聲明帶基類接口起始 #define DeclareBasedInterface(name, base) _Interface_ name : \ public base{ \ public: \ virtual ~name() {}; \ //#ifdef FRAMEWORKCORE_EXPORTS //聲明帶輸出接口起始 #define DeclareAPIInterface(name) \ _Interface_ name { \ public: \ virtual ~name() {}; \ //聲明帶基類帶輸出接口起始 #define DeclareBasedAPIInterface(name, base) _Interface_ name : \ public base { \ public: \ virtual ~name() {}; \ //聲明帶基類帶輸出接口起始 #define DeclareBasedAPIInterface2(name, base1,base2) _Interface_ name : \ public base1,public base2 { \ public: \ virtual ~name() {}; \ //聲明帶基類帶輸出接口起始 #define DeclareBasedAPIInterface3(name, base1,base2,base3) _Interface_ name : \ public base1,public base2 ,public base3{ \ public: \ virtual ~name() {}; \ //聲明接口結束 #define EndInterface };
- 另外為了能唯一標識某些類或標識添加的一個按鈕,這就需要GUID;但是為了能靈活用GUID,這里也定義了下GUIDHelper
class XPCORE_API GuidHelper { public: static const GUID NewGUID(); static const char* GUIDToChar(const GUID &guid); static bool CharToGUID(const char* str,GUID &guid); }; //新建GUID #define _NEW_GUID_ GuidHelper::NewGUID() //源 const GUID GuidHelper::NewGUID() { GUID guid; #ifdef WIN32 CoCreateGuid(&guid); #else uuid_generate(reinterpret_cast<unsigned char *>(&guid)); #endif return guid; } const char* GuidHelper::GUIDToChar(const GUID &guid) { char buf[128] = {0}; #ifdef __GNUC__ snprintf( #else // MSVC _snprintf_s( #endif buf, sizeof(buf), "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); return buf; } bool GuidHelper::CharToGUID(const char* str,GUID &guid) { memset(&guid, 0, sizeof(GUID)); int nRet=sscanf_s( str, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", &(guid.Data1), &(guid.Data2), &(guid.Data3), &(guid.Data4[0]), &(guid.Data4[1]), &(guid.Data4[2]), &(guid.Data4[3]), &(guid.Data4[4]), &(guid.Data4[5]), &(guid.Data4[6]), &(guid.Data4[7]) ); return (nRet == 11)? true : false ; }
- 因為是插件式管理框架,所以需要定義每個插件對應的配置,這里選擇用LUA角本語言來定義插件配置,因此,在這個庫里也內嵌了LUA的源代碼,不過只用到了一種方法就是將定義好的C++類綁定到Lua角本編譯器的虛擬機中,實現對配置信息的讀入和加載
//單個插件 struct typedef struct tagPluginInfo { char name[MAX_PATH]; char url[MAX_PATH]; char description[MAX_PATH]; char author[MAX_PATH]; bool isHiddenInManager; bool isLoadAutoStart; bool isUnload; }_pluginInfo,*P_pluginInfo; //單個插件 class XPCORE_API plugin:implements XPCore::Object { public: plugin(); plugin(plugin &other); plugin(_pluginInfo &other); ~plugin(); public://插件描述信息 char* GetName(); void SetName(const char* val); char* GetAuthor(); void SetAuthor(const char* val); char* GetURL(); void SetURL(const char* val); char* GetDescription(); void SetDescription(const char* des); bool IsHiddenInManager(); void SetIsHiddenInManager(bool val); bool IsLoadAutoStart(); void SetIsLoadAutoStart(bool val); bool IsUnload(); void SetIsUnload(bool val); protected: char name[MAX_PATH]; char url[MAX_PATH]; char description[MAX_PATH]; char author[MAX_PATH]; bool isHiddenInManager; bool isLoadAutoStart; bool isUnload; public: VectorArray<pluginItem> Items; }; //Lua角本中編寫 local pin=plugin.create() --初始化插件 plugin.setName(pin,"Base")--設置插件名 plugin.setAuthor(pin,"Xp.W")--設置插件作者 plugin.setUrl(pin,"http://www.ruitesen.com")--設置插件網址 plugin.setDescription(pin,"基礎插件,構建了基本的菜單項和工具條,該插件不可卸載。")--設置插件描述 plugin.setIsHiddenInManager(pin,false)--設置插件是否插件管理中隱藏 plugin.setIsLoadAutoStart(pin,true)--設置插件是否有自啟動項 --插件中的控件集合,注意這里的集合名必須與c項目中一致 --集合中的每一項的索引標識固定,且順序固定,更改會導致異常 --plugin.addItem(pin,"index@parentIndex@name@type@size@label@shortcut@tooltip@icon@functionName@conditioName") --添加一級菜單 類型有:Menu MenuCommand CheckMenuCommand MenuSeparator plugin.addItem(pin,"0@-1@base_File@Menu@size@base_File@shortcut@base_File@icon@functionName@conditioName") plugin.addItem(pin,"1@-1@base_Edit@Menu@size@base_Edit@shortcut@base_Edit@icon@functionName@conditioName") plugin.addItem(pin,"2@-1@base_View@Menu@size@base_View@shortcut@base_View@icon@functionName@conditioName") plugin.addItem(pin,"3@-1@base_Option@Menu@size@base_Option@shortcut@base_Option@icon@functionName@conditioName") plugin.addItem(pin,"4@-1@base_Tool@Menu@size@base_Tool@shortcut@base_Tool@icon@functionName@conditioName") plugin.addItem(pin,"5@-1@base_Plugin@Menu@size@base_Plugin@shortcut@base_Plugin@icon@functionName@conditioName") plugin.addItem(pin,"6@-1@base_Help@Menu@size@base_Help@shortcut@base_Help@icon@functionName@conditioName") --添加二級菜單 plugin.addItem(pin,"0@0@base_File_OpenRMP@MenuCommand@size@base_File_OpenRMP@shortcut@base_File_OpenRMP@Icon_Base_Map_Open@OpenRmpProjectCommand@MapOpenedConditionEvaluator") plugin.addItem(pin,"1@0@MenuSeparator_File1@MenuSeparator@size@MenuSeparator_File1@shortcut@tooltip@icon@functionName@conditioName") plugin.addItem(pin,"2@0@base_File_Exit@MenuCommand@size@base_File_Exit@shortcut@base_File_Exit@icon@ExitCommand@conditioName") plugin.addItem(pin,"0@5@base_Plugin_Manager@MenuCommand@size@base_Plugin_Manager@shortcut@base_Plugin_Manager@icon@ShowPluginManagerCommand@conditioName") plugin.addItem(pin,"0@6@base_Plugin_Progress@MenuCommand@size@base_Plugin_Progress@shortcut@base_Plugin_Progress@icon@ShowProgressWindowCommand@conditioName") --添加默認工具條 plugin.addItem(pin,"0@-1@base_Toolbar_Default@Toolbar@size@base_Toolbar_Default@shortcut@base_Toolbar_Default@icon@functionName@conditioName") --添加工具條按鈕 類型有:Button ToggleButton SplitButton DropdownButton RadioButton CheckBox ComboBox TextBox TextBlock ToolbarSeparator plugin.addItem(pin,"0@0@base_Toolbar_Default_FullExtent@Button@Large@base_Toolbar_Default_FullExtent@shortcut@base_Toolbar_Default_FullExtent@Icon_Base_MapFullExtent@MapFullExtentCommand@MapOpenedConditionEvaluator") plugin.addItem(pin,"1@0@base_Toolbar_Default_PanMap@ToggleButton@Large@base_Toolbar_Default_PanMap@shortcut@base_Toolbar_Default_PanMap@Icon_Base_Map_Pan@MapPanMapCommand@MapOpenedConditionEvaluator") plugin.addItem(pin,"2@0@name@ToolbarSeparator@size@label@shortcut@tooltip@icon@functionName@conditioName") plugin.addItem(pin,"3@0@name@ComboBox@size@label@shortcut@tooltip@icon@functionName@conditioName") plugin.load(pin)--導入到插件管理
- 同樣的插件式管理框架也需要對dll的動態加載和函數獲取
// dll庫管理類 class XPCORE_API DLLManager { public: DLLManager(); virtual ~DLLManager(void){FreeALLDll();} //注冊Dll庫 bool AddDll(char* dllFileName); //是否包含對應GUID的Dl庫 bool ContainsDll(char* dllFileName); //是否包含對應GUID的Dl庫,並返回對應索引 bool ContainsDll(char* dllFileName,int &index); //反注冊Dll庫,釋放對應內存 bool FreeDll(char* dllFileName); //獲取對應GUID的dll模塊 HMODULE &GetMoudle(char* dllFileName); HMODULE &GetMoudle(const int index); //反注冊所有Dll庫,釋放對應內存 void FreeALLDll(); protected: VectorDic<char*,HMODULE> _modeules; }; //DllMAnager 源 DLLManager::DLLManager() { } bool DLLManager::AddDll(char* dllFileName) { HMODULE hModule; if(!ContainsDll(dllFileName)) { #ifdef UNICODE wchar_t fileName[MAX_PATH]; wchar_t* _fileName=fileName; CharToUnicode(dllFileName,_fileName); hModule=::LoadLibrary(_fileName); #else char _fileName[MAX_PATH]; strcpy(_fileName,dllFileName); hModule=::LoadLibrary(_fileName); #endif _modeules.Add(dllFileName,hModule); return true; } return false; } bool DLLManager::ContainsDll(char* dllFileName) { return _modeules.ContainsKey(dllFileName); } bool DLLManager::ContainsDll(char* dllFileName,int &index) { return _modeules.ContainsKey(dllFileName,index); } bool DLLManager::FreeDll(char* dllFileName) { int index=0; if(_modeules.ContainsKey(dllFileName,index)) { ::FreeLibrary(_modeules.GetValue(index)); _modeules.RemoveAt(index); return true; } return false; } HMODULE &DLLManager::GetMoudle(char* dllFileName) { int index=0; if(_modeules.ContainsKey(dllFileName,index)) { return _modeules.GetValue(index); } HMODULE _nullModule; return _nullModule; } HMODULE &DLLManager::GetMoudle(const int index) { if(_modeules.Count()>index && index>-1) { return _modeules.GetValue(index); } HMODULE _nullModule; return _nullModule; } void DLLManager::FreeALLDll() { for(int i=0;i<_modeules.Count();i++) { ::FreeLibrary(_modeules.GetValue(i)); } _modeules.Clear(); } //函數獲取類 模板定義 //從指定的DLL模塊中實例化對應對象的指針 template<typename T> T *GetPtrFromMoudle(HMODULE &moudle,const char *moudleName) { return (T*)::GetProcAddress(moudle,moudleName); } template<typename T> T GetObjFromMoudle(HMODULE &moudle,const char *moudleName) { return (T)::GetProcAddress(moudle,moudleName); }
- 資源的管理
class XPCORE_API ResourceService { public: //獲取字符資源從資源字典(返回的為字符串的轉換名或Imge的全路徑) static char *ParseStringFormDic(char *val); //獲取命令從資源字典 static XPCore::ICommand* ParseCommandFromDic(char *val); //獲取條件命令從資源字典 static XPCore::IConditionEvaluator* ParseConditionEvaluatorFromDic(char *val); };
- 基本命令接口,用於綁定到控件觸發事件中
namespace XPCore { /// <summary> /// A basic command interface. A command has simply an owner which "runs" the command /// and a Run method which invokes the command. /// </summary> DeclareBasedAPIInterface(ICommand,XPCore::Object) virtual bool IsEnabled()=0; virtual void SetIsEabled(bool val){}; virtual XPCore::Object* Owner()=0; virtual void SetOwner(XPCore::Object *val){}; virtual void OnOwnerChanged(){}; virtual void Run(){}; EndInterface /// <summary> /// A basic checked command interface. A command has simply an owner which "runs" the command /// and a Run method which invokes the command. /// </summary> DeclareBasedAPIInterface(ICheckedCommand,XPCore::ICommand) virtual bool IsChecked()=0; virtual void SetIsChecked(bool val){}; EndInterface }
- 基本條件命令接口,用於返回需要對控件狀態刷新的條件操作動作
//條件執行動作 enum XPCORE_API ConditionAction { //非激活 disable_action, //隱藏 hide_action, //無 null_action };
namespace XPCore { /// <summary> /// ConditionEvaluator /// </summary> DeclareBasedAPIInterface(IConditionEvaluator,XPCore::Object) //返回值 為枚舉型的整數值 virtual int ConditionEvaluator()=0; EndInterface }
寫到這,相信應該明白為什么要寫這個庫了,這是這個插件式框架的基石,有了它我就可以擴展了:這個插件式框架的主要思想就是:框架的開發與插件的開發要完全獨立,插件間也要完全獨立,框架要能實現動態加載插件中定義的方法和界面的對應的資源加載,所以用LUA角本定義配置信息,插件Dll開放指定兩個方法:AutoStart(加載命令和條件綁定資源)和LoadStringResource(加載字符和圖標資源)兩個方法就可以,具體調用可以上面提到的DLLManager,來調用定兩個方法,實現資源加載,動態生成控件和根據綁定條件刷新狀態,所有的綁定都是通過字符串來實現。
最后賦上運行圖片(主界面和插件管理界面),下一篇將寫一下如何基於SharpUI編寫一個自己要想的控件(以插件管理器中的導航面版為例):
界面中所有菜單和工具按鈕全是通過Base插件中自動生成。
本文版權所有,如轉發和引用請注明。