[Mono-list] need some help with PInvoke..

David Jeske jeske@chat.net
Thu, 10 Jul 2003 01:22:55 -0700


--KDt/GgjP6HVcx58l
Content-Type: text/plain; charset=us-ascii

On Wed, Jul 09, 2003 at 02:15:09PM -0400, Jonathan Pryor wrote:
> The first way is similar to what's done in Gtk# -- use System.IntPtr
> instead of "void*" and use the IntPtr exclusively as a pointer into
> managed memory:

For opaque stuff, I like the IntPtr concept. However, I want specific
types of IntPtrs. I have a bunch of different opaque types and turning
everything into an IntPtr is too dangerous.

You'd think they would have wanted to have a more specific type than
IntPtr on all those HWND elements. I can easily crash the world with
supposedly "safe" code just by handing an IntPtr of the wrong type
somewhere.

However, unless I'm totally misunderstanding something, it seems like
I can do what I want with unsafe code. 

> However, what you posted doesn't exactly match the above.  You have a
> "mostly opaque" data structure (given that your C code directly
> references the `desc' member of the NOERR class).
> 
> There's a problem with this.  The .NET/mono runtime systems make two
> assumptions: structs are located on the stack, and classes are allocated
> in garbage-collected, .NET-controlled, memory.  Non-stack, non-garbage
> collected memory doesn't enter the picture AT ALL.

That's fine. What I want to do shouldn't conflict with this
concept. For non-opaque types (C-structs), I just want .NET to keep a
pointer in managed memory, but I want it to point to unmanaged data
(which it can clearly already handle). Then want the ability to use a
C-style struct definition to get at elements in the unmanaged struct
memory. I'm fine if I have to do this inside unsafe code blocks.

I used unsafe structs and it seems to do exactly what I
want. Accessing structure members in the unmanaged memory works
correctly. There is no object machinery around structs, so the offsets
match the unmanaged data just fine. The only question is, does the GC
ignore a struct pointer or an unsafe struct pointer? 

For example, given this code:

  unsafe struct DATA {};

  unsafe class Foo {
    unsafe DATA *bar;
  }

Will the GC have any problems if bar points to unmanaged memory?

I can see why it would want to take a look at the location bar is
pointing to, because there are cases where you are allowed to have
pointers which point to the interior of managed objects. However, it
can't go walking the bar pointer, because there is no object machinery
on the other end. Because of this, I can't see why it would crash the
GC if this pointed to unmanaged memory.

Can anyone more in the know confirm what happens here?

I've attached my most recent test code which uses unsafe structs and
seems to do the right thing. (i.e. it can correctly access internal
structure members of the data sitting in unmanaged memory)

-- 
David Jeske (N9LCA) + http://www.chat.net/~jeske/ + jeske@chat.net

--KDt/GgjP6HVcx58l
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="pitest2.cs"


using System;
using System.Runtime.InteropServices;


[StructLayout(LayoutKind.Sequential)]
public unsafe struct HDF {
  public int link;
  public int alloc_value;
  public char *name;
  public int name_len;
  public char *value;
  // ...
};

[StructLayout(LayoutKind.Sequential)]
unsafe struct NEOERR {
};

unsafe public class Hdf {

  [DllImport("libneo.so", EntryPoint="hdf_init")]
  private static extern unsafe void hdf_init(HDF **foo);

  // NEOERR* hdf_set_value (HDF *hdf, char *name, char *value);

  [DllImport("libneo.so", EntryPoint="hdf_set_value")]
  private static unsafe extern void hdf_set_value(
         HDF *hdf,
       [MarshalAs(UnmanagedType.LPStr)] 
         string name,
       [MarshalAs(UnmanagedType.LPStr)]
         string value
       );

  // NEOERR* hdf_dump (HDF *hdf, char *prefix);

  [DllImport("libneo.so", EntryPoint="hdf_dump")]
  private static extern void hdf_dump(
       HDF *hdf,
       [MarshalAs(UnmanagedType.LPStr)]
         string prefix);

  // HDF* hdf_get_obj (HDF *hdf, char *name)

  [DllImport("libneo.so", EntryPoint="hdf_get_obj")]
  private static extern HDF* hdf_get_obj(
     HDF *hdf, 
       [MarshalAs(UnmanagedType.LPStr)]
     string name);


    public unsafe HDF *p;

    public static unsafe int Main(string[] argv) {
      Hdf h = new Hdf();
   return 0;
    }
    public Hdf() {
    
    Console.WriteLine("start test2");

    hdf_init(&p);
    Console.WriteLine((int)p);

    hdf_set_value(p,"b","1");
    //hdf_read_file(p,"test.hdf");
    //Console.WriteLine("b ", hdf_get_value(_hdf,"b","5"));


    hdf_dump(p,null);

    HDF *n = hdf_get_obj(p,"b");
    Console.WriteLine("object name {0}", 
      Marshal.PtrToStringAnsi((IntPtr)n->name));

 }

};

--KDt/GgjP6HVcx58l--