Topic: Calling fortran dll from Visual Basic.net (VS 2019)

OK, it is 2022 and I am trying to relearn how to interface fortran dynamic link libraries with visual basic.net (relearn as I used to be able to do this, but it was decades ago). The overall objective is to send an integer to the function in the fortran dll, add 1 to it and return the value (and of course the real objective is to figure out how to get VB.NET to play nicely with a fortran dll).

So I have a fortran dll that complies with no errors or warnings; here is the source code:

      Function dllinteger(i) bind(c)
     
      use ISO_C_BINDING
     
      implicit none

cGCC$ ATTRIBUTES STDCALL, DLLEXPORT :: dllinteger

      integer(kind=c_int)::dllinteger  !must declare the function type
      integer(kind=c_int), value::i     !declare integer

      dllinteger=i+1                          !increment i by 1
           
      end function dllinteger


Note that the Microsoft specific complier flags mentioned in the Simply Fortran blog about creating fortran dlls that work with Microsoft compilers were used when compiling.


Now here is the VB.NET code (under Visual Studio 2019):


Public Class Form1

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles btnCallDLL.Click

        Dim n As Int16                              'input integer
        Dim response As Int16                   'response from dllinteger function

        n = CInt(txtInteger.Text)                'convert integer in text format to an integer

        response = dllinteger(n)                 'response = value returned by dllinteger function

        lblResult.Text = CStr(response)       'convert response integer to text and display in a label

    End Sub

    Private Function dllinteger(n As Short) As Short

        Return dllinteger

    End Function
End Class


So Form1 has a textbox that accepts an integer, converts it from  text to integer, calls the function and then converts the response to text and shows the result in a label.  Note that the fortran-library.dll has been added to the VB solution by adding via Solution > Add > Existing item.  Likewise the 'dllinteger' function is also specifically noted in the solution file.  It compiles with no errors or warnings.

When you run the VB solution, you can enter an integer, hit the button, but the value of 'response' is always zero. But, no runtime errors are noted.

Any input appreciated, particularly if it turns out I made a dumb mistake (or more).  I will note that the blog post on creating a fortran dll to work with Microsoft compilers specifically noted the use of lib.exe to create a .lib file, but the details were somewhat lacking on exactly how to do this, and where/how the .lib was supposed to be stored/implemented.

Thanks.

Re: Calling fortran dll from Visual Basic.net (VS 2019)

First, I would highly suggest you work in 64-bit mode only with your DLL.  The attribute directing the compiler to export the function using the STDCALL calling convention is only necessary in 32-bit mode, and dealing with calling conventions is always frustrating.  In 64-bit mode on Windows, there is one and only one calling convention allowed, meaning you don't need to specify it to match what Microsoft expects. 

I think the problem is the inclusion of an actual function in your class called dllinteger.  I would say the correct declaration in VB.NET would be:

Declare Function dllinteger Lib "fortran-library.dll"  (Byval i As Integer) As Integer

In your code, I think the routine is actually calling your VB code and returning 0 rather than actually accessing the DLL at all.  I would try changing the code to:

Declare Function dllinteger Lib "fortran-library.dll"  (Byval i As Integer) As Integer

Public Class Form1

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles btnCallDLL.Click

        Dim n As Int16                              'input integer
        Dim response As Int16                   'response from dllinteger function

        n = CInt(txtInteger.Text)                'convert integer in text format to an integer

        response = dllinteger(n)                 'response = value returned by dllinteger function

        lblResult.Text = CStr(response)       'convert response integer to text and display in a label

    End Sub
End Class

I haven't tried the above, but it should work correctly.  Have a look at Microsoft's docs on the Declare statement, which is what you should be using to access the DLL function.

Jeff Armstrong
Approximatrix, LLC

3 (edited by Lewist57 2022-06-27 23:07:51)

Re: Calling fortran dll from Visual Basic.net (VS 2019)

Here's what it took to get the dll and its function working right:

