从Fortran调用特定的C ++ DLL [英] Call specific C++ DLL from Fortran

查看:77
本文介绍了从Fortran调用特定的C ++ DLL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我收到了一个用C ++制成的DLL,并且我正在构建一个Fortran程序来调用C ++ DLL.我的编译器(gfortran)没有显示警告,但在运行时崩溃,显示以下说明:

I received a DLL made in C++, and I'm building a Fortran program to call the C++ DLL. My compiler (gfortran) shows no warnings, but it crashes during runtime with the following description:

    forrtl: severe (157): Program Exception - access violation
    Image              PC        Routine            Line        Source
    MainDLL_v10.dll    0B7A6B01  Unknown               Unknown  Unknown
    MainDLL_v10.dll    0B7A1BEF  Unknown               Unknown  Unknown
    ...

我猜我的调用参数有问题.C ++ DLL包括以下内容:

I guess something is wrong with my call arguments. The C++ DLL includes the following:

    #include <DllClasses.h>
   ...
   extern "C"
   {
   ...
     __declspec(dllexport) RESULT __cdecl Initialize(char *DllNames[], int NumberOfDlls, char *InputFile,  char *OutputFile, char *CtrlVersion, int InitState)
     {
     ...
     }
   ...
   } // extern C

我的Fortran程序是这样写的.这是我在CONTAINS之前的代码的一部分.

My Fortran program is written like this. Here is a part of my code before CONTAINS.

    ABSTRACT INTERFACE
        SUBROUTINE Initialize(PDLLNames, NumberOfDLLs, PInputfile, Poutputfile, CtrlVersion, InitState) BIND(C)
            USE, INTRINSIC :: ISO_C_Binding
            IMPLICIT NONE
            !DEC$ ATTRIBUTES C :: Initialize
            CHARACTER(KIND=C_CHAR), INTENT(IN   ), DIMENSION(9) :: PDLLNames    
            INTEGER(C_INT),         INTENT(IN   )               :: NumberOfDLLs   
            CHARACTER(KIND=C_CHAR), INTENT(IN   )               :: PInputfile  
            CHARACTER(KIND=C_CHAR), INTENT(INOUT)               :: Poutputfile 
            CHARACTER(KIND=C_CHAR), INTENT(IN   )               :: CtrlVersion 
            INTEGER(C_INT),         INTENT(IN   )               :: InitState
        END SUBROUTINE Initialize
        SUBROUTINE MainDll(InputSignals, OutputSignals, PErrorMessage) BIND(C)
            USE, INTRINSIC :: ISO_C_Binding
            IMPLICIT NONE
            !DEC$ ATTRIBUTES C :: MainDll
            REAL(C_DOUBLE),          INTENT(IN   )   :: InputSignals   (*) 
            REAL(C_DOUBLE),          INTENT(  OUT)   :: OutputSignals  (*)
            CHARACTER(KIND=C_CHAR),  INTENT(  OUT)   :: PErrorMessage  (*)
        END SUBROUTINE MainDll
    END INTERFACE

这是过程中我的Fortran代码的一部分.

