delphi - 从 Fortran 调用 Delphi 函数时出现段错误

标签 delphi windows-7 32bit-64bit gfortran

我有一个 Fortran 90 程序,它重复调用 Delphi 函数。该函数被多次调用,但最终程序因段错误而退出。

我有一个用 IBM fortran 编译的代码的可执行文件,它工作得很好,我必须使用 gfortran 重新编译整个代码

我有主程序的源代码,但没有函数的源代码,它位于随代码提供的 DLL 中,以及可能支持 Delphi 位的 borlndmm.dll

DLL 是 32 位的,我正在 Windows 7 系统上工作,使用 32 位 gfortran 编译器,规范如下:

COLLECT_GCC=C:\program files (x86)\gcc\bin\gfortran.exe
COLLECT_LTO_WRAPPER=c:/program files (x86)/gcc/bin/../libexec/gcc/i686-pc-mingw32/4.7.2/lto-wrapper.exe
Target: i686-pc-mingw32
Configured with: ../gcc-4.7.2-mingw/configure --host=i686-pc-mingw32 --build=x86_64-unknown-linux-gnu --target=i686-pc-mi    ngw32 --prefix=/home/gfortran/gcc-home/binary/mingw32/native/x86_32/gcc/4.7.2 --with-gcc --with-gnu-as --with-gnu-ld --wi    th-cloog=/home/gfortran/gcc-home/binary/mingw32/native/x86_32/cloog --with-gmp=/home/gfortran/gcc-home/binary/mingw32/nat    ive/x86_32/gmp --with-mpfr=/home/gfortran/gcc-home/binary/mingw32/native/x86_32/mpfr --with-mpc=/home/gfortran/gcc-home/b    inary/mingw32/native/x86_32/mpc --enable-cloog-backend=ppl --with-sysroot=/home/gfortran/gcc-home/binary/mingw32/cross/x8    6_32/gcc/4.7.2 --disable-shared --disable-nls --disable-tls --disable-win32-registry --enable-libquadmath-support --enabl    e-libquadmath --enable-languages=c,c++,fortran --enable-libgomp --enable-threads=win32 --enable-lto --enable-static --ena    ble-shared=lto-plugin --enable-plugins --with-host-libstdcxx='-lstdc++ -lsupc++ -lm' --with-ppl=/home/gfortran/gcc-home/b    inary/mingw32/native/x86_32/ppl --enable-ld=yes
Thread model: win32
gcc version 4.7.2 (GCC)

I've previously posted a question about this code (see Segmentation fault when calling a C function from Fortran repeatedly) but that was only the first stumbling block.

I compile the code with

>> gfortran -o cmod cmod.f90  -fbounds-check -ffree-line-length-none -dH -mrtd -g -L. Clues.dll

But I can't even get a dump output when it fails. I am thinking that I have a problem with memory alignment when calling the Delphi function, which eventually kills me. Or I may not be compiling correctly for 32 bit on a 64 bit system, I don't have any experience with this. Any idea on how to proceed would be most welcome.

The function definition in the original fortran code for IBM fortran is:

module overseer
 use kernel32
 interface
   function CluesOvr(scenario,region,soilorder,topography,rainfall,ASoildepth,Snumdairy,Snumsheep,Snumbeef,Snumdeer,AdditionalNitrogen,Supplementrate,SupplementType,Nloss,Ploss,ErrStr)
   !DEC$ ATTRIBUTES  VALUE :: scenario,region,soilorder,topography,rainfall,ASoildepth,Snumdairy,Snumsheep,Snumbeef,Snumdeer,AdditionalNitrogen,Supplementrate,SupplementType
   !DEC$ ATTRIBUTES  REFERENCE :: Nloss,Ploss,ErrStr
   LOGICAL CluesOvr
   integer*4 scenario,region,soilorder,topography,ASoildepth
   real*8 rainfall,Snumdairy,Snumsheep,Snumbeef,Snumdeer
   real*8 AdditionalNitrogen,Supplementrate
   Integer*4 SupplementType
   real*8 Nloss,Ploss
   character ErrStr(40)
   end function CluesOvr
 end interface
