Create Fortran DLL for .NET

August 24, 2010 12:00

In my last post, I discussed how it is that you could import a DLL written in C++ into a VB.NET application and execute all the subroutines and methods normally. Since then, the need has arisen for me to take all of this library-writing and low-level code a step further and get just about as close to machine code as possible without writing actual Assembly. And, following some research, it appears that getting the best results out of math-intensive code means working with Fortran. Now now, I'm sure there are equally viable possiblities out there besides Fortran, but that's what I've decided on, and that's what I'm going to be sticking to. And on a side note, for all you sticklers out there, Fortran used to be written in all capitals like you're thinking. That was, until Fortran90 was released. Every release beyond that has used regular capitalization. So that's not me being ignorant =)

The tools I've chosen to utilize for this little project will be G95, the open source Fortran comiler, and Visual Studio 2010 to create the Visual Basic project. The express edition of Visual Studio is completely free, so using these tools should not limit anyone in following along in all the steps I outline. When I started out on this project for myself, I had absolutely zero knowledge of Fortran, so I'm going to assume the reader has limited knowledge as well. It's a tricky process learning a language and creating DLL files at the same time.

So to begin, make sure you download the G95 installer from the G95 project website. After installing, make sure it installed correctly by typing in "g95" without the quotes at the command prompt. It should send back the string "g95: no input files". If it responds telling you g95 is not recognized, you have not yet installed g95, or the installer did not run correctly.

So, onto our first file in Fortran. Open up some kind of text editor that does not allow rich text formatting. Notepad is the most basic, but I myself prefer Notepad++. Interestingly enough, when writing Fortran files to be exported as a DLL, there are absolutely zero special constructions or keywords that we need to learn to be able to do so. We will only write the functions and subroutines to be exported. There will be no main body, or anything of that nature in the file. So, let's begin with a very basic example of a function in Fortran, and I'll explain a little bit of what's happening in each part.

function ex1(i) 
    integer*4 :: ex1, i
	ex1=i+1
	return 
end function
So, let's examine this small method part by part. The function keyword should be familiar, it tells the compiler that this method will have some kind of value returned from it. If we preferred instead that the method returned no value, we would instead use the word "subroutine". ex1 will be the name of the method, and also the name of the variable that this function will be returning. This may be a bit of a change for you if you are unfamiliar with Fortran. This is why at the end of the function, we see simply a "return" statement without a variable specified to return. The function will simply return the value of the variable with the same name as the function. In this case, we specified the value of ex1 the line beforehand, so it should be clear what it is the function is returning.

Continuing the examination of the method, we'll notice that the types of the parameters are not specified in the signature. Rather, we define what it is at the beginning of the function. In the first line of the function body, we'll see these variables declared. ex1 and i are both being defined as 4-byte integers. i need not be assigned a value because in its case, we are simply specifying that the input parameter is in fact a 4-byte integer. It's value was defined when the method was called. Remember that since ex1 is the name of the function, ex1 in this line is the value the function will return at the end. Thus, we're stating that this function will be returning a 4-byte integer. The rest of the function should be easy enough to understand.

Something interesting to note that in Fortran, all local variables must be declared at the beginning of the function. If you do otherwise, the compiler will indeed give you errors.

This will be the entire structure of our fortran file. Save it as test.f95. Now, onto our definitions file. A definition file will tell the compiler how external programs will see the methods, which methods they'll see, and how they'll be named. Something crucial is that all of your methods in the file you'll be exporing as a DLL MUST be limited in the number of characters they have. If they have more than six characters, they will indeed be modified by the compiler, and the definitions file will not be able to access them. Instead, keep the names simple, and use the definition file to choose the names you'd like to have your external program use to access your methods.

Use a similar editor that does not utilize rich text formatting to create your .def file. In our case, the .def file will be quite simple.
EXPORTS	   sweetFunction = ex1_
Note the use of the underscore. The left side of the equals sign tells us the name external programs will see as the name of this method. The right side tells us what method we are referencing. If we wanted instead to maintain the same name for our external program, we would instead use:
EXPORTS	   ex1 = ex1_
And that is all we will be putting in our small file. Save it is test.def.

Now for some useful commands to create our DLL. First, we want to create something called an object file from our source code. Open up the command prompt, and navigate to the directory where the .f95 and .def files are. Type the following command in:

g95 -c test.f95

This will create your object file, if there are no errors of course, which there shouldn't be. Now, you'll want to link the source code, the object file, and the definition file together to ultimately create your .dll. Still in the same directory, use this command:

g95 -s -shared -mrtd -o test.dll test.def test.o

this command will link the object file test.o with the definition file test.def and create a dll called test.dll. That's all there is to it! We now have a DLL written in Fortran ready to be used by any .NET language. If you need any details on how to get that done, please refer to my previous post regarding a C++ DLL. You'll end up following the exact same set of instructions. Good luck!

Got something to say? Tell me!

Name*

Homepage

Comment*



Feb.12.2011
12:06

Doug

Great article


Feb.12.2011
12:12

Doug

I do have one question here. I followed your instruction to create the Fortran DLL, but when I try to access it via MS VB Express 2010, I get this error:
"A first chance exception of type 'System.AccessViolationException' occurred in FortranTesting.exe".

My function is called "ex1", the DLL is called "ftest.dll" and my VB code is as shown:

Imports System
Imports System.Runtime.InteropServices
Public Class Form1
_
Public Shared Function ex1(ByVal number As Integer) As Integer
End Function

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim testnum As Integer
testnum = 5

Dim test As Integer = ex1(testnum)
MsgBox("Finished!")
End Sub
End Class


....Any ideas where I'm going wrong?


Feb.12.2011
12:12

Doug

I do have one question here. I followed your instruction to create the Fortran DLL, but when I try to access it via MS VB Express 2010, I get this error:
"A first chance exception of type 'System.AccessViolationException' occurred in FortranTesting.exe".

My function is called "ex1", the DLL is called "ftest.dll" and my VB code is as shown:

Imports System
Imports System.Runtime.InteropServices
Public Class Form1
_
Public Shared Function ex1(ByVal number As Integer) As Integer
End Function

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim testnum As Integer
testnum = 5

Dim test As Integer = ex1(testnum)
MsgBox("Finished!")
End Sub
End Class


....Any ideas where I'm going wrong?


Feb.12.2011
12:16

Doug

...Sorry for the multiple posts...got trigger happy with the mouse button apparently :)...Also, my code didn't post properly. The correct version is here:

Imports System
Imports System.Runtime.InteropServices

Public Class Form1
_
Public Shared Function ex1(ByVal number As Integer) As Integer
End Function

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim testnum As Integer
testnum = 5

Dim test As Integer = ex1(testnum)
MsgBox("Finished!")
End Sub
End Class

...any help is much appreciated!


Feb.12.2011
13:30

Doug

Fixed the problem...needed to pass variable from VB "ByRef", not "ByVal"...


Jul.28.2011
21:15

oro77

It was really helpful.

For an VBA/Excel Fortran DLL, I used the following command to create the DLL file :
g95 -s -shared -mrtd -o test.dll test.def test.o


Dec.26.2013
23:42

Manu

I am getting the ' Attempted to read or write protected memory. This is often an indication that other memory is corrupt. ' error in my c# application while calling the ex1(p).
Can you please tell me how to call this function