简体   繁体   English

通过IPC端口在C#和Visual C ++之间进行通信(或:在Visual C ++ DLL和C#应用程序之间共享类型)

[英]Communicating between C# and Visual C++ over IPC port (OR: Sharing a type between a Visual C++ DLL and a C# application)

I have a DLL written in Visual C++ and an application written in C#. 我有一个用Visual C ++编写的DLL和一个用C#编写的应用程序。 The application that is written in C# already uses IPC between multiple instances of itself so that it only ever runs one instance (it attempts to start an IPC server, and if it can't assumes there's already one running, in which case it sends the command line arguments over IPC to the existing application). 用C#编写的应用程序已经在其多个实例之间使用了IPC,因此它只能运行一个实例(它尝试启动IPC服务器,如果不能假设已经有一个正在运行,则在这种情况下,它将发送IPC到现有应用程序的命令行参数)。

Now I want to send commands from a Visual C++, however, even when I create a type definition in Visual C++ that matches the one in C# (on an implementation level), it rejects the connection because they are fundamentally still two different types (from two different assemblies). 现在,我想从Visual C ++发送命令,但是,即使我在Visual C ++中创建与C#中的类型定义匹配的类型定义(在实现级别上),它也会拒绝连接,因为它们从根本上还是两种不同的类型(从两个不同的程序集)。

I thought about using Reflection in Visual C++ to fetch the type from the C# assembly, but I can't do that because then I'd have to ship the assembly along side the DLL (which defeats the purpose of the DLL being an API to the application). 我曾考虑过在Visual C ++中使用Reflection来从C#程序集中获取类型,但是我不能这样做,因为那样的话,我必须将程序集与DLL一起运送(这违背了DLL作为API的目的。应用程序)。

I'm not sure of any other way I could really do it, other than store the class in yet another DLL and make both the application and the API DLL reference the class in that, but this is also not an ideal solution as I'd like a single API DLL to distribute. 除了将类存储在另一个DLL中并使该应用程序和API DLL都引用该类之外,我不确定是否可以实现此目的,但这并不是理想的解决方案,因为d像要分发的单个API DLL。

Are there any suggestions as to how I can connect over IPC (other forms of communication like TCP are not permitted) to send requests to the application? 关于如何通过IPC连接(不允许其他形式的通信,如TCP)将请求发送到应用程序,有什么建议吗?

The solution was to place the InterProcess class in the API DLL and simply make the C# application use the DLL as a reference to bring in the class. 解决方案是将InterProcess类放置在API DLL中,并使C#应用程序使用DL​​L作为引入该类的引用。

It is also important to note that in order to initialize the shared object correctly, I had to initialize the server side of the sharing in a separate AppDomain and make the C# application a client like so (this is a new version of the previous paste): 同样重要的是要注意,为了正确地初始化共享库,我必须在单独的AppDomain中初始化共享的服务器端,并使C#应用程序成为这样的客户端(这是先前粘贴的新版本) :

try
{
    // Set up an interprocess object which will handle instructions
    // from the client and pass them onto the main Manager object.
    this.m_ServerDomain = AppDomain.CreateDomain("roketpack_server");
    this.m_ServerDomain.DoCallBack(() =>
        {
            // We must give clients the permission to serialize delegates.
            BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider();
            serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

            IpcServerChannel ipc = new IpcServerChannel("roketpack", "roketpack", serverProv);
            ChannelServices.RegisterChannel(ipc, true);

            RemotingConfiguration.RegisterWellKnownServiceType(
                typeof(API.InterProcess),
                "InterProcessManager",
                WellKnownObjectMode.Singleton);
        });

    // Now initialize the object.
    IpcClientChannel client = new IpcClientChannel();
    ChannelServices.RegisterChannel(client, true);
    this.m_InterProcess = (API.InterProcess)Activator.GetObject(
        typeof(API.InterProcess),
        "ipc://" + name + "/InterProcessManager");
    InterProcessHandle.Manager = this;
    this.m_InterProcess.SetCalls(InterProcessHandle.CallURL,
                    InterProcessHandle.IsLatestVersion,
                    InterProcessHandle.RequestUpdate);

    return true;
}
catch (RemotingException)
{
    // The server appears to be already running.  Connect to
    // the channel as a client and send instructions back
    // to the server.
    IpcClientChannel client = new IpcClientChannel();
    ChannelServices.RegisterChannel(client, true);

    API.InterProcess i = (API.InterProcess)Activator.GetObject(
        typeof(API.InterProcess),
        "ipc://" + name + "/InterProcessManager");

    if (i == null)
    {
        Errors.Raise(Errors.ErrorType.ERROR_CAN_NOT_START_OR_CONNECT_TO_IPC);
        return false;
    }

    if (Environment.GetCommandLineArgs().Length > 1)
        i.CallURL(Environment.GetCommandLineArgs()[1]);

    return false;
}

I hope this solution helps someone else :) 我希望这个解决方案可以帮助其他人:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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