我在C中有一个库,我想用它来使用C#.
从我从互联网上收集的内容来看,一个想法是将它包装在C++ DLL中,然后用DllImport包装它.
问题是我想调用的函数有一个相当讨厌的参数集:包括对函数的引用(将是一个.NET函数),以及一些数组(一些写,一些读).
int lmdif(int (*fcn)(int, int, double*, double*, int*),
int m, int n, double* x, double ftol, double xtol, double gtol,
int maxfev, double epsfcn, double factor)
Run Code Online (Sandbox Code Playgroud)
鉴于这样的界面,我应该注意哪些恶意?(还有解决方案,请)
你为什么不......
- 用C#重写?我开始了,但它已经从FORTRAN机器翻译了,我不太喜欢编码我无法理解的东西.
- 使用现有的.NET库?我现在正在尝试,但结果并不完全相同
- 用C++重新编译?我正在考虑它,但它看起来很痛苦
根据记录,我获得了大部分方法来实现此功能,然后最终将适当的 C 文件拉入 C++ 项目(因为我正在与我根本不需要的代码中的兼容性问题作斗争)。
以下是我一路上学到的一些技巧,可能对遇到这个问题的人有所帮助:
double*在 C 中,指向 double ( ) 的指针和 double 数组 ( )之间没有区别double*。当您进行互操作时,您需要能够消除歧义。我需要传递 的数组double,因此签名可能如下所示:
[DllImport(@"PathToDll")]
public static extern Foo(
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)[In] double[] x,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)[Out] double[] y,
int x_size,
int y_size)
Run Code Online (Sandbox Code Playgroud)
C 需要数组长度的额外信息,您必须将其作为单独的参数传递。编组还需要知道该大小在哪里,因此您指定SizeParamIndex,它指示参数列表中大小参数的从零开始的索引。
您还可以指定数组要传递的方向。在此示例中,x被传递到 Foo,它“发回” y。
您实际上不需要了解这意味着什么的更详细的细节(换句话说,我不需要),您只需要知道存在不同的调用约定,并且它们需要在双方上匹配。C# 默认为StdCall,C 默认为Cdecl。这意味着您只需要显式指定调用约定(如果它与您使用的哪一方的默认调用约定不同)。
在回调的情况下,这尤其棘手。如果我们将回调传递给Cfrom C#,我们打算使用 来调用该回调StdCall,但是当我们传递它时,我们使用的是Cdecl。这会产生以下签名(有关上下文,请参阅此问题):
//=======C-code======
//type signature of callback function
typedef int (__stdcall *FuncCallBack)(int, int);
void SetWrappedCallback(FuncCallBack); //here default = __cdecl
//======C# code======
public delegate int FuncCallBack(int a, int b); // here default = StdCall
[DllImport(@"PathToDll", CallingConvention = CallingConvention.Cdecl)]
private static extern void SetWrappedCallback(FuncCallBack func);
Run Code Online (Sandbox Code Playgroud)
显而易见,但对我来说并不是立即显而易见:
int MyFunc(int a, int b)
{
return a * b;
}
//...
FuncCallBack ptr = new FuncCallBack(MyFunc);
SetWrappedCallback(ptr);
Run Code Online (Sandbox Code Playgroud)
您想要从 C++ 项目公开的任何函数(待DllImport编辑)都需要在ModDef.def文件中说明,其内容如下所示:
LIBRARY MyLibName
EXPORTS
SetWrappedCallback @1
Run Code Online (Sandbox Code Playgroud)
如果您想在 C++ 中使用 C 函数,则必须将它们声明为extern "C". 如果您要包含 C 函数的头文件,请像这样:
extern "C" {
#include "C_declarations.h"
}
Run Code Online (Sandbox Code Playgroud)
为了避免编译错误,我必须做的另一件事是为每个“C”文件Right-click -> Properties -> C/C++ -> Precompiled Headers设置Precompiled header为“不使用预编译头”。
| 归档时间: |
|
| 查看次数: |
5131 次 |
| 最近记录: |