I have successfully called a C routine in a dll from Fortran and a Fortran routine in a dll called from VB many times. This is the first time I've tried using VB to call Fortran to call C.
The simple test routines below try to pass an integer from a Fortran routine called by VB to a C routine.
The value being passed = 12, but when it reaches the C routine, the value = 1239536.
Suggestions?
VB 2010 code:
Declare Sub TEST_FTN Lib "LHM_Fsrc.dll" ()
Call TEST_FTN()
FTN code:
SUBROUTINE TEST_FTN()
!DEC$ ATTRIBUTES DLLEXPORT, STDCALL :: TEST_FTN
!DEC$ ATTRIBUTES ALIAS:'TEST_FTN' :: TEST_FTN
IMPLICIT NONE
INTERFACE
SUBROUTINE Test_Int(i1)
!DEC$ ATTRIBUTES DLLIMPORT :: Test_Int
!DEC$ ATTRIBUTES DECORATE, ALIAS:'Test_Int' :: Test_Int
INTEGER :: i1
END SUBROUTINE Test_Int
END INTERFACE
INTEGER :: i1
i1 = 12
CALL Test_Int(i1)
RETURN
END SUBROUTINE TEST_FTN
C code:
__declspec(dllexport) void Test_Int(long i1);
void Test_Int(long i1)
{
long i2;
i2 = i1;
}
Regards, Mike
链接已复制
You've told C that i1 is being passed by value, but Fortran thinks it is by refrerence. You could fix this by any of the following (in my decreasing order of preference):
1. Change the Fortran declaration of Test_Int to use the C interoperability features and the VALUE attribute:
INTERFACE
SUBROUTINE Test_Int(i1) BIND(C,NAME="Test_Int")
!DEC$ ATTRIBUTES DLLIMPORT :: Test_Int
INTEGER, VALUE :: i1
END SUBROUTINE Test_Int
END INTERFACE
2. Add the following directive to the interface body:
!DEC$ ATTRIBUTES VALUE :: i1
I want to point out that the VALUE attribute in 1 above, if you didn't have BIND(C), is not equivalent to ATTRIBUTES VALUE. With BIND(C), it is - at least in this case.
3. Change the C code to accept the argument by reference (*i1 in the prototype) and dereference it in the code.
Hi Steve,
Following your #1 preference works for me.
How would you change the following Fortran code which passes a character string to a C routine, or would you?
Fortran code:
SUBROUTINE TEST_FTN(choice, fname_)
!DEC$ ATTRIBUTES DLLEXPORT, STDCALL :: TEST_FTN
!DEC$ ATTRIBUTES ALIAS:'TEST_FTN' :: TEST_FTN
!DEC$ ATTRIBUTES REFERENCE :: fname_
IMPLICIT NONE
INTERFACE
SUBROUTINE C_Routine(iChoice, FileName)
!DEC$ ATTRIBUTES DLLIMPORT :: C_Routine
!DEC$ ATTRIBUTES DECORATE, ALIAS:'C_Routine' :: C_Routine
INTEGER, VALUE :: iChoice
CHARACTER(LEN=256) :: FileName
!DEC$ ATTRIBUTES REFERENCE :: FileName
END SUBROUTINE C_Routine
END INTERFACE
!Type call list variables
INTEGER, INTENT(IN) :: choice
CHARACTER(LEN=256), INTENT(IN) :: fname_
! Type local variables
CHARACTER(LEN=256) :: fname
INTEGER :: i
fname = ' '
fname(1:255) = fname_(1:255)
i = LEN_TRIM(fname)
fname(i+1:i+1) = CHAR(0)
CALL C_Routine(choice, fname)
RETURN
END SUBROUTINE TEST_FTN
C code:
__declspec(dllimport) void C_Routine (int iChoice, char *FileName);
void C_Routine(int iChoice, char *FileName)
{
....
}
Regards, Mike
INTERFACE
SUBROUTINE C_Routine(iChoice, FileName) BIND(C,NAME="C_Routine")
USE, INTRINSIC :: ISO_C_BINDING
!DEC$ ATTRIBUTES DLLIMPORT :: C_Routine
INTEGER(C_INT), VALUE :: iChoice
CHARACTER, DIMENSION(*) :: FileName
END SUBROUTINE C_Routine
END INTERFACE
The standard makes an exception in this case for the rule about passing a scalar to an array.
