Bringing in FORTRAN dlls using DLLimport

I'm having a problem getting some unmanaged code to link into a program I'm writing. I have some FORTRAN legacy code that I don't have the option of rewriting, and I need to link several pieces of it together, as well as create a GUI for it. I've created a wrapper class for it using a DLLimport statement and I keep running into the following error:

System.BadImageFormatException was unhandled
Message="An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)"
Source="FORTlib"

where FORTlib is my wrapper class. The code is attached, the mentioned dll is the dll named in the code, called "readFile.dll". Surprising I know. This is a very simple piece of code, I'm just simply trying to link the two right now before I go much further and deeper into what I'm trying to do with it.

Imports System

Imports System.IO

Imports System.Runtime.InteropServices

Friend Class fortranNativeMethods

'import fortran file reader dll

<DllImport("readFile.Dll")> Public Shared Function READFILE(ByVal fileName As String) As String

End Function

End Class

Public Class readWrapper

'wrapper method

Public Function readFile(ByVal fileName) As String

Return fortranNativeMethods.READFILE(fileName)

End Function

End Class



Answer this question

Bringing in FORTRAN dlls using DLLimport

  • RPagels

    There are basically two way to make your external dll reference in VB:

    http://msdn.microsoft.com/library/default.asp url=/library/en-us/vblr7/html/vastmDeclare.asp

    Declare Statement

    Used at module level to declare references to external procedures in a dynamic-link library (DLL).

    Remarks

    For Function procedures, the data type of the procedure determines the data type it returns. You can use an As clause following arglist to specify the return type of the function. Within arglist, you can use an As clause to specify the data type of any of the arguments passed to the procedure.

    Note   If the external procedure was created on a platform other than Visual Basic .NET, you must take care that the data types correspond. For example, if you declare a reference to a Visual Basic 6.0 procedure with an Integer argument (two bytes in Visual Basic 6.0), you must identify that argument as Short in the Declare statement, because that is the two-byte integer type in Visual Basic .NET.

    Example

    The following example declares a function that returns the current user name.

    Declare Function GetUserName Lib "advapi32.dll" Alias _
    "GetUserNameA" (ByVal lpBuffer As String, ByRef nSize As Integer) As Integer
    Function GetUser()
      Dim RetVal As Integer
      Dim UserName As String
      Dim Buffer As String
      Buffer = New String(CChar(" "), 25)
      RetVal = GetUserName(Buffer, 25)
      UserName = Strings.Left(Buffer, InStr(Buffer, Chr(0)) - 1)
      MsgBox(UserName)
    End Function

    The DllImport attribute provides an alternative way of using functions in unmanaged code. The following example declares an imported function without using a Declare statement.

    ' Add an Imports statement at the top of the class or module
    ' where the DllImport attribute will be used.
    Imports System.Runtime.InteropServices
    '...
    <DllImport("KERNEL32.DLL", EntryPoint:="MoveFileW", SetLastError:=True, _
    CharSet:=CharSet.Unicode, ExactSpelling:=True, _
    CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function _
    MoveFile(ByVal src As String, ByVal dst As String) As Boolean
      ' This function copies a file from the path src to the path dst.
      ' Leave function empty - DLLImport attribute forces calls 
      ' to MoveFile to be forwarded to MoveFileW in KERNEL32.DLL.
    End Function


  • ozakiweb

    This is just a WAG because I'm unfamiliar with Fortran data types, but...i'm betting it is an issue of how the string is being passed nad what fortran expects as a string...ie a null terminated string or a pointer to a string etc....in either case take a look at the marshal class which enables data type transformations for unmannaged code:

    Marshal Class:

    http://msdn.microsoft.com/library/default.asp url=/library/en-us/cpref/html/frlrfSystemRuntimeInteropServicesMarshalClassTopic.asp

    Marshal.StringToBSTR Method

    Marshal.StringToCoTaskMemAnsi Method

    Marshal.StringToHGlobalAuto Method

    Marshal.StringToHGlobalUni Method

    are just a few of the string conversion methods that may be of interest



  • Mike3983

    Ok new problem. I found the issue I was having before, but now the damn thing can't locate the entry point to the dll. I've tried using the standard entry point and defining the entry point and I keep getting the same error: Unable to find an entry point named 'READFILE' in 'readFile.dll' any suggestions
  • Anarchy

    FYI:

    I think you can change the calling convention by adding the following to your fortran subroutine:

    !DEC$ ATTRIBUTES C, ALIAS:'FooFunc_' :: FooFunc

    It depends on your particular compiler, but doing a quick search on the internet I've seen several examples from several vendors that use this syntax, so I think it will probably work for you.

    -Scott Wisniewski


  • Tyrael Tong

    Unless your FORTRAN compiler has specific support for COM, you can't reference the fortran library via com. You would have to writer a wrapper dll in another language that supports the pascal calling convention, such as C++.

    Did you check to see if your FORTRAN compiler supports changing the calling convention

    That would probably be the easiest way to get things to work.

    -Scott


  • Koray Samsun

    It could be that, but I don't think so, I avoided the problem of null terminated strings by just over extending the character variables on the recieving end on fortran. ie: the variable that accepts the input filename is 200 chars long when it shouldn't ever be that long. I will check that to make sure but the other reason I doubt that is that it doesn't seem to even get that far, it gets to the call of the function and stops before it makes the call. I think it is unhappy about the type of dll I have created. Does anyone know if there is anything special I have to do in compiling the FORTRAN dll to make it available to DLLimport
  • PhilipDaniels

    Also, did you use the "ALIAS" stuff when defining the entry point in fortran

    If so, try either a) removing it, or b) using the aliased name (i.e. readfile_) in the VB file.

    -Scott

  • Zapp

    Also, you may want to add this:

    !dec$ attributes dllexport :: FooFunc


  • Kumar Venkat

    This may be caused because FORTRAN uses a differnt calling covention (a protocol for manipulating the stack and registers) than C does, and the VB declare statement is desgined to allow you to call into functions that conform to the C calling convention (like the WIN32 api).

    Does your fortran compiler have any syntax that enables you to specify calling conventions If so, I would try recompiling the function specifying the C calling convention.

    If that doesn't work or is not an option, you could write a wrapper dll in C++ that access the fortran dll using the __pascall calling convention(something like extern void __pascall MyCoolFunction() ) and then expose the methods in one of three ways:

    1) Via a c wrapper function
    2) Via managed C++
    3) Via COM

    If this option is not attractive, I beleive this company: http://www.lahey.com/lf71/lfnet.htm#compiler
    as a fortran compiler that targets the CLR. You may be able to use their tool to recompile the app as a managed dll which you could then add directly as a reference to your VB project.

    Hope this helps!

    -Scott Wisniewski
    MS VB Compiler Dev


  • EmekaAwagu

    What was the fix for the previous issue

    Also, did you add the dll export declaration to the fortran function
    If not, try adding it.




  • Eric van Feggelen

    Ok but how do I reference the dll as a com library I've tried doing that already and its quite been disagreeable about cooperating
  • Bringing in FORTRAN dlls using DLLimport