5-5 VB与Fortran的混合编程 下载本文

5-5 VB与Fortran的混合编程

汪润生 (07级硕士研究生)

一、 实验简介

不同的计算机语言各有其应用目的,在某个相关领域,一种语言可能比较有优势,然而在其他领域,则会显出劣势来。在允许的条件下,将不同的语言结合起来,各取其长处,以弥补单一预言的缺陷,这是计算机语言混合编程的原因。

众所周知,Fortran语言在计算方面见长,很多人用他做科学计算的工具;然而其面向对象性和人机交互性很差。VB是一种有名的面向对象编程语言,被人们广泛用来设计操做界面、窗体应用程序、网络应用程序等。而它却不擅长做计算。

一些应用中需要结合这两种语言的长处:既要人机交互性好,又要运算速度快,就需要将这两种语言结合起来,通过混合编程的方法实现:用Fortran设计计算部分的核心模块,而用VB设计人机交互界面。

我们通过本次实验来体验和实现这两种语言的混合编程。 二、 实验目的

1.掌握VB和Fortran混合编程的方法。 2.掌握Fortran中动态链接库的创建方法。 3.掌握VB中对动态链接库的调用方法。 三、试验条件

在这个实验中,我们需要在PC机上安装VB设计软件和Fortran编译软件。建议安装Microsoft Visual Basic 2005和Compaq Visual Fortran 6.5。

四、 实验原理

一般人们熟知的实现VB 与Fortran混合编程的方法主要有两种, 即VB中直接调用可执行文件(利用Shell函数直接调用Fortran编译出来的可执行文件) 和利用动态链接库DLL (Dynamic Link Library) 与Fortran 混合编程。

第一种方法比较简单,将Fortran源程序编译为可执行文件(扩展名为.exe)之后在VB环境下用shell()函数调用即可。VB中shell()函数的语法如下:

Public Function Shell( _

ByVal PathName As String, _

Optional ByVal Style As AppWinStyle = AppWinStyle.MinimizedFocus, _ Optional ByVal Wait As Boolean = False, _

1

Optional ByVal Timeout As Integer = -1 _ ) As Integer

shell()函数的参数中第一项为可执行文件名,如可执行文件不在当前路径下,文件名应包含完整的驱动器和路径名。比如在C盘根目录下由一个名为test.exe的可执行文件,则其pathname=”C:/test.exe”。后面三个参数为可选参数,可根据实际需要选取和设置。因此,对这个可执行文件的调用可以通过下面一条简单的代码来实现:

shell(”C:/test.exe”)

在整个运行程序过程中, Fortran应用程序始终在后台运行,VB 和Fortran 之间的所有数据交换都是通过磁盘文件进行。这种方法适合于计算量较大而交互操作不多的时候。但是, Shell 函数是以异步方式执行的, 这种执行方式使VB 程序不能等待Fortran 程序计算结束, 而是继续执行后续的程序, 从而容易使最终结果出错。

另一种方法是将Fortran源程序编译为动态链接库(扩展名为.dll),然后在VB环境下调用动态链接库里的函数和过程来完成各项计算任务。

虽然没有第一种方法操作简单,但是调用动态链接库的方法更为灵活和实用。下面会尽量详细的介绍这种方法。

五、 Fortran中动态链接库(.dll文件)的创建

出于简单、实用的目的,我们先比较简略的介绍在Visual Fortran 6.5环境下动态链接库的创建步骤和注意事项,当然这些步骤和方法具有一定的通用性。我们在这里列出一些必要的注意事项,但不做详细的说明,因为我们会在后面做出尽量详细的解释和补充,如果有需要可以查阅这些内容。当然这不是必须的,这里所列出的内容已经足够用于创建大部分在VB环境中调用的动态链接库了。下面就做这些介绍。

在Compaq Visual Fortran 6.5中创建“.Dll”文件的步骤如下: 1) 创建dll项目(Project)

跟一般的Fortran项目相似,首先要创建一个dll项目,具体步骤如下:

点击File ——New,在弹出的new对话框中选择Projects项下的Dynamic Link Library,在右侧Project Name下面的文本框中输入项目名称,在Location下的文本框中选好路径之后点击Ok,这样我们就创建了一个空的dll项目文件。

2)在dll项目中添加文件

在刚才创建的dll项目中添加一个空文件,这跟普通的Fortran项目中添加文件的方法一样。

点击file——new,在弹出的new对话框中选择Files项,在列表框中选择文件类型(单

2

击选中即可),一般选择Fortran Fixed format Source Files(固定格式源文件)或Fortran Free format Source Files(自由格式源文件),在右边File标签下的文本框中输入源文件名,点击OK,一个空的源文件就建好了,接下来可以在里面编写Fortran源程序了。

3)创建子程序(过程)和函数

Dll文件是一种特殊的可执行文件,在其源程序中没有主程序,而是一个或多个子程序或函数,我们通过调用这些子程序和函数来完成一些特定的任务。

在Dll项目中创建子程序和函数的方法跟一般Fortran项目文件中的没有太大的差别,只需在子程序或函数开始时加入如下一些微软扩展属性编译伪指令即可:

!MS$ attributes dllexport !MS$ attributes alias !MS$ attributes value !MS$ attributes reference

微软扩展属性编译伪指令是一些特定的指令,有三种写法: ①以$符号为起始的写法; ②以!MS$开头的写法;③以!DEC$ 开头的写法。①中的$必须位于首列, ②中的!MS$中间不能有空格,三种写法$后的空格都被忽略。

微软扩展属性($Attributes) 编译伪指令是用来指定标识符的微软扩展属性的,它仅有声明作用,不具有定义作用。

