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.
Exporting and calling procedures from a Fortran DLL
.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
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 3Ftn 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
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.