桥接非托管C dll和托管C#dll

桥接非托管C dll和托管C#dll,c#,c,dll,interop,wrapper,C#,C,Dll,Interop,Wrapper,我有一个第三方Windows应用程序,它支持一个C插件/驱动程序(见下面的规范),一旦初始化,它就是一个被动数据接收器。现在我发现了一个C#包,它负责数据收集和推送。这里唯一缺少的是C dll和C#dll之间的桥梁 数据流是这样的:当应用程序启动时,它加载并调用包含几个导出函数(包括init函数)的C dll。在这个init函数中,我喜欢建立对C#的调用,以建立一些网络连接,并为传入数据做准备。完成后,根据驱动程序规范,C#dll将收集数据并将其传输到接收驱动程序。为了适应这一点,我有两个想法(

我有一个第三方Windows应用程序,它支持一个C插件/驱动程序(见下面的规范),一旦初始化,它就是一个被动数据接收器。现在我发现了一个C#包,它负责数据收集和推送。这里唯一缺少的是C dll和C#dll之间的桥梁

数据流是这样的:当应用程序启动时,它加载并调用包含几个导出函数(包括init函数)的C dll。在这个init函数中,我喜欢建立对C#的调用,以建立一些网络连接,并为传入数据做准备。完成后,根据驱动程序规范,C#dll将收集数据并将其传输到接收驱动程序。为了适应这一点,我有两个想法(你可能会提出更多):

1) 使用C++/Cli包装C#,并从驱动程序中调用expose C#like方法。用gcroot声明一个对象,然后用gcnew实例化它,然后调用该方法。我试过了,结果我得了stackoverflowexception。我不熟悉这种混合模式编程,不明白为什么会发生这种情况

2) 以某种方式包装C dll(如使用C++/Cli导入C函数,然后与C#data streamer交互),以便从C#调用。最好的方法是什么

我读过一些书,看起来C++/Cli是一种简单的方法,但我也愿意接受其他不太复杂的选择。我必须添加/修改哪些项目设置才能使其正常工作?我应该选择C++/Cli还是您建议的任何方式

由于我是处理此类问题的新手,所以任何示例或相关链接都会有所帮助。因此,如果你能演示一下事情是如何以这种或那种方式运作的,我将不胜感激

下面是引用的一段骨架C#dll(省略了其他方法):

公共类客户端 {


要在外部DLL中调用C函数,可以使用前面提到的C++/CLI,或者使用p/Invoke(平台调用)

使用p/Invoke,您可以在C#程序集中定义一个
静态extern
方法,然后使用适当的属性对其进行修饰。之后,您可以按照任何其他C#方法调用该方法,.NET Framework管道将处理DLL的加载和方法参数的来回编组

例如:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, uint pvParam, uint fWinIni);
该方法用
static
extern
关键字声明,并用
DllImport
属性修饰,该属性标识包含C函数的DLL。这通常是您需要的最小值


最困难的部分是确定哪些C类型映射到方法参数和返回类型的.NET类型:这有点像黑魔法!如果您访问,您可以看到Windows API是如何翻译的,这可能会有所帮助。在web上搜索“pinvoke”也应该提供一些有用的资源。

C++/CLI使得从托管程序调用C代码很容易。但是这不是你想要做的,你正试图去相反的方向。直到CLR被加载和初始化之前,你无法得到任何地方,C++ C++非常重要,使它不那么痛苦。@ Hans Passant。你说得对。你建议在C++中包装C DLL?我有两个选择:1)C DLL有它的规格,2)数据流是C语言包。谢谢,Steven Rands!谢谢,Steven Rands!正如我在我的描述中提到的,我的应用程序将加载其中的inDit函数是我想要用来启动数据ST的C DLL。在C#中通过调用其连接方法进行扩孔,而不是相反。我尝试了几种方法来包装C#,使用C++/Cli、Robert Giesecke的unmanagedexport包等,但没有成功。您在回答中提到了P/Invoke。我相信SWIG可以使用P/Invoke机制生成C#代码。但这不是为了公开C函数以调用b吗y C#,不是相反?我看错了吗?@双梁啊,我现在明白你的意思了:你想从C应用程序调用C#代码,而不是相反。在这种情况下,P/Invoke不会有帮助。答案(从C调用C#)列出了一些可能的选项。
//APIs
#ifdef __cplusplus
extern "C"{
#endif

#define DLL __declspec(dllexport)

////////////////////////////////////////////////////////////////////////////
// Initialization: do some prep for receiving data from C#
// params:
//      hWnd            handle
//      Msg             message
//      nWorkMode       work mode
// return:
//       1              true    
//      -1              false
DLL int Init(HWND hWnd, UINT Msg, int nWorkMode);


// Quitting and closing
// Param:
//      hWnd            same handle as Init
//  return:
//       1              true    
//      -1              fals
DLL int Quit(HWND hWnd);

#ifdef __cplusplus
}
#endif
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, uint pvParam, uint fWinIni);