[Mono-list] CustomMarshaler for structure element using P/Invoke

Jonathan Pryor jonpryor at vt.edu
Tue Nov 15 06:52:32 EST 2005


On Mon, 2005-11-14 at 19:54 -0800, Bill Medland wrote:
> Can any expert on P/Invoke tell me if what I want to do is 
> impossible; it's looking that way to me.

It's possible, it just depends on how much manual work you want to do.

> I want to make P/Invoke calls with structures containing strings, 
> but unfortunately they aren't quite strings in the usual sense.  
> I can almost get there by using ByValTStr on the strings but 
> unfortunately I don't want them null-terminated; I want fixed 
> well-known lengths (specified by the SizeConst parameter of the 
> attribute).

Then ByValTStr isn't for you, as it should always null-terminate the
strings (for sanity/safety reasons).

Instead of ByValTStr, you can use ByValArray for a byte[] array...

> For example in C I have
> 
> typedef struct {
> unsigned short length;
> char mystring1 [8];\
> signed int myint;
> char mystring2 [12];
> } mystruct;
> 
> void myfunc (const mystruct *input);

Becomes the following C# code:

        struct mystruct {
                public ushort length;
                [MarshalAs (UnmanagedType.ByValArray, SizeConst=8)]
                public byte[] mystring1;
                public int myint;
                [MarshalAs (UnmanagedType.ByValArray, SizeConst=12)]
                public byte[] mystring2;
        }
        
        class Imports {
                [DllImport ("...")]
                private static extern void myfunc (ref mystruct input);
        }

> I just about see how I could do this if I marshal the whole 
> structure myself but I actually want to let the default 
> marshaling handle the hard work and just let me marshal the char 
> arrays (since actually there are several structures)

The char arrays are now byte arrays, so you can either fill the byte
arrays directly, or you can use Encoding.GetBytes() to get a byte array
from a string:

        mystruct input = new mystruct ();
        input.length = 16;
        input.mystring1 = Encoding.UTF8.GetBytes ("12345678");
        input.myint = 32;
        input.mystring2 = Encoding.UTF8.GetBytes ("123456789ABC");
        myfunc (ref input);

> I don't see any documentation anywhere that explains in enough 
> detail how the custom marshaling occurs to let me do this.  Does 
> anyone know?

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

Attached is a working example program.  Compile & run as:

        gcc -g -shared -o libmedland.so medland.c
        mcs medland.cs
        mono medland.exe

 - Jon

-------------- next part --------------
A non-text attachment was scrubbed...
Name: medland.c
Type: text/x-csrc
Size: 547 bytes
Desc: not available
Url : http://lists.ximian.com/pipermail/mono-list/attachments/20051115/7ce2f5a6/medland.bin
-------------- next part --------------
A non-text attachment was scrubbed...
Name: medland.cs
Type: text/x-csharp
Size: 645 bytes
Desc: not available
Url : http://lists.ximian.com/pipermail/mono-list/attachments/20051115/7ce2f5a6/medland-0001.bin


More information about the Mono-list mailing list