VC 中调用Fortran动态链接库函数开发说明
时间:2010-08-18 来源:破碎
VC 中调用Fortran动态链接库函数开发说明
说明:使用Fortran建立动态链接库,在C/C++语言环境中载入动态链接库,并调用动态链接库中函数。此方法使用动态载入动态链接库的方法。
开发环境:
Compaq Visual Fortran 6.5
Visual C++ 6.0
1. 程序中特殊要求:
1.1 Fortran :
在Fortran函数内部添加以下声明:
!DEC$ ATTRIBUTES DLLEXPORT::FunctionName |
表示这个函数为DLL导出函数,其中FunctionName为函数名
特别提示:Fortran 函数调用传递的参数为传地址。所以在C/C++语言中调用的时候要传递参数的地址。
1.2 C/C++:
1.2.1 加载动态链接库:
HMODULE LoadLibrary(PCTSTR pszDLLPathName);
HMODULE LoadLibraryEx( PCTSTR pszDLLPathName, //DLL路径以及名称 HANDLE hFile, DWORD dwFlags); //加载选项 |
这两个函数会在将一个DLL映射到进程的地址空间中。返回值类型为HMODULE(和HINSTANCE等价)为DLL被映射的虚拟内存地址。
使用这两个函数将DLL动态加载。
LoadLibraryEx函数中 参数hFile为系统为将来扩充所保留,现在必须设为NULL.
dwFlags 为动态链接库加载方式选项, 一般使用DONT_RESOLVE_DLL_REFFERENCE, 告诉系统只需将DLL映射到进程地址空间。
1.2.2 卸载动态链接库:
BOOL FreeLibrary(HMODULE hInstDll); |
1.2.3 检索指定的动态链接库(DLL)中的输出库函数地址:
FARPROC GetProcAddress( HMODULE hModule, // DLL模块句柄 LPCSTR lpProcName );// 函数名 |
返回值为函数的指针,记得要强制类型转换,否则编译过程中会发生错误。同时,Fortran语言中时忽略大小写的,所以检索的时候要求函数名全部为大写字母。
2. 实例
2.1 实例1:
说明:Fortran实现两个整数加法
Fortran部分:
新建项目,项目类型为Fortran Dynamic Link Library, 项目名称为testA,选择An empty DLL application, 添加一个test.f90文件,文件中编辑如下内容:
function GetAdd(a, b) result(r)
implicit none
!DEC$ ATTRIBUTES DLLEXPORT::GetAdd integer :: a integer :: b integer :: r
r = a + b return end |
编译生成DLL文件。
C/C++ 部分:
新建一个MFC AppWizard(exe)项目,项目名称为 testAMFC, 选择Dialog based选项。
编辑资源:
删除ok cancel 按钮,添加一个按钮,按钮标题ADD, ID为IDC_BUTTON_ADD。设为缺省按钮(就是敲回车等于按了这个按钮)。
添加三个可编辑文本框,ID分别为IDC_EDIT_A, IDC_EDIT_B, IDC_EDIT_RESULT
为三个文本框添加成员变量 变量类型为 int 变量名分别为 m_a, m_b, m_result。
为按钮ADD添加控制函数,函数名称为OnButtonAdd
编写此函数:
void CTestAMFCDlg::OnButtonAdd() { this->UpdateData(); HMODULE hDll = LoadLibraryEx(TEXT("testA.dll"), NULL, DONT_RESOLVE_DLL_REFERENCES);
if (!hDll) { MessageBox("加载动态链接库失败", "ERROR", MB_OK); return; }
int (__stdcall *proc)(int *, int *); //注意声明方式指向函数的指针,要求有__stdcall
proc = (int (__stdcall *)(int *, int *))GetProcAddress(hDll, "GETADD");
if (!proc) { MessageBox("加载函数失败", "ERROR", MB_OK); FreeLibrary(hDll); return; }
m_result = proc(&m_a, &m_b); this->UpdateData(false); FreeLibrary(hDll); } |
将Fortran编译出来的DLL文件拷贝到当前项目目录,编译执行。
2.2 实例二:
说明:调用Fortran动态链接库实现可变长数组加法。
Fortran部分:
新建项目,项目类型为Fortran Dynamic Link Library, 项目名称为test,选择An empty DLL application, 添加一个test.f90文件,文件中编辑如下内容:
function GetAdd(a, b, n, r) result(rr)
implicit none
!DEC$ ATTRIBUTES DLLEXPORT::GetAdd
integer :: a(*) !参数为一个可变大小的一维数组 integer :: b(*) !参数为一个可变大小的一维数组 integer :: r(*) !参数为一个可变大小的一维数组 integer :: n integer :: i integer :: rr
do i=1, n !使用循环计算加法 r(i) = a(i) + b(i) end do
rr = n return end |
C/C++ 部分:
新建一个MFC AppWizard(exe)项目,项目名称为 testAMFC, 选择Dialog based选项。
编辑资源:
删除ok cancel 按钮,添加一个按钮,按钮标题ADD, ID为IDC_BUTTON_ADD。设为缺省按钮(就是敲回车等于按了这个按钮)。
添加九个可编辑文本框,ID分别为IDC_EDIT_A1 ~ IDC_EDIT_A3, IDC_EDIT_B1 ~ IDC_EDIT_B3, IDC_EDIT_C1 ~ IDC_EDIT_C3。
分别为其添加成员变量
m_a1,m_a2,m_a3; m_b1,m_b2,m_b3; m_c1,m_c2,m_c3;
为按钮ADD添加控制函数 函数名称为OnButtonAdd
编辑此函数
void CTestmfcDlg::OnButtonAdd() { this->UpdateData(); int a[3]; int b[3]; int c[3]; int n = 3;
/* m_a1 = 1; m_a2 = 2; m_a3 = 3;
m_b1 = 3; m_b2 = 2; m_b3 = 1; */ // this->UpdateData(false);
a[0] = m_a1; a[1] = m_a2; a[2] = m_a3;
b[0] = m_b1; b[1] = m_b2; b[2] = m_b3;
HMODULE hDll = LoadLibraryEx(TEXT("test.dll"), NULL, DONT_RESOLVE_DLL_REFERENCES);
if (!hDll) { MessageBox("加载动态链接库失败", "ERROR", MB_OK); FreeLibrary(hDll); return; }
//注意声明方式指向函数的指针,要求有__stdcall int (__stdcall *proc)(int *, int *, int *, int *);
proc = (int (__stdcall *)(int *, int *, int *, int *))GetProcAddress(hDll, "GETADD");
if (!proc) { MessageBox("加载函数失败", "ERROR", MB_OK); FreeLibrary(hDll); return; }
proc(a, b, &n, c);
m_c1 = c[0]; m_c2 = c[1]; m_c3 = c[2];
this->UpdateData(false); FreeLibrary(hDll); } |
将Fortran编译出来的DLL文件拷贝到当前项目目录,编译执行。
还有一个问题之前没有提到,就是Fortran的函数参数传递为传址的方式,所以调用fortran动态链接库里面的函数的时候传递的都是地址。