PowerBuilder编程新思维1:扩展(Lua)
<第一部分 Inside 无形的枷锁>
PB实在太古老了,长久的积淀变成了沉重的包袱,像是一个无形的枷锁制约着工具的发展。
前言
PowerBuilder作为开发工具退出一线行列已经很久了,在2019年来谈这样一款老旧的编程工具是否有意义?诚然,PB有着太多硬伤,但还是有它的用武之地的。而且今天讲的这个“新思维”大部分内容是我在其它地方没有见过的,包含一些比较新的思想,但愿能够给各位读者带来耳目一新的感觉和有价值的参考。
由于内容比较多,打算合起来作为一个库,名字叫PowerPlume,中文为“孔雀翎”,古龙书中强大又美丽的武器。
PowerBuilder编程新思维1:扩展(Lua)
PB环境是封闭的,导致有些部分的能力极弱,依赖开发各类DLL和扩展(PBNI)。把脚本语言引擎引入到PB中,有着很多的现实意义,最大的好处就是能够直接利用脚本语言的各类资源与源码,不用再重复开发。
常见的脚本语言有JS、Python、Ruby等,为什么选择Lua?因为小、因为快。JS由于历史原因,太庞大了。Python和Ruby也不是很小巧。而且环境配置复杂。Lua小巧,接口也很友好,资源也丰富。
接口方面,选择PBNI而不是直接使用DLL,是因为需要处理一些指针和支持PowerObject,总体与LuaApi基本一致。
global type n_lua from nonvisualobject native "pblua105.dll" public function long register(string name, powerobject obj) public function long setglobal(string name) public function long getglobal(string name) public function long setfield(long idx, string key) public function long getfield(long idx, string key) public function long pushnil() public function long pushboolean(boolean value) public function long pushlong(long value) public function long pushdouble(double value) public function long pushstring(string value) public function long pushpowerobject(powerobject value) public function long toboolean(long idx, ref boolean value) public function long tolong(long idx, ref long value) public function long todouble(long idx, ref double value) public function long tostring(long idx, ref string value) public function long topowerobject(long idx, ref powerobject value) public function boolean isboolean(long idx) public function boolean islong(long idx) public function boolean isdouble(long idx) public function boolean isstring(long idx) public function boolean ispowerobject(long idx) public function boolean isnil(long idx) public function boolean istable(long idx) public function long spop(long n) public function long scopy(long idx) public function long sinsert(long idx) public function long sremove(long idx) public function long sreplace(long idx) public function long sgettop() public function long createtable(long arr, long rec) public function long settable(long idx) public function long gettable(long idx) public function long setmetatable(long idx) public function long nextkey(long idx) public function long docall(long args, long results) public function long dofile(string path) public function long dostring(string str) public function long enablecall(boolean ui) end type
最先实现的功能是在Lua中很简单,PB却无法提供的功能——HashTable。
实例:function integer of_map_set (string as_table, string as_key, powerobject an_value)
在Lua接口基础上,添加了pushpowerobject这个接口,以处理PB对象。
int ret ret = api.getglobal(as_table) if (ret = LUA_TNIL) then api.createtable(0, 0); elseif (ret <> LUA_TTABLE) then return FAILURE end if api.pushstring(as_key) api.pushpowerobject(an_value) api.settable(-3); if (ret = LUA_TNIL) then api.setglobal(as_table) end if return SUCCESS
其次,必须利用Lua中比较成熟的资源,可以在https://luarocks.org/上查找下载数较多的模块,放入lib\lua目录下即可require。需要注意的是我们使用的是最新的Lua53,有些库可能不兼容。在源码中已经放入socket(http,ftp,stmp),xml,json库。后续会陆续补上相关的封装接口。
实例:使用cjson模块解析json
1 string res 2 3 i_lua.api.dostring("return require('cjson')") 4 i_lua.api.pushstring('decode') 5 i_lua.api.gettable(-2) 6 7 if (not i_lua.api.isfunction(-1)) then 8 messagebox("","error") 9 end if 10 11 i_lua.api.pushstring(mle_json.text) 12 i_lua.api.docall(1,1) 13 14 i_lua.api.pushstring("sites") 15 i_lua.api.gettable(-2) 16 17 string key,val 18 integer idx 19 idx = i_lua.api.sgettop() 20 21 i_lua.api.pushnil() 22 do while i_lua.api.nextkey(idx)<>0 23 i_lua.api.pushstring("name") 24 i_lua.api.gettable(-2) 25 i_lua.api.tostring(-1, val) 26 i_lua.api.spop(2) 27 tv_1.InsertItemFirst(0,val,1) 28 loop 29 30 i_lua.api.spop(3)
另外,在构建PowerPlume这个库的时候,整体架构在Lua这个模块之上,主要是利用其HashTable这个功能。
效果及源码
源码: PowerPlumeDemoV0.1.1.rar
提供了PB10.5 PB11.5 PB12.5三个版本
<本节完>