在单独的控制台和 Windows 应用程序之间传递信息

Posted

技术标签:

【中文标题】在单独的控制台和 Windows 应用程序之间传递信息【英文标题】:Pass informations between separate consoles and windows applications 【发布时间】:2014-07-14 07:31:28 【问题描述】:

我有两个独立的程序,一个是控制台应用程序,另一个是 Windows 应用程序。

我的 Windows 应用程序:

具有图形界面、按钮和其他功能。

其中一个名为“research”的按钮:当我单击它时,我会使用这行代码启动控制台应用程序:

string strResult = ProcessHelper.LaunchProcessWaitForPipedResult("MyExecFile.exe", strArguments, 10 * 60 * 1000, true);   // 10 mins max

我的控制台应用程序:

对目录中的所有现有文件进行查询。

我的问题:

我想在 windows 应用程序上创建一个进度条来显示控制台应用程序的进度。问题是我不知道如何在两个进程之间传递这些信息。唯一的限制是不使用数据库或文件。

【问题讨论】:

你有控制台的源码吗?因为我记得控制台将在最后返回绝对结果......(除非你可以“产生”结果) 有很多 IPC(进程间通信)选项(例如 windows 消息、邮槽、命名管道、共享内存 TCP/IP 套接字……)。为了帮助缩小范围:这两个应用程序是否总是在同一个登录会话中运行? (或者是否需要更复杂的访问控制?) 考虑使用 Namepd 管道在两个应用程序之间共享内存:msdn.microsoft.com/pl-pl/library/bb546085%28v=vs.110%29.aspx 进一步思考:为什么你有两个独立的程序?在 GUI 应用程序中以 background worker(或其他并发方法)执行处理会使事情变得很多 easier。 在我看来这不是将其保留为控制台应用程序的充分理由:最好是可以被其他程序引用的程序集(类库)。公开event,以便调用者可以获取进度更新。 (管理单独的进程一开始并不难,但随着复杂程度的增加会很快变得困难:例如与父进程之间的通信越来越多。) 【参考方案1】:

给定同一用户会话中的两个进程,并希望避免在该会话之外进行任何通信,我会考虑三个选项:

1。使用命名管道。

父进程使用随机名称创建一个命名管道(并通过打开它来确认该名称未被使用)。它将该名称传递给子进程。使用了一个简单的协议,允许孩子发送更新。

有许多挑战需要克服:

获取确保名称唯一正确的逻辑(命名管道名称是全局的)。 确保没有其他进程可以连接(默认命名管道 ACL 限制与会话的连接:这可能就足够了)。 处理不同父进程不支持进度更新的情况。 处理崩溃的孩子或父母。 避免过于聪明地使用通信协议,但要留有增长空间(如果需要的不仅仅是简单的进度条,会发生什么情况?)

2。使用共享内存

在这种情况下,默认情况下,对象的名称是会话本地的。默认情况下,这更安全。

父进程创建了足够多的共享内存(对于简单的进度更新:不多)、互斥体和事件。

然后,父进程与 GUI 同时等待事件发出信号,当它进入互斥体并读取共享内存的内容时。然后它取消设置事件并离开互斥体。

同时发送更新,孩子进入互斥锁,更新和内存并在离开互斥锁之前设置事件。

这里的挑战包括:

定义共享内存的布局。如果没有共享程序集,这很可能容易出错。 避免其他人使用共享内存和同步对象。 .NET 在这里让事情变得更难:在 Win32 中,我将句柄设为可继承,因此无需命名对象(调试除外)并直接传递给子对象。 正确获取共享内存、互斥体和事件的顺序至关重要。内存损坏和更微妙的错误等待任何错误。 使用共享内存处理可变长度数据更加困难,这对于简单的进度计数来说不是问题,但客户总是想要更多。

总结

我可能会首先考虑命名管道(或者如果我想要更大的灵活性,可能会考虑自定义 WMI 类型)。 但是我只会在尝试一切之后才这样做,以避免首先需要多个进程。共享库和其他人的控制台包装器,而我直接使用该库将是一个更容易的选择。

【讨论】:

使用像 WCF 这样的库会发生什么?对于一个简单的进度条,像 WCF 这样的高级库的性能应该会引起很少的问题。但如果性能是一个问题。不应该使用 IPC。 @Aron WCF 可以工作,但是(1)任何人都可以与服务器通信,(2)WCF 是非常多的客户端-服务器 RPC 模式,但这种情况是一方面对信息性的、非关键的数据进行处理并忘记。简短版本:它可以工作,但恕我直言,这不是 IPC 的正确风格。 您的所有批评都是针对特定类型的 WCF 绑定的。使用命名管道绑定应该可以解决这个问题。 @Aron 很有可能——我并没有声称自己是最新的 WCF,我试图避免它和 WS-*,因为大多数好处在大多数情况下都是无关紧要的。但请注意我对 Q 的第一条评论:有许多 IPC 选项可以使用,但 KISS 应始终适用。最后,任何 IPC 都是一个糟糕的选择(见这个答案的最后一句话)。 我绝对同意最后一点。 IPC 在这里完全没有意义和有害。但仅供参考,命名管道是 WCF 附带的原始绑定之一。人们经常忘记 MSMQ 绑定,而是专注于 BasicHttp 和 WS-*。

以上是关于在单独的控制台和 Windows 应用程序之间传递信息的主要内容,如果未能解决你的问题,请参考以下文章

如何在视图控制器之间传递数据 - 不起作用

在单独运行的 Python 脚本之间传递数据

在两个 TableView 之间传递数据

如何在 Windows 上从 C 中的另一个程序启动一个独立程序(在单独的控制台窗口中)?

Angular 8:通过本地服务在单独模块中的组件之间传递数据

asp.net mvc 在视图和控制器之间传递参数