[Mono-list] PInvoke Conventions

James Perry jeperry@uwaterloo.ca
Tue, 31 Jul 2001 20:18:40 +0100

Ahh. Well, I mostly agree with you then.

I appoligise for this, it's mostly pointless.... ;)

On July 31, 2001 12:38 AM, Fergus Henderson <fjh@cs.mu.oz.au> wrote:
>> When you start considering 3rd party developers (you know, the people who
>> would actually /use/ mono:) it's a major barrier for two reasons, one of
>> which hasn't been touched on yet. The first one means that if you want to
>> write something which talks to an external library you can either a)
>> the library in Mono (bad) or b) become responsible for writing a wrapper
>> every platform mono supports (bad) or c) making a wrapper for a single
>> platform (defeats the point of using a platform independent architecture,
>> bad). I can't see a good solution to this.>
>Write a single wrapper (in unmanaged C/C++) and compile it once for each
>different platform.
>Using native-code libraries will of course reduce the portability
>of your code.  This should come as no surprise.  However, it doesn't
>entirely defeat the point of using a platform independent architecture,
>because although you need to distribute N copies of the wrappers, one
>for each platform, once you've built the wrappers they are unlikely to
>change much; whereas for your main application, which does change often,
>you only need to distribute one copy.
>I think you are exaggerating the drawbacks of this approach a bit.
>But I agree that it does have significant drawbacks.
>> Ultimately, even if the runtime interop stuff isn't sufficient for
>> it could be implemented in a platform dependent way that mitigates a lot
>> the problems of the other two: have a shared library which describes the
>> platform dependencies in an abstract way (sizes of integers, sizes of
>> etc...) and then have the logic to convert written in PInvoke based on
>> information.
>The trouble is that the "etc..." is large; it includes "offset of tm_idst
>in struct tm", "size of nlink_t", "value of O_CREAT", etc.
>Still, it may be the best that we can do.
>Doing it this way would probably make things easier for Mono users,
>albeit at the expense of making things harder for Mono developers.

Yes, I hadn't thought of that problem. The advantages of mailing lists and
the disadvantage of joining a mailing-list discussion half-way through. :)

A purely academic point, but a possible solution to that would be to store
all that platform-dependent type-data as metadata in a library somewhere. Of
course, this would require a working ilasm, and probably be worse than an
unmanaged solution in C (for the reasons you mentioned). Anyway, I mostly
agree with you that a separate library is needed, with qualifications.

However, you pointing out this (significant) oversight on my part started me
thinking about the problem of PInvoke. Consider the sockaddr structs and the
automagic conversion of these (as PInvoke supposedly is supposed to do). Am
I the only one who thinks a generalized automagic conversion would be
hellish to implement? It would require a certain amount of semantic
knowledge of the data - not just syntactic fiddling. This sort of
intelligence seems to me to be above and beyond the call of duty of PInvoke,
but seems to be a task PInvoke is being given. So I looked at the specs. :)

CLI, Partition II: Metadata Definition and Semantics, section 14.6.2
   - Calling Unmanaged Methods (page 72)

   Platform Invoke (PInvoke) is a combination of the transitional
   management provided by IJW with data marshalling similar to that
   provided by COM Interop. It allows existing APIs to be called
   from managed code, with automatic conversion between some
   managed types and their unmanaged equivalents.

It strikes me that the examples given (different layouts and sizes of
structures, different values of #define's, etc...) is much beyond the scope
of what PInvoke is supposed to do - it says 'some' automatic conversion
between 'managed types and their unmanaged _equivalents_'.

While I agree with you now that an external 'wrapper' library of sorts will
be needed for this kind of conversion (PosixTypeAttribute is _way_ too much
work for the runtime to do), I disagree with the naming of it. :)

IMHO, all the pinvoke logic for basic type conversion should still be in
managed C#, not unmanaged C, but an extra /portability/ library be provided
to give the managed class library a standardized base to work from.
Similarly, any code which calls through to this platform dependent library
should be kept separate from the rest of the class library, since it really
won't be portable to platforms with poor (or non-existent) implementations
of POSIX. :)

It may be a difference in naming, but an important one which helps draw a
line at what PInvoke should be capable of doing and what it should rely on
outside assistance for. This alleviates my concern of 3rd party developers
having to write and maintain unmanaged wrappers for external libraries they
want to talk to.

 - James Perry