[英]Bridging unmanaged C dll and managed C# dll
I have a third-party Windows app that supports a C plugin/driver (see spec below) to be a passive data receiver once initialized. 我有一个支持C插件/驱动程序的第三方Windows应用程序(请参阅下面的规范),一旦初始化,它就是一个被动数据接收器。 Now I found a C# package that does the data gathering and Pushing.
现在我找到了一个C#包来进行数据收集和Pushing。 The only missing piece here is a bridge between the C dll and the C# dll.
这里唯一缺少的是C dll和C#dll之间的桥梁。
The data flow is like this: When the app is launched, it loads and calls the C dll which contains several exported functions including an init function. 数据流如下所示:当应用程序启动时,它会加载并调用包含多个导出函数(包括init函数)的C dll。 In this init function, I like to establish a call to the C# to setup some network connection and prepare for incoming data.
在这个init函数中,我喜欢建立对C#的调用来设置一些网络连接并准备传入数据。 Once that done, according to the driver spec, the C# dll will gather data and stream it to the receiving driver.
完成后,根据驱动程序规范,C#dll将收集数据并将其传输到接收驱动程序。 To accommodate this, I have two thoughts (you may come up with more):
为了适应这种情况,我有两个想法(你可以想出更多):
1) to wrap the C# with C++/Cli and call the expose C#-like methods from the driver. 1)用C ++ / Cli包装C#并从驱动程序中调用暴露的C#类方法。 Declare an object with gcroot, then instantiate it with gcnew then call the method(s).
用gcroot声明一个对象,然后用gcnew实例化它然后调用方法。 Tried that and I got stackoverflowexception.
尝试过,我得到了stackoverflowexception。 I am new to this mix-mode programming and can't figure out why that happened.
我是这种混合模式编程的新手,无法弄清楚为什么会发生这种情况。
2) to wrap the C dll in some way (like using C++/Cli to import the C functions then interact with the C# data streamer) to be callable from C#. 2)以某种方式包装C dll(比如使用C ++ / Cli导入C函数然后与C#数据流交互)可以从C#调用。 What is the best way to do this?
做这个的最好方式是什么?
I have done some reading and it seems C++/Cli is the easy route but I am open to other not so complicated options as well. 我已经做了一些阅读,看起来C ++ / Cli似乎很容易,但我对其他不那么复杂的选项持开放态度。 What are the project settings I have to add/modify to make it work should I choose C++/Cli or any way you suggest?
如果我选择C ++ / Cli或您建议的任何方式,我必须添加/修改哪些项目设置才能使其正常工作?
As I am new to tackle this kind of problem, any samples or related links are helpful. 由于我是新手来处理这类问题,所以任何样本或相关链接都是有用的。 So I appreciate if you could demonstrate how things work one way or the other.
如果你能证明事情是如何运作的,那么我感谢你。
Here is piece of the skeletal C# dll referenced (other methods are omitted): 这是引用的骨架C#dll的一部分(其他方法被省略):
public class Client { 公共类客户{
public Client()
{
//reset();
}
public void test()
{
Console.WriteLine("test");
}
/// <summary>
/// Connect connects the Client to the server.
/// Address string has the form host:port.
/// </summary>
public void Connect(string address)
{
Disconnect();
// validate address
int sep = address.IndexOf(':');
if (sep < 0)
{
throw new ArgumentException("Invalid network address");
}
// set host and port
host = address.Substring(0, sep);
toPort(ref port, address.Substring(sep + 1));
// connect
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(host, port);
rw.Set(socket, CLIENT_DEFAULT_BUFFER_SIZE);
}
/// <summary>
/// Disconnect disconnects the Client from the server.
/// </summary>
public void Disconnect()
{
backlog.Clear();
try
{
if (Connected)
{
write("close");
}
}
catch (Exception e)
{
}
//reset();
//rw.Close();
}
} }
Here is the skeletal spec of the C dll: 这是C dll的骨架规格:
//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
To call C functions in an external DLL, you can use C++/CLI as you've already mentioned, or use P/Invoke (Platform Invoke). 要在外部DLL中调用C函数,可以使用已经提到的C ++ / CLI,或使用P / Invoke(平台调用)。
With P/Invoke, you define a static extern
method in your C# assembly then decorate it with appropriate attributes. 使用P / Invoke,您可以在C#程序集中定义
static extern
方法,然后使用适当的属性对其进行装饰。 After that, you can call the method as per any other C# method, and the .NET Framework plumbing will handle the loading of the DLL and marshalling the method parameters back and forth. 之后,您可以按照任何其他C#方法调用该方法,.NET Framework管道将处理DLL的加载并来回编组方法参数。
For example: 例如:
[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);
The method is declared with the static
and extern
keywords, and decorated with the DllImport
attribute which identifies the DLL that contains the C function. 该方法使用
static
和extern
关键字声明,并使用DllImport
属性进行修饰,该属性标识包含C函数的DLL。 That's generally the minimum you will need. 这通常是您需要的最低限度。
The hardest part is determining which C types map to which .NET types for the method parameters and return type: this is a bit of a black art! 最难的部分是确定哪些C类型映射到方法参数和返回类型的.NET类型:这是一个黑色艺术! If you visit pinvoke.net you can see how the Windows APIs have been translated, which may help.
如果您访问pinvoke.net,您可以看到Windows API的翻译方式,这可能有所帮助。 Searching the web for "pinvoke" should also turn up a number of useful resources.
在网上搜索“pinvoke”也应该提供一些有用的资源。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.