欢迎访问 Lu程序设计

用C/C++设计Lu扩展动态库

1 说明

    要演示本文的例子,你必须下载Lu64脚本系统。本文的例子 仅需要C++格式的头文件lu64.h,相信你会找到并正确使用这个文件。

    用C/C++编译器创建一个DLL程序,使用本文的例子代码生成 DllExample.dll

2 关于Lu扩展动态库

    往Lu中添加常量、函数或其他任意类型的数据是非常方便的。为了便于函数和数据共享,常将函数和数据封装到动态库中,以动态库的形式向Lu添加,这种动态库称Lu扩展动态库。Lu扩展动态库只需要一个输出函数:

    //Lu扩展动态库唯一的输出函数;
    //hLu:Lu64.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 LuDll64(HINSTANCE hLu,int iInit,void *me)
    {
                .
                .
                .

        if(iInit)   
//初始化动态库
        {
                .
                .
                .

            return 1;
        }
        else       
//释放动态库
        {
                .
                .
                .

            return 1;
        }
    }

    可以看出,虽然Lu扩展动态库只有一个输出函数,但该函数接受了主调程序加载的Lu64.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 *),然后设luVOID m=0; 将该函数的地址用InsertKey((char *)&(m),sizeof(luVOID),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
LuDll64		@1

    DllExample.CPP文件:

#include "windows.h"
#include "lu64.h"
//保存Lu64.dll的句柄
HINSTANCE hLu;
//保存Lu64.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时,进行初始化。LuDll64=0:初始化失败;LuDll64=1:初始化成功;LuDll64=2:初始化成功,仅注册一些常量,初始化完成后可卸载该库。
//iInit=0时,LuDll64=0:释放失败;LuDll64=1:释放成功。
extern "C" int _stdcall LuDll64(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扩展动态库

    在Lu64脚本系统中,已经实现的主要Lu扩展库参考Lu脚本系统说明,源代码下载:lu2code.zip

6 其他

    你可能注意到了,我的联系方式就在下面,如有不明之处或有什么建议,可随时与我进行联系。


版权所有© Lu程序设计 2002-2021,保留所有权利
E-mail: forcal@sina.com
  QQ:630715621
最近更新: 2021年05月23日