views:

1634

answers:

3

I have a small C library in a DLL and I need to call a handful of its methods.

It uses pointers and a few structs but is otherwise quite simple. Problem is I'm not terribly knowledgable on .NET's interop with the unmanaged world and my attempts so far keep hitting memory access violation exceptions (presumably due to me not getting the pointers quite right).

Could anyone give me some pointers (ooh a pun!) on the best way to approach this?

Thank you

extern vconfig_t *Pobsopen(Ppoly_t ** obstacles, int n_obstacles);


extern int Pobspath(vconfig_t * config, Ppoint_t p0, int poly0,
      Ppoint_t p1, int poly1,
      Ppolyline_t * output_route);

extern void Pobsclose(vconfig_t * config);

struct vconfig_t {
    int Npoly;
    int N;
    Ppoint_t *P;
    int *start;
    int *next;
    int *prev;
};

typedef struct Ppoly_t {
    Ppoint_t *ps;
    int pn;
} Ppoly_t;

typedef Ppoly_t Ppolyline_t;

typedef struct Pxy_t {
    double x, y;
} Pxy_t;

typedef struct Pxy_t Ppoint_t;
typedef struct Pxy_t Pvector_t;
+1  A: 

Maybe you should write your wrapper in C++/CLI, because the interop between managed code and unmanaged code is very seamless.

Update

Here is a link to a trivial example: C data structure to mimic C#’s List>?

Giovanni Galbo
+4  A: 

You should check out the tool given in this MSDN Magazine article that can translate a C snippet to C# P/Invoke signatures, and of course the post as well.

Running the tool for your code snippet gives you this:

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct vconfig_t {

    /// int
    public int Npoly;

    /// int
    public int N;

    /// Ppoint_t*
    public System.IntPtr P;

    /// int*
    public System.IntPtr start;

    /// int*
    public System.IntPtr next;

    /// int*
    public System.IntPtr prev;
}

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct Ppoly_t {

    /// Ppoint_t*
    public System.IntPtr ps;

    /// int
    public int pn;
}

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct Pxy_t {

    /// double
    public double x;

    /// double
    public double y;
}

public partial class NativeMethods {

    /// Return Type: vconfig_t*
    ///obstacles: Ppoly_t**
    ///n_obstacles: int
    [System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="Pobsopen")]
public static extern  System.IntPtr Pobsopen(ref System.IntPtr obstacles, int n_obstacles) ;


    /// Return Type: int
    ///config: vconfig_t*
    ///p0: Ppoint_t->Pxy_t
    ///poly0: int
    ///p1: Ppoint_t->Pxy_t
    ///poly1: int
    ///output_route: Ppolyline_t*
    [System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="Pobspath")]
public static extern  int Pobspath(ref vconfig_t config, Pxy_t p0, int poly0, Pxy_t p1, int poly1, ref Ppoly_t output_route) ;


    /// Return Type: void
    ///config: vconfig_t*
    [System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="Pobsclose")]
public static extern  void Pobsclose(ref vconfig_t config) ;

}
mherle
+1  A: 

I wrote a long and helpful answer, which StackOverflow discarded when I posted it.

The gist was:

  1. You may find the site pinvoke.net useful, though it's not always accurate.
  2. The .NET framework source is a very useful repository of correct p/invoke signatures for Win32 functions, and has often given me inspiration for my own p/invoke problems.
  3. The Marshal class contains a lot of useful functions - some of which might help explain things like what you actually do with an IntPtr.

You may also need to be careful about fixed/pinning - particularly with something like your linked-list structure, thought I'm not sure how it will get used in your managed app.

Will Dean