一个框架基础的东西,一般也是操作的最基础的类,比如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插件中自动生成。
本文版权所有,如转发和引用请注明。