桥接非托管C dll和托管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(省略了其他方法): 公共类客户端 {桥接非托管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将收集数据并将其传输到接收驱动程序。为了适应这一点,我有两个想法(
要在外部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);