Click here to Skip to main content
15,884,298 members
Please Sign up or sign in to vote.
4.00/5 (5 votes)
See more:
Hello guys,

I'm allways searching stuff around here, and almost all the time I find what I need.
But right know I need something a little more specific and I can't find it on google neither here.

I have a big code on FORTRAN 77. With a bunch of subroutines and functions.
And I want to re-use that code in this new C# app, that I'm programming, I would like to make those functions and subroutines avaliable on a class or something like that.

As I've seen on the web and seams that the right way is making a DLL with the code and using it in Visual Studio.

But I can't do that, I already tried Lahey-Fujitsu Fortran, WATCOM and Silverfrost.

With Lahey and WATCOM I can make the dll but VS2008 won't accept it as a reference.
It says: "Please make sure that the file is accessible, and that it is a valid assembly or COM component"

With silverfrost I can reference the DLL but.. when I run the code ( at runtime ) it says that the VS couldn't couldnt find any exports on the DLL.

I have no idea of what to do know. Can anyone post a exemple here or show me how to do that please?

I would be very gratefull. :-)


Thanks,

Lucas
Posted
Updated 8-Dec-19 19:50pm
Comments
Sergey Alexandrovich Kryukov 8-Nov-12 14:34pm    
Even if you could do something like that, it could not be called "converting" -- things are way too different...
--SA

Hello there folks! :)

After non-stopping researches I just made an simple example work out. And now I think I can expand that to my hole project!

