Silverfrost Forums

Welcome to our forums

Exporting and calling procedures from a Fortran DLL

20 May 2009 6:40 #4628

I am compiling a large legacy FORTRAN code into a Visual Studio .net 2005 DLL (Framework 2). I marked the function needed in the Visual Basic main program as Assembly_Interface(name='xyz'). This directive should create the necessary interface between FORTRAN and say VB. Nevertheless, I got the error number 1148, 'not of assumed shape and so cannot appear as an argument to a routine containing an Assembly_Interface' for each array used as parameter of the subroutine. What is the right shape? (On the other hand, I cannot change the shape of arrays in the FORTRAN legacy code). I build the DLL ignoring error 1148. As a result I got the run time error 'Unable to find an entry point called 'xyz' in DLL …' by calling the function 'xyz'. I used dumpbin.exe to check the DLL: nothing is exported and this is the problem: what can I do? (Options like /exportall work only on Win32, not on .net platform.) I also wrote a simple function without array parameters, so I didn't get any error using the Assembly_Interface, but even in this case the function is not exported. I used Silverfrost Version 5.10 and then Version 5.30 with the same result.

4 Aug 2012 2:24 #10556

.NET will not pass/receive fixed size arrays, only assumed size arrays, so in your legacy code, change every declaration of array(number[,number]) to array(:[,:]) and you should be ok

4 Aug 2012 6:39 (Edited: 4 Aug 2012 6:52) #10557

I found a way of using fixed size arrays. I would not recommend it because involves the use of pointers, but it is possible.

Imagine you have this subroutine in fortran:

subroutine Example(A,B)
implicit none

double precision, intent(in ):: A(3,3)
double precision, intent(out):: B(3,3)

B(:, 1) = A(:,2)
B(:, 2) = A(:,1)
B(:, 3) = A(:,3)

endsubroutine

And you want to use it in c# (Sorry I dont have vb.net)

You would add a console application project to the solution and write this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        unsafe static void Main(string[] args)
        {
            Double[,] A = new Double[3, 3] {
                {1.0,1.0,1.0},
                {2.0,2.0,2.0},
                {3.0,3.0,3.0},
            };
            Double[,] B = new Double[3, 3];

            fixed (double* ap = &A[0, 0])
            {
                fixed (double* bp = &B[0, 0])
                {
                    FortranApplicationExtension1.EXAMPLE(ap, bp);
                }
            }


            Console.WriteLine('A:');
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    Console.Write(A[i, j]);
                    Console.Write(' ');
                }
                Console.WriteLine();
            }

            Console.WriteLine('B:');
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    Console.Write(B[i, j]);
                    Console.Write(' ');
                }
                Console.WriteLine();
            }

            Console.ReadLine();
        }
    }
}

this is the output in my machine

A:
1 1 1
2 2 2
3 3 3
B:
2 2 2
1 1 1
3 3 3

Ftn needs a pointer to the first element in the arrays. you do that in C# with the fixed statement

http://msdn.microsoft.com/en-us/library/f58wzh21.aspx

No assembly_interface needed, but you do need to change the c# project properties to allow unsafe code.

This is partly hinted in the ftn documentation:

args) { Double[,] A = new Double[3, 3] { {1.0,1.0,1.0}, {2.0,2.0,2.0}, {3.0,3.0,3.0}, }; Double[,] B = new Double[3, 3];

            fixed (double* ap = &A[0, 0])
            {
                fixed (double* bp = &B[0, 0])
                {
                    FortranApplicationExtension1.EXAMPLE(ap, bp);
                }
            }


            Console.WriteLine('A:');
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    Console.Write(A[i, j]);
                    Console.Write(' ');
                }
                Console.WriteLine();
            }

            Console.WriteLine('B:');
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    Console.Write(B[i, j]);
                    Console.Write(' ');
                }
                Console.WriteLine();
            }

            Console.ReadLine();
        }
    }
}

this is the output in my machine

A:
1 1 1
2 2 2
3 3 3
B:
2 2 2
1 1 1
3 3 3

Ftn needs a pointer to the first element in the arrays. you do that in C# with the fixed statement

http://msdn.microsoft.com/en-us/library/f58wzh21.aspx

No assembly_interface needed, but you do need to change the c# project properties to allow unsafe code.

This is partly hinted in the ftn documentation:

[quote:2e33834529]The use of an ASSEMBLY_INTERFACE is not necessary when all of the arguments are scalar INTEGERs or REALs. However, the call (from C# say) must stipulate that all of the arguments are passed as 'unsafe' pointer types (using 'fixed' if necessary) and the name of the routine (in C#) must not use lower case letters.

http://www.silverfrost.com/ftn95-help/netprog/callingfortranfromother.aspx

It seems that the fixed statement is not present in VB.Net, see discussion in msdn

http://social.msdn.microsoft.com/Forums/en/vbinterop/thread/d5ee7d18-2db2-4b82-84b2-c59a4645f072

I hope that helps

4 Aug 2012 6:44 #10558

Also note that in the fortran project the Linker option Interface Only should be set to No, which is the default, but just in case.

Please login to reply.