从 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++ 中挂钩非托管函数一样在 C# 中挂钩托管函数?