[Mono-dev] Marshal Variable length structure Array in Mono

Jonathan Pryor jonpryor at vt.edu
Mon Sep 5 22:31:18 EDT 2005


Quick question: does anybody know of a "standard" Win32, POSIX, or
GLib/GTK/Gnome-related function that uses variable length structures?
I'd like to use one as a canonical example in the Marshaling guide:

	http://www.mono-project.com/Interop_with_Native_Libraries

More complete answer below...

On Fri, 2005-09-02 at 09:02 -0400, Yogendra Thakur wrote:
> Hi ,
>  I want to marshal following C structure .
> ----------------------------
> [C]
> struct Foo
> {
>    int First;
>    int Second;
> };
>
> struct FooList
> {
>    int Count;
>    Foo List[1];
> };
>
> void GetFooList(struct * FooList fList);
>
>
> I am doing it following way
> [C#]
> --------------------
> [StructLayout(LayoutKind.Sequential)]
> class Foo
> {
>   public Int32 First;
>   public Int32 Second;
> }

Personally, I would suggest using a struct to alleviate GC pressure, but
a class will also work.

> [StructLayout(LayoutKind.Sequential)]
> class FooList
> {
>    public Int32 Count;
>    private IntPtr list;//pointer to first
>    public Foo[] Foos
>    {
>       //???? HOW TO DO THIS

Short answer: you don't.  Not like that, anyway.

You shouldn't do things like this because you need to keep marshaling as
a logically separate activity: when invoking unmanaged code you allocate
an unmanaged representation, and when the unmanaged code returns you
convert it into a managed representation.  Trying to keep the unmanaged
and managed representations identical can be problematic, especially in
this case where the unmanaged representation is so unusual.

>    }
> }
> 
> My problem is how to form objects from IntPtr and return as Foo[].
> (If i directly use Marshal.PtrToStruct(list,typeof(Foo)); it throws
> object reference not set to object while access Foo.First.)
> 
> I googled about it and I found a solution which uses kernel32.dll and
> uses GlobalFree, GlobalAlloc API's.

I'm not sure why anyone would need to P/Invoke into kernel32.dll, since
the GlobalAlloc-related APIs are exposed directly on
System.Runtime.InteropServices.Marshal.

Attached is sample code to deal with variable length structures.
Compile and run with:

	$ gcc -g -shared -o libvlist.so vlist.c
	$ mcs -debug+ vlist.cs
	$ mono vlist.exe

vlist.c contains two canonical exports: GetFooList() takes an IN-OUT
pointer to a FooList structure, which allows some data (the Count in
this case) to be passed in by the caller.  AllocFooList() takes a double
pointer to a FooList structure, allocating and filling the variable
length structure.

>From the C# side of things, GetFooList() is more complicated because a
variable-length structure needs to be manually allocated -- you can't
rely on the default P/Invoke marshaler to do this for you, as it doesn't
know how.  This is done within FooList.ToIntPtr(), which allocates
unmanaged memory using Marshal.AllocHGlobal() and fills that memory
using Marshal.StructureToPtr().  Note the use of FooListMarshal, since
the FooList type can't be properly marshaled (since it contains extra
book-keeping information to simplify things).  Once an unmanaged
variable-length structure is allocated we can call GetFooList(), which
will fill our structure.  FooList.FillFromIntPtr reads the unmanaged
variable-length structure and fills the current FooList instance with
the appropriate data.

AllocFooList() is simpler to deal with, mostly because you don't need to
manually construct a variable-length structure; you instead just need to
read it, making it 1/2 as difficult as the GetFooList() case.

 - Jon

-------------- next part --------------
A non-text attachment was scrubbed...
Name: vlist.c
Type: text/x-csrc
Size: 1263 bytes
Desc: not available
Url : http://lists.ximian.com/pipermail/mono-devel-list/attachments/20050905/2c91bff1/attachment.bin 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: vlist.cs
Type: text/x-csharp
Size: 3314 bytes
Desc: not available
Url : http://lists.ximian.com/pipermail/mono-devel-list/attachments/20050905/2c91bff1/attachment-0001.bin 


More information about the Mono-devel-list mailing list