简体   繁体   English

桥接非托管C dll并管理C#dll

[英]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. 该方法使用staticextern关键字声明,并使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM