Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

fortran calling a cpp dll

David_Mccabe
Beginner
900 Views

Hi, I am writing a Fortran 2003 program which will make calls to a C++ dynamic link library. An initial call to the .dll seems to work fine however, consecutive calls return unexpected results.

My dll is composed of the files util_lib.cpp a header file util_lib.h


Heres the util_lib.cpp, the routine readLongInt should simply print a long int:

[cpp]#include 
#include "util_library.h"

extern "C"
{
  UTIL_API void CALLING readLongInt(long a)
  {
	std::cout<<"Here is a long int: "<<<"\n"<<:ENDL>


Here is the associated header file util_lib.h:

[cpp]#pragma once

#ifdef UTIL_EXPORTS
#define UTIL_API __declspec(dllexport)
#else
#define UTIL_API __declspec(dllimport)
#endif

#define CALLING __stdcall

extern "C"
{
  UTIL_API void CALLING readLongInt(long);
}
[/cpp]


Here is the Fortran program which calls readLongInt 3 times in succession:

[...



0 Kudos
1 Solution
Steven_L_Intel1
Employee
900 Views
Here is the smoking gun:

!DEC$ATTRIBUTESALIAS:'_readLongInt@4'::read_long

Any time you explicitly put @n in an alias, in an attempt to solve linking issues, you're just creating trouble. The reason is that the @n suffix denotes a STDCALL convention routine, and if you don't tell Fortran you're calling a STDCALL routine, you get stack corruption as the stack gets popped twice on every call.

In the C++ code, you have the define for CALLING specifying STDCALL.

The solution is to replace that directive with this:

!DEC$ATTRIBUTES STDCALL, DECORATE, ALIAS:'readLongInt'::read_long

You can remove the ATTRIBUTES VALUE directive, since STDCALL implies that, or leave it in.

An alternative is to remove the __stdcall from the #define and use this interface instead:

[fortran] subroutine read_long(a) bind(C,NAME="readLongInt")
  use iso_c_binding  
  integer(c_int),value :: a  
 end subroutine read_long  [/fortran]

View solution in original post

0 Kudos
4 Replies
Steven_L_Intel1
Employee
901 Views
Here is the smoking gun:

!DEC$ATTRIBUTESALIAS:'_readLongInt@4'::read_long

Any time you explicitly put @n in an alias, in an attempt to solve linking issues, you're just creating trouble. The reason is that the @n suffix denotes a STDCALL convention routine, and if you don't tell Fortran you're calling a STDCALL routine, you get stack corruption as the stack gets popped twice on every call.

In the C++ code, you have the define for CALLING specifying STDCALL.

The solution is to replace that directive with this:

!DEC$ATTRIBUTES STDCALL, DECORATE, ALIAS:'readLongInt'::read_long

You can remove the ATTRIBUTES VALUE directive, since STDCALL implies that, or leave it in.

An alternative is to remove the __stdcall from the #define and use this interface instead:

[fortran] subroutine read_long(a) bind(C,NAME="readLongInt")
  use iso_c_binding  
  integer(c_int),value :: a  
 end subroutine read_long  [/fortran]

0 Kudos
IanH
Honored Contributor III
900 Views
While you are fixing up that interface change C_INT to C_LONG to avoid future confusion/problems.
0 Kudos
David_Mccabe
Beginner
900 Views
Problem solved, thanks!

so the lesson is, decoration in the alias is incompatablewith C or STDCALL attribute.

@IanH

thanks for spotting that, I will change it right away. One of my other cpp dlls uses an unsigned int argument, I was going to pass itinteger*4, but perhaps I should rethink?
0 Kudos
Steven_L_Intel1
Employee
900 Views
The @n decoration is specific to STDCALL. If you had specified STDCALL in the Fortran, it would have worked. I suggested using the DECORATE attribute to let the compiler worry about the decoration, but I think the better solution is to remove the STDCALL on the C++ side.
0 Kudos
Reply