I'm writing some fortran code to read Nastran op2 files. I am using fseek and ftell to store the position of certain data blocks. This code is compiled to a DLL and called either from C++ code or C# code. When I call the function from c++ fseek/ftell works correctly, but when called from C# using PInvoke both return always -1. Am I missing something?
[DllImport("mydll.dll", EntryPoint = "abcd", CallingConvention = CallingConvention.StdCall)] [return: MarshalAs(UnmanagedType.I4)] static extern int abcd([param: MarshalAs(UnmanagedType.I4)] Int32 dummyInt);
Fortran DLL code:
function abcd(input) result(istat) !DEC$ ATTRIBUTES ALIAS:'abcd' :: abcd !DEC$ ATTRIBUTES DLLEXPORT :: abcd !DEC$ ATTRIBUTES VALUE :: input use ifport integer,intent(in) :: input integer(4) istat, offset, ipos, posactual, res integer :: f f=1 OPEN (UNIT=f, IOSTAT=ios, ERR=100, FILE='C:/test.op2', form='unformatted', STATUS='OLD', ACTION='READ') READ (f, END=100) res res=fseek(f, 10, 0) istat=ftell(f) 100 end function abcd
First thing to resolve is if which function failed or if the C# interface is wrong.
At line 11 above insert istat=999111
At line 14 above insert istat=999222
At line 18 above, insert istat=123456
Then see what the return is to C#.
999111 indicates open fail,
999222 indicates read fail,
123456 indicates success (though value you do not want)
-1 indicates something wrong with interface.
By the way, you will need to set in your own error codes at lines 11 and 14. Currently you would return uninitialized data.
Thanks jimdempseyatthecove for your response. I get 123456 as return, but my problem is that I cannot place the file pointer where I want using fseek. I have tried INQUIRE(UNIT=f, POS=ipos) but the position does not change after seeking 10 positions.
The c# declares the procedure to be stdcall, but there is no visible corresponding declaration in the Fortran source.
Which compiler are you using? What compile options are you using? If you are using Intel Fortran without some sort of compile option to specify stdcall - then you have a calling convention mismatch.
I strongly recommend using the C interoperability features for Fortran 2003 for interoperating with other languages that know the relevant C calling convention.
The value of res after line 16 is -1.
I have tried changing calling convention to cdecl in the C# dllimport or adding !DEC$ATTRIBUTES STDCALL :: abcd to the fortran function, but the result is the same.
The compiler is Intel Fortran 16.0 for Windows with these options:
/nologo /debug:full /Od /warn:interfaces /module:"x64\Debug\\" /object:"x64\Debug\\" /Fd"x64\Debug\vc120.pdb" /traceback /check:bounds /check:stack /libs:dll /threads /dbglibs /c
We've had good success calling Fortran subroutines from C# for FEA result post processing and returning scalar and array values, so it is possible. While you are working on the calling conventions, perhaps a comparison to the syntax we're using would help. Some differences that I see in our syntax is that in the C# code I only specified the DLL name, am using "static extern void" to call the subroutine, and am passing arrays by reference to return values from Fortran to C#, for example:
static extern void mysub1(ref int arraySize, int myIntArray, double[,] myRealArray);
I think arrays are passed by reference by default ("ref" not needed), and passing scalars would need to have the "ref" statement added. Does it make calling Fortran any easier to use "void" instead of returning an integer? Could the integer be returned as one of the parameters?
The syntax in the Fortran look similar, except we're using the "REFERENCE" attribute:
!DEC$ATTRIBUTES REFERENCE :: arraySize, myIntArray, myRealArray