And here is a part of my Fortran code in a procedure.

        ! Variables for dll interface
        PROCEDURE(Initialize), BIND(C), POINTER                 :: Initialize_proc
        INTEGER(C_INT)                                          :: NumberOfDLLs=9, InitState
        CHARACTER(KIND=C_CHAR, LEN=56), TARGET                  :: MainDll, DLLInputfile, DLLOutputfile, StateControllerName  
        CHARACTER(KIND=C_CHAR, LEN=56), TARGET, DIMENSION(9)    :: DLLname
        CHARACTER(KIND=C_CHAR, LEN=56), POINTER                 :: PoInputfile, PoOutputfile, PoStateControllerName    
        CHARACTER(KIND=C_CHAR, LEN=56), POINTER, DIMENSION(9)   :: PoDLLname(:)           
        PoInputfile => DLLInputfile
        PoOutputfile => DLLOutputfile
        PoStateControllerName => StateControllerName
        PoDLLname(1:) => DLLname(1:9)
    ...    
        ! Load DLL
        module_handle = LoadLibrary(MainDll // C_NULL_CHAR)
        proc_address = GetProcAddress( module_handle, C_CHAR_'Initialize' // C_NULL_CHAR )
        ! Call Initialize function in DLL
        CALL C_F_PROCPOINTER(proc_address, Initialize_proc)        
        CALL Initialize_proc(PoDLLname, NumberOfDLLs, PoInputfile, PoOutputfile, PoStateControllerName, InitState)

推荐答案

C函数的特性与相关的Fortran接口主体描述的特性不匹配.

The characteristics of your C functions and that described by the associated Fortran interface bodies do not match.

在Fortran中调用可互操作过程(具有BIND(C)的过程)时,不带VALUE属性的标量参数将通过引用传递给C ++函数.如果要通过值传递参数,则需要在Fortran端添加VALUE属性.

When an interoperable procedure is called (one that has BIND(C)) in Fortran, scalar arguments without the VALUE attribute are passed by reference to the C++ function. If you want the argument to be passed by value, you need to add the VALUE attribute on the Fortran side.

例如,在C ++片段中:

For example, in the C++ fragment:

__declspec(dllexport) RESULT __cdecl Initialize(... int NumberOfDlls

NumberOfDlls按值传递,但是Fortran显示:

NumberOfDlls is pass by value, but the Fortran shows:

SUBROUTINE Initialize(... NumberOfDLLs, ...) BIND(C)
  ...
  INTEGER(C_INT), INTENT(IN) :: NumberOfDLLs   

无值属性-Fortran参数对应于 int * NumberOfDlls 的C ++参数.对于按值传递,请使用以下Fortran参数声明:

No value attribute - the Fortran argument corresponds to a C++ parameter of int *NumberOfDlls. For pass by value, use a Fortran argument declaration of:

  INTEGER(C_INT), INTENT(IN), VALUE :: NumberOfDLLs   

您的Fortran界面还包含gfortran以外的一系列编译器系列(今天由Intel Fortran代表)的编译器指令(!DEC $ ATTRIBUTES ... ).该指令可能会以与C函数匹配的方式更改该系列编译器在Fortran方面的参数行为.但是gfortran不理解该指令-它认为它只是一个注释.

Your Fortran interface also includes compiler directives (!DEC$ ATTRIBUTES...) for a family of compilers (represented today by Intel Fortran) other than gfortran. That directive would change the behaviour of the arguments on the Fortran side for that family of compilers, possibly in a way that matches the C function. But gfortran does not understand that directive - it considers it to be just a comment.

gfortran有其自己的等效指令,但是像这样的指令的使用反映了该语言标准不支持C互操作性的时间.

gfortran has its own equivalent directives, but the use of directives like that reflects a time when the language standard had no C interoperability support.

由于编译器开始支持Fortran 2003,因此最好使用标准语言功能来管理互操作性-将VALUE添加到需要它的参数中(也是InitState),然后删除指令.

Since compilers started supporting Fortran 2003, you are better off using the standard language features to manage interoperability - add VALUE to the arguments that need it (InitState too), and delete the directives.

问题中未显示Windows API的LoadLibrary和GetProcAddress的详细信息.我假设已经为所有可能使用的编译器正确地描述了它们.

Not shown in your question are the specifics around the Windows API's LoadLibrary and GetProcAddress. I am assuming they have been described correctly for all compilers that might be used.

关于在调用C代码的需求方面的其他误解,在Fortran中准备参数的方式(建议使用大量的指针-为什么?)有一个建议.

There is a suggestion in the way the arguments are being prepared in Fortran (lots of pointers being used - why??) of other misunderstandings around the requirements for calling C code.

这篇关于从Fortran调用特定的C ++ DLL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