[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.