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.