views:

48

answers:

2

I'm currently working on being able to import a DLL written in Fortran into Visual Basic. I've got all the basics down, so now I'm trying to take it a step further. The title basically says it all, but I'll explain what it is I'm trying to do anyways.

For kicks and giggles, let's just assume I want to pass an object that has three double values in it, possibly representing a point in space in three dimensions. In my Fortran method, I want to take that object, print out the x value, then change the x value to 7.5. Here's my Fortran code that does just that.

module test
   type Point
      double precision x, y, z
   end type Point
end module test

function ex1(ThreeDubs)
   use test
   type (Point) :: ThreeDubs
   print *, ThreeDubs%x
   ex1 = 1
   return
end function

And this code works great!...For structures only. In other words, Let's assume I have the following structure and class in VB

Public Structure StructurePoint
   Public x As Double
   Public y As Double
   Public z As Double
End Structure

Public Class ObjectPoint
    Public x As Double
    Public y As Double
    Public z As Double
End Class

Creating an instance of StructurePoint yields perfect results: the Fortran method prints out the x value, and then modifies the value of x. Perfect. Now the problem. When I pass an instance of ObjectPoint, the program prints out a value similar to 1.523E-306. Basically, telling me that the location in which it thinks the x value is located is not the x value. So, herein lies my question. Is it even possible to pass an Object to a Fortran DLL and access it correctly, and if so, how would I go about doing so?

The Solution

Modifying the Class declaration is the ONLY thing that has to be done in order to pass this object to Fortran.

<StructLayout(LayoutKind.Sequential)> _
Public Class CustomPoint3d
    Public x As Double
    Public y As Double
    Public z As Double
End Class

<DllImport("passPoint3d.dll")> _
Public Shared Function PrintX(ByVal point As CustomPoint3d) As Boolean
End Function
+1  A: 

I don't know about Visual Basic, but I've shared user-defined types between Fortran & C. This is supported by the ISO C Binding of Fortran 2003, which is already widely supported by Fortran 95 compilers. You declare a Fortran user-defined type and give it the bind C attribute and a bind name. As long as all of the sub-components of the type are inter-operable with C, then the user-defined type is also inter-operable with C. And this method is standard and portable. I've done this by passing the information with the Fortran user-defined type variable being a module variable, and the C structure variable being in global memory via being declared at the top of a file. Perhaps you can use the ISO C Binding on the Fortran side, and somehow tell Visual Basic to use a C-like interface?

M. S. B.
I think Andy's already got this working: Fortran user-defined type to and from Vb.Net structure, which is the equivalent data type in VB, similar to a C struct. But Andy wants to pass a VB.Net object into the Fortran.
MarkJ
+1  A: 

This might be difficult, and I don't think there's any benefit, so I advise you not to bother!

Here goes anyway! I think the VB.Net object will be marshalled as a pointer. There is some support for pointers in Fortran 90. It might work if you add pointer to the Fortran declaration of ThreeDubs.

function ex1(ThreeDubs) 
   use test 
   type (Point), pointer :: ThreeDubs ! Note additional pointer keyword
   print *, ThreeDubs%x 
   ex1 = 1 
   return 
end function 

I doubt you would ever be able to call methods in the ThreeDubs object from the Fortran, so I'm not sure of the benefit of passing an object.

Here are two articles on PInvoke: PInvoke is the .Net name for calling oldschool "unmanaged" DLLs like your Fortran. The articles explain how .Net arguments are "marshalled" (translated) into the Fortran DLL. You have some control over the marshalling using attributes: the articles explain more. They tend to use C and C# for examples :(

MarkJ
hmm, making the Point type in my code a pointer yields the exact same results. I'll spend a little bit looking at these links you put up. Thanks =)
AndyPerfect
OK here's another guess from another article http://msdn.microsoft.com/en-us/library/xedhyxyd(VS.71).aspx Keep the `pointer` in the Fortran, and in the VB.Net add this line `< StructLayout(LayoutKind.Sequential )> _` just before the VB.Net `Public Class ...` definition. You haven't posted your declare statement: it will need something like `Declare Function ex1 Lib "???.dll" ( <[In], Out> ByVal x As ObjectPoint ) As Integer` Or is `ex1` returning a double??
MarkJ
That did it my good sir! I'll update my code to reflect what the solution ended up looking like to pass an object to Fortran. Thanks a bunch.
AndyPerfect