PB动态脚本解释器

教程发布:风哥 教程分类:ITPUX技术网 更新日期:2022-02-12 浏览学习:183

当你看到VB、VFP等开发语言提供的强大的宏执行功能,是不是很羡慕呢?当你寻遍PB的帮助、关于PB开发的书籍或网站而不可得的时候,是不是感到有一丝的遗憾?如果你看到这篇文章,你应该感到振奋,因为你终于可以解决这个问题,而且解决问题的思路既是如此简单、代码既是如此简短。如果再加上你的智慧,应该比我的解决方法更漂亮。
先让我们来了解一些基本知识。
一.代码的载体
在PB中,只有三个地方可以存放代码,那就是函数、事件、属性。这里所指的函数包括有返回值的通常意义下的函数和无返回值的过程以及声明的WINAPI函数,所指的事件指在对象中定义的处理程序,所指的属性指PB系统属性之外的实例变量、共享变量、全局变量。函数和事件是可以用来调用执行的,属性则只能用来赋值和取值。通常我们是在函数或事件中编写代码。
二.对象的创建
如果对象类型是已知的,可以使用CREATE o b j e c ttype 来创建对象,如果对象类型是动态的,可以使用CREATE USING o b j e c ttypestring来创建对象。
三.对象函数的调用方式
如果调用一个已知类型的对象的函数或事件,通常采用静态模式,也可采用动态模式,如果调用一个动态创建的对象的函数或事件,则必须采用动态模式,否则编译出错。采用动态模式调用函数是在函数前加dynamic 关键字。读者可查阅PB帮助。
四.库文件的搜索
PB中用于编程的对象是保存在PBL、PBD、DLL中的,如果想要使库文件中的对象在应用程序运行时有效,常用的方法是直接将该PBL编译进去或者说使该PBL在库搜索列表中。如果需要在运行状态下改变库文件搜索列表,PB提供了SetLibraryList和AddToLibraryList两个函数。SetLibraryList函数只能在应用对象的open事件脚本中使用,否则应用程序会崩溃,AddToLibraryList为PB9新增的函数,用于将新文件加入到库文件搜索列表中,这两个函数都是只能在编译环境下有效。
五.PB库文件的创建与销毁
PB提供了LibraryCreate函数用于创建库文件,提供LibraryDelete、FileDelete函数用于删除库文件。
六.PB实体的导入
PB提供了LibraryImport函数用于根据对象语法创建PB实体并导入到库文件中,但该函数目前只支持数据窗口对象类型的导入。不过,PB提供了相应的WINAPI函数支持其它类型实体的导入,这些相关的WINAPI包括在PBORCX0.DLL中(不同的PB版本有不同的文件名称,如PBORC90.DLL、PBORC80.DLL)。有关实体的导入的WINAPI包括PBORCA_SessionOpen、PBORCA_SessionClose、PBORCA_SessionSetLibraryList、PBORCA_SessionSetCurrentAppl、PBORCA_CompileEntryImport等,读者可以到Sybase网站找ORCA Guide相应文章寻求支持。
七.PB实体的查找
使用FindClassDefinition或FindFunctionDefinition或LibraryDirectory可以在库文件中查找PB实体是否存在,使用FindClassDefinition或FindFunctionDefinition性能要好。
以下讲开发思路。
一.创建临时库文件
1. 取临时目录作为库文件的存放目录
2. 取待创建的临时库文件名称,保证不与已有文件重名
3. 使用LibraryCreate函数创建临时库文件
二.构造用于导入库文件的临时PB实体语法
1. 取临时PB实体名称,保证不与库文件列表中已有PB实体重名
2. 构造临时PB实体语法,区分函数和过程
三.将临时PB实体导入临时库文件
1. 取库文件列表和应用对象所在pbl
2. 将实际不存在的库文件从库文件列表中删除,目的是使调用PBORCA_SessionSetLibraryList成功
3. 调用PBORCA_CompileEntryImport将临时PB实体导入临时库文件
四.将临时库文件加入到库文件搜索列表
1.调用AddToLibraryList加入新文件到库文件搜索列表
五.创建临时PB实体所对应的对象并调用其函数以执行动态脚本
1. 使用CREATE USING o b j e c ttypestring语句创建对象
2. 通过动态调用对象的of_exec函数执行动态脚本,区分返回值类型
六.销毁所有临时对象
1.调用LibraryDelete函数删除创建的临时库文件
以下讲我在开发时遇到的一些矛盾或问题。
一.代码是逐行解释还是让PB编译器去解释
有些开发人员试图对动态脚本自行逐行解释,这是很困难的事情。一行代码如果脱离它的语境去执行,可能会产生错误的结果,即便你对PB所支持的函数全部做出解释,使用PB开发出来的对象、函数、事件等,你又如何去解释?这等同于你要花很大力气去编写一个PB编译器,除非你与PB编译器的开发团队合作,否则你很难获得成功。所以你必须想办法让PB编译器去解释。既然每行代码不能脱离其它代码而执行,那就创建一个函数或事件,让这个函数或事件包括你想写的所有代码。而函数或事件又不能脱离对象而存在,所以你必须想办法动态创建对象以及函数或事件,对象的声明必须依赖于库文件中的PB实体,由此推出关键是创建PB实体。
二.如何创建PB实体
前面已讲过要使用PBORCX0.DLL中的WINAPI函数来创建并导入实体,这项技术并不难,在sybase的网站或随便狗狗(百度)一下就能出来一大把。
三.创建的PB实体是存放在现有库文件中还是新文件中再导入
我最初的想法是放在现有库文件中,这样就不必花费时间在创建库文件和删除库文件的执行上,结果发现,创建是成功,但运行时PB就是不“认识”我创建的PB实体,一创建该实体的对象就报错,想来PB在程序启动时就读取库文件中有哪些实体形成列表,在没有改变库文件列表之前,其实体列表不会改变,这样对新建的实体就视而不见了。所以我不得不试着新建一个PBL,在新建的PBL中创建PB实体,然后使用AddToLibraryList将新建的PBL包括进来,这一试果然成功。
四.使用数据窗口的Describe调用全局函数还是其它方式来取得返回值
大家都知道,使用数据窗口的Describe函数可以调用全局函数,但是它有很多的局限性,全局函数必须有简单类型的返回值,所有参数只能是简单数据类型而且不能通过参考传值。如果在需要调用的地方直接使用新建对象的函数将不受这些限制。
五.如何进行垃圾对象的清理
既然每次执行动态脚本要创建PB实体,如果执行得多了,就有很多垃圾对象,所以应进行清理。可以通过LibraryDelete函数或FileDelete删除库文件。有意思的是,一旦创建PB实体,即便你删除了,使用FindClassDefinition或FindFunctionDefinition还是能够找到,但你想使用该实体创建对象则失败,这再次说明PB在程序启动时就读取库文件中有哪些实体形成列表,在没有改变库文件列表之前,其实体列表不会改变。
以下是所附代码的几点说明
一.所附代码是在PB9环境下开发的,程序运行时必须有PBORC90.DLL,如果改成PB其它版本,请将nvo_pbcompiler中WINAPI函数所使用的动态库做相应修改。
二.nvo_pbcompiler用于创建PB实体,这是PB动态脚本解释器的核心函数;f_execpbscript()用于执行一段PB脚本的样例代码函数,返回值类型为字符串,如果要使用到其它场合,读者可自行编写函数,思路类似;w_pbcompiler_test为一个用来执行PB脚本的样例界面窗口;其它函数有各自功能。
三.如果想运行PB动态脚本编译器,请先将所有代码分对象导入库文件,然后编译,PB动态脚本编译器在PB开发环境下无效。
四.为了程序方面的简化,有些所使用的全局函数请参考作者的其它文章。
五.所附代码仅为脚本没有参数的情况下有效,如果你想代码有参数,只需要简单地对脚本语法作些改变就可,当然前台需要用户定义参数。
六.本PB动态脚本解释器可执行所有有效的PB代码,例如访问全局变量、使用PB所有的系统函数、使用程序员开发的自定义函数、打开窗口、访问菜单、使用数据窗口等。
七.通常将本PB动态脚本解释器嵌入到现有的使用PB开发出来的系统而不是单独使用,这样可以加载很多免编译的外挂程序。
八.如果再拓宽它的应用范围,你甚至可以做到只需要一个框架程序,其它代码全部动态加载和执行,这样就只需一次编译,升级和维护就变得非常简单,不过你要考虑系统的可用性、系统性能和系统的稳定性等。

本文标签:
本文标题:PB动态脚本解释器
网站声明:本文由风哥整理发布,转载请保留此段声明,本站所有内容将不对其使用后果做任何承诺,请读者谨慎使用!
【上一篇】
【下一篇】