基于hotfox的客户端的结构
来源:互联网 发布:淘宝教程 百度网盘 编辑:程序博客网 时间:2024/05/19 20:39
1.简述
hotfox是程序框架,由插件提供具体的应用入口,登录实现和业务主窗口.具体的应用业务逻辑由相应的插件实现。
除hotfox外,下文所有模块的代码在SVN上的nxclient目录下.以后除供应宝(合适的时候再迁移)以外的新的客户端程序全部采用本文所说的方法.
Frame1是一个常见的应用模式的实现插件.
logina是一个风格简单的登录模块.
AppEntryStyle1是一个动态构造菜单系统的模块,可以作为应用的主界面插件提供者.
GDSN_Supplier是一个具体应用的插件,该插件提供主窗口.
以下用示例描述这些组件如何组合构造不同的应用(未包含实际应用需要的其它模块)
GGOM应用的构造:
.hotfox
.Frame1
.logina
.GDSN_Supplier:GGOM客户端插件
单据监控应用构造:
.hotfox
.Frame1
.logina
.AppEntryStyle1
.dxm_c: 单据监控客户端插件
由于AppEntryStyle1是自绘风格的,通过宏USE_OWNERDRAW的控制保证应用模块风格的一致(如复用本地管理的模块).
如对TFrmOwnerDrawCommon的定义如下:
#ifdef USE_OWNERDRAW#include "TFrmOwnerDrawBase.h"class CSDK_FORMPUBLIC_API TFrmOwnerDrawCommon:public TFrmOwnerDrawBase{public: __fastcall TFrmOwnerDrawCommon(TComponent* Owner, bool load_res = true); void __fastcall LoadFormRes();protected: void __fastcall WndProc(TMessage& Message);};#else#include "BaseForm1.h"typedef TfrmBase1 TFrmOwnerDrawCommon;#endif
2.实现逻辑
2.1 hotfox
hotfox主程序代码如下:
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int){ try { Application->Initialize(); g_cfg_info_.Load(); Application->HelpFile = ExtractFilePath(Application->ExeName) + g_cfg_info_.help_file_; ///< 设置为非NT服务方式 HOTFOX::instance()->set_service_mode(false); HTX_LOGGER::instance()->sync_flag(true); HTX_LOGGER::instance()->hook_verbose(SEVERITY_DEBUG); HTX_LOGGER::instance()->set_callback(LoggerCallback,g_cfg_info_.show_startup_ ? (void*)1:(void*)2); if (g_cfg_info_.show_startup_) { frmStartup = new TfrmStartup(NULL); frmStartup->Show(); } else { wait_form = TfrmWaitForm::NewWaitForm(0,"启动程序"); } ///< 启动hotfox if (HOTFOX::instance()->svc()) { if (g_cfg_info_.show_startup_) delete frmStartup; if (last_error.IsEmpty()) { last_error = "程序启动失败,未描述的错误." ; } ShowMessage(last_error); return -1; } Application->Title = HOTFOX::instance()->server_info_.app_name_.c_str(); if (g_cfg_info_.show_startup_) { ::PostMessage(frmStartup->Handle,WM_CLOSE,0,0); Application->ProcessMessages(); } else { delete wait_form; } HTX_LOGGER::instance()->sync_flag(HOTFOX::instance()->server_info_.sync_log_); HTX_LOGGER::instance()->reset_callback(); ///< @note 本程序不支持插件日志挂钩 AppEntryFunc app_entry = HOTFOX::instance()->GetAppEntry(); short ok_flag = 1; CleanupFunc fp = 0; if (app_entry) { HTX_LOGGER::instance()->log(LO_STDOUT|LO_FILE,SEVERITY_INFO,"调用应用入口...\n"); if ((*app_entry)(0,&fp)) { ///< 应用入口执行失败或者不需要继续执行(如需要升级), 则程序不进程循环,直接结束退出 ok_flag = 0; } HTX_LOGGER::instance()->log(LO_STDOUT|LO_FILE,SEVERITY_INFO,"调用应用入口%s.\n",ok_flag ? "成功":"失败"); } if (ok_flag) Application->Run(); if (fp) (*fp)(); HOTFOX::instance()->stop(); HOTFOX::instance()->wait(); } catch (Exception &exception) { Application->ShowException(&exception); } catch (...) { try { throw Exception(""); } catch (Exception &exception) { Application->ShowException(&exception); } } return 0;}
2.2 Frame1
Frame1是一种应用入口,是应用客户端的常见形式:---用户执行登录操作
---升级检测和启动升级
---登录成功后打开应用主窗口
EZEntry函数是Frame1向hotfox登记的入口函数.
在插件Initialize时登记:
mgr_->SetAppEntry(EZEntry);
Frame1调用运行时初始化,提供释放操作由hotfox在结束前调用.
int EZEntry(void *arg,CleanupFunc *fp) { ///< 在hotfox中设置Application->HelpFile为什么不起作用? ()// AnsiString FileName = ExtractFilePath(Application->ExeName) + "ggom.chm";// Application->HelpFile = FileName; ///< 设置应用窗口Icon. if (!CEZMainPlugin::instance()->app_icon_file_.empty()) { HICON old_icon = NULL; TIcon *Icon = new TIcon(); Icon->LoadFromFile(CEZMainPlugin::instance()->app_icon_file_.c_str()); old_icon = CPluginHelper::SetIcon(2,Icon->Handle); ///< id=2是窗口基类用来指定窗口Icon的id if (old_icon) FreeResource(old_icon); Icon->ReleaseHandle(); delete Icon; ///< 如果不执行下行代码,则frmLogin的窗体的ICON为默认的.(为什么会这样?) Application->Icon->LoadFromFile(CEZMainPlugin::instance()->app_icon_file_.c_str()); } CPluginHelper::Init(); CBasePlugInModule::sc_->set_callback(SyncCallCallback); LoginFunc login_fp = CEZMainPlugin::instance()->mgr_->GetLoginFunc(); if (login_fp) { int ret = (*login_fp)(); if (ret==1) { ///< 检查是否需要升级 CBasePlugInModule::nlogger_->log(LO_FILE|LO_STDOUT,SEVERITY_DEBUG,"开始启动客户端升级程序\r\n"); LJShellExecute("CltLiveUpdate.exe", "1", "open", ExtractFilePath(Application->ExeName).c_str()); CBasePlugInModule::nlogger_->log(LO_FILE|LO_STDOUT,SEVERITY_DEBUG,"启动客户端升级程序结束\r\n"); CPluginHelper::Cleanup(); return 1; ///< 需要升级 } if (ret==-1) { CPluginHelper::Cleanup(); ///< @note 如果不执行,则会导致程序退出时异常. CBaseClientModule::g_async_fc_form return -1; } } INative_Logger_Base *log = CEZMainPlugin::instance()->nlogger_; bool sync_flag = log->sync_flag(); log->sync_flag(true); log->hook_verbose(SEVERITY_DEBUG); log->set_callback(LoggerCallback,CEZMainPlugin::instance()->show_startup_ ? (void*)1:(void*)2); if (CEZMainPlugin::instance()->show_startup_) { frmStartup = new TfrmStartup(NULL); frmStartup->Show(); } CPluginHelper::ShareResource(CachedData::instance(), CACHEDDATA_INFO, NULL); ///<同步调用获取过时的数据 int ret = CachedData::instance()->GetExpiredDataVersion(); if( ret ){ AnsiString err_str = AnsiString("获取数据版本失败,错误码")+ret; MessageShow(NULL,err_str.c_str(),"系统提示",MSGERROR); if (CEZMainPlugin::instance()->show_startup_) ::PostMessage(frmStartup->Handle,WM_CLOSE,0,0); CPluginHelper::Cleanup(); return -1; } ///< 登录成功,执行各插件的登录后操作(如从服务器下载数据) if (CBasePluginModule::plugin_mgr_->OnLogin()) { MessageShow(NULL,"登录处理失败","系统提示",MSGERROR); if (CEZMainPlugin::instance()->show_startup_) ::PostMessage(frmStartup->Handle,WM_CLOSE,0,0); CPluginHelper::Cleanup(); return -1; } if (CEZMainPlugin::instance()->show_startup_) { ::PostMessage(frmStartup->Handle,WM_CLOSE,0,0); Application->ProcessMessages(); } log->reset_callback(); log->sync_flag(sync_flag); ///< 恢复日志的同步标志 CEZMainPlugin::instance()->NotifyUserReady(); ///< 通知服务器客户端已就绪(可以接收服务器主动推送的消息) AppMainWindowFunc main_wnd_entry = CEZMainPlugin::instance()->mgr_->GetAppMainWindowEntry(); if (main_wnd_entry==0) { ///< 未指定启动的主窗口 CPluginHelper::Cleanup(); return -1; } (*main_wnd_entry)(0); *fp = &Cleanup; return 0;}
2.3 logina
logina插件实现了一种常用的登录模式.
风格简单.支持本地服务器和服务器查找,支持网络设置.
///< 登录函数int Login() { TfrmLogin *frmLogin = new TfrmLogin(NULL); int result = frmLogin->ShowModal(); ///< 登录过程包含一个版本比较操作,决定是否需要升级 if (frmLogin->GetUpdateFlag()) { ///< 检查是否需要升级 delete frmLogin; return 1; ///< 需要升级 } if (result!=mrOk) { delete frmLogin; return -1; } CLoginA::instance()->first_logon_ = false; ///< 已经登录过,以后连接断开只需要重新登录(597协议) CLoginA::instance()->connector_ = frmLogin->GetConnector(); delete frmLogin; return 0;}
登录模块的登记是在Prepare中完成的.
int CLoginA::Prepare() { parent::Prepare(); mgr_->SetLoginFunc(Login); ///< 由本插件提供登录入口 return 0;}
2.4 AppEntryStyle1
AppEntryStyle1插件从供应宝业务主窗口改造而来,具有以下特性:.从服务器获取菜单信息,动态构造菜单
.具有权限控制
.响应菜单操作启动相应功能
int Main_Wnd(void *arg) { ///< 启动业务窗口 TBusinessMainForm *frmBiz; Application->CreateForm(__classid(TBusinessMainForm), &frmBiz); return 0;}int CAppEntryStyle1::Initialize() { parent::Initialize(); mgr_->SetAppMainWindowEntry(Main_Wnd); return 0;}
2.5 一个应用:GDSN_Supplier
GDSN_Supplier插件是实现GGOM功能的客户端插件.在GGOM应用中作为主窗口的提供者.
///< 应用主窗口函数int Main_Wnd(void *arg) { AnsiString FileName = ExtractFilePath(Application->ExeName) + "ggom.chm"; Application->HelpFile = FileName; if (UserIsAdmin()) { ///< 管理员模式 TfrmSystemManage *frmMain; Application->CreateForm(__classid(TfrmSystemManage), &frmMain); } else { ///< 非管理员模式 TFrmMainGDSNSup *frmMain; Application->CreateForm(__classid(TFrmMainGDSNSup), &frmMain); } return 0;}
主窗口函数在Initialize时登记.
int CAppEntryStyle1::Initialize() { parent::Initialize(); mgr_->SetAppMainWindowEntry(Main_Wnd); return 0;}
- 基于hotfox的客户端的结构
- 初探基于TCP的服务器/客户端结构的聊天系统
- Hotfox插件向导生成工程后配置的调整
- 基于doubango的iphone客户端:源代码结构简介
- 使用Hotfox Plugin Wizard创建客户端插件
- 初探基于TCP的服务器/客户端结构的聊天系统(三)之表情聊天的实现
- 初探基于TCP的服务器/客户端结构的聊天系统(四)视频聊天的实现
- 基于SOA的结构
- 基于Socket通信的BS结构文件服务器客户端的简易程序(1)
- 基于Socket通信的BS结构文件服务器客户端的简易程序(2)
- 基于Socket通信的BS结构文件服务器客户端的简易程序(3)
- 初探基于TCP的服务器/客户端结构的聊天系统(二)之应用层通信协议设计
- 【读书笔记】iOS-使用Web Service-基于客户端服务器结构的网络通信(一)
- 基于Qwt的Qt客户端
- 基于Swing的GUI客户端
- 基于MFC的FTP客户端
- 基于eXosip的SIP客户端
- 基于AssetBundle的客户端资源
- Query类的中方法list()与iterator()的区别?
- Kettel应用实例及可视化展示
- win7无线连接不上 || 无线已连接但是上不了网
- 安卓busybox的几种安装方式
- pomelo的Test game server点击无效
- 基于hotfox的客户端的结构
- c/c++中const的常用方法
- 基本数据类型对象包装类
- DirectX的Vertex Buffer顶点缓冲的理解和应用 Shader必知必会
- 汇编语言中PTR的含义及作用
- Windows server 2008 II7下架设ASP网站标准流程
- 一类void 递归函数的非递归实现
- php发布webservice
- 进程与线程的一个简单解释