第一条指令用以说明一个动态链接库接口,说明这一子程序是从动态链接库中输出的; 第二条指令用以说明子程序或公共区的外部名称,该外部名称用字符串指定,区分大小写,其它程序(如VB) 要访问这一变量或调用这一函数时,所用名称要用指定外部名称;

第三条指令用以说明子程序的某个形参是以传值的形式与实参结合的,这时所传递的是参数的值;

第四条指令用以说明子程序的某个形参是以引用的形式与实参结合的,在这种引用方式下,所传递的都是参数的地址,如果子过程中对参数进行了修改,这一修改将带回到调用过程。

需要说明的是Fortran程序默认情况下是以传递地址方式传递参数的,即若不指定参数传值方式,则默认为是reference方式。

大部分的编译伪指令可写在程序的任意位置。在一条编译伪指令中可赋予多种不冲突的属性,在一条!MS$Attributes 指令中不同属性或不同标识符间也用逗号隔开,属性和标识符之间用∷隔开。

举一个简单的例子,如果要编写一个计算双精度实数加法的子程序,子程序名为subplus,输入参数为a和b,输出参数为c,则完整的源程序可以这样写:

3

subroutine subplus(a,b,c) !MS$ attributes dllexport :: subplus !MS$ attributes alias :'subplus'::subplus !MS$ attributes value::a,b !MS$ attributes reference::c

real(8)::a,b,c c=a+b return

end subroutine subplus

其中伪指令!MS$ attributes reference::c 可以省略不写,但为增加源程序的可读性,建议将所有参数的传值方式显式的写出来。

一般情况下我们将输入参数定义为传递数值方式,而将输出变量定义为传递地址方式。但这也不是必须的,可根据实际情况而灵活变化。

虽然编译伪指令可写在程序的任意位置,但还是建议写在子程序开始之后、其它代码之前,这样也可增强源程序可读性。

像这样添加一些子程序函数,然后可以将他们编译和生成dll文件(快捷键是F7)。之后在该项目文件目录下的debug文件夹中可以找到这个以项目名称命名的dll文件,我们可以在VB环境中调用它。

下面我们简要介绍一下在VB环境下对Dll文件的调用。 六、 VB2005中对动态链接库的调用

VB 对动态链接库的调用如同对普通子程序或函数的调用,在调用之前必须先对Dll 中的子程序或函数声明。声明格式如下:

[Public|Private] Declare Sub|Function Name Lib“Libname”[Alias“aliasname”] [([arglist ])] 声明中各项的意义如下:

Public , Private 可选的。Public 用于声明对所有模块中的所有其它过程都可以使用的过程(默认) ;Private用于声明只能在包含该声明的模块中使用的过程。

Declare是用以声明的关键字。

Sub , Function 可选的(但Sub 或Function 二者需选其一) 。Sub 表示该过程没有返回值;Function 表示该过程会返回一个可用于表达式的值。

Name 任何合法的过程或函数名,调用动态链接库的入口,注意区分大小写。

4

Lib 必需的,指明包含所声明过程的动态链接库或代码资源,所有声明都需要Lib 子句。 Libname 必需的,包含所声明的过程动态链接库名或代码资源名。

Alias aliasname 可选的,表示将调用的过程在动态链接库中还有另外的名称。当外部过程名与某个关键字重名时,就可以使用这个参数,当动态链接库的过程与同一范围内的公用变量、常数或任何其它过程的名称相同时,也可以使用Alias ;如果该动态链接库过程中的某个字符不符合动态链接库的命名约定时,也可以使用Alias。aliasname 指动态链接库中该过程的入口处的名称,如果首字符是# ,则随后的字符必须指定该过程入口处的顺序号。

arglist 参数的语法为[Optional ] [ByVal| ByRef ] varname [ () ] [As type ] 。

Optional 可选的,表示参数不是必需的。如果使用该选项,则arglist 中的后续参数都必须是可选的,而且必须都使用Optional 关键字声明。ByVal 可选的,表示该参数按值传递。ByRef 表示该参数按地址传递。ByRef 是Visual Basic 的缺省选项。varname 必需的,代表传给该过程的参数的变量名,遵循标准的变量命名约定。() 对数组变量是必需的,指明varname 是一个数组。type 可选的,传递给该过程的参数的数据类型,可以是Byte 、Boolean、Integer 、Long、Currency、Single 、Double 、Date 、St ring (只支持变长) 、Object 、Variant 、用户自定义的类型或对象类型。

例如在C盘根目录下有一个名为mathfunction.dll的动态链接库,我们对这个库中名为subplus的子程序的声明如下:

Public Declare Sub subplus Lib \ (ByVal a As Double, ByVal b As Double, ByRef c As Double)

在声明之后这些函数或过程就可以向普通的函数或过程一样在VB环境下调用了。 七、 一些重要的说明和补充

这部分是对五、六两部分相关内容的补充和解释,在本次实验中不是必需的,但这些内容很重要,可根据需要查阅。

1 动态链接库

动态链接库(DLL)是一种在运行时连接的可执行代码和数据模块,是Microsoft Windows 系列操作系统的重要组成部分,是一种特殊的且现在广为应用的函数库。

使用普通的函数库时,可以在程序链接时将库中的代码拷贝到可执行文件中,这是一种静态链接。在多个同样的程序执行时,系统保留了许多重复的代码副本,造成了内存资源的浪费。在使用DLL 的情况下,当建立应用程序的可执行文件时,不必将DLL 链接到程序中,而是在应用程序运行时动态地装载DLL 。装载时, DLL 将被映射到进程的地址空间中。同时,使用DLL 的动态链接并不是将库代码拷贝,只是在程序中记录了函数的入口点和接口。不管多少程序使

5