[Mono-list] Deep Marshaling
Giuseppe Greco
giuseppe.greco at agamura.com
Sun Oct 23 09:21:18 EDT 2005
Jon,
that you said is really interesting... and I'm wondering how
can I solve another similar problem. Giving the following type:
[StructLayout(LayoutKind.Sequential)]
internal struct MyStruct
{
public int Id;
public byte[] Data; // of course, that's wrong!!!
}
... I'd like to fill it like this:
public unsafe void FillMyStruct(string s)
{
//
// convert the given string into a byte array
//
byte[] data = Encoding.UTF8.GetBytes(s);
//
// create another byte array for storing
// a new instance of MyStruct
//
byte[] buffer = new byte[
sizeof(int) // Size of MyStruct.Id
+ data.Length]; // Length of MyStruct.Data
//
// fill the buffer
//
fixed (byte* pBuffer = buffer) {
MyStruct* pMyStruct = (MyStruct*) pBuffer;
pMyStruct->Id = 100; // OK
pMyStruct->Data = data; // ERROR
}
}
Any help would be really appreciated,
j3d.
Jonathan Pryor wrote:
> On Thu, 2005-10-20 at 16:07 -0700, Shankari wrote:
>
>>While marshalling class and structure members, Mono
>>doesnt do a deep marshal.
>>If the structure has a string member, a default of
>>charset.auto is set.
>
>
> Would you prefer some other default?
>
>
>>But if the structure has an array of integers, what
>>would be done in that case?
>
>
> You could always try it... :-)
>
> And get this:
>
> ** ERROR **: Structure field of type Int16[] can't be marshalled
> as LPArray
> aborting...
> Aborted
>
> That was for marshaling this structure:
>
> struct Outer {
> public int size;
> public short[] inner;
> }
>
> For which the corresponding C structure would be:
>
> struct Outer {
> int size;
> short *inner;
> };
>
> However, *this* does marshal correctly:
>
> // C#
> struct Outer {
> int size;
> [MarshalAs (UnmanagedType.ByValArray, SizeConst=100)]
> short[] inner;
> }
>
> /* C */
> struct Outer {
> int size;
> short inner [100];
> };
>
> But the above structure has very different semantics than the previous
> pair.
>
>>From this we can see theorize that Mono's marshaler doesn't like nested
> pointers, unless those pointers are for strings.
>
> There are workarounds.
>
>
>>In general, if an array of simple types is a member of
>>the structure , how would it be marshalled(if at all)?
>
>
> It depends on what the C layout is like. If the array is "inline", e.g.
>
> struct Foo {
> char inline_array [100];
> };
>
> Then you can use [MarshalAs (UnmanagedType.ByValArray, SizeConst=100)]
> on the appropriate member:
>
> struct Foo {
> [MarshalAs (UnmanagedType.ByValArray, SizeConst=100)]
> public byte[] inline_array;
> }
>
> If the structure member is a *pointer* to the arrar, e.g.
>
> struct Foo {
> char *external_array;
> };
>
> Then you'll need to marshal it manually; see the next answer, as the
> solution applies to both built-in types and user-defined types.
>
>
>>For array of user defined structures, I assume no
>>marshalling will be done. (Am I correct?)
>
>
> No marshaling will be done by default -- you'll abort the program instead.
>
> If the default marshaler won't handle it, you can marshal it yourself.
> It's not fun, but it's possible.
>
> To marshal these structures:
>
> /* C */
> struct Inner {
> char a, b;
> };
>
> struct Outer {
> int size;
> struct Inner *inner;
> };
>
> // C#
> struct Inner {
> public byte a, b;
> }
>
> struct Outer {
> public int size;
> public IntPtr inner; // [1]
> }
>
> The [1] comment is the first sign that we're doing things ourselves. To
> actually invoke a C function defined as:
>
> void PrintOuter(struct Outer *outer);
>
> we'd need the C# code:
>
> [DllImport ("test")]
> private static extern void PrintOuter (ref Outer outer);
>
> public static void Main ()
> {
> // Create inner array to marshal
> Inner[] inner = new Inner [26];
> for (int i = 0; i < inner.Length; ++i) {
> inner [i].a = (byte) ((int) 'a' + i);
> inner [i].b = (byte) ((int) 'z' - i)
> }
>
> Outer o = new Outer ();
> o.size = inner.Length;
>
> // Manually marshal the Inner[] to an IntPtr
> int inner_size = Marshal.SizeOf (typeof(Inner));
> o.inner = Marshal.AllocHGlobal
> (inner_size*inner.Length);
> for (int i = 0; i < inner.Length; ++i) {
> IntPtr p = (IntPtr) ((long) o.inner + (long)
> i*inner_size)
> Marshal.StructureToPtr (inner [i], p, false);
> }
>
> // We're done!
> PrintOuter (ref o);
>
> // Cleanup
> Marshal.FreeHGlobal (o.inner);
> }
>
> See the attached code:
>
> gcc -shared -o libsm.so sm.c
> mcs sm.cs
> LD_LIBRARY_PATH=`pwd` mono sm.exe
>
> - Jon
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> Mono-list maillist - Mono-list at lists.ximian.com
> http://lists.ximian.com/mailman/listinfo/mono-list
--
----------------------------------------
Giuseppe Greco
::agamura::
call giuseppe.greco via Skype
phone: +41 (0)91 604 67 65
mobile: +41 (0)79 590 33 06
email: giuseppe.greco at agamura.com
web: www.agamura.com
----------------------------------------
More information about the Mono-list
mailing list