0

我想从我的 C# 应用程序中调用 C 中的函数。DDL 有几个功能,我将只介绍其中两个。第一个初始化环境并具有以下调用:

在 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);

我在 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);

第二个函数使用环境并在 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);

在 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);

当我调用第二个函数时,在运行时发生错误:“尝试读取或写入受保护的内存”

怎么了?

问题可能出在第二个函数上,因为它调用了回调:

回调 C 代码:

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);

我的代码 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
        )

欢迎任何形式的帮助!

4

2 回答 2

2

这些double *int *参数应该在 C# 端ref doubleref int

很可能导致您出现问题的原因是您正在通过一个IntPtr并且一切正常工作了一段时间。然后 GC 运行并四处移动,突然间该指针正在引用不再使用的内存(或者,更糟糕的是,正在被其他东西使用)。

为了防止这种情况,您需要将这些东西编组为数组,如下所示:

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

这会将数组固定在内存中,这样垃圾收集器就不会移动它。不用担心性能。数组没有被复制。一个指针被传递到固定的内存位置。

当然,这很难确定,因为您没有显示实际调用该函数的 C# 代码。

于 2013-03-30T04:04:05.100 回答
0

通过使用 DLL C/C++ 调用约定是'CallingConvention.StdCall'。但是,默认情况下调用回调 DLL 具有“CallingConvention.Cdec”。

因此,代表应该是

在 C# 中:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 公共委托 void CallbackParams();

于 2013-04-01T21:53:16.797 回答