[Mono-list] Re: [Mono-devel-list] Managed/Unmanaged Code Interop Documentation

Jonathan Pryor jonpryor@vt.edu
Wed, 03 Sep 2003 20:20:21 -0400


Thank you for the feedback.

Now for some clarifications...

On Wed, 2003-09-03 at 05:21, Paolo Molaro wrote:
<snip/>
> In some cases, no marshaling and no copy of data happens, for example
> when the data is blittable most of the time it's enough to pass a
> pointer to the managed representation.

How can you do that?  The only time I can see this happening is when
you're passing a pointer to a structure (using ref or out).

This doesn't appear to happen with passing classes (which is why the
[Out] attribute is needed to see changes made to the instance by the
unmanaged function), and structures without "ref" or "out" should be
completely copied, or else the unmanaged function won't be getting what
it expects on the stack.

> >    <p>What's the memory management policy for using "string" as a return
> >    value?  Does the runtime expect to free it?</p>
> 
> Yes, though I don't remember if we insert the free() yet: note we will
> use free by default on unix-like platforms and the MS-specified free
> routine on windows.

Would it be more .NET-compatible if I said that unmanaged memory were
freed from within the runtime "as if" via
System.Runtime.InteropServices.Marshal.FreeCoTaskMem (IntPtr)?

Now, on Unix this could call the platform-native free(3), but under
Win32 this could call CoTaskMemFree().

Does it make sense to document it this way, or should I just not mention
Marshal.AllocCoTaskMem/FreeCoTaskMem at all?

<snip/>

> >    <h3>Marshaling Class and Structure Members</h3>
> > 
> >    <p>Aside from the major differences between classes and structures outlined
> >    above, the members of classes and structures are marshaled identically.</p>
> > 
> >    <p>The general rule of advice is this: never pass classes or structures
> >    containing members of reference type (classes) to unmanaged code.
> >    This is because unmanaged code can't do anything safely with the unmanaged 
> >    reference (pointer), and the CLI runtime doesn't do a "deep marshal"
> >    (marshal members of marshaled classes, and their members, ad
> >    infinitum).</p>
> > 
> >    <p>The immediate net effect of this is that you can't have string and array
> >    members of marshaled classes.</p>
> > 
> >    <p>It's not quite as bad as this makes out.  You can't pass strings and
> >    arrays BY DEFAULT.  If you help the runtime marshaler by addorning the
> 
> I'm not sure this is right: you can use strings and arrays in types that
> will be marshaled and by default they will be converted to pointers to
> the data.
>
> 	string -> char* (or gunichar2*, depending on the charset property)
> 	int[]  -> gint32*
> 	etc.

That was my argument for "BY DEFAULT."  By default, there is no
StructLayout attribute, and hence there is no CharSet specified.

If CharSet isn't set, is there a default marshal format for strings and
arrays?  I didn't think there was.  (Platform-native would be a sensible
default, but since platform-native is UCS-2 on NT-based platforms and
Ansi on Win9x-based platforms, this wouldn't be particularly developer
friendly, so requiring that the CharSet be specified would be a good
idea regardless.)

<snip/>

> >    <monodoc:example id="">
> >       [StructLayout(LayoutKind.Sequential)]
> >       unsafe struct NEOERR {
> >         public int error;
> >         public int err_stack;
> >         public int flags;
> >         public byte[256] desc;  // this is invalid, can't contain size
> 
> 	[MarshalAs (UnmanagedType.ByValArray, SizeConst=256)]
> 	public byte[] desc;
> should work.
> 
> 	[MarshalAs (UnmanagedType.ByValTStr, SizeConst=256)]
> 	public string desc;
> may work as well.

I'll need to test those.

> Thanks for writing this document: it looks like a good start.
> 
> lupus

Thanks,
 - Jon