[Mono-list] Deep Marshaling
Jonathan Pryor
jonpryor at vt.edu
Fri Oct 21 07:17:29 EDT 2005
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
-------------- next part --------------
A non-text attachment was scrubbed...
Name: sm.c
Type: text/x-csrc
Size: 309 bytes
Desc: not available
Url : http://lists.ximian.com/pipermail/mono-list/attachments/20051021/5bd6d742/sm.bin
-------------- next part --------------
A non-text attachment was scrubbed...
Name: sm.cs
Type: text/x-csharp
Size: 866 bytes
Desc: not available
Url : http://lists.ximian.com/pipermail/mono-list/attachments/20051021/5bd6d742/sm-0001.bin
More information about the Mono-list
mailing list