我有一个支持C插件/驱动程序的第三方Windows应用程序(请参阅下面的规范),一旦初始化,它将成为被动数据接收器。现在我找到了一个C#包来进行数据收集和Pushing。这里唯一缺少的是C dll和C#dll之间的桥梁。
数据流如下:当应用程序启动时,它会加载并调用包含多个导出函数(包括init函数)的C dll。在这个init函数中,我喜欢建立对C#的调用来设置一些网络连接并准备传入数据。完成后,根据驱动程序规范,C#dll将收集数据并将其传输到接收驱动程序。为了适应这种情况,我有两个想法(你可以想出更多):
1)用C ++ / Cli包装C#并从驱动程序中调用暴露的C#类方法。用gcroot声明一个对象,然后用gcnew实例化它然后调用方法。尝试过,我得到了stackoverflowexception。我是这种混合模式编程的新手,无法弄清楚为什么会发生这种情况。
2)以某种方式包装C dll(比如使用C ++ / Cli导入C函数然后与C#数据流交互)可以从C#调用。做这个的最好方式是什么?
我已经完成了一些阅读,看起来C ++ / Cli似乎很容易,但我对其他不那么复杂的选项持开放态度。如果我选择C ++ / Cli或您建议的任何方式,我必须添加/修改哪些项目设置才能使其正常工作?
由于我是新手解决此类问题,因此任何样本或相关链接都是有帮助的。如果你能证明事情是如何运作的,那么我感谢你。
这是引用的骨架C#dll的一部分(其他方法被省略):
公共类客户端 {
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();
}
}
这是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
答案 0 :(得分:0)
要在外部DLL中调用C函数,您可以使用已经提到的C ++ / CLI,或者使用P / Invoke(平台调用)。
使用P / Invoke,您可以在C#程序集中定义static 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类型:这是一种黑色艺术!如果您访问pinvoke.net,您可以看到Windows API的翻译方式,这可能有所帮助。在网上搜索“pinvoke”也应该提供一些有用的资源。