Problem with C++ dll being used in FORTRAN - Programmers Heaven

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories

Welcome to the new platform of Programmer's Heaven! We apologize for the inconvenience caused, if you visited us from a broken link of the previous version. The main reason to move to a new platform is to provide more effective and collaborative experience to you all. Please feel free to experience the new platform and use its exciting features. Contact us for any issue that you need to get clarified. We are more than happy to help you.

Problem with C++ dll being used in FORTRAN

Hi,
I am stuck at a point where I am using mixed language programming of C++ and FORTRAN. I have a C++ function in a dll which returns a pointer. I tried to call it from my FORTRAN program. I have no problem in compiling, linking and running. However, after the run I get the C pointer returned as 0. It is not a problem with the function in the dl because I have checked with the dll being called from both C++ and C# programs. So I think it is something to dow ith FORTRAN calling the C++ function. Here is the structure of the program:

[code]// C++ Header
// ---------------
# include statements
#ifdef BUILD_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
// #define DLL_EXPORT __declspec(dllimport)
#endif

//#ifdef __cplusplus
extern "C"
{
double DLL_EXPORT __cdecl *CalcAirProperties(int InputCombination, double Input1, double Input2, double Pressure);
}
// ---------------
//C++ source code
// ---------------
double DLL_EXPORT __cdecl *CalcAirProperties(int InputCombination, double Input1, double Input2, double Pressure)
{
double *AirProperties = new double[7];
//Do Calculations
return AirProperties
}
// ---------------[/code]

Here is my FORTRAN code:

[code]!********************
PROGRAM ProgramMain
USE Statements
USE iso_c_binding, ONLY : c_ptr,c_double,c_f_pointer
IMPLICIT NONE
TYPE(c_ptr) :: c_p
REAL(c_double), POINTER :: f_p(:)
INTERFACE

FUNCTION CalcAirProperties(InputComb, InpValue1,InpValue2,BarometricPressure) BIND(C,NAME='CalcAirProperties')

USE ISO_C_BINDING

INTEGER(kind=C_INT), INTENT(IN) :: InputComb
REAL(kind=C_DOUBLE), INTENT(IN) :: InpValue1
REAL(kind=C_DOUBLE), INTENT(IN) :: InpValue2
REAL(kind=C_DOUBLE), INTENT(IN) :: BarometricPressure

TYPE(c_ptr) :: CalcAirProperties
END FUNCTION

END INTERFACE
REAL :: TempDB_Test
REAL :: TempRH_Test
REAL :: BaroPressure

TempDB_Test = 308.15
TempRH_Test = 0.69
BaroPressure = 101.325

c_p = CalcAirProperties(2,TempDB_Test,TempRH_Test,BaroPressure)

CALL c_f_pointer(c_p,f_p,[7])

RHiC = f_p(3)
RhoAiC = f_p(7)
END ProgramMain
!********************[/code]

In the above set up the pointer returned by the c_p=CalcAirProperties() call is 0 and thus the values f_p is not pointing to the right array start.
So to remove all the problems with pointers I converted the C++ function to accept an array (by reference) so that I can set the desired array values inside the C++ function and thus pass the array back to FORTRAN. Here is what I did for that:

[code]// C++ Header
// ---------------
# include statements
#ifdef BUILD_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
// #define DLL_EXPORT __declspec(dllimport)
#endif

//#ifdef __cplusplus
extern "C"
{
void DLL_EXPORT __cdecl CalcAirProperties(int InputCombination, double Input1, double Input2, double Pressure,double PropertyArray[]);
}
// ---------------
//C++ source code
// ---------------
void DLL_EXPORT __cdecl CalcAirProperties(int InputCombination, double Input1, double Input2, double Pressure,double PropertyArray[])
{
double *AirProperties = new double[7];
//Do Calculations
for(int i =0;i<7;i++)
{
PropertyArray(i) = AirProperties(i);
}
}
// ---------------[/code]

Here is my FORTRAN code:
[code]!********************
PROGRAM ProgramMain
USE Statements
USE iso_c_binding, ONLY : c_ptr,c_double,c_f_pointer
IMPLICIT NONE
TYPE(c_ptr) :: c_p
REAL(c_double), POINTER :: f_p(:)
INTERFACE

SUBROUTINE CalcAirProperties(InputComb, InpValue1,InpValue2,BarometricPressure,PropertyArray) BIND(C,NAME='CalcAirProperties')

USE ISO_C_BINDING

INTEGER(kind=C_INT), INTENT(IN) :: InputComb
REAL(kind=C_DOUBLE), INTENT(IN) :: InpValue1
REAL(kind=C_DOUBLE), INTENT(IN) :: InpValue2
REAL(kind=C_DOUBLE), INTENT(IN) :: BarometricPressure

REAL(kind=C_DOUBLE), DIMENSION(7), INTENT(OUT) :: PropertyArray
END SUBROUTINE

END INTERFACE
REAL :: TempDB_Test
REAL :: TempRH_Test
REAL :: BaroPressure
REAL(kind=C_DOUBLE), DIMENSION(7) :: PropertyArray
TempDB_Test = 308.15
TempRH_Test = 0.69
BaroPressure = 101.325

CALL CalcAirProperties(2,TempDB_Test,TempRH_Test,BaroPressure,PropertyArray)

RHiC = PropertyArray(3)
RhoAiC = PropertyArray(7)

END ProgramMain
!********************[/code]
The above method also did not work. So I am kind of lost. I am still a newbie when it comes to mixed language programming.

I am using gcc with Code::Blocks to create the C++ dll and gfortran with Simply Fortran IDE to create the fortran exe.

I would appreciate any help in this regards.

Regards
SNKP
Sign In or Register to comment.