从 C# 获取非托管 C++ 函数

Posted

技术标签:

【中文标题】从 C# 获取非托管 C++ 函数【英文标题】:Getting at unmanaged C++ functions from C# 【发布时间】:2009-03-02 23:20:56 【问题描述】:

我有一些权威的 ANSI 标准 C 代码。这意味着虽然我有源代码,但我不能翻译成另一种语言,也不能修改调用参数,因为这些操作会使权限失效。有超过 150 种功能。

我可以进行附带更改,例如将文件名从 .C 更改为 .CPP,以便使用 Visual Studio 2009 的 C++ 编译器进行编译,我已经这样做了。也可以添加编译器指令等。如有必要,我还可以通过包装层。

另一个限制是我的公司希望我在任何 C# 代码中使用 unsafe 关键字。

我需要从 C# 程序中获取这些函数。

典型的 C/C++ 函数如下所示: double SomeFunction(double a, double[3] vec, double[3][3] mat); 数组内容有时输入,有时输出,很少同时输入。

我首先尝试制作一个非托管 DLL(带有标记为 Extern C 的函数)。只有简单参数(int、double)的函数运行良好,但我无法确定如何编组数组。 (其实我确实找到了一些示例代码,但是复制150次是极其复杂和不合理的。)

然后我在同一个解决方案中尝试了两个项目,一个在 C++ 中,另一个在 C# 中。在 C++ 项目中,我创建了一个托管函数,它只调用了标记为非托管的原始函数。这是非常干净和简单的,同样,简单的参数也很好用。但是对于数组,我找不到如何使参数类型跨 C# 到 C++ 边界匹配:<i> Argument '2': cannot convert from 'double[]' to 'double*'</i> (如上所述,我不能使用 unsafe 来获取指针)。

当然,我想做的事情一定是可能的。 获得这些功能的最佳方法是什么? (使用上述函数的示例代码真的很酷。)

【问题讨论】:

【参考方案1】:

示例 C/C++ 实现:

extern "C" __declspec(dllexport)
double SomeFunction(double a, double vec[3], double mat[3][3]) 
  double sum = a;
  for (int ix = 0; ix < 3; ++ix) 
    sum += vec[ix];
    for (int iy = 0; iy < 3; ++iy) 
      sum += mat[ix][iy];
    
  
  return sum;

示例 C# 用法:

private void Form1_Load(object sender, EventArgs e) 
  double[] vec = new double[3];
  double[,] mat = new double[3, 3];
  for (int ix = 0; ix < 3; ++ix) 
    vec[ix] = ix;
    for (int iy = 0; iy < 3; ++iy) 
      mat[ix, iy] = (ix + 1) * iy;
    
  
  double sum = SomeFunction(1, vec, mat);

[System.Runtime.InteropServices.DllImport("cpptemp8.dll")]
private static extern double SomeFunction(double a, double[] vec, double[,] mat);

【讨论】:

啊,谢谢!这个问题的关键在于,在 C++ 中,数组被声明为 double[][],而在 C# 中则被声明为 double[,]。前者虽然是合法的 C# 语法,但并不代表同一个内部组织。没有关键的洞察力,它就行不通。【参考方案2】:

如果您无法使用 extern 和 P/Invoke 解决方案,那么包装器可能是您的最佳选择。创建一个同时使用托管和非托管代码的托管 C++ DLL。向这个 DLL 添加一个 .NET 类,它只是对 C DLL 中的函数的一个薄包装。您的 C# 代码可以调用 C++ .NET 类,该类将依次转发 C 函数。

这样您可以自己编写 .NET 和非托管代码之间的转换,而不是依赖运行时为您完成。

【讨论】:

【参考方案3】:

使用 swig,它会为你生成 pinvoke

【讨论】:

以上是关于从 C# 获取非托管 C++ 函数的主要内容,如果未能解决你的问题,请参考以下文章

如何从非托管 C++ 代码获取结构化列表值到 C#?

从 C++ 非托管 dll 传递 C# 函数

未导出成员函数时,从 C# 调用 C++ 本机/非托管成员函数

有没有办法像在 C++ 中挂钩非托管函数一样在 C# 中挂钩托管函数?

有没有办法像在 C++ 中挂钩非托管函数一样在 C# 中挂钩托管函数?

从 C# 线程调用非托管代码