简体   繁体   中英

Error in C# Calling DLL C

I want to call a function in C from my C # application. The DDL has several functions which I will present only two. The first initializes the environment and has the following call:

In C:

int  init (context_ptr           p0,
       const int             p1,
       const int             p2,
       const int             p3,
       const double * const  p4,
       const double * const  p5,
       const int             p6,
       const int    * const  p7,
       const double * const  p8,
       const double * const  p9,
       const int             p10,
       const int    * const  p11,
       const int    * const  p12,
       const int             p13,
       const int    * const  p14,
       const int    * const  p15,
       const double * const  p16,
       const double * const  p17);

My code in C#:

[DllImport("DLL", SetLastError=true)]
public static extern int init(
            IntPtr   p0, 
            int      p1,
            int      p2,
            int      p3,
            IntPtr   p4,
            IntPtr   p5,
            int      p6,
            IntPtr   p7,
            IntPtr   p8,
            IntPtr   p9,
            int      p10,
            IntPtr   p11,
            IntPtr   p12,
            int      p13,
            IntPtr   p14,
            IntPtr   p15,
            IntPtr   p16,
            IntPtr   p17);

The second function uses the environment and has the following call in C:

int  do( context_ptr      q0,
     double * const   q1,
     double * const   q2,
const int              q3,
     double * const   q4,
const double * const   q5,
     double * const   q6,
     double * const   q7,
const double * const   q8,
     double * const   q9,
     void   * const   q10);

And in C#:

[DllImport("DLL", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern int do(
            IntPtr   q0,
        ref IntPtr   q1,
        ref IntPtr   q2,
        int          q3,
        ref double   q4,
        ref IntPtr   q5,
        ref IntPtr   q6,
        ref IntPtr   q7,
        ref IntPtr   q8,
        ref IntPtr   q9,
            IntPtr   q10);

The error occurs at runtime when I call the second function: "Attempted to read or write protected memory"

What´s wrong?

The problem is perhaps the second function, because it calls a callback:

Callback C code:

typedef int     callback (const int             evalRequestCode,
                      const int             n,
                      const int             m,
                      const int             nnzJ,
                      const int             nnzH,
                      const double * const  x,
                      const double * const  lambda,
                            double * const  obj,
                            double * const  c,
                            double * const  objGrad,
                            double * const  jac,
                            double * const  hessian,
                            double * const  hessVector,
                            void   *        userParams);

And my code C#:

    public static int Callback(
        int evalRequestCode,
        int n,
        int m,
        int nnzJ,
        int nnzH,
        ref double[] x,
        ref double[] lambda,
        ref double obj,
        ref double[] c,
        ref double objGrad,
        ref double jac,
        ref double[] hessian,
        ref double[] hessVector,
        IntPtr ptrParamss
        )

Any kind of help is welcome!

Those double * and int * parameters should be ref double and ref int on the C# side.

Very likely what's causing your problem is that you're passing an IntPtr and everything works for a while. Then the GC runs and moves things around and all of a sudden that pointer is referencing memory that's no longer used (or, worse, is being used by something else).

To prevent that, you need to marshal those things as arrays, like this:

public static extern int do(
        IntPtr   q0,
    [MarshalAs(UnmanagedType.LPArray)] double[] q1,
    [MarshalAs(UnmanagedType.LPArray)] double[] q2,
    etc...);

That pins the array in memory so that the garbage collector won't move it. Don't worry about performance. The array isn't copied. A pointer is passed to the pinned memory location.

It's hard to be sure, of course, because you don't show the C# code that's actually calling the function.

By using a DLL C / C + + calling convention is 'CallingConvention.StdCall'. However, the callback is invoked by default DLL has 'CallingConvention.Cdec'.

Thus, the delegate should be

in C #:

[UnmanagedFunctionPointer (CallingConvention.Cdecl)] public delegate void CallbackParams ();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM