家庭承诺已久DLL感谢长安大学瞬变电磁团队的帮助。它们提供了最原始的计算程序模块。 在写这篇Dll在调用文章的过程中,最初的想法是写清楚界面定义和函数调用模块参数说明,考虑到每个人都在写DLL过程中可能踩到的坑,所以将我在Fortran中国参数的定义,以及C 所有的引用过程都贴出来供大家参考。 1、调用函数
要使用DLL首先要知道文件DLL文件的位置,层状介质正在演奏DLL文件名称Dll2.dll(命名不是很随意吗?写的时候只是版本太多,懒得起名字。O(∩_∩)O哈哈~),放在程序可执行文件相同的目录中。当你想使用自己的时候Dll请备份文件,然后将您的文件命名为Dll2.dll可以替换。
主要调用文件 BfwdLineSource;// = (bfwdLine)mylib.resolve("bfwdline");///半空间线源磁场dB/dt计算 ResistInvese;// = (Resreturn)mylib.resolve("resreturn");////平移计算电阻率 HalfSpaceForwardLineSource;// = (halfBFwdLine)mylib.resolve("halfbfwdline");//均匀半空间磁场dB/dt计算 LayerForword;// = (wndProc)mylib.resolve("layerforword"); 援引layerforword() 函数 Fortran默认为大写,但是当用stdcall调用时所有小写 这些函数是C 的接口。
2、C 中DLL函数名和变量定义
////层状介质正演DLL文件 //定义函数指针,以备调用注意声明指向函数的指针。__stdcall //typedef float (*Fun)(float, float, float, float, float, float); //Fun open = (Fun)mylib.resolve("cal_resistivity_z"); //援引CAL_RESISTIVITY_Z() 函数 Fortran默认为大写,但是当用stdcall调用时所有小写 //(&nLayer, &flag, & , &tmax, &I0, RHO, H, time, dBx_t, dBy_t, dBz_t, , allres, depth, &nSource, &tnum, &receive_point_num, Source_A, Source_B, x, y, z, &out_type) typedef void(__stdcall* wndProc)(long nLayer, long flag, float tmin, float tmax, float TxCurr, float* RHO, float* modelH, float* time, float** dBx_t, float** dBy_t, float** dBz_t, float** halfdBz_t, float** allres, float** depth, long nSource, long tnum, long receive_point_num, float* Source_A, float* Source_B, float*xx, float*yy, float* zz, char* out_type); //BFwdLine(RHO, H, nLayer, A, B, x, y, z, t, Bx_t, By_t, Bz_t, out_type) typedef void(__stdcall* bfwdLine)(float* RHO, float* modelH, long nLayer, float* AA, float* BB, float xx, float yy, float zz, float tt, float* Bx_t, float* By_t, float* Bz_t, char* out_type); //resreturn(tobs, obsBz_t,nSource,tnum, receive_point_num, Source_A, Source_B, I0, x, y, z, allres, depth, out_type) typedef void(__stdcall* Resreturn)(float* twin, float* Vt, long nSource, long tnum, long receive_point_num, float* Source_A, float* Source_B, float TxCurr, float x, float y, float z, float* allres, float* depth, char* out_type); //halfBFwdLine(RHO, I0 , A, B, x,y,z,t,Bz_t,out_type) typedef void(__stdcall* halfBFwdLine)(float Rho, float TxCurr, float* AA, float* BB, float xx, float yy, float zz, float tt, float* Bz_t, char* out_type);
bfwdLine BfwdLineSource;// = (bfwdLine)mylib.resolve("bfwdline");///半空间线源磁场dB/dt计算 Resreturn ResistInvese;// = (Resreturn)mylib.resolve("resreturn");////平移计算电阻率 halfBFwdLine HalfSpaceForwardLineSource;// = (halfBFwdLine)mylib.resolve("halfbfwdline");//均匀半空间磁场dB/dt计算 wndProc LayerForword;// = (wndProc)mylib.resolve("layerforword"); 援引layerforword() 函数 Fortran默认为大写,但是当用stdcall调用时所有小写 要使得你DLL可以调用文件,您需要将动态链接库中函数的命名和参数的定义与该界面中函数的名称和参数类型一致。 需要注意的是C 中DLL编译函数名称大小写的规定。depend打开你写的文件,查看DLL函数名称大小写及参数定义是否符合上述规定。 (好像很复杂,如果能写的话。DLL最好直接输出文本文件graph绘图? 事实上,只要你足够熟练,程序就能快速计算结果并实时显示,节省绘图时间。对于多个不同参数的计算结果,速度必须比较graph画画快,节省时间玩游戏他不香吗?
3、Fortran中动态链接库的写法
subroutine LayerForword(nLayer,flag,tmin,tmax,I0,RHO,H,time,dBx_t,dBy_t,dBz_t,halfdBz_t,allres,depth,nSource,tnum,receive_point_num,Source_A,Source_B,x,y,z,out_type) implicit none ! Expose subroutine Dll2 to users of this DLL ! !DEC$ ATTRIBUTES stdcall,DLLEXPORT::LayerForword !!ms$Attributes alias:'LayerForword':: LAYERFORWORD !给函数取一个别名这样方便调用在C++中直接用Dll名 !!ms$Attributes value::nLayer,flag,out_typeflag,tmin,tmax,I0 ,nSource,tnum,receive_point_num !!ms$Attributes reference:: RHO,H,time,dBx_t,dBy_t,dBz_t,halfdBz_t,allres,depth,Source_A,Source_B,x,y,z !输出值只能以引用调用 ! Variables
INTEGER*4,intent(in):: nLayer,flag !n层地层,计算标志 REAL*4 ,intent(in):: tmin,tmax,I0 !I0 REAL*4 ,intent(in) ::RHO(nLayer),H(nLayer) !定义了两个一维实型数组,分别为电阻率,层厚 INTEGER*4 ,intent(in) ::nSource,tnum,receive_point_num !nSource:电性源个数,tnum:时间道数receive_point_num:接收点个数 REAL*4 ::time(tnum) REAL*4 ::dBx_t(tnum,receive_point_num),dBy_t(tnum,receive_point_num),dBz_t(tnum,receive_point_num) !定义了四个一维实型数组(时间、响应的x,y,z三个分量) REAL*4 ::halfdBz_t(tnum,receive_point_num) !半空间中的磁场强度 REAL*4 ::allres(tnum,receive_point_num),depth(tnum,receive_point_num) !电阻率和深度反演出来的,应该是用的平移法 REAL*4 ,intent(in) ::Source_A(nSource*2),Source_B(nSource*2) !源的起讫点A、B REAL*4 ,intent(in) ::x(receive_point_num),y(receive_point_num),z(receive_point_num) !CHARACTER*255 :: prefix,outX,outY,outZ,halfoutZ,OUTPS,OUTDP,resout !prefix,前缀 CHARACTER(len = 2),intent(in) ::out_type [REFERENCE] !输出类型 必须引用调用,C语言中char*str = new char[2];
! 定义了DLL后必须在调用前写一个接口,相当于C++语言的extern 里面定义变量就可以 ! THIS IS THE RIGHT WAY interface interface !计算长导线源AB(I=1.0)在(x,y)处的时域响应---------------------BFwdLine------------------------------------- SUBROUTINE BFwdLine(RHO,H,nLayer,A,B,x,y,z,t,Bx_t,By_t,Bz_t,out_type) !DEC$ ATTRIBUTES stdcall,DLLEXPORT::BFwdLine !dll输出标志 INTEGER ::nLayer [VALUE] CHARACTER(len = 2) ,intent(in) ::out_type [REFERENCE] !输出类型 必须引用调用,C语言中char*str = new char[2]; REAL :: x,y,z,t REAL :: RHO(nLayer),H(nLayer-1),A(2),B(2) REAL :: Bx_t [REFERENCE],By_t [REFERENCE],Bz_t [REFERENCE] endsubroutine BFwdLine !----------------------BFwdLine------------------------------------- !计算各点视电阻率及视深度 ---------------------Resreturn----------------------------------------------------------------- SUBROUTINE Resreturn(tobs,obsBz_t,nSource,tnum,receive_point_num,Source_A,Source_B,I0,x,y,z,allres,depth,out_type) !DEC$ ATTRIBUTES stdcall,DLLEXPORT::Resreturn !dll输出标志 CHARACTER(len = 2) ,intent(in) ::out_type [REFERENCE] !输出类型 必须引用调用,C语言中char*str = new char[2]; INTEGER ::nSource,tnum,receive_point_num REAL ::Source_A(2*nsource),Source_B(2*nsource),tobs(tnum),obsBz_t(tnum) REAL :: x,y,z,I0 REAL :: allres(tnum),depth(tnum) endsubroutine Resreturn !---------------------Resreturn----------------------------------------------------------------- !计算长导线源AB(I=1.0)在(x,y)处的时域响应 ------------------------------halfBFwdLine-------- SUBROUTINE halfBFwdLine(RHO,I0,A,B,x,y,z,t,Bz_t,out_type) !DEC$ ATTRIBUTES stdcall,DLLEXPORT::halfBFwdLine !dll输出标志 REAL :: RHO,I0,A(2),B(2),x,y,z,t REAL :: Bz_t [REFERENCE] CHARACTER*2 ,intent(in) ::out_type [REFERENCE] !输出类型 必须引用调用,C语言中char*str = new char[2]; ENDSUBROUTINE halfBFwdLine !------------------------------halfBFwdLine----------
end interface