[Mono-list] PInvoke Conventions
Rhys Weatherley
rweather@zip.com.au
Wed, 18 Jul 2001 15:04:30 +1000
Bob Salita wrote:
> >The Windows version of PInvoke doesn't do this. It always
> >thunks a numeric type to the same sized type, unless there is
> >an explicit override. So, "long" maps to "__int64" under
> >Win32, not "native long", which is only 32 bits. I'm following
> >the same conventions here.
>
> Ouch. Is there a difference in size depending on CallingConvention type
> (CDecl, StdCall, WinAPI)? Does one of these match my suggestion?
No. They just change the x86 instructions used to make the
call and the order of the parameters. e.g. flipping between
C and Pascal style calling conventions. But my brain is a
bit rusty on this - I've been on Linux long enough to forget
most of that stuff, thank God. :-)
Microsoft avoids the problems that occur because when
all the world is an x86, it is easy for it to "just work". :-)
I just found an even nastier case for why your method won't
work. Passing structs by reference. Consider the function
"gettimeofday":
struct timeval {
long tv_sec;
long tv_usec;
};
struct timezone {
int tz_minuteswest;
int tz_dsttime;
};
int gettimeofday(struct timeval *tv, struct timezone *tz);
The naive C# version would like something like this:
public struct timeval
{
public long tv_sec;
public long tv_usec;
}
public struct timezone
{
public int tz_minuteswest;
public int tz_dsttime;
}
[DllImport("libc")]
extern public unsafe int gettimeofday(timeval *tv, timezone *tz);
Problem is, the CLR will lay out the "timeval" type with 64-bit
fields, because it sees them as CLR "long"'s. But the C function
will expect to get a pointer to a structure with 32-bit fields
(assuming a 32/32 system).
There's really no way that the CLR knows how to marshal this
without some extra information. e.g.
public struct timeval
{
[NativeTypeSizes(true)] public long tv_sec;
[NativeTypeSizes(true)] public long tv_usec;
}
This will cause the CLR to lay out the structure properly.
There are lots of other aberrant cases like this in the Unix
/usr/include directory. Windows avoids it because it always
uses WORD, DWORD, etc, in its API definitions, and so the
structure sizes are identical on 32-bit and 64-bit platforms.
Cheers,
Rhys.