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 - [email protected]
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: [EMAIL PROTECTED]
web: www.agamura.com
----------------------------------------
_______________________________________________
Mono-list maillist - [email protected]
http://lists.ximian.com/mailman/listinfo/mono-list