1) Insert the following as first line; this is needed to use DllImport
Imports System.Runtime.InteropServices

2) Invoke DllImport to reference the DLL.  Note that the text enclosed with the brackets <  > are on the same line as the Private Shared Function; weird, but I guess this is some sort of compiler inline flag. Note that the corresponding End Function is NOT on the same line
<DllImport("C:\Users\lewis\source\repos\DLLTest1\bin\fortran-library.dll", CallingConvention:=CallingConvention.Cdecl)> Private Shared Function dllinteger(ByVal n As Short) As Short
    End Function

3) The Private Declare Function you listed is not needed for the interface to work (see comments below). DllImport is used instead of the Declare function.

4) I hard coded the location of the DLL into the code.  I am pretty sure that there is a way to specify its location without hard coding, but was just happy to get VB talking with the Fortran DLL.


Here is the updated VB.NET code, no changes were required to the Fortran source code. As per your suggestion, I did set the compiler flag to 64 bits, and added the -W1--output-def,fortran-library.def compiler flags.  I did not try to use the Visual Studio library manager (lib.exe) as per the original blog, and apparently it was not needed.  I did place the fortran-library.def file in the same folder as fortran-library.dll, but not sure if that was needed or not.


Imports System.Runtime.InteropServices
Public Class Form1

    <DllImport("C:\Users\lewis\source\repos\DLLTest1\bin\fortran-library.dll", CallingConvention:=CallingConvention.Cdecl)> Private Shared Function dllinteger(ByVal n As Short) As Short
    End Function


    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles btnCallDLL.Click

        Dim n As Int16
        Dim response As Int16

        n = CInt(txtInteger.Text)

        response = dllinteger(n)

        lblResult.Text = (response)

    End Sub


End Class


I got the DLL working with VB as a result of your input, a video on YouTube and the "DllImportAttribute Class" document on the Microsoft Docs site.  As a side note, although the use of Declare function may have worked, most references insist that DllImport is better for VB.net to talk with DLLs. 

The somewhat frustrating part is that there are not a lot of references in mid 2022 (YouTube videos, online documents, web pages, etc.) that are specifically for using VB.NET 2019 (or 2022) with a Fortran.dll.  A lot of them are how to interface a dll with VBA, VB 6, or VB.NET from 20 years ago. 

And, of course, this is just a start, as all I have accomplished is to send an integer from VB.net to a Fortran.dll and received the modified integer back. There are plenty of other variable types to work with, single and multiple dimension arrays, text, etc. to work with. But in any case, thanks for your help, and perhaps I can eventually provide a unfiled source of "how to" get Fortran to play nicely with VB.net.

Re: Calling fortran dll from Visual Basic.net (VS 2019)

Interfacing a DLL can be frustrating, and a lot of the complication is because the languages (VB.NET and Fortran) are so disparate.  In addition, VB.NET runs inside a managed runtime (not "natively" like Fortran), making some of the syntax that much less pleasant.

Passing more complicated data will be harder.  The iso_c_binding module does help a lot with this.  However, I will warn you that arrays in Fortran are drastically different than other languages.  I would suggest treating, in Fortran, foreign arrays simply as type(c_ptr) and using Fortran's C_F_POINTER intrinsic to convert these pointers to something Fortran actually understands.

Additionally, C, which is the common pass-through standard that all these languages are relying upon for interoperability, technically has no concept of "multidimensional arrays."  C arrays that appear to be multidimensional are actually just an array of pointers.  Furthermore, the order which these arrays of pointers are addressed in C (row-major) is different from Fortran (column-major).  I would highly suggest passing info around as a single-dimension array for your own sanity.

And then there are strings...

Jeff Armstrong
Approximatrix, LLC

5 (edited by Lewist57 2022-06-28 17:32:21)

Re: Calling fortran dll from Visual Basic.net (VS 2019)

Oh yes, cognizant of the array order, strings (and don't forget complex numbers) and other issues.  But we will see how far I  can take things.