我可能会让自己感到困惑,但之前没有做过这样的事情,而且一点方向会非常有用。
我试图从C
应用程序调用一些C#
代码。我尝试过使用PInvoke
,但发现它有点棘手。我以为我会尝试做一个C++\CLI
包装器。
有一些复杂的结构具有可变长度的双重数组,PInvoke
很难处理
我已经读了一下如何做到这一点,但我无法弄明白。我发现的大部分内容与包裹C++
而不是C
有关。 C
代码已经在导出其功能,这些功能已经从Java应用程序及其JNA
服务中运行。我有C
代码,标题,库和dll,但宁愿不对现有的任何内容进行更改,以免扰乱其他消费应用程序。调用它的C#
应用程序将是64位,大多数示例都是创建win32库,这有关系吗?
更新:在下面添加代码:
注意:这只是几个函数中的一个函数,可能是最简单的函数,但它们都非常相似。
C HEADER:
typedef struct myStruct_t
{
double prefix[8];
int length;
double array[1];
}
myStruct;
C:
extern "C" __declspec( dllexport ) myStruct *doSomething(const myStruct *input, double a)
{
myStruct *output;
//doSomething
return output;
}
答案 0 :(得分:1)
包装C和C ++之间的区别非常小。您需要创建C ++ / CLI类库。然后,您在托管本机代码的托管C ++ ref类中编写函数。
例如,假设DLL导出此函数:
int sqr(int x)
然后在您的类库中,您将包含头文件:
#include <mynativelibrary.h>
您还需要将导入库提供给链接器。
然后你可以公开这个功能。最简单的方法是将函数包装为ref类的静态方法。例如:
public ref class Class1
{
public:
static int sqr(int x)
{
return ::sqr(x);
}
};
然后,您可以像使用任何其他程序集一样在C#代码中使用此程序集。
答案 1 :(得分:1)
我在VisualStudio 2012中创建了一些项目,它们使用托管代码包装旧的MFC dll。我是这样做的:
请不要忘记为托管C ++代码创建Unittesting。 (我总是忘记...... :))
祝你好运。答案 2 :(得分:1)
如果Java可以通过jna调用你的C代码,那么通过PInvoke应该没有C#的问题。虽然C ++ interop(使用C ++ / Cli)是一种PInvoke(隐式PInvoke),但使用DllImport是显式的PInvoke。
隐式PInvoke非常有用,当您不需要指定如何封送函数参数时,或者在显式调用DllImportAttribute时可以指定的任何其他详细信息,但是您需要创建一个额外的C ++ / CLI Dll。
在这两种方式中,你必须处理marshal本地数据类型到管理数据类型,这是不可避免和痛苦的。
在C#中,结构可以声明为:
[StructLayout(LayoutKind.Sequential)]
public struct myStruct {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
double prefix[] intersects;
public int length;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public double[] array;
}
但是对于该函数,DLLImport无法处理这种情况,因为C#不能为函数返回的非托管指针删除内存,可以在C中创建另一个wrap函数使其使用out参数返回结果,在这种情况下,C#代码是:
[DllImport("...")]
public static extern void doSomething([In, Out] myStruct[] results, myStruct[] input, int len);
或者您可以使用C ++ / CLI互操作,因为它可以处理本机和管理类型,因此调用顺序为:
C#代码使用托管数据类型调用此C ++ / CLI函数:
ManagedmyStruct [] doSomething(ManagedmyStruct []输入,双倍a)
在C ++ / CLI函数domSomething中,它调用本机函数,步骤如下:
ManagedmyStruct [] doSomething(ManagedmyStruct []输入,双倍a) {
//convert the ManagedmyStruct[] input to native type myStruct* input
myStruct ret* = doSomething(input, a);
//convert ret to managed type ManagedmyStruct[] rets
return rets;
}