P/Invoke to Fortran DLL - weird parameters...

  • Thread starter Holger (David) Wagner
  • Start date
H

Holger (David) Wagner

Hi all,

we're currently developing an application in the .NET environment that
needs to access a DLL implemented in Fortran. There is one procedure
with about 17 parameters, most of them arrays. After some trial and
error experiments, we've found out that

a) the parameters must be ordered by type, i.e. we cannot mix double,
integers and Strings (char-Arrays) - instead, we first need to put
all the float[]-Arrays and Int32[]-Arrays, and after that, all the
byte[]-Arrays
b) each byte[] parameter but the first must exist twice in our C#
representation of the DLL procedure ("DllImport... public extern
static void...")
c) we couldn't pass two-dimensional byte-arrays (byte[][]) representing
one-dimensional arrays of Strings. Instead, we're serializing these
two-dimensional arrays to one-dimensional arrays.

Doing it this way, the parameters get to the DLL as intended, and where
needed they also get back to our .NET context (in/out) - but we're a
little puzzled why this is the case...

Possibly, a) is just an artefact of not paying attention to b) (it may
be that when each byte[] parameter is given twice, float[] can be given
in between, however, since the first byte[] parameter must exist only
once, this is not very probable...)

Any ideas or pointers to documentation on this behavior? We've found
some information on p/invoke, but nothing about complex cases as the one
we are facing. Also, this behavior may be specific to Fortran DLLs...

kind regards,
david
--
Auch das geht vorüber. (Sufi-Weisheit)

Holger (David) Wagner Tel: +49 (89) 890 50 962
Dewetstrasse 1 Mobil: +49 (177) 274 12 45
D-80807 München Fax: +49 (177) 992741245
 
N

Nicholas Paldino [.NET/C# MVP]

David,

There definitely seems to be something wrong. Can you give the actuall
declarations (C equivalent) for the functions exported from the DLL? Also,
what is the calling mechanism for the functions exported from this DLL?
 
H

Holger (David) Wagner

Nicholas said:
There definitely seems to be something wrong. Can you give the actuall
declarations (C equivalent) for the functions exported from the DLL? Also,
what is the calling mechanism for the functions exported from this DLL?

Unfortunately, I don't have access to the Fortran-Declarations -
however, we finally fixed the problem(s). One major problem was that
..NET automatically adds a parameter to byte[]-Arrays or multidimensional
bytearrays. While in the original Fortran-Signature, these parameters
(e.g. outParam1) exist only once - the C#-declaration must have
outParam1 and another outParam1X which is probably used to return the
length of the array.

We're ignoring this parameter, but if it's missing in the declaration,
everything gets messed up (without an error message or exception).

The float/int problem has "disappeared"... probably, that was an
artefact of the problem with the strings.

What remains is that we cannot use LOGICAL on the Fortran side. We *can*
send arrays of bool/logical to the DLL - but when we invert the values,
we get back weird results (e.g. everything becomes true). By using
integers, we found out that Fortran seems to simply change the sign and
subtract 1, so 0 becomes -1, 1 becomes -2, 2 becomes -3 and so on...
seems like Fortran is only interested in the last bit while C#/.NET
compares with 0. We fixed this by using integers in the Fortran-DLL an
converting them to logicals 1=true, 0=false.

The import-statement on the C#/.NET side now looks as follows:

[DllImport("dllName.DLL",
BestFitMapping=false,
CallingConvention=CallingConvention.Winapi,
CharSet=CharSet.Ansi,
EntryPoint="PROCEDURENAME",
ExactSpelling=true,
PreserveSig=true,
SetLastError=false,
ThrowOnUnmappableChar=true
)]
public extern static void wstksdll(
[In] float[] inParam1, // REAL (4), 200
[In] Int32[] inParam2, // INTEGER (4), 21
[In] float[] inParam3, // REAL (4), 21
[In, Out] byte[] outParam1, // CHARACTER 34, 40, 34
[In, Out] Int32 outParam1Length,// not in Fortran-Signature!!!
[In, Out] Int32[] outParam2, // INTEGER (4), 40
[In, Out] float[] outParam3, // REAL (4), 40
[In, Out] float[] outParam4, // REAL (4), 40
[In, Out] byte[] outParam5, // CHARACTER 14, 40, 14
[In, Out] Int32 outParam6, // CHARACTER 34, 20, 34
[In, Out] Int32[] outParam7, // INTEGER (4), 40
[In, Out, MarshalAs(UnmanagedType.LPArray,
ArraySubType=UnmanagedType.I1)]
bool[] outParam8, // LOGICAL (4), 40
[In, Out] byte[] outParam9, // CHARACTER 34, 20, 34
[In, Out] Int32 outParam9Length,// CHARACTER 30, 20, 30
);


--
Auch das geht vorüber. (Sufi-Weisheit)

Holger (David) Wagner Tel: +49 (89) 890 50 962
Dewetstrasse 1 Mobil: +49 (177) 274 12 45
D-80807 München Fax: +49 (177) 992741245
 
M

Mattias Sjögren

Holger,
Unfortunately, I don't have access to the Fortran-Declarations -
however, we finally fixed the problem(s). One major problem was that
.NET automatically adds a parameter to byte[]-Arrays or multidimensional
bytearrays. While in the original Fortran-Signature, these parameters
(e.g. outParam1) exist only once - the C#-declaration must have
outParam1 and another outParam1X which is probably used to return the
length of the array.

It's good to hear that you got it working. But I can assure you that
C# or the .NET runtime doesn't magically add parameters like that.

I don't know enough about Fortran to even guess how it exports
functions or why your changes made it work, but there certainly aren't
any hidden parameters being added on the managed side.

What remains is that we cannot use LOGICAL on the Fortran side. We *can*
send arrays of bool/logical to the DLL - but when we invert the values,
we get back weird results (e.g. everything becomes true). By using
integers, we found out that Fortran seems to simply change the sign and
subtract 1, so 0 becomes -1, 1 becomes -2, 2 becomes -3 and so on...

That's a binary NOT operation (~ in C#).

~0 == -1
~2 == -3



Mattias
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top