[Mono-list] Platform invoke for stdarg

Jonathan Pryor jonpryor@vt.edu
Mon, 15 Nov 2004 20:54:22 -0500


On Mon, 2004-11-15 at 20:24 +0100, Francis Brosnan Blázquez wrote:
> Hi,
> 
> I'm trying to do a P/Invoke call for functions such as 
> 
> 	void Test(int value, ...); 
> 
> But I don't get it working. Is it posible to do a platform invoke for c
> functions that make use of stdarg api?

No, and Maybe. :-)

There is no general way to marshal "..." parameters, which requires that
all the parameters be passed on the stack -- the Cdecl calling
convention.  The .NET marshaller can only work with a fixed number of
arguments.

However, there are two solutions:

1.  Standard overloading: If there is a "reasonable" number of
parameters you need, you can explicitly specify them as overloads.  I do
this in Mono.Posix to wrap open(2):

	DllImport ("libc", CallingConvention=CallingConvention.Cdecl)
	public static extern int open (string pathname, int flags);

	DllImport ("libc", CallingConvention=CallingConvention.Cdecl)
	public static extern int open (string pathname, int flags, uint mode);

If you plan on using this code on Windows, you *must* specify
CallingCOnvention.Cdecl, as the default is Stdcall, which doesn't permit
variable argument lists.

Obviously, this is only viable if you have a limited number of potential
overloads.  Wrapping printf(3) is impractical, as it could result in
hundreds (thousands?) of overloads.

2.  Get creative, take an object[] array, and generate some
System.Reflection.Emit code which accepts the proper number of
parameters of the proper type, and invoke the recently generated code.
IIRC cocoa-sharp does something similar to this for its msg_send
implementation.  Pro: it works for any argument list.  Con: it's not
easy.

 - Jon