The way to go is by using OPEN WATCOM FORTRAN ( whitch is free, dowload it here: http://www.openwatcom.org/index.php/Main_Page[^] and I used VS2010 but I think it doesn't matter.

I will show you guys how to do it!

Intro:

I going to create a subroutine in FORTRAN77 that takes 3 doubles as parameters 1 as a value and other 2 as references, I will call it DON.

DON( double1, double2, double 3 )

This subroutine is gonna be called from a C# code and its supossed to return (double1+1) and ( double1+2 ).

So.. here is the FORTRAN code:

*$pragma aux DON "DON" export parm(value*8, reference, reference)


SUBROUTINE DON(DAA,DBB,DCC)
REAL*8, DAA,DBB,DCC
DBB=DAA+1
DCC=DBB+1
RETURN
END


* Important stuff about the code is the first line! The one that starts with *$pragma ..yes! that line! It is used by the OPEN WATCOM COMPILER, is a directive used to indicate that the DLL receive a double as value, and other 2 references

* Dont forget that your FORTRAN code must have the right indentation. ( right number of spaces, I think is 6 )

Then create a DLL project in WATCOMP, and add that code as source. Use the default make and link settings.

Build and you will have created the DLL, put it in the same folder as your .exe (Don't try adding it in your project with "add reference" from References because it is not gonna work.)

Now the C# code:

I will post my hole class code:

C#
public unsafe class Program
    {

        [DllImport("Lks.dll",
            CharSet = CharSet.Auto,
            CallingConvention = CallingConvention.StdCall)]
        public static extern void DON(
            [MarshalAs(UnmanagedType.R8)] double DAA,
            [MarshalAs(UnmanagedType.R8)] ref double DBB,
            [MarshalAs(UnmanagedType.R8)] ref double DCC
            );

        static unsafe void Main(string[] args)
        {
            //double TIME = 100.0;
            double DAA = 5.5;
            double DBB = 7;
            double DCC = 9;
            //START( ENERIN, VAL1);
            DON(DAA,ref DBB, ref DCC);

            Console.Write("val1 = " + DAA);
            Console.Write("val2 = " + DCC);
            Debug.WriteLine("VAR = " + DBB.ToString());
            Console.Write("Press any key to exit");
            Console.ReadKey(false);
        }
    }


It's going to as for Systme.Runtime.InteropServices, just add that in the top.

Run the code and you will get:

val1 = 5,5val2 = 7,5Press any key to exit

Which means all went well DAA = 5,5 and DCC now equals to 7,5.

Thanks guys! And don't give up.

Lucas
 
Share this answer
 
Listen to a good friendly advice: don't waste you time finding a way to automatically "translate" the code. FORTRAN is just archaeology (no matter what people using it would say). Better properly learn .NET and C#, sit down and write the code in C#, using FORTRAN code only as a reference.

—SA
 
Share this answer
 
v2
Comments
Lucas Martins de Souza 8-Nov-12 14:52pm    
I just want to do something like this guy done.

http://www.codeproject.com/Articles/1696/Fortran-for-Microsoft-NET

I think it's possible and will save me a lot of time.
Sergey Alexandrovich Kryukov 8-Nov-12 17:06pm    
Well, what stops you from using the results of this guy? Interesting, but I would not overestimate the use of it...
--SA
Lucas Martins de Souza 9-Nov-12 9:40am    
I could not make it work. Everthing he mentioned in his article is outdated,I could not find the LaheyFortranPreview1 which I think, is the key point for the whole "magic".
I was looking for other solutions like this one here:
http://coding.derkeiler.com/Archive/Fortran/comp.lang.fortran/2007-08/msg00015.html
That uses OpenWatcom but could not make it work neither.
The closeiest I got was using SilverFrost ( http://www.silverfrost.com/52/ftn95/ftn95_express.aspx) to make a DLL and trying a simple program like this one ( http://stackoverflow.com/questions/10317691/making-fortran-dll-and-calling-it-from-c-sharp)

But the VS2008 says that my DLL has no exports. Seams like a job for a hardcore programmer, that knows a lot about windows DLL and Fortran, not quiet sure if I'm gonna make it.
Sergey Alexandrovich Kryukov 9-Nov-12 11:35am    
Honestly, follow my advice. This is a myth that re-use of old code is good. When you write the code by yourself and use the legacy one only as a reference, you do not reproduce old bugs; and the new ones you can debug easier because your experience is fresh... using the automated "translation" can be just frustration and waste of time.

If you feel convinced, please indicate it by accepting my answer formally (green button) -- thanks. :-)
--SA
Lucas Martins de Souza 9-Nov-12 15:10pm    
I have a few days more to keep trying new stuff out, and if I find something new and interesting I will post here to help others ;-) Thanks for your time anyways!
PROGRAM VLM
use MSIMSL
IMPLICIT NONE
REAL*8,allocatable   ::  XB(:),A(:,:),BL(:),SOLV(:),PHI(:),PHIW(:),PHIOLD(:)
REAL*8,allocatable   ::  CF(:)
INTEGER               ::  I,J,NW,NB,IT
REAL*8      ::  UINF,ALPHA,PI,DT,CL,AINF,DX,TIME,T,T0,MACH,SUM1

   
   OPEN (6,FILE="CLT.DAT")
   OPEN (4,FILE="CIRCUL.DAT")

   PI = Dacos(-1.0D0)
   
   ALPHA = 2.0D0 * PI / 180.0d0 
   DX   = 0.01D0 
   MACH = 0.000001D0
!   AINF = 300.0d0
!   UINF = MACH * AINF
   UINF = 1.0D0
   AINF = UINF / MACH
   DT = 0.01d0  !1.5D0 / ( 1.0d0/MACH+1.0d0)
   TIME = 10.0D0
   NW = TIME / DT
   NB = 1.0D0 / DX + 1
   ALLOCATE(XB(NB),A(NB,NB),BL(NB),SOLV(NB),PHI(NB),PHIOLD(NB),PHIW(NW),CF(NB-1))
   
   CALL READMESH (NB,DX,XB)
  
   PHI = 0.0D0 ; PHIW = 0.0D0 ;  PHIOLD =0.0D0

SUM1 = 0.0D0 
 
DO IT = 1 , TIME/DT
     T= IT * DT
     T0 = 0.0D0
     PHIW(IT) = PHI(NB)
	 PHIOLD = PHI

     CALL COEFF_MATRIX (DT,T,T0,UINF,AINF,NB,XB,A)
	 CALL RHS_VECTOR (NB,NW,IT,SUM1,XB,PHIW,ALPHA,UINF,AINF,DT,T,T0,BL)

     CALL DLSARG (NB, A, NB, BL, 1, SOLV)
     
	 DO I = 1 , NB
       PHI(I) = SOLV(I)
	 END DO
	 
	 CALL PRESS(DX,DT,UINF,NB,PHI,PHIOLD,CF,CL)
     
	 WRITE(6,*)IT*DT , CL/(2.0d0*PI*alpha)
     WRITE(*,*)IT*DT , CL/(2.0d0*PI*alpha)
    
END DO  ! TIME
   
     DO I = NB-1 , 1 ,-1
            WRITE(4,102)XB(I) , PHI(I)
	 END DO

102 Format (1x,10(1x,f14.5))
STOP
END
!-----------------------------------------------------------------------------------------
!-------------------------------- SUBROUTINES --------------------------------------------
!-----------------------------------------------------------------------------------------
SUBROUTINE PRESS(DX,DT,UINF,NB,PHI,PHIOLD,CF,CL)
   Implicit NONE
   INTEGER,INTENT(IN)  :: NB
   REAL*8,INTENT(IN)   :: PHI(NB),PHIOLD(NB),DT,UINF,DX
   REAL*8,INTENT(OUT)  :: CF(NB-1),CL
   REAL*8              :: SUM
   INTEGER             :: I,J
   CF = 0.0D0
   DO I = 1 , NB-1
	 SUM = 0.0D0
	 DO J = 1 , I
	    SUM = SUM + (PHI(J) - PHIOLD(J) )
     END DO 
      CF(I) = 1.0D0 * UINF *  PHI(I) + 1.0D0 / DT  * SUM * DX 
   END DO

   CL = 0.0D0
   DO I = 1 , NB-1
     CL = CL + CF(i) / (0.5 * 1.0D0 * UINF**2 * 1.0D0)
   END DO
END SUBROUTINE PRESS 

SUBROUTINE RHS_VECTOR (NB,NW,IT,SUM1,XB,PHIW,ALPHA,UINF,AINF,DT,T,T0,BL)
   Implicit NONE
   INTEGER,INTENT(IN) :: NB,NW,IT
   REAL*8,INTENT(IN)  :: XB(NB),PHIW(NW),ALPHA,UINF,AINF,DT,T,T0
   REAL*8,INTENT(INOUT) :: SUM1
   REAL*8,INTENT(OUT) :: BL(NB)
   REAL*8             :: X,PI,PI2,DX,DTL,SUM2
   INTEGER::I,J,K
   PI = Dacos(-1.0D0)
   PI2 = 2.0D0*PI
   

     SUM1 = SUM1 + PHIW(IT)  
     BL(NB) = -SUM1    

     Do I = 1 , NB-1            ! loop over collocation points , X0 : Collocation Point
   	   X = ( 3.0D0*XB(I) + 1.0D0*XB(I+1) ) / 4.0D0 
	   SUM2 = 0.0D0
	   DO J = 1 , IT
         DTL = (IT+2-J) * DT  	     
	     DX = X - (1.0D0 + UINF * DTL)  
!	 if ((AINF * DTL)**2 - DX**2 .lt. 0.0d0) then 
!	  write(*,*)'pause3'
!	  write(*,*)t ,i ,j , x ,  1.0D0 + UINF * DT 
!	  end if
         SUM2 = SUM2 - PHIW(J) / (PI2 * AINF * DTL * DX)  * DSQRT ( (AINF * DTL)**2 - DX**2)
!	     SUM2 = SUM2 - PHIW(J) / (PI2 * DX) 
       END DO 
     BL(I) = -UINF * alpha - SUM2
	 END DO
END SUBROUTINE RHS_VECTOR
						
SUBROUTINE COEFF_MATRIX (DT,T,T0,UINF,AINF,NB,XB,A)
   Implicit NONE
   INTEGER,INTENT(IN) :: NB
   REAL*8,INTENT(IN)  :: XB(NB),DT,T,T0,UINF,AINF
   REAL*8,INTENT(OUT) :: A(NB,NB)
   REAL*8             :: X,X0,G,PI,PI2,DX,DTL
   INTEGER::I,J,K
   PI = Dacos(-1.0D0)
   PI2 = 2.0D0*PI
   DTL = T - T
   A=0.0D0
   
   Do I=1,NB-1            ! loop over collocation points , X : Collocation Point
   	  X = ( 3.0D0*XB(I) + 1.0D0*XB(I+1) ) / 4.0D0
	  Do J=1,NB-1         ! loop over ELEMENTS OF AIRFOIL (B)
    	 X0 = ( 1.0D0*XB(J) + 3.0D0*XB(J+1)) / 4.0D0
		 DX = X - X0
!	  if ((AINF*DT)**2 - (DX-UINF*DT)**2 .lt. 0.0d0) then 
!	  write(*,*)'pause1'
!	  write(*,*) i , j , x ,  DX , (AINF*DT)**2 - (DX-UINF*DT)**2
!	  end if
         G  =  -1.0D0 / (PI2 * AINF *DX * DT)  * DSQRT ((AINF*DT)**2 - (DX-UINF*DT)**2) 
   		 A(I,J) = G
      END DO  ! J
  
      DX = X - ( 1.0D0 + UINF * DT )
!	  if ((AINF * DT)**2 - DX**2 .lt. 0.0d0) then 
!	  write(*,*)'pause2'
!	  write(*,*)t ,i , x ,  (AINF * DT)**2 , DX**2
!	  end if
      G  =  -1.0D0/(PI2 * AINF * DT * DX) * DSQRT ((AINF*DT)**2 - DX **2)
!      G  =  -1.0D0/(PI2 * DX) 
 	  A(I,NB) = G
   END DO     ! I
   A(NB,:) = 1.0D0
END SUBROUTINE COEFF_MATRIX


SUBROUTINE READMESH (NB,DX,XB)
   Implicit NONE
   INTEGER,INTENT(IN):: NB
   REAL*8 , INTENT (IN):: DX
   REAL*8 , INTENT (OUT):: XB(NB)
   INTEGER::I,J
   DO I = 1 , NB
	 XB(I) = 1.0D0 - (I-1)*DX
   END DO	 	 
END SUBROUTINE READMESH
 
Share this answer
 
v2
Comments
CHill60 31-Aug-13 14:11pm    
Is this supposed to be solution to this year old question?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900