/** /file FILENAME /mainpage 让主程序可以通过python脚本扩展功能及boost.python的使用 /brief 本文的内容是:在主程序中嵌入一种脚本语言:python,并且可以通过写python脚本扩展程序功能。 /author 刘凯 mslk.sa@gmail.com /date 20060525 一般情况,为python写个扩展模块(即python脚本中调用扩展模块的功能),或者主程序中调用python解释器执行脚本, 都是单向的。 但要想让python脚本做为主程序的扩展,就像emacs中写lisp来扩展功能,情况就会复杂一点, 即主程序要调用python解释器执行脚本,脚本执行中,要使用主程序的功能或者修改主程序中对象状态。 如果在使用主程序的功能时,主程序又要访问修改当前执行脚本中的python对象的状态或功能,情况会更加复杂。就是必须有双向的通信关系。 如果程序中提供有脚本扩展的能力,好处还是非常大,某些功能用户可以自己实现, 比如有程序中生成了很多对象,都有名字和一些属性,用户可以写段脚本按名字分类整理计算(有了新公式对数据进行处理)输出数据等等。 某些性能无关的功能,用脚本实现真是很方便。 其实嵌入任何脚本都是不错的,脚本语言本身都很简单,但boost.python实在简化了大量大量的工作,所以就选python做扩展,简单嘛。 这里把我的一点经验说一下, 首先,要搞清楚,想从python脚本中访问的功能,就必须做成python的扩展模块(用BOOST_PYTHON_MODULE) 其次,模块中要导出主程序中的根对象和其功能(boost::python::class_),通过根对象可以逐渐访问主程序中其它需要的对象(也要导出), 这也包括需要的一些继承关系为多态(boost::python::wrapper, boost::python::bases)和全局函数(boost::python::def)。 注意: 1.可以建多个扩展模块,有继承关系的类,不能放到不同的模块中,否则子类就不能在脚本中使用了。 2.对于任何模块,如:BOOST_PYTHON_MODULE(PowerApp),要在“Py_Initialize();”调用之后 调一下initPowerApp()(模块名前加init)这个函数,最好也调一下”PyRun_SimpleString("import PowerApp/n");“。 3.def的函数如果有返回值,可能就需要bp::return_value_policy<>,把这个相关的文档先看看 4.新建的mfc项目要把:[项目属性 >> c/c++ >> 语言] 中的[启用运行时类型信息]打开, [项目属性 >> c/c++ >> 代码生成]中的[运行时库]要选 ”多线程[调试] DLL“ 具体用法很简单看boost.python文档,我英文半级的水平都可以看。 为了快速建立信心,这里举个小例子:假定都有这行代码:namespace bp = boost::python 先决定把程序中那个对象作为根来导出,这里根对象的意思是其它对象都可以通过根的属性、函数等直接或间接的访问到,当然可以导出多个根。 如果无法决定,可以先把CWinApp的子类(假设为:CPowerApp)作为根好了,就是AfxGetApp()得到的static_cast一下。 我们在PowerApp模块中提供函数来访问得到它的引用。 主程序中所有的类,用类似的方法均可导出到扩展模块中,更具体的细节:异常的处理,复杂的数据,参考boost.python文档都没什么问题。 */ # include "stdafx.h" # include # include # ifdef _DEBUG # pragma comment(lib, "boost_python-vc71-mt-gd-1_33_1") # else # pragma comment(lib, "boost_python-vc71-mt-1_33_1") # endif # include "power.h" CPowerApp *GetApp() { assert(dynamic_cast(AfxGetApp())); return static_cast(AfxGetApp()); } # include /// 演示用的父类 class IPeople { std::string _name; public: virtual void msg_box() = 0; std::string const& get_name(); void set_name(std::string const&); }; /// 演示用的子类 class ApplicationAuthor : public IPeople { std::wstring _content; // 对程序的一下说明 public: void msg_box(); void set_content(std::wstring const&); }; /// 伪造一个CPowerApp的成员函数 /** 如果改为成员函数,需要在CPowerApp加一个成员变量和函数 -# ApplicationAuthor _author; -# ApplicationAuthor &GetAuthor(); -# ApplicationAuthor &GetAuthor() {return _author;} // 不要inline,取不到地址了 修改”关于“对话框显示:_author.get_name() 和 _author.get_content()这两个成员的内容 */ ApplicationAuthor& CPowerApp_GetAuthor(CPowerApp *pApp) { static ApplicationAuthor suppose_PowerApp_memeber; // 假定为CPowerApp的成员变量 return suppose_PowerApp_memeber; } namespace bp = boost::python; BOOST_PYTHON_MODULE(PowerApp) { bp::def("GetApp", &GetApp, bp::return_value_policy<:reference_existing_object>()); bp::class_("App") .def("About", &CPowerApp::OnAppAbout) .def("GetAuthor", &CPowerApp_GetAuthor, bp::return_value_policy<:reference_existing_object>()) ; } /// 对于抽象类,需要包装,把纯虚函数处理一下,具体参考文档 struct IPeopleWrapper : public IPeople, public bp::wrapper { void msg_box() {this->get_override("msg_box")();} }; BOOST_PYTHON_MODULE(DataManager) { bp::class_("IPeople") .def("set_name", &IPeople::set_name) .def("get_name", &IPeople::get_name, bp::return_internal_reference<>()) .def("msg_box", &IPeople::msg_box) ; bp::class_ >("ApplicationAuthor") .def("set_content", &ApplicationAuthor::set_content) ; } std::string const& IPeople::get_name() {return _name;} void IPeople::set_name(std::string const& v) {_name = v;} void ApplicationAuthor::set_content(std::wstring const& c) {_content = c;} void ApplicationAuthor::msg_box() {MessageBoxW(NULL, _content.data(), L"PowerApp good! Content:", MB_OK); MessageBoxA(NULL, get_name().data(), "IPeople::name", MB_OK);} /** 遗留的问题: -# .def的函数,std::string、wstring作为函数的返回值有问题,但作为函数的参数可以 */ /// CPowerApp构造函数调用这个函数 void InitPy() { Py_Initialize(); PyRun_SimpleString("import wx/n"); initPowerApp(); PyRun_SimpleString("import PowerApp/n"); /// 模块太多的话,就需要简化一下了,定义一个宏,把模块名传入宏 # define INIT_PM(v) init##v##();PyRun_SimpleString("import " #v "/n"); INIT_PM(DataManager); # undef INIT_PM } /// CPowerApp的析构调用这个函数:Py_Finalize() /// 最后一下,加个菜单调一下这个函数, void pyShell() { PyRun_SimpleString("from PyShell import main/nmain()/n"); } /** 使用指南 要同时安装好: python24(http://www.python.org) wxPython(http://www.wxpython.org) 编译好:boost.python(http://www.boost.org) 编译方法很简单,参考文章http://blog.csdn.net/mslk/archive/2005/11/08/525278.aspx的最后说明。 bjam --with-python-root=python24主目录路径 将PowerApp.exe,boost_python* 放入python24的主目录,执行调出pyShell dir (PowerApp) dir (DataManager) app = PowerApp.GetApp() app.About() a = app.GetAuthor() a.msg_box() a.set_name("LiuKai mslk.sa@gmail.com") a.set_content("boost.python Very Good!") a.msg_box() app.About() …………………… */ /** 菜鸟指南: 打开vs2003,[文件 >> 新建 >> 项目] 选 [mfc >> mfc 应用程序],名称:Power,完成 [工具 >> 选项 >> 项目 >> vc++目录] 配置[包含文件]添加boost,和python24/include 配置[库文件]添加boost/bin和python24/libs 把这篇文章保存到一个cpp后缀的文件,加入项目中 找到CPowerApp::CPowerApp函数,添加函数调用 InitPy(); CPowerApp构造函数前面加上声明: void InitPy(); void pyShell(); 打开资源,添加一个菜单名:pyShell,消息处理函数选为CPowerApp的成员, 消息处理函数内调用: pyShell(); 再强调一下: [项目属性 >> c/c++ >> 语言] 中的[启用运行时类型信息]打开, [项目属性 >> c/c++ >> 代码生成]中的[运行时库]要选 ”多线程[调试] DLL“ 编译后,将Power.exe拷入Python24的主目录,执行后点菜单,弹出来pyShell, 按照使用指南键入命令,即可看到效果。 */
boost python单步调试_让主程序可以通过python脚本扩展功能及boost.python的使用
最新推荐文章于 2022-05-15 09:29:24 发布