end module

我已经翻译成:

INTERFACE
 LOGICAL (C_BOOL) FUNCTION CluesOvr(scenario,region,soilorder,topography,rainfall, &
    ASoildepth,Snumdairy,Snumsheep,Snumbeef,Snumdeer,AdditionalNitrogen, &
    Supplementrate, SupplementType,Nloss,Ploss, &
    ErrStr) BIND (C, name='CluesOvr')
    USE, INTRINSIC :: ISO_C_BINDING
    IMPLICIT NONE
    INTEGER (C_INT), INTENT(IN), VALUE :: scenario,region,soilorder,topography,ASoildepth
    REAL (C_DOUBLE), INTENT(IN), VALUE :: rainfall,Snumdairy,Snumsheep,Snumbeef,Snumdeer
    REAL (C_DOUBLE), INTENT(IN), VALUE :: AdditionalNitrogen,Supplementrate
    INTEGER (C_INT), INTENT(IN), VALUE :: SupplementType
    REAL (C_DOUBLE), INTENT(OUT) :: Nloss,Ploss
    CHARACTER(C_CHAR), INTENT(OUT) :: ErrStr(*)
  END FUNCTION CluesOvr
END INTERFACE

IBM 代码也使用

 pointer (q,CluesOvr)
 p = loadlibrary("CluesOvr.dll")
 q = getprocaddress(p, "CluesOvr")

访问该功能。我不会用 gfortran 这样做。

最佳答案

borlandmm.dll 的存在表明您的任务几乎是不可能的。该 DLL 用于允许不同的模块(例如可执行文件和 DLL)共享公共(public)的 Delphi 内存管理器。这允许一个模块(例如可执行文件)分配一个 Delphi 字符串,并将其传递给另一个模块(例如 DLL),后者又可以释放该字符串。

除非两个模块共享相同的堆,否则这样的架构无法工作。 borlandmm.dll 库使跨模块的堆共享成为可能。任何希望使用其主机的 Delphi 内存管理器的 DLL 都包含 Sharemem 单元,该单元又使用 borlandmm.dll 库来实现内存管理器共享。

现在,您的 Fortran 主机不可能满足所需的契约(Contract)。唯一可以提供Delphi内存管理器的是Delphi主机。将会发生的情况是,您调用的 DLL 认为它负责释放它传递的内存。 DLL 可能接收堆分配的 Delphi string 变量。当 DLL 尝试释放内存时,该内存已在 Fortran 主机进程中分配。这种不匹配很可能导致访问违规。这些不一定会在每次调用该函数时发生。

这个 DLL 的设计使用 borlandmm.dll 是合理的,前提是它预计只能从 Delphi 主机调用。如果 DLL 的开发人员知道他们在做什么,那么他们就会意识到该限制。事实上,您没有 DLL 的文档,这表明您已从另一个程序中提取了 DLL,并试图以未设计的方式使用它。你成功的机会非常低。

关于delphi - 从 Fortran 调用 Delphi 函数时出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16683391/

相关文章:

perl - 如何让 2 个版本的 perl 在 Windows 7 上运行?

c++ - 'GetProcessIdOfThread' : identifier not found

c# - 64 位服务器中的 ASMX 到 COM 调用

cocoa - 以编程方式强制 Cocoa 应用程序以 32 位模式启动

windows - 为什么Windows在新的x64进程中使用RCX、RDX作为指针,与新创建的32位进程中的EAX、EBX不同?

delphi - TStringList 的 addObject 方法

delphi - 继续支持不同版本的软件,每个版本都使用不同的 Delphi 或组件版本构建

delphi - 如何从辅助类函数中获取 "helped"类?

delphi - 如何防止 Vista 因异常而终止我的程序?

windows - 操作系统/Windows 内部视频