——设计可由OpenForcal调用的动态库
目录
1、为什么进行功能扩展
2、如何进行功能扩展
3、如何编写动态库函数说明文件
4、最简单的例子
5、不使用FORCAL表达式的例子
6、使用FORCAL表达式的例子
7、扩展动态库中含有窗口的例子
OpenForcal可以加载多个动态库进行功能扩展,这些动态库可以提供预编译和多种数值计算功能。扩展动态库中也可以包含窗口,OpenForcal支持对扩展动态库中窗口的刷新,也可以重新对另一个源程序进行编译和计算。
OpenForcal功能扩展的意义在于:借助于FORCAL,OpenForcal可以管理各种类型的数值计算函数,这些函数来自于不同的动态库。当需要某些函数时,就加载相应的动态库,不需要时就卸载它们。您可以使用由他人设计的动态库,您也可以自己设计动态库供他人使用,只要都按OpenForcal约定的规则来写就可以。
设计供OpenForcal调用的动态库比设计自己加载FORCAL.DLL的一般程序更简单,而且效率更高。因为OpenForcal是使用FORCAL.DLL的,它可以把FORCAL中的函数提供给扩展的动态库使用。
在作者网站可以下载到部分OpenForcal扩展动态库的完整源代码,以帮助您方便地构建一个OpenForcal扩展动态库。
为了便于集中管理来自多个扩展动态库中的所有函数,OpenForcal要求您在设计扩展动态库时,不要自己加载FORCAL.DLL。
OpenForcal扩展动态库中的类型定义及需要输出的函数如下:
2.1 初始化动态库:void InitDll(void);
在动态库被加载时,该函数被OpenForcal自动调用,因此扩展动态库要输出该函数;
2.2 释放动态库:void FreeDll(void);
在动态库被加载时,该函数被OpenForcal自动调用,因此扩展动态库要输出该函数;
2.3 自定义预编译处理程序:bool PreCom(char *&str);
该函数在OpenForcal编译源程序前被自动调用,因此扩展动态库要输出该函数。
其中字符串指针str指向存放源程序的地址,除了不能用该指针释放该地址空间之外,您可以进行其他任意的操作,包括将该指针指向另一个地址空间。
预编译没有错误时返回true。
2.4 向OpenForcal发送信息
typedef void (* pDllMessage) (char *); //类型定义;
pDllMessage pDllMessagep; //函数指针,定义为全局变量;
void DllMessage(pDllMessage ); //在动态库被加载时,该函数被OpenForcal自动调用,因此扩展动态库要输出该函数;
void DllMessage(pDllMessage message) {pDllMessagep=message;}
//可以用pDllMessagep向OpenForcal发送信息,例如:
pDllMessagep("\r\n这里是预处理程序!\r\n");
2.5 定义可由OpenForcal调用的实数函数
void RegRealFun(char **&,int *&,double (**&)(int ,double *)); //向OpenForcal注册实数函数,在动态库被加载时,该函数被OpenForcal自动调用,因此扩展动态库要输出该函数;
//实数函数均具有以下形式;
double rfc_add(int ,double *);
double rfc_sub(int ,double *);
double rfc_nstr(int ,double *);
//ppchRealNameDll、piRealParaDll、ppRealFunDll要对应,均定义为全局变量。
char *ppchRealNameDll[]={"add","sub","nstr",""}; //定义在OpenForcal源程序中使用的函数名;
int piRealParaDll[]={1,1,1}; //-2表示有不确定的多个自变量,-1表示有0个自变量,0表示有1个自变量,1表示有2个自变量;
double (*ppRealFunDll[])(int ,double *)={rfc_add,rfc_sub,rfc_nstr}; //函数指针数组;
void RegRealFun(char **&ppchRealName,int *&piRealPara,double (**&ppRealFun)(int ,double *))
{ppchRealName=ppchRealNameDll; piRealPara=piRealParaDll; ppRealFun=ppRealFunDll;
}
//请参考FORCAL使用说明1.6中的11、“设置可由FORCAL调用的外部函数”;
//请参考不使用FORCAL表达式的例子中的相关例子;
2.6 定义可由OpenForcal调用的整数函数
//该部分的说明与定义可由OpenForcal调用的实数函数类似,请参考上面的说明。
void RegIntFun(char **&,int *&,long (**&)(int ,long *)); //向OpenForcal注册整数函数,在动态库被加载时,该函数被OpenForcal自动调用,因此扩展动态库要输出该函数;
long ifc_add(int ,long *);
long ifc_sub(int ,long *);
char *ppchIntNameDll[]={"add","sub",""};
int piIntParaDll[]={1,1};
long (*ppIntFunDll[])(int ,long *)={ifc_add,ifc_sub};
//请参考FORCAL使用说明1.6中的11、“设置可由FORCAL调用的外部函数”;
//请参考不使用FORCAL表达式的例子中的相关例子;
2.7 定义可由OpenForcal调用的复数函数
//该部分的说明与定义可由OpenForcal调用的实数函数类似,请参考上面的说明。
void RegComplexFun(char **&,int *&,_complex (**&)(int ,_complex *)); //向OpenForcal注册复数函数,在动态库被加载时,该函数被OpenForcal自动调用,因此扩展动态库要输出该函数;
_complex cfc_add(int ,_complex *);
_complex cfc_sub(int ,_complex *);
char *ppchComplexNameDll[]={"add","sub",""};
int piComplexParaDll[]={1,1};
_complex (*ppComplexFunDll[])(int ,_complex *)={cfc_add,cfc_sub};
//请参考FORCAL使用说明1.6中的11、“设置可由FORCAL调用的外部函数”;
//请参考不使用FORCAL表达式的例子中的相关例子;
2.8 使用字符串
char ** ppchFcStr; //字符串数组指针,定义为全局变量;
long * plFcStrMax,StrsMax; //plFcStrMax指向一个存放字符串大小的长整形数组,该数组与ppchFcStr相对应,指出了ppchFcStr中各个字符串的大小;StrsMax为字符串数组ppchFcStr的大小;plFcStrMax,StrsMax均定义为全局变量。
void GetFcStr(char **,long *,long ); //函数说明,扩展动态库要输出GetFcStr函数;
void GetFcStr(char **ppCh,long *pm,long n)
{ppchFcStr=ppCh; plFcStrMax=pm; StrsMax=n;}
//以后可以使用字符串;
//请参考FORCAL使用说明中的字符数据处理;
//请参考不使用FORCAL表达式的例子中double rfc_nstr(int m,double *x)的函数定义;
//使用FORCAL字符串需要注意以下问题:
//(1)、使用字符串之前先检查地址是否有效,字符串地址用一个整数表示,0<=地址<StrsMax;
//(2)、如果释放了一个字符串,把该指针置为NULL,同时将串的大小置为0。
2.9 使用Forcal实数表达式
typedef double (* pRCALS) (int ); //计算实数表达式的值;
typedef int (* pFCERRNUM) (void); //获得Forcal中实数表达式运行错误代码,0表示没有错误;
typedef void (* pSETFCERR) (int ,char *); //设置外部函数运行错误,字符串指针指出出错函数名;
pRCALS prcals;
pSETFCERR psetfcerr;
pFCERRNUM pfcerrnum;
int *forpara; //存放各个实数表达式的自变量个数;
bool *fortrue; //存放各个实数表达式的编译状态,表达式编译通过时设为true;
double **allin; //allin指向存放各实数表达式自变量的指针数组;
int rfor_max; //最多可用的实数表达式数目;
void GetRealFor (pRCALS ,pFCERRNUM ,pSETFCERR ,bool * ,double **,int *,int); //从OpenForcal获得使用实数表达式的有关函数地址和变量,在动态库被加载时,该函数被OpenForcal自动调用,因此扩展动态库要输出该函数;
void GetRealFor (pRCALS cal,pFCERRNUM num,pSETFCERR err,bool * b,double **d,int *i,int ir)
{prcals=cal; pfcerrnum=num; psetfcerr=err; fortrue=b; allin=d; forpara=i; rfor_max=ir;}
//请参考FORCAL使用说明1.6中相关函数的说明;
//请参考使用FORCAL表达式的例子中double rfc_sintegrate(int m,double *xx)的函数定义;
//从rfc_sintegrate的定义中可以看出,使用FORCAL表达式进行计算需要注意以下问题:
//(1)、检查rfor_max是否大于0,rfor_max>0时可以使用表达式,在OpenForcal中,rfor_max总是大于0,因此也可以不检查此项;
//(2)、检查表达式是否存在,0<=表达式序号<rfor_max;
//(3)、检查表达式编译是否通过,fortrue[表达式序号]=true时可以使用;
//(4)、检查表达式参数个数是否匹配;
//(5)、用pfcerrnum()函数可以获得FORCAL运行错误,出现错误时不再进行计算;
//(6)、如果pfcerrnum()==0,可以用psetfcerr()函数向FORCAL报告错误;
//(7)、一般情况下,FORCAL函数不允许递归。终止递归的方法是设置一个静态变量,用以记录该函数被调用的次数,当被调用的次数大于setstackmax(n)函数的设定值时,即认为出现了递归。当然,这种检测递归的方法同时也限制了该函数被嵌套调用的次数。
2.10 使用Forcal整数表达式
//该部分的说明与使用Forcal实数表达式类似,请参考上面的说明。
typedef long (* pICALS) (int ); //计算整数表达式的值;
typedef void (*pISETFCERR) (int ,char *); //设置外部函数运行错误,字符串指针指出出错函数名;
typedef int (* pIFCERRNUM) (void); //获得Forcal中整数表达式运行错误代码,0表示没有错误;
pICALS picals;
pISETFCERR pisetfcerr;
pIFCERRNUM pifcerrnum;
int *iforpara; //存放各个整数表达式的自变量个数;
bool *ifortrue; //存放各个整数表达式的编译状态,表达式编译通过时设为true;
long **iallin; //allin指向存放各整数表达式自变量的指针数组;
int ifor_max; //最多可用的整数表达式数目;
void GetIntFor (pICALS ,pIFCERRNUM ,pISETFCERR ,bool * ,long **,int *,int); //从OpenForcal获得使用整数表达式的有关函数地址和变量,在动态库被加载时,该函数被OpenForcal自动调用,因此扩展动态库要输出该函数;
void GetIntFor (pICALS cal,pIFCERRNUM num,pISETFCERR err,bool * b,long **l,int *i,int ii)
{picals=cal; pifcerrnum=num; pisetfcerr=err; ifortrue=b; iallin=l; iforpara=i; ifor_max=ii;}
//请参考FORCAL使用说明1.6中相关函数的说明;
//请参考使用FORCAL表达式的例子中double rfc_sintegrate(int m,double *xx)的函数定义;
2.11 使用Forcal复数表达式
//该部分的说明与定义可由OpenForcal调用的实数函数类似,请参考上面的说明。
typedef _complex (* pCCALS) (int ); //计算复数表达式的值;
typedef void (*pCSETFCERR) (int ,char *); //设置外部函数运行错误,字符串指针指出出错函数名;
typedef int (* pCFCERRNUM) (void); //获得Forcal中复数表达式运行错误代码,0表示没有错误;
pCCALS pccals;
pCSETFCERR pcsetfcerr;
pCFCERRNUM pcfcerrnum;
int *cforpara; //存放各个复数表达式的自变量个数;
bool *cfortrue; //存放各个复数表达式的编译状态,表达式编译通过时设为true;
_complex **callin; //allin指向存放各复数表达式自变量的指针数组;
int cfor_max; //最多可用的复数表达式数目;
void GetComplexFor (pCCALS ,pCFCERRNUM ,pCSETFCERR ,bool * ,_complex **,int *,int); //从OpenForcal获得使用复数表达式的有关函数地址和变量,在动态库被加载时,该函数被OpenForcal自动调用,因此扩展动态库要输出该函数;
void GetComplexFor (pCCALS cal,pCFCERRNUM num,pCSETFCERR err,bool * b,_complex **c,int *i,int ic)
{pccals=cal; pcfcerrnum=num; pcsetfcerr=err; cfortrue=b; callin=c; cforpara=i; cfor_max=ic;}
//请参考FORCAL使用说明1.6中相关函数的说明;
//请参考使用FORCAL表达式的例子中double rfc_sintegrate(int m,double *xx)的函数定义;
2.12 使用FORCAL实数数组
typedef double **(* pGETFCDOUBLEARRAY) (long &,long *&);
pGETFCDOUBLEARRAY pGETFCDOUBLEARRAYp;
void GetFcDoubleArray(pGETFCDOUBLEARRAY); //从OpenForcal获得使用FORCAL实数数组的函数地址,在动态库被加载时,该函数被OpenForcal自动调用,因此扩展动态库要输出该函数;
double **ppfcdoublearray; //多维存储数组doublearray的指针;
long fcdoublearrayMax; //多维存储数组doublearray的大小;
long *pfcdoublearrayMax; //多维存储数组doublearray中各维数组长度的整数组的指针;
void GetFcDoubleArray(pGETFCDOUBLEARRAY getda) {pGETFCDOUBLEARRAYp=getda;}
//请参考FORCAL使用说明1.6中相关函数的说明;
//请参考不使用FORCAL表达式的例子中double rfc_outarray(int m,double *x)的函数定义;
//从rfc_outarray的定义中可以看出,使用FORCAL数组需要注意以下问题:
//(1)、检查ppfcdoublearray是否为真,ppfcdoublearray为真时可以使用数组;
//(2)、检查数组是否存在,0<=数组序号fcdoublearrayMax<rfor_max;
//(3)、使用数组不要越界;
2.13 使用FORCAL复数数组
//该部分的说明与使用FORCAL实数数组类似,请参考上面的说明。
typedef _complex **(* pCGETFCCOMPLEXARRAY) (long &,long *&);
pCGETFCCOMPLEXARRAY pCGETFCCOMPLEXARRAYp;
void GetFcComplexArray(pCGETFCCOMPLEXARRAY); //从OpenForcal获得使用FORCAL复数数组的函数地址,在动态库被加载时,该函数被OpenForcal自动调用,因此扩展动态库要输出该函数;
_complex **ppfccomplexarray; //多维存储数组_complexarray的指针;
long fccomplexarrayMax; //多维存储数组_complexarray的大小;
long *pfccomplexarrayMax; //多维存储数组_complexarray中各维数组长度的整数组的指针;
void GetFcComplexArray(pCGETFCCOMPLEXARRAY getca) {pCGETFCCOMPLEXARRAYp=getca;}
2.14 使用FORCAL整数数组
//该部分的说明与使用FORCAL实数数组类似,请参考上面的说明。
typedef long **(* pIGETFCLONGARRAY) (long &,long *&);
pIGETFCLONGARRAY pIGETFCLONGARRAYp;
void GetFcLongArray(pIGETFCLONGARRAY); //从OpenForcal获得使用FORCAL复数数组的函数地址,在动态库被加载时,该函数被OpenForcal自动调用,因此扩展动态库要输出该函数;
long **ppfclongarray; //多维存储数组longarray的指针;
long fclongarrayMax; //多维存储数组longarray的大小;
long *pfclongarrayMax; //多维存储数组longarray中各维数组长度的整数组的指针;
void GetFcLongArray(pIGETFCLONGARRAY getia) {pIGETFCLONGARRAYp=getia;}
2.15 得到OpenForcal编译函数的地址,可在扩展动态库中编译源程序
void
outl(long);
//输出一个整数的值;
void
outd(double); //输出一个实数的值;
void
outc(_complex); //输出一个复数的值;
void DllMessage(char *); //输出一个字符串;
typedef void (* pLONGfun) (long );
typedef void (* pDOUBLEfun) (double );
typedef void (* pCOMPLEXfun) (_complex );
typedef void (* pDllMessage) (char *);
typedef int (* pDllComFor) (char *,char *&,pLONGfun
,pDOUBLEfun ,pCOMPLEXfun ,pDllMessage); //类型定义;
pDllComFor pDllComForp; //函数指针,定义为全局变量;
void GetComFor(pDllComFor ); //在动态库被加载时,该函数被OpenForcal自动调用,因此扩展动态库要输出该函数;
void GetComFor(pDllComFor pFun)
{pDllComForp=pFun;}
//可以用pDllComForp编译OpenForcal源程序。例如:
pDllComForp(FcStr,ErrStr,outl,outd,outc,DllMessage);
//FcStr为指向源程序字符串的指针;ErrStr返回编译信息;outl、outd、outc、DllMessage四个函数在执行表达式时被调用,输出信息,这四个参数也可设为NULL。该函数返回值的意义如下:
//pDllComForp=0,编译成功。
//pDllComForp=-1,禁止编译执行表达式,表示OpenForcal要释放动态库,因此要做好退出前的清理工作。
//pDllComForp=-2,表示资源被占用,无法对源程序进行编译,可稍后重新进行编译;
//pDllComForp=-3,没有表达式;
//pDllComForp=-4,内存错误;
//pDllComForp=-5,预编译错误;
//pDllComForp=-6,注释符号/* ... */不成对;
//pDllComForp=-7,文件太长,需重新设置文件最大长度;
//pDllComForp=-8,不能使用FORCAL;
//pDllComForp=-9,表达式太长;
//pDllComForp=-10,整数表达式不够用,需重新设置;
//pDllComForp=-11,复数表达式不够用,需重新设置;
//pDllComForp=-12,实数表达式不够用,需重新设置;
//pDllComForp=-13,不能正常设置一个常量;
//pDllComForp=-14,常量定义错误,常量名由ErrStr返回;
//pDllComForp=-15,不能正常设置一个自动常量;
//pDllComForp=-16,自动常量定义错误,自动常量名由ErrStr返回;
//pDllComForp=1,不正确的运算方式;
//pDllComForp=2,无表达式;
//pDllComForp=3,变量说明错,等号前有非法字符;
//pDllComForp=4,变量应放在 ( ) 内;
//pDllComForp=5,非法变量字符(以英文字母开头的英文字母与数字的组合);
//pDllComForp=6,变量名以英文字母开头;
//pDllComForp=7,变量重复说明;
//pDllComForp=8,括号不成对;
//pDllComForp=9,在复数计算时,不能用 i
作为变量(该返回值在编译复数表达式时使用);
//pDllComForp=10,不可识别函数名;
//pDllComForp=11,数学表达式太长,接近32766个字符;
//pDllComForp=12,不可识别变量;
//pDllComForp=13,数字错误;
//pDllComForp=14,不可识别字符、函数名、变量名或者一级函数有多个自变量;
//pDllComForp=15,内存分配失败;
//pDllComForp=16,二级函数错误;
//pDllComForp=17,符号定义错误或无表达式或括号不成对;
//pDllComForp=18,表达式中的字符串无效,即"..."不匹配;
//pDllComForp=19,没有启用forcal的字符串处理功能;
//pDllComForp=20,表达式中的字符串太多或表达式太长;
//pDllComForp=21,内存分配失败;
//pDllComForp=22,找不到字符串$"..."所表示的表达式的类型;
//pDllComForp=23,找不到字符串#"..."所表示的表达式的序号;
//pDllComForp=24,找不到字符串&"..."或@"..."的地址;
//pDllComForp=25,字符串数组不够用,需重新设置;
//pDllComForp=26,超出共享版允许的字符限制,请注册使用正式版[在正式版中无此返回值];
2.16 得到OpenForcal执行函数的地址,用于扩展动态库窗口的刷新
typedef int (* pDllExeFor) (long ,long
,int ); //类型定义;
pDllExeFor pDllExeForp; //函数指针,定义为全局变量;
void GetExeFor(pDllExeFor ); //在动态库被加载时,该函数被OpenForcal自动调用,因此扩展动态库要输出该函数;
void GetExeFor(pDllExeFor pFun)
{pDllExeForp=pFun;}
//可以用pDllExeForp执行OpenForcal主程序。例如:
pDllExeForp(DrawSceneBegin,DrawSceneEnd,mode);
//DrawSceneBegin为开始执行的起始地址,DrawSceneEnd为结束地址,这两个地址可在OpenForcal主程序中由GetAddress[]函数获得。mode用于设置运行模式。
//mode=1:执行编译表达式时设定的输出函数,且遇到另一个程序正在运行时返回代码2;
//mode=2:执行编译表达式时设定的输出函数,且遇到另一个程序正在运行时不返回代码2,等待运行;
//mode=3:不执行编译表达式时设定的输出函数,且遇到另一个程序正在运行时返回代码2;
//mode=4:不执行编译表达式时设定的输出函数,且遇到另一个程序正在运行时不返回代码2,等待运行;
//该函数返回值意义如下:
//pDllExeForp=0,正常执行程序;
//pDllExeForp=-1,禁止编译执行表达式,表示OpenForcal要释放动态库,因此要做好退出前的清理工作;
//pDllExeForp=1,程序没有编译,不能运行;
//pDllExeForp=2,另一个程序正在运行,不能同时执行,当mode=1或mode=3时返回该参数;
//pDllExeForp=3,运行地址错误,表示DrawSceneBegin或DrawSceneEnd非法;
//如果pDllExeForp以mode=3或mode=4方式运行,只能禁止编译表达式时设定的输出函数的输出,并不能禁止其他动态库中任何形式的输出,在OpenForcal的源程序中需要特别注意这一点。
//pDllExeForp的使用参见动态库扩展OpenFCGl.dll的设计,可以在作者网站下载到该动态库的全部源代码。
2.17 使用Openforcal的临界区
typedef void (* pOfcCriticalSection)(int );//临界区函数类型;
pOfcCriticalSection pOfcCriticalSectionp=NULL;//存放函数地址;
void GetOfcCriticalSection(pOfcCriticalSection);//在动态库被加载时,该函数被OpenForcal自动调用,因此扩展动态库要输出该函数;
//函数定义;
void GetOfcCriticalSection(pOfcCriticalSection p) {pOfcCriticalSectionp=p;}
//说明:
pOfcCriticalSectionp(1);//进入临界区,但并不禁止源代码的编译和执行,动态库的说明信息,只许读,不许写;
pOfcCriticalSectionp(2);//进入临界区,同时禁止源代码的编译和执行,允许读写动态库说明信息;
pOfcCriticalSectionp(0);//离开临界区;
//注意:不要在临界区中使用OpenForcal扩展动态库的任何一个输出函数。
//通常,使用动态库的说明信息时需要在临界区中进行。例如:
pOfcCriticalSectionp(1);//进入临界区;
//不要在临界区中使用OpenForcal扩展动态库的输出函数;
//...访问动态库的说明信息...
pOfcCriticalSectionp(0);//离开临界区;
2.18 得到动态库的说明信息
class DllFunChar
{public:
3 如何编写动态库函数说明文件 [目录]
在开发了一个OpenForcal扩展动态库之后,需要为它编写一个说明文件以方便用户使用。
动态库函数说明文件为文本文件,格式如下:
example.txt
#example.dll:这是一个动态库扩展的例子
<add: 计算两个数的和
add(a,b): 计算两个数的和
... ...
>
<sub: 计算两个数的差
sub(a,b): 计算两个数的差
... ...
>
文件信息的存储请参考“2.18
得到动态库的说明信息”中类DllFunChar和类DllFunFile的说明,其中类DllFunChar是类DllFunFile的一个对象成员。
该文件中第一个以#开头的行进行动态库功能的描述,该行信息将保存在DllFunFile::DllFunFilename中。
每一个动态库函数的说明都放在一对尖括号<...>内,“<”和“>”必须是行首字符。在“<”后同一行的内容将保存在DllFunChar::pstrname中,其余内容将保存在DllFunChar::pstr中。
需要将该说明文件的简介以函数说明的方式添加到OpenFChlp.ini文件中,OpenForcal将自动加载OpenFChlp.ini文件。说明文件的简介格式如下:
<example.txt : 一个动态库扩展的例子的说明文件
example.dll:这是一个动态库扩展的例子
>
注意example.txt为该文件的名字(包含文件路径),并且名字的后面必须留一个空格。
另外,在动态库函数说明文件中可以进行常量定义,不过在等号后的常数表达式中不能使用以前定义的常量。格式如下:
<const: 定义一些常量,行首字符必须为const:
pi=3.14, _e_=2.718, eps=1e-10
>
在动态库函数说明文件中不能定义自动常量。
关于常量定义的说明,请参考“OpenForcal的用户界面”中的介绍。
用Visual C++6.0向导建立一个Win32 Dynamic-Link Library工程,工程名为Simplest,其余使用默认选项。工程建好后,将以下文件:simplest.cpp添加到工程。然后选择菜单
Build->Set Active Configuration中Wiin32 Release选项进行编译即可。
Simplest.cpp文件
#include "windows.h"
#include "math.h"
extern "C" __declspec(dllexport) void RegRealFun(char **&,int *&,double (**&)(int ,double *));
double rfc_mul(int ,double *);
double rfc_pi(int ,double *);
char *ppchNameDll[]={"mul","pi",""}; //外部函数名;
int piParaDll[]={1,-1}; //-2表示有不确定的多个自变量,-1表示有0个自变量,0表示有1个自变量,1表示有2个自变量;
double (*ppFunDll[])(int ,double *)={rfc_mul,rfc_pi}; //外部函数指针数组;
/////////////////////////////////////////////////////////////////////////////
// 动态库的输出函数;
extern "C" __declspec(dllexport) void RegRealFun(char **&ppchName,int *&piPara,double (**&ppFun)(int ,double *))
{ppchName=ppchNameDll; piPara=piParaDll; ppFun=ppFunDll;
}
// 定义一些简单的实数函数;
double rfc_mul(int m,double *x) //计算两个数的积;
{return x[0]*x[1];
}
double rfc_pi(int m,double *x) //pi常量函数;
{return 3.14159265358979;
}
5 不使用FORCAL表达式的例子 [目录]
用Visual C++6.0向导建立一个Win32 Dynamic-Link Library工程,工程名为NotUseFor,其余使用默认选项。工程建好后,将以下文件:NotUseFor.cpp添加到工程。然后选择菜单Build->Set Active Configuration中Wiin32 Release选项进行编译即可。
NotUseFor.cpp文件
#include "windows.h"
#include "math.h"
//初始化动态库;
extern "C" __declspec(dllexport) void InitDll(void);
//自定义预编译处理程序,在编译前被调用;
extern "C" __declspec(dllexport) bool PreCom(char *&);
//释放动态库;
extern "C" __declspec(dllexport) void FreeDll(void);
//向OpenForcal发送信息;
typedef void (* pDllMessage) (char *);
pDllMessage pDllMessagep;
extern "C" __declspec(dllexport) void DllMessage(pDllMessage );
//使用Forcal字符串;
char ** ppchFcStr;
long * plFcStrMax,StrsMax;
extern "C" __declspec(dllexport) void GetFcStr(char **,long *,long );
//定义可由OpenForcal调用的实数函数;
extern "C" __declspec(dllexport) void RegRealFun(char **&,int *&,double (**&)(int ,double *));
double rfc_add(int ,double *);
double rfc_sub(int ,double *);
double rfc_nstr(int ,double *);
double rfc_outarray(int ,double *);
double rfc_notusefordllfile(int m,double *x);
char
*ppchRealNameDll[]={"add","sub","nstr","outarray","notusefordllfile",""}; //外部函数名;
int piRealParaDll[]={1,1,1,0,-1}; //-2表示有不确定的多个自变量,-1表示有0个自变量,0表示有1个自变量,1表示有2个自变量;
double (*ppRealFunDll[])(int ,double *)={rfc_add,rfc_sub,rfc_nstr,rfc_outarray,rfc_notusefordllfile}; //外部函数指针数组;
//定义可由OpenForcal调用的整数函数;
extern "C" __declspec(dllexport) void RegIntFun(char **&,int *&,long (**&)(int ,long *));
long ifc_add(int ,long *);
long ifc_sub(int ,long *);
char *ppchIntNameDll[]={"add","sub",""}; //外部函数名;
int piIntParaDll[]={1,1}; //-2表示有不确定的多个自变量,-1表示有0个自变量,0表示有1个自变量,1表示有2个自变量;
long (*ppIntFunDll[])(int ,long *)={ifc_add,ifc_sub}; //外部函数指针数组;
//定义可由OpenForcal调用的复数函数;
extern "C" __declspec(dllexport) void RegComplexFun(char **&,int *&,_complex (**&)(int ,_complex *));
_complex cfc_add(int ,_complex *);
_complex cfc_sub(int ,_complex *);
char *ppchComplexNameDll[]={"add","sub",""}; //外部函数名;
int piComplexParaDll[]={1,1}; //-2表示有不确定的多个自变量,-1表示有0个自变量,0表示有1个自变量,1表示有2个自变量;
_complex (*ppComplexFunDll[])(int ,_complex *)={cfc_add,cfc_sub}; //外部函数指针数组;
//使用实数数组;
typedef double **(* pGETFCDOUBLEARRAY) (long &,long *&);
pGETFCDOUBLEARRAY pGETFCDOUBLEARRAYp;
extern "C" __declspec(dllexport) void GetFcDoubleArray(pGETFCDOUBLEARRAY); //输出函数;
double **ppfcdoublearray; //多维存储数组doublearray的指针;
long fcdoublearrayMax; //多维存储数组doublearray的大小;
long *pfcdoublearrayMax; //多维存储数组doublearray中各维数组长度的整数组的指针;
//使用复数数组;
typedef _complex **(* pCGETFCCOMPLEXARRAY) (long &,long *&);
pCGETFCCOMPLEXARRAY pCGETFCCOMPLEXARRAYp;
extern "C" __declspec(dllexport) void GetFcComplexArray(pCGETFCCOMPLEXARRAY); //输出函数;
_complex **ppfccomplexarray; //多维存储数组_complexarray的指针;
long fccomplexarrayMax; //多维存储数组_complexarray的大小;
long *pfccomplexarrayMax; //多维存储数组_complexarray中各维数组长度的整数组的指针;
//使用整数数组;
typedef long **(* pIGETFCLONGARRAY) (long &,long *&);
pIGETFCLONGARRAY pIGETFCLONGARRAYp;
extern "C" __declspec(dllexport) void GetFcLongArray(pIGETFCLONGARRAY); //输出函数;
long **ppfclongarray; //多维存储数组longarray的指针;
long fclongarrayMax; //多维存储数组longarray的大小;
long *pfclongarrayMax; //多维存储数组longarray中各维数组长度的整数组的指针;
//得到动态库的说明信息;
class DllFunChar
{public:
char *pstrname,*pstr;
DllFunChar *headDllFunChar,*endDllFunChar;
DllFunChar();
DllFunChar(DllFunChar *);
~DllFunChar();
bool setDllFunCharName(char *);
bool setDllFunChar(char *);
};
class DllFunFile
{public:
char *DllFunFilename;
DllFunChar *pDllFunChar,head_DllFunChar;
DllFunFile *headDllFunFile,*endDllFunFile;
DllFunFile();
DllFunFile(DllFunFile *);
~DllFunFile();
bool setDllFunFilename(char *);
};
typedef DllFunFile *(* pGetDllFunFile)();
extern "C" __declspec(dllexport) void GetDllFunFile(pGetDllFunFile );//在动态库被加载时,该函数被OpenForcal自动调用,因此扩展动态库要输出该函数;
pGetDllFunFile pGetDllFunFilep=NULL;//存放函数地址;
DllFunFile *pDllFunFile;//工作指针;
/////////////////////////////////////////////////////////////////////////////
// 动态库的输出函数;
extern "C" __declspec(dllexport) void InitDll(void)
{MessageBox(NULL,"NotUseFor.dll初始化!","NotUseFor",MB_OK);}
extern "C" __declspec(dllexport) bool PreCom(char *&str) //NotUseFor.dll预处理程序,注意不能释放字符串str;
{pDllMessagep("\r\nNotUseFor.dll预处理程序!\r\n");
return true;
}
extern "C" __declspec(dllexport) void FreeDll(void)
{MessageBox(NULL,"释放NotUseFor.dll!","NotUseFor",MB_OK);}
extern "C" __declspec(dllexport) void DllMessage(pDllMessage message)
{pDllMessagep=message;}
extern "C" __declspec(dllexport) void GetFcStr(char **ppCh,long *pm,long n)
{ppchFcStr=ppCh; plFcStrMax=pm; StrsMax=n;}
extern "C" __declspec(dllexport) void RegRealFun(char **&ppchRealName,int *&piRealPara,double (**&ppRealFun)(int ,double *))
{ppchRealName=ppchRealNameDll; piRealPara=piRealParaDll; ppRealFun=ppRealFunDll;
}
extern "C" __declspec(dllexport) void RegIntFun(char **&ppchIntName,int *&piIntPara,long (**&ppIntFun)(int ,long *))
{ppchIntName=ppchIntNameDll; piIntPara=piIntParaDll; ppIntFun=ppIntFunDll;
}
extern "C" __declspec(dllexport) void RegComplexFun(char **&ppchComplexName,int *&piComplexPara,_complex (**&ppComplexFun)(int ,_complex *))
{ppchComplexName=ppchComplexNameDll; piComplexPara=piComplexParaDll; ppComplexFun=ppComplexFunDll;
}
extern "C" __declspec(dllexport) void GetFcDoubleArray(pGETFCDOUBLEARRAY getda) {pGETFCDOUBLEARRAYp=getda;}
extern "C" __declspec(dllexport) void GetFcComplexArray(pCGETFCCOMPLEXARRAY getca) {pCGETFCCOMPLEXARRAYp=getca;}
extern "C" __declspec(dllexport) void GetFcLongArray(pIGETFCLONGARRAY getia) {pIGETFCLONGARRAYp=getia;}
extern "C" __declspec(dllexport) void GetDllFunFile(pGetDllFunFile pFunFile) {pGetDllFunFilep=pFunFile;}
// 定义一些简单的实数函数;
double rfc_add(int m,double *x) //计算两个数的和;
{return x[0]+x[1];}
double rfc_sub(int m,double *x) //计算两个数的差;
{return x[0]-x[1];}
double rfc_nstr(int m,double *x) //该函数将一个字符串复制了n次;
{long i,j,k;
i=(long)x[0]; j=(long)x[1];
if(i<0||i>=StrsMax)
{pDllMessagep("\r\nnstr( )错误:指定的字符串不存在!\r\n"); return 0.0;}
if(ppchFcStr[i])
{for(k=0;k<j;k++) pDllMessagep(ppchFcStr[i]);}
else
{pDllMessagep("\r\nnstr( )错误:指定的字符串不存在!\r\n"); return 0.0;}
return 0.0;
}
double rfc_outarray(int m,double *x) //输出一个实数数组的所有值;
{long i,j;
char ch[32];
ppfcdoublearray=pGETFCDOUBLEARRAYp(fcdoublearrayMax,pfcdoublearrayMax);
if(ppfcdoublearray)
{i=(long)x[0];
if(i<0||i>=fcdoublearrayMax) {pDllMessagep("\r\noutarray( )错误:指定的数组不存在!\r\n"); return 0.0;}
for(j=0;j<pfcdoublearrayMax[i];j++)
{pDllMessagep(gcvt(ppfcdoublearray[i][j],16,ch));
pDllMessagep(" ");
}
}
else
{pDllMessagep("\r\noutarray( )错误:本系统没有使用数组!\r\n");}
return 0.0;
}
double rfc_notusefordllfile(int m,double *x)
{pDllFunFile=pGetDllFunFilep();;
while(pDllFunFile->endDllFunFile)
{pDllFunFile=pDllFunFile->endDllFunFile;
pDllMessagep("\r\n*****动态库说明文件:");
pDllMessagep(pDllFunFile->DllFunFilename);
pDllMessagep("\r\n");
pDllFunFile->pDllFunChar=&(pDllFunFile->head_DllFunChar);
while(pDllFunFile->pDllFunChar->endDllFunChar)
{pDllFunFile->pDllFunChar=pDllFunFile->pDllFunChar->endDllFunChar;
pDllMessagep("**函数:");
pDllMessagep(pDllFunFile->pDllFunChar->pstrname);
pDllMessagep("\r\n");
pDllMessagep("**函数说明:\r\n");
pDllMessagep(pDllFunFile->pDllFunChar->pstr);
}
}
return 0.0;
}
// 定义一些简单的整数函数;
long ifc_add(int m,long *x)
{return x[0]+x[1];}
long ifc_sub(int m,long *x)
{return x[0]-x[1];}
// 定义一些简单的复数函数;
_complex cfc_add(int m,_complex *x)
{x[0].x=x[0].x+x[1].x; x[0].y=x[0].y+x[1].y; return x[0];}
_complex cfc_sub(int m,_complex *x)
{x[0].x=x[0].x-x[1].x; x[0].y=x[0].y-x[1].y; return x[0];}
6 使用FORCAL表达式的例子 [目录]
用Visual C++6.0向导建立一个Win32 Dynamic-Link Library工程,工程名为UseFor,其余使用默认选项。工程建好后,将以下文件:UseFor.cpp添加到工程。然后选择菜单Build->Set Active Configuration中Wiin32 Release选项进行编译即可。
UseFor.cpp文件
#include "windows.h"
#include "math.h"
//定义可由OpenForcal调用的实数函数;
extern "C" __declspec(dllexport) void RegRealFun(char **&,int *&,double (**&)(int ,double *));
double rfc_a999(int ,double *);
double rfc_sintegrate(int ,double *);
char *ppchRealNameDll[]={"a999","sintegrate",""}; //外部函数名;
int piRealParaDll[]={-2,-2}; //-2表示有不确定的多个自变量,-1表示有0个自变量,0表示有1个自变量,1表示有2个自变量;
double (*ppRealFunDll[])(int ,double *)={rfc_a999,rfc_sintegrate}; //外部函数指针数组;
//定义可由OpenForcal调用的整数函数;
extern "C" __declspec(dllexport) void RegIntFun(char **&,int *&,long (**&)(int ,long *));
long ifc_a999(int ,long *);
char *ppchIntNameDll[]={"a999",""}; //外部函数名;
int piIntParaDll[]={-2}; //-2表示有不确定的多个自变量,-1表示有0个自变量,0表示有1个自变量,1表示有2个自变量;
long (*ppIntFunDll[])(int ,long *)={ifc_a999}; //外部函数指针数组;
//定义可由OpenForcal调用的复数函数;
extern "C" __declspec(dllexport) void RegComplexFun(char **&,int *&,_complex (**&)(int ,_complex *));
_complex cfc_a999(int ,_complex *);
char *ppchComplexNameDll[]={"a999",""}; //外部函数名;
int piComplexParaDll[]={-2}; //-2表示有不确定的多个自变量,-1表示有0个自变量,0表示有1个自变量,1表示有2个自变量;
_complex (*ppComplexFunDll[])(int ,_complex *)={cfc_a999}; //外部函数指针数组;
//准备使用Forcal表达式;
typedef double (* pRCALS) (int ); //计算实数表达式的值;
typedef int (* pFCERRNUM) (void); //获得Forcal中实数表达式运行错误代码,0表示没有错误;
typedef void (* pSETFCERR) (int ,char *); //设置外部函数运行错误,字符串指针指出出错函数名;
pRCALS prcals;
pSETFCERR psetfcerr;
pFCERRNUM pfcerrnum;
typedef _complex (* pCCALS) (int ); //计算复数表达式的值;
typedef void (*pCSETFCERR) (int ,char *); //设置外部函数运行错误,字符串指针指出出错函数名;
typedef int (* pCFCERRNUM) (void); //获得Forcal中复数表达式运行错误代码,0表示没有错误;
pCCALS pccals;
pCSETFCERR pcsetfcerr;
pCFCERRNUM pcfcerrnum;
typedef long (* pICALS) (int ); //计算整数表达式的值;
typedef void (*pISETFCERR) (int ,char *); //设置外部函数运行错误,字符串指针指出出错函数名;
typedef int (* pIFCERRNUM) (void); //获得Forcal中整数表达式运行错误代码,0表示没有错误;
pICALS picals;
pISETFCERR pisetfcerr;
pIFCERRNUM pifcerrnum;
int *forpara; //存放各个实数表达式的自变量个数;
bool *fortrue; //存放各个实数表达式的编译状态,表达式编译通过时设为true;
int *cforpara; //存放各个复数表达式的自变量个数;
bool *cfortrue; //存放各个复数表达式的编译状态,表达式编译通过时设为true;
int *iforpara; //存放各个整数表达式的自变量个数;
bool *ifortrue; //存放各个整数表达式的编译状态,表达式编译通过时设为true;
double **allin; //allin指向存放各实数表达式自变量的指针数组;
_complex **callin; //allin指向存放各复数表达式自变量的指针数组;
long **iallin; //allin指向存放各整数表达式自变量的指针数组;
int rfor_max; //最多可用的实数表达式数目;
int ifor_max; //最多可用的整数表达式数目;
int cfor_max; //最多可用的复数表达式数目;
extern "C" __declspec(dllexport) void GetRealFor (pRCALS ,pFCERRNUM ,pSETFCERR ,bool * ,double **,int *,int);
extern "C" __declspec(dllexport) void GetIntFor (pICALS ,pIFCERRNUM ,pISETFCERR ,bool * ,long **,int *,int);
extern "C" __declspec(dllexport) void GetComplexFor (pCCALS ,pCFCERRNUM ,pCSETFCERR ,bool * ,_complex **,int *,int);
/////////////////////////////////////////////////////////////////////////////
// 动态库的输出函数;
extern "C" __declspec(dllexport) void RegRealFun(char **&ppchRealName,int *&piRealPara,double (**&ppRealFun)(int ,double *))
{ppchRealName=ppchRealNameDll; piRealPara=piRealParaDll; ppRealFun=ppRealFunDll;
}
extern "C" __declspec(dllexport) void RegIntFun(char **&ppchIntName,int *&piIntPara,long (**&ppIntFun)(int ,long *))
{ppchIntName=ppchIntNameDll; piIntPara=piIntParaDll; ppIntFun=ppIntFunDll;
}
extern "C" __declspec(dllexport) void RegComplexFun(char **&ppchComplexName,int *&piComplexPara,_complex (**&ppComplexFun)(int ,_complex *))
{ppchComplexName=ppchComplexNameDll; piComplexPara=piComplexParaDll; ppComplexFun=ppComplexFunDll;
}
extern "C" __declspec(dllexport) void GetRealFor (pRCALS cal,pFCERRNUM num,pSETFCERR err,bool * b,double **d,int *i,int ir)
{prcals=cal; pfcerrnum=num; psetfcerr=err; fortrue=b; allin=d; forpara=i; rfor_max=ir;}
extern "C" __declspec(dllexport) void GetIntFor (pICALS cal,pIFCERRNUM num,pISETFCERR err,bool * b,long **l,int *i,int ii)
{picals=cal; pifcerrnum=num; pisetfcerr=err; ifortrue=b; iallin=l; iforpara=i; ifor_max=ii;}
extern "C" __declspec(dllexport) void GetComplexFor (pCCALS cal,pCFCERRNUM num,pCSETFCERR err,bool * b,_complex **c,int *i,int ic)
{pccals=cal; pcfcerrnum=num; pcsetfcerr=err; cfortrue=b; callin=c; cforpara=i; cfor_max=ic;}
// 定义一些简单的实数函数;
double rfc_a999(int m,double *x) //返回常数999;
{return 999.0;}
double rfc_sintegrate(int m,double *xx) //一元积分函数;
{double a,b,eps,*pIn; //a为积分下限,b为积分上限,eps为积分精度要求;
int n,k,nfor; //nfor指出对第nfor个表达式进行积分;
double h,t1,t2,s1,s2,ep,p,x;
static int sintegratenum=0,sintegratemax=10; //sintegratemax为递归调用的最大次数,sintegratenum记录递归调用的实际次数;
if(pfcerrnum()!=0) goto end; //pfcerrnum()函数获取Forcal的运行错误,若出现过任何运行错误,不再进行计算;
if(++sintegratenum>sintegratemax) {if(pfcerrnum()==0) psetfcerr(-2,"sintegrate"); goto end;} //递归次数超出限制,用psetfcerr()函数设定运行错误;
if(rfor_max<1) {if(pfcerrnum()==0) psetfcerr(-1,"sintegrate"); goto end;} //未设置可接受外部函数功能;
if(m<3) {if(pfcerrnum()==0) psetfcerr(3,"sintegrate"); goto end;} //函数的参数个数不匹配;
nfor=(int)xx[3]; //nfor指出对第nfor个表达式进行积分;
if(nfor<0||nfor>=rfor_max) {if(pfcerrnum()==0) psetfcerr(1,"sintegrate"); goto end;} //指定的表达式不存在;
if(!fortrue[nfor]) {if(pfcerrnum()==0) psetfcerr(2,"sintegrate"); goto end;} //指定的表达式编译未通过,fortrue数组存放表达式的编译状态;
n=forpara[nfor]; //获取该表达式的自变量个数;
if(m!=3+n) {if(pfcerrnum()==0) psetfcerr(3,"sintegrate"); goto end;} //函数的参数个数不匹配;
pIn=allin[nfor]; //pgetin(nfor)获取第nfor个表达式的自变量指针;
for(k=1;k<=n;k++) pIn[k]=xx[3+k]; //当n>0时,进行两个表达式之间的参数传递;
a=xx[0]; b=xx[1]; eps=xx[2];
////////////////////////////////////以下进行积分!
n=1; h=b-a;
pIn[0]=a; x=prcals(nfor); //prcals(nfor)计算第nfor个表达式的值;
pIn[0]=b;
t1=h*(x+prcals(nfor))/2.0;
s1=t1;
ep=eps+1.0;
while (ep>=eps)
{ p=0.0;
for (k=0;k<=n-1;k++)
{ pIn[0]=a+(k+0.5)*h;
p=p+prcals(nfor);
}
t2=(t1+h*p)/2.0;
s2=(4.0*t2-t1)/3.0;
ep=fabs(s2-s1);
t1=t2; s1=s2; n=n+n; h=h/2.0;
}
////////////////////////////////以上进行积分!
if(pfcerrnum()==0) {sintegratenum--; return(s2);} //未发生任何错误退出时,递归次数减1;
end: //出错时,递归次数设为0;
sintegratenum=0; return 0.0;
}
// 定义一些简单的整数函数;
long ifc_a999(int m,long *x)
{return 999;}
// 定义一些简单的复数函数;
_complex cfc_a999(int m,_complex *x)
{x[0].x=999.0; x[0].y=999.0; return x[0];}
请参考作者网站上的扩展动态库OpenFCGl.dll,可以下载到该动态库的全部源代码。
[目录]