【SQL开源代码栏目提醒】:本文主要为网学会员提供“PB代码动态解析执行器 - 艺术”,希望对需要PB代码动态解析执行器 - 艺术网友有所帮助,学习一下!
PB
代码动态解析执行器 VFP当你看到
VB、 等开发语言提供的强大的宏执行功能, 是不是很羡慕呢?当你寻遍 PB 的帮助、关于 PB 开发的书籍或网站而不可得的时候,是不是感到有一丝的遗憾?如果你看到这篇文章,你应该感到振奋,因为你终于可以解决这个问题,而且解决
问题的思路既是如此简单、
代码既是如此简短。
如果再加上你的智慧,应该比我的解决方法更漂亮。
先让我们来了解一些基本知识。
一.
代码的载体在 PB 中,只有三个地方可以存放
代码,那就是函数、事件、属性。
这里所指的函数包括有返回值的通常意义下的函数和无返回值的过程以及声明的 WINAPI 函数,所指的事件指在对象中定义的处理程序,所指的属性指 PB 系统属性之外的实例变量、共享变量、全局变量。
函数和事件是可以用来调用执行的,属性则只能用来赋值和取值。
通常我们是在函数或事件中编写
代码。
二.对象的创建 可以使用 CREATE objecttype 来创建对象,如果对象类型是已知的, 如果对象类型是动态的,可以使用 CREATE USING objecttypestring 来创建对象。
三.对象函数的调用方式如果调用一个已知类型的对象的函数或事件,通常采用静态模式,也可采用动态模式,如果调用一个动态创建的对象的函数或事件,则必须采用动态模式,否则编译出错。
采用动态模式调用函数是在函数前加 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 G七.PB 实体的查找使用 FindClassDefinition 或 FindFunctionDefinition 或 LibraryDirectory 可以在库文件 使用 FindClassDefinition 或 FindFunctionDefinition 性能要好。
中查找 PB 实体是否存在,以下讲开发思路。
一.创建临时库文件1. 取临时目录作为库文件的存放目录2. 取待创建的临时库文件名称,保证不与已有文件重名3. 使用 LibraryCreate 函数创建临时库文件二.构造用于导入库文件的临时 PB 实体语法1. 取临时 PB 实体名称,保证不与库文件列表中已有 PB 实体重名2. 构造临时 PB 实体语法,区分函数和过程三.将临时 PB 实体导入临时库文件1. 取库文件列表和应用对象所在 pbl2 . 将 实 际 不 存 在 的 库 文 件 从 库 文 件 列 表 中 删 除 , 目 的 是 使 调 用PBORCA_SessionSetLibraryList 成功3. 调用 PBORCA_CompileEntryImport 将临时 PB 实体导入临时库文件四.将临时库文件加入到库文件搜索列表1. 调用 AddToLibraryList 加入新文件到库文件搜索列表五.创建临时 PB 实体所对应的对象并调用其函数以执行动态脚本1. 使用 CREATE USING objecttypestring 语句创建对象2. 通过动态调用对象的 of_exec 函数执行动态脚本,区分返回值类型六.销毁所有临时对象1. 调用 LibraryDelete 函数删除创建的临时库文件以下讲我在开发时遇到的一些矛盾或问题。
一.
代码是逐行解释还是让 PB 编译器去解释有些开发人员试图对动态脚本自行逐行解释,这是很困难的事情。
一行
代码如果脱离它的语境去执行,可能会产生错误的结果,即便你对 PB 所支持的函数全部做出解释,使用 PB 开发出来的对象、函数、事件等,你又如何去解释?这等同于你要花很大力气去编写一个 PB 编译器,除非你与 PB 编译器的开发团队合作,否则你很难获得成功。
所以你必须想办法让 PB 编译器去解释。
既然每行
代码不能脱离其它
代码而执行,那就创建一个函数或事件,让这个函数或事件包括你想写的所有
代码。
而函数或事件又不能脱离对象而存在,所以你必须想办法动态创建对象以及函数或事件,对象的声明必须依赖于库文件中的 PB 实体,由此推出关键是创建 PB 实体。
二.如何创建 PB 实体前面已讲过要使用 PBORCX0.DLL 中的 WINAPI 函数来创建并导入实体,这项技术并不难,在sybase 的网站或随便狗狗(百度)一下就能出来一大把。
三.创建的 PB 实体是存放在现有库文件中还是新文件中再导入我最初的想法是放在现有库文件中,这样就不必花费时间在创建库文件和删除库文件的执行上,结果发现,创建是成功,但运行时 PB 就是不“认识”我创建的 PB 实体,一创建该实体的对象就报错,想来 PB 在程序四.使用数据窗口的 Describe 调用全局函数还是其它方式来取得返回值大家都知道,使用数据窗口的 Describe 函数可以调用全局函数,但是它有很多的局限性,全局函数必须有简单类型的返回值,所有参数只能是简单数据类型而且不能通过参考传值。
如果在需要调用的地方直接使用新建对象的函数将不受这些限制。
五.如何进行垃圾对象的清理既然每次执行动态脚本要创建 PB 实体,如果执行得多了,就有很多垃圾对象,所以应进行清理。
可以通过 LibraryDelete 函数或 FileDelete 删除库文件。
有意思的是,一旦创建 PB 实体,即便你删除了,使用 FindClassDefinition 或 FindFunctionDefinition 还是能够找到,但你想使用该实体创建对象则失败, 这再次说明 PB 在程序启动时就读取库文件中有哪些实体形成
列表,在没有改变库文件列表之前,其实体列表不会改变。
以下是所附
代码的几点说明一.所附
代码是在 PB9 环境下开发的,程序运行时必须有 PBORC90.DLL,如果改成 PB 其它版本,请将 nvo_pbcompiler 中 WINAPI 函数所使用的动态库做相应修改。
二.nvo_pbcompiler 用于创建 PB 实体, f_execpbscript 这是 PB 动态脚本解释器的核心函数;用于执行一段 PB 脚本的样例
代码函数,返回值类型为字符串,如果要使用到其它场合,读者可自行编写函数,思路类似;w_pbcompiler_test 为一个用来执行 PB 脚本的样例界面窗口;其它函数有各自功能。
三.如果想运行 PB 动态脚本编译器,请先将所有
代码分对象导入库文件,然后编译,PB 动态脚本编译器在 PB 开发环境下无效。
四.为了程序方面的简化,有些所使用的全局函数请参考作者的其它文章。
五.所附
代码仅为脚本没有参数的情况下有效,如果你想
代码有参数,只需要简单地对脚本语法作些改变就可,当然前台需要用户定义参数。
六.本 PB 动态脚本解释器可执行所有有效的 PB
代码,例如访问全局变量、使用 PB 所有的
系统函数、使用
程序员开发的自定义函数、打开窗口、访问菜单、使用数据窗口等。
七.通常将本 PB 动态脚本解释器嵌入到现有的使用 PB 开发出来的系统而不是单独使用,这样可以加载很多免编译的外挂程序。
八.如果再拓宽它的应用范围,你甚至可以做到只需要一个框架程序,其它
代码全部动态加载和执行,这样就只需一次编译,升级和维护就变得非常简单,不过你附完整源
代码一.pbcompilerPBExportHeaderpbcompiler.sraPBExportCommentsPB 动态脚本解释器应用对象forwardglobal type pbcompiler from applicationend typeglobal transaction sqlcaglobal dynamicdescriptionarea sqldaglobal dynamicstagingarea sqlsaglobal error errorglobal message messageend forwardglobal variablesend variablesglobal type pbcompiler from applicationstring appname quotpbcompilerquotend typeglobal pbcompiler pbcompileron pbcompiler.createappnamequotpbcompilerquotmessagecreate messagesqlcacreate transaction
sqldacreate dynamicdescriptionareasqlsacreate dynamicstagingareaerrorcreate errorend onon pbcompiler.destroydestroysql
cadestroysqldadestroysqlsadestroyerrordestroymessageend onevent openopenw_pbcompiler_testend event二.f_execpbscriptPBExportHeaderf_execpbscript.srfPBExportComments执行动态脚本的样例函数global type f_execpbscript from function_objectend typeforward prototypesglobal function string f_execpbscript string as_returntype string as_pbscriptend prototypesglobal function string f_execpbscript string as_returntype stringas_pbscript/函数名称:f_execpbscript参数: as_returntype string 返回值类型as_pbscript string 动态
代码返回值: string 用户自定义或错误信息功能描述:执行动态
代码只返回字符串创建人: 康剑民创建日期:2007-02-12版本号: V1.0/nvo_pbcompiler lnv_pbcompilernonvisualobject luo_pbcompilerstring ls_entrynamels_librarynamestring ls_returnany la_returnlnv_pbcompiler create nvo_pbcompiler//创建实体对象iflnv_pbcompiler.of_createentryas_returntypeas_pbscriptls_librarynamels_entryname 1 thenif not isnullFindClassDefinitionls_entryname thenluo_pbcompiler create using ls_entrynamechoose case loweras_returntypecaseanyblobbooleancharcharacterdatedatetimedecdecimaldoubleintintegerlongrealstringtimeuintulongunsignedintunsignedintegerunsignedlongla_return luo_pbcompiler.dynamic of_exec//执行动态
代码ls_return stringla_returncase noneluo_pbcompiler.dynamic of_exec//执行动态
代码ls_return quotnonequotcase elseluo_pbcompiler.dynamic of_exec//执行动态
代码ls_return quotresult is disabledquotend chooseif isvalidluo_pbcompiler then destroy luo_pbcompilerelsels_return quoterrorquotend ifelsels_return quoterrorquotend ifif isvalidlnv_pbcompiler then destroy lnv_pbcompilerLibraryDeletels_librarynamereturn ls_returnend function三.f_parsePBExportHeaderf_parse.srf PBExportComments分解字符串到数组global type f_parse from function_objectend typeforward prototypesglobal function long f_parse readonly string as_text readonly string as_sep refstring as_listend prototypesglobal function long f_parse readonly string as_text readonly string as_sep refstringas_list/函数名称:f_parse参数: as_text string 来源字符串as_sep string 分隔字符as_list ref string 分析后形成的字符串数组返回值: long 分析后形成的数组元素个数功能描述:分析字符串到一个数组中创建人: 康剑民创建日期:2002-11-19版本号: V1.0/long ill_posstring ls_nullls_textls_text as_textas_list ls_nulli0ll_pos poswlowerls_textloweras_sepdo while ll_pos gt 0i as_listileftwls_textll_pos - 1ls_textmidwls_textll_pos lenwas_seplenwls_textll_pos poswlowerls_textloweras_seploopas_listi 1 ls_textreturn upperboundas_listend function四.f_replacetextPBExportHeaderf_replacetext.srfPBExportComments替换字符串global type f_replacetext from function_objectend typeforward prototypesglobal function string f_replacetext readonly string as_source readonly stringas_oldtag readonly string as_newtag readonly long al_seqend prototypesglobal function string f_replacetext readonly string as_source readonly stringas_oldtag readonly string as_newtag readonly longal_seq/函数名称:f_replacetext参数: as_source string 源字符串as_oldtag string 待替换特征字符串as_newtag string 替换后特征字符串al_seq long 第几个特征替换字符串需替换,0 表示全部返回值: string 替换后字符串功能描述:用一特征字符串替换指定字符串中的特征字符串参数 al_seq0 时表示全部替换创建人: 康剑民创建日期:2002-11-19版本号: V1.0/long ll_start_pos1ll_len_old_tagi 0string ls_leftls_returnls_sourcels_source as_sourcell_len_old_tag lenwas_oldtagll_start_pos poswlowerls_sourceloweras_oldtag1if al_seq 0 thenDO WHILE ll_start_pos gt 0ls_left leftwls_sourcell_start_pos - 1 as_newtagls_return ls_return ls_leftls_source midwls_sourcell_start_pos lenwas_oldtaglenwls_sourcell_start_pos poswlowerls_sourceloweras_oldtag1LOOPelseif al_seq gt 0 thenDO WHILE ll_start_pos gt 0i if al_seq i thenls_left leftwls_sourcell_start_pos - 1 as_newtagls_return ls_return ls_leftls_source midwls_sourcell_start_pos lenwas_olll_start_pos poswlowerls_sourceloweras_oldtag1end ifloopend ifls_return ls_return ls_sourcereturn ls_returnend function五.nvo_pbcompilerPBExportHeadernvo_pbcompiler.sruPBExportCommentsPB 动态脚本解释器forwardglobal type nvo_pbcompiler from nonvisualobjectend typeend forwardglobal type nvo_pbcompiler from nonvisualobjectend typeglobal nvo_pbcompiler nvo_pbcompilertype prototypes//打开一个会话Function long SessionOpen Library quotPBORC90.DLLquot Alias for quotPBORCA_SessionOpenquot//关闭一个会话Subroutine SessionClose long hORCASession Library quotPBORC90.DLLquot Alias forquotPBORCA_SessionClosequot//设置当前会话的库清单Function int SessionSetLibraryList long hORCASession ref string pLibNames intiNumberOfLibs Library quotPBORC90.DLLquot Alias for quotPBORCA_SessionSetLibraryListquot//设置当前会话对应的应用Function int SessionSetCurrentAppl long hORCASession string lpszApplLibNamestring lpszApplName Library quotPBORC90.DLLquot Alias forquotPBORCA_SessionSetCurrentApplquot//导入并编译实体Function int CompileEntryImport long hORCASession string lpszLibraryName stringlpszEntryName long otEntryType string lpszComments string lpszEntrySyntax longlEntrySyntaxBuffSize long pCompErrorProc long pUserData Library quotPBORC90.DLLquotAlias for quotPBORCA_CompileEntryImportquot//取临时目录Function long GetTempPathlong nBufferLength ref string lpBuffer Libraryquotkernel32quot Alias for quotGetTempPathAquot//获取一个已装载模板的完整路径名称FUNCTION ulong GetModuleFileNameulong hModuleref string lpFileNameulong nSizeLIBRARY quotkernel32.dllquot ALIAS FOR quotGetModuleFileNameAquotend prototypestype variablesend variablesforward prototypespublic function string of_gettemppath public function string of_getapppath public function integer of_createentry string as_returntype string as_pbscriptref string as_libraryname ref string as_entrynameend prototypespublic function string of_gettemppath/函数名称:of_gettemppath参数: 无返回值: string 临时路径功能描述:取临时路径创建人: 康剑民创建日期:2006-12-26版本号: V1.0/string ls_pathulong lu_size256ls_pathspace256GetTempPathlu_sizels_pathreturn trimwls_pathend functionpublic function string of_getapppath/函数名称:of_getapppath参数: 无返回值: string 应用程序路径功能描述:取应用程序路径创建人: 康剑民创建日期:2002-11-22版本号: V1.0/string ls_apppathls_apppathspace256GetModls_apppathReversels_apppathls_apppathReversemidwls_apppathposwls_apppath1return ls_apppathend functionpublic function integer of_createentry string as_returntype string as_pbscriptref string as_libraryname ref stringas_entryname/函数名称:of_createentry参数: as_returntype string 返回值类型as_pbscript string 动态
代码as_libraryname ref string 创建的库文件名称as_entryname ref string 创建的实体名称返回值: long 是否成功1 表示成功-1 表示失败功能描述:根据动态
代码创建实体创建人: 康剑民创建日期:2007-02-12版本号: V1.0/long ll_sid//会话编号long ll_index//对象序号string ls_librarylist//库文件列表string ls_librarylist_tmp//库文件列表临时string ls_temp_libraryname//临时库文件名称string ls_temp_path//临时目录string ls_syntax//实体语法string ls_app_libraryname//应用程序所在库文件名称integer li_result//结果string ls_entryname//对象名称classdefinition lcd_app//应用程序类定义对象string ls_librarylist_files//库文件integer ij//临时变量//开发环境下直接退出if handleGetApplication lt 0 then return -1//取库文件列表ls_librarylist_files getlibrarylist //取应用对象所在 pbllcd_app getapplication.classdefinitionls_app_libraryname lcd_app.librarynamels_temp_path this.of_gettemppath //取临时目录//取待创建的临时库文件名称ll_index 1ls_temp_libraryname ls_temp_path quottempquotstringll_index quot.pblquotdo while fileexistsls_temp_libraryname orposwquotquotls_librarylist_filesquotquotquotquotls_temp_librarynamequotquot gt 0ll_index ls_temp_libraryname ls_temp_path quottempquotstringll_index quot.pblquotloop//创建临时库文件LibraryCreatels_temp_librarynamequot临时库文件quotf_parsels_librarylist_filesls_librarylist//分解字符串到数组//判断库文件是否存在并形成新列表j 0for i 1 to upperboundls_librarylistif fileexistsls_librarylisti thenj ls_librarylist_tmpj ls_librarylisti.