[Gtk-sharp-list] Interop

Jonathan Pryor jonpryor@vt.edu
Sun, 08 Feb 2004 13:26:13 -0500


Below...

On Sun, 2004-02-08 at 08:13, Rui Barreiros wrote:
> Sorry i'm writing to this list, it's not gtksharp related but it's the
> list i'm subscribed right now and it a kind of urgent.

mono-list would be more appropriate for this.

> I'm trying to write a GUI from clamav but i have some troubles with the
> struct's defined in clamav.h one is:
> 
> struct cl_node
> {
>   char islast;
	// Note: pointer; is this an array or a single instance?
>   struct cli_patt *list;
	// Note: array of pointers
>   struct cl_node *trans[CL_NUM_CHILDS], *fail;
>   unsigned int maxpatlen, partsigs;
>   unsigned int nodes;
	// NOte: pointer to array of pointers?
>   struct cl_node **nodetable;
> }
> 
> How can i use this struct in mono?
> 
> i tried this, i always get compile errors about the loop reference in
> the struct, and probably there are other things not right:

That's because your structure declaration is wrong. :-)

> [StructLayout(LayoutKind.Sequential)]
> public struct cl_node
> {
	// Note: was declared as a 'char' in C; short=16 bits, char=8.
>   public short islast;
	// Note: NOT a pointer
>   public cli_patt list; // I already have struct cli_patt defined above
	// Note: NOT an array of pointers
>   private cl_node trans;
	// Note: NOT a pointer
>   private cl_node fail;
>   public uint partsigs;
>   public uint maxpatlen;
>   public uint nodes;
	// Note: NOT a pointer to an array of pointers?
>   private cl_node nodetable;
> 
>   [DllImport("libclamav")]
>   public static extern void PassByValue(cl_node n);
> 
>   [DllImport("libclamav")]
>   public static extern void PassByReference(cl_node n);
> }

Basically, your C# structure declaration doesn't match your C
declaration.  Even if it did compile (which it won't, as you've noted),
it wouldn't work properly because the runtime marshaller would be doing
the wrong thing.

What you need is closer to:

	struct cl_node
	{

		public static int CL_NUM_CHILDS = /* something */;

		public sbyte islast;
			// or `byte', depending on default 
			// signed-ness of compiler
		public IntPtr list;
		[MarshalAs(UnmanagedType.ByValArray, 
			SizeConst=CL_NUM_CHILDS)]
		public IntPtr[] trans;
		public IntPtr fail;
		public uint maxpatlen, partsigs;
		public uint nodes;
		public IntPtr nodetable;
	}

Of course, you need a way to extract information from all those IntPtr
fields.  System.Runtime.InteropServices.Marshal.PtrToStructure() can be
used to do this:

	cl_node n = get_cl_node ();
	cl_node child0 = (cl_node) Marshal.PtrToStructure (
		n.trans[0], typeof (cl_node));
	// operate on child...

If `list' refers to a single instance, the same thing can be done to
obtain access to it.  If `list' is actually an array, you'll need to
change the `list' declaration to:

	cli_patt[] list;

This introduces more complexities, which I won't go into here.

I would suggest that you read up on marshaling and interoperability on
MSDN:

	http://msdn.microsoft.com

Searching for Interop and Array Marshaling should get you close.  You
can also read this:

	http://www.jprl.com/~jon/interop.html

 - Jon