欢迎访问 Lu程序设计
用C/C++设计Lu扩展动态库
1 说明
要演示本文的例子,你必须下载Lu32脚本系统。本文的例子仅需要C++格式的头文件lu32.h,相信你会找到并正确使用这个文件。
用C/C++编译器创建一个DLL程序,使用本文的例子代码生成 DllExample.dll。
2 关于Lu扩展动态库
往Lu中添加常量、函数或其他任意类型的数据是非常方便的。为了便于函数和数据共享,常将函数和数据封装到动态库中,以动态库的形式向Lu添加,这种动态库称Lu扩展动态库。Lu扩展动态库只需要一个输出函数:
//Lu扩展动态库唯一的输出函数; //hLu:Lu32.dll的句柄;iInit!=0:初始化动态库,iInit=0:释放动态库; //me:指向任意数据的指针,可用于验证用户能否使用该库,为了方便验证,约定该指针指向一个wchar_t类型的字符串。 //iInit!=0时,返回值LuDll=0:初始化失败;LuDll=1:初始化成功;返回值LuDll=2:初始化成功,仅注册一些常量,初始化完成后可卸载该库。 //iInit=0时,返回值LuDll=0:释放失败;LuDll=1:释放成功; extern "C" int _stdcall LuDll32(HINSTANCE hLu,int iInit,void *me) { . . . if(iInit) //初始化动态库 { . . . return 1; } else //释放动态库 { . . . return 1; } }
可以看出,虽然Lu扩展动态库只有一个输出函数,但该函数接受了主调程序加载的Lu32.dll的句柄,因而可以完成任意复杂的功能。为了应用程序的安全性,在Lu扩展动态库中禁止使用InitLu(初始化Lu)和FreeLu(释放Lu)这两个函数。
设计商业性Lu扩展动态库时,在初始化过程中要验证me,看宿主程序提供的字符串形式的注册码是否符合要求,若符合要求,商业库可提供全部功能,否则仅提供部分功能或禁止使用该库。
如果在动态库中启动了另一线程,要注意多线程程序中使用Lu函数的原则,即:除了GetRunErr()、TestRunErr()和SetRunErr()三个函数外,其余的函数只能在单线程中使用(不允许两个及两个以上的线程同时运行这些函数)。为此,约定用pUseLu=SearchKey("UseLu",5,luPriKey_User); 获得一个函数指针进行多线程之间互斥使用Lu的通讯,该函数可在主程序或Lu扩展动态库中定义,函数说明如下:
//(1)iUse=1时,表示要申请使用Lu,若函数返回值 UseLu=0:申请成功;UseLu=1:申请不成功, //其他线程正在使用Lu,稍后再进行申请;UseLu=-1:申请不成功,表示应用程序要释放Lu, //因此要做好退出前的准备工作。 //(2)iUse=2时,表示要申请使用Lu,如果其他线程正在使用Lu,函数不返回,进行等待,直至申请成功。 //若函数返回值 UseLu=0:申请成功;UseLu=1:申请不成功,线程本身正在使用Lu,不能重复进行申请; //UseLu=-1:申请不成功,表示应用程序要释放Lu,因此要做好退出前的准备工作。 //(3)iUse=0时,表示要归还Lu的使用权,函数返回值无意义。 //(4)iUse=3时,设置安全标志,表示Lu运行正常,函数返回值无意义。 一般在二级函数中设置该标志,当该函 //数在较长时间内运行时,可用此标志通知Lu,此时的运行是正常的,没有陷入无限循环等情况。 //(5)iUse=4时,取消安全标志,表示Lu运行处于不可控制阶段(有陷入无限循环的可能),函数返回值无意义。 //(6)iUse=5时,查询安全标志,UseLu=0:运行正常;UseLu=1:运行情况无法预测(有陷入无限循环的可 //能),这是Lu运行的一般情况。 //注意1:Lu是极为重要而有限的资源,用完后要及时归还。 //注意2:UseLu(1)(或者UseLu(2))和UseLu(0)必须成对使用。注意不能在二级函数中使用该功能, //因为二级函数本身就是在Lu工作区中运行的。 //注意3:UseLu(3)和UseLu(4)也要成对使用,且一般在二级函数中使用该功能。 extern "C" int _stdcall UseLu(int iUse);
在主调程序或任一个Lu扩展动态库中均可以设置一个函数void _stdcall LuMessage(wchar_t *)。然后将该函数的地址用InsertKey("\0\0\0\0",4,luPubKey_User,LuMessage,NULL,NULL,1,v)传送给Lu。约定所有Lu扩展动态库都使用该函数发送信息。任一线程均可根据需要设置该函数。
在设计Lu扩展动态库时,要采用二级函数命名空间方式(例如:"Fun2Space::FunName")输出函数,以尽量避免函数重名。
在设计Lu扩展动态库时,要遵循谁注册函数和数据谁释放的原则。
在加载和卸载Lu扩展动态库时,要遵循先进后出的原则,即先加载的后进行卸载。
可以用C/C++、delphi、FORTRAN等任一种高级语言设计Lu扩展动态库。
本文的例子定义了两个函数和一个常量:Add(1,2)、Add(1.0,2.0)用于计算两个整数或实数的和;Sub(1,2)、Sub(1.0,2.0)用于计算两个整数或实数的差;常量pi=3.1416。
3 代码
模块定义文件:
; DllExample.def : Declares the module parameters for the DLL. LIBRARY "DllExample" EXPORTS ; Explicit exports can go here LuDll32 @1
DllExample.CPP文件:
#include "windows.h" #include "lu32.h" //保存Lu32.dll的句柄 HINSTANCE hLu; //保存Lu32.dll中的输出函数地址 luSetFunction pSetFunction; luSetConst pSetConst; luDeleteKey pDeleteKey; /////////////////////////////////////////////////////// //定义可由Lu调用的二级函数(外部函数) LuData _stdcall lu_Add(luINT ,LuData *,void *); LuData _stdcall lu_Sub(luINT ,LuData *,void *); wchar_t *FunName[]={L"Add",L"Sub",L""}; //二级函数名 luINT FunPara[]={1,1}; //-2表示有不确定的多个自变量,-1表示有0个自变量,0表示有1个自变量,1表示有2个自变量 LuData (_stdcall *FunCal[])(luINT ,LuData *,void *)={lu_Add,lu_Sub}; //二级函数指针数组 bool FunReg[2]; //记录是否在Lu注册了 /////////////////////////////////////////////////////// //Lu动态库唯一的输出函数 //iInit!=0时,进行初始化。LuDll32=0:初始化失败;LuDll32=1:初始化成功;LuDll32=2:初始化成功,仅注册一些常量,初始化完成后可卸载该库。 //iInit=0时,LuDll32=0:释放失败;LuDll32=1:释放成功。 extern "C" int _stdcall LuDll32(HINSTANCE hLU,int iInit,void *me) { int i; if(iInit) //初始化动态库 { hLu=hLU; pSetFunction=(luSetFunction) GetProcAddress(hLu,"SetFunction"); pSetConst=(luSetConst) GetProcAddress(hLu,"SetConst"); pDeleteKey=(luDeleteKey) GetProcAddress(hLu,"DeleteKey"); //注册二级函数 for(i=0;FunName[i][0];i++) { FunReg[i]=pSetFunction(FunName[i],FunCal[i],FunPara[i])?false:true; if(!FunReg[i]) MessageBox(NULL,FunName[i],L"DllExample 注册函数失败!",32); } //注册常量 LuData a; a.BType=luStaData_double; a.VType=luStaData_double; *(double *)&(a.x)=3.1416; pSetConst(L"pi",&a); return 1; } else //释放动态库 { //注销二级函数 for(i=0;FunName[i][0];i++) { if(FunReg[i]) pDeleteKey((char *)FunName[i],wcslen(FunName[i])*2,luKey_Function,NULL,0); } //注销常量 pDeleteKey((char *)L"pi",4,luKey_Const,NULL,0); return 1; } } ////////////////////////////////////////////////////二级函数定义 LuData _stdcall lu_Add(luINT mm,LuData *xx,void *vFor) //两个数相加 { LuData a; if(xx->VType==luStaData_int64 && (xx+1)->VType==luStaData_int64) { a.BType=luStaData_int64; a.VType=luStaData_int64; a.x=xx->x+(xx+1)->x; } else if(xx->VType==luStaData_double && (xx+1)->VType==luStaData_double) { a.BType=luStaData_double; a.VType=luStaData_double; *(double *)&(a.x)=*(double *)&(xx->x)+*(double *)&((xx+1)->x); } else { a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0; } return a; } LuData _stdcall lu_Sub(luINT mm,LuData *xx,void *vFor) //两个数相减 { LuData a; if(xx->VType==luStaData_int64 && (xx+1)->VType==luStaData_int64) { a.BType=luStaData_int64; a.VType=luStaData_int64; a.x=xx->x-(xx+1)->x; } else if(xx->VType==luStaData_double && (xx+1)->VType==luStaData_double) { a.BType=luStaData_double; a.VType=luStaData_double; *(double *)&(a.x)=*(double *)&(xx->x)-*(double *)&((xx+1)->x); } else { a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0; } return a; }
4 函数说明
本例用到了Lu的3个输出函数:设置外部二级函数SetFunction、设置常量函数SetConst、删除一个键DeleteKey。从这里查看这些函数的说明:Lu编程指南。
5 难点分析
本文仅用来说明如何用C/C++设计Lu扩展动态库,并给出了一个简单例子,关于如何加载使用本文生成的DllExample.dll,参考下一篇教程C/C++使用Lu扩展动态库。
在Lu32脚本系统中,已经实现的主要Lu扩展库参考Lu脚本系统说明,源代码下载:lu1code.rar。
6 其他
你可能注意到了,我的联系方式就在下面,如有不明之处或有什么建议,可随时与我进行联系。
版权所有? Lu程序设计 2002-2013,保留所有权利
E-mail: forcal@sina.com QQ:630715621
最近更新: 2014年01月15日