【问题标题】:Handle events from another application处理来自另一个应用程序的事件
【发布时间】:2014-05-13 09:26:54
【问题描述】:

你好

问题很简单,但答案似乎五花八门,而且很不清楚。

我如何在应用 A 中处理应用 B 发送的事件,以及如何在 B 中实现这些事件?知道 B 不知道 A 的存在。 p>

假设 B 是一个“类批处理”类型的程序,在后面做事,没有任何图形显示,而 A 是一个不错的 GUI(双关语),应该写消息 B通过对话或其他方式发送给他。

我找到了有趣的答案(例如this onethis one),但实际上没有一个答案可以用 C# 的示例来回答;充其量,它们会重定向到一些外部工具。

我听说这是 C# 中的一个问题,但最后,有没有一种干净的方法可以做到这一点?谢谢。

如果这可以缓解问题,假设 A 启动 B(使用 Process 或其他东西),知道 B 也可以单独启动(在这种情况下,我不需要整个事件处理)。

【问题讨论】:

  • 您是在谈论连接到另一个应用程序吗?还是仅限于将消息从一个应用程序发送到第二个应用程序?
  • A只需要接收B的消息,仅此而已。

标签: c# process event-handling


【解决方案1】:

您可以使用MemoryMappedFileMutexEventWaitHandle 的组合来管理进程之间的这种情况。

下面的例子展示了它是如何工作的。在实际代码中,producer() 方法与consumer() 方法在不同的应用程序中,但这用于说明实现:

using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        void run()
        {
            Task.Run(() => consumer());
            Task.Run(() => producer());

            Console.WriteLine("Press <ENTER> to stop.");
            Console.ReadLine();
        }

        static void producer()
        {
            using (var mmf = MemoryMappedFile.CreateOrOpen("MyMapName", 1024))
            using (var view = mmf.CreateViewStream())
            {
                var writer = new BinaryWriter(view);
                var signal = new EventWaitHandle(false, EventResetMode.AutoReset, "MyEventName");
                var mutex = new Mutex(false, "MyMutex");

                for (int i = 0; i < 100; ++i)
                {
                    string message = "Message #" + i;

                    mutex.WaitOne();
                    writer.BaseStream.Position = 0;
                    writer.Write(message);
                    signal.Set();
                    mutex.ReleaseMutex();

                    Thread.Sleep(1000);
                }
            }
        }

        static void consumer()
        {
            using (var mmf = MemoryMappedFile.CreateOrOpen("MyMapName", 1024))
            using (var view = mmf.CreateViewStream())
            {
                var reader = new BinaryReader(view);
                var signal = new EventWaitHandle(false, EventResetMode.AutoReset, "MyEventName");
                var mutex = new Mutex(false, "MyMutex");

                while (true)
                {
                    signal.WaitOne();
                    mutex.WaitOne();
                    reader.BaseStream.Position = 0;
                    var message = reader.ReadString();
                    Console.WriteLine("Received message: " + message);
                    mutex.ReleaseMutex();
                }
            }
        }

        static void Main()
        {
            new Program().run();
        }
    }
}

重要提示:此实现不使用队列,因此如果消费者在新消息到达之前未对其进行处理,则可能会错过消息。

如果您不能错过任何消息,则必须改用某种排队实现,例如MSMQ

但是,您也可以考虑使用Windows Communications Foundation,它允许您在另一个进程中调用远程方法 - 但这可能需要比您想要的更多的进程之间的耦合。

最后,另一种可能性是使用Named Pipe。我实际上认为这可能是最适合您的解决方案。

这里有一个 Microsoft 示例显示使用命名管道的服务器和客户端 IPC:http://msdn.microsoft.com/en-us/library/bb546085%28v=vs.110%29.aspx

【讨论】:

  • 乍一看,我喜欢这样,它很聪明。我要试试。
  • 它有点简单,并且存在您可能错过事件的主要缺点,但如果这不是问题,它可能是您的最简单解决方案。跨度>
  • 我唯一的目标是通知用户我的后台操作的状态,如果他使用 GUI 应用程序启动它。丢失一条消息,我想,没什么大不了的,因为如果消费者没有足够的时间来显示它,用户可能没有时间阅读它:p
  • 我有一个问题:如果我在没有消费者进程的情况下启动我的生产者进程,它不会产生关于未收到信号或其他什么的意外问题吗?
  • @Kilazur 不,这些消息将被忽略(您可以通过在我的示例程序中注释掉 Task.Run(() =&gt; consumer()); 来测试这一点。)
【解决方案2】:

取决于您的场景会变得多么复杂。 您可以使用进程间通信,甚至可以使用两个应用程序写入/读取的一些简单文件(或数据库表)(您需要同步对它的访问)。

【讨论】:

  • 哦,场景再简单不过了。在理想情况下,B 有一个属性public string Message,在设置时会触发 OnMessageChanged 事件。
  • 好的,但是您打算如何在应用 A 中订阅应用 B 触发的事件?据我所知,你不能。
  • 我做了,他的例子看起来很棒,我可能会使用它。虽然它没有按我的意愿工作,但我想没有办法做到这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多