C dll called from Fortran dll called from VB

C dll called from Fortran dll called from VB

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

7 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

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.

Retired 12/31/2016

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.

Retired 12/31/2016

I'll need to study that a bit.

Thanks Steve

>>...I have successfully called a C routine in a dll from Fortran and a Fortran routine in a dll called from VB many times...

Hi Mike,

I wonder if you will be able to upload small Visual Studio project? I think it iwll be a very valuable contribution on the Fortran forum!

Yes, I'll build one and post it Sergey

Leave a Comment

Please sign in to add a comment. Not a member? Join today