C#-C 进程间通信

Posted

技术标签:

【中文标题】C#-C 进程间通信【英文标题】:C#-C Interprocess communication 【发布时间】:2011-03-01 03:44:44 【问题描述】:

好的,所以我有一个用 c# 编写的程序,它启动了一个运行另一个程序的进程,这个程序是用 C 编写的。现在我已经解决了从 C 程序重定向标准输出并在 C# 端拾取它的问题,并且效果很好。但是我需要一种方法让 C# 程序告诉 C 程序结束。我的第一个想法是,由于 C 程序最初是通过测试 conio.h 中的 kbhit 来控制的,所以我可以重定向 stdin 并流写入一些东西,它会检测到一个键击,但这不起作用(我猜是 kbhit不适合重定向),所以我四处搜索,很多人一直建议 PeekConsoleInput(),因为我是专门为 Windows 编写这个程序(实际上是特定的机器)。所以我将 c 程序更改为使用 PeekConsoleInput 而不是 kbhit 并重定向标准输入,但它仍然没有检测到我发送给它的任何内容。例如在 C...

#include <stdio.h>
#include <windows.h>
int main() 
    BOOL peeked = 0;
    HANDLE input_handle = GetStdHandle(STD_INPUT_HANDLE);
    DWORD events = 0;      // how many events took place
    INPUT_RECORD input_record;  // a record of input events
    DWORD input_size = 1;    // how many characters to read
    printf("Hello World\n");
    fflush(stdout);
    while (1) 
        FlushConsoleInputBuffer(input_handle);
        peeked = PeekConsoleInput(input_handle, &input_record, input_size, &events);
        if (peeked && events>0) 
            break;
        
    
    printf("Hit Detected\n");
    return 0;

还有一个来自 C# 代码的 sn-p...

ProcessStartInfo info = new ProcessStartInfo("CTest.exe");
info.CreateNoWindow = true;
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
info.RedirectStandardInput = true;
pro = new Process();
pro.StartInfo = info;


pro.Start();
StreamWriter sw = pro.StandardInput;
sw.AutoFlush = true;
pro.BeginOutputReadLine();
pro.OutputDataReceived += new DataReceivedEventHandler(pro_OutputDataReceived);
sw.WriteLine("Q");

C 程序自行执行,但是当 C# 程序运行它时,它永远不会达到“Hit Detected”。我还将 s.WriteLine("Q") 延迟了几秒钟,看看是否是时间问题,它仍然没有工作。

理想情况下,我希望 C 程序能够自己运行,或者由 C# 程序运行,但即使你不能自己运行 C 程序,也不会那么糟糕。

我尝试过的一件事是让 C# 程序只写一个文件,让 C 程序只用 fopen 轮询,直到它成功打开它,但这个 C 程序的主要目的之一是写入数据到磁盘的速度非常快,我担心轮询磁盘可能会减慢速度。

另一件有点奏效的事情就是关闭进程。但这很麻烦,因为 C 程序需要在关闭之前清理一些东西(除非有某种方法可以让 C 程序在关闭之前执行一些代码,但我不确定你是否可以这样做)。

完成此操作的其他方法是套接字、管道等,但对于一位信号来说似乎需要做很多工作。此外,我能找到的所有关于如何做到这一点的示例似乎都是如何让两个 C# 程序进行通信或如何让两个 C 程序进行通信,而不是两种不同语言的两个不同程序。

那么,首先,有什么方法可以让这个 stdin 重定向工作正常吗?如果没有,告诉 C 进程它需要退出的最简单的解决方案是什么?

【问题讨论】:

您的 C 程序在等待结束时在做什么?是处理数据吗?它是否从标准输入读取? C 程序正在通过 USB 从外部设备收集数据,将数据写入磁盘,写入标准输出以了解它正在传输的数据量,并检查它是否应该停止。除了(最初)检查 kbhit 以查看它是否应该停止之外,它对 stdin 没有任何作用。 我应该提到我已经找到了一个解决方法。我添加了一个命令行参数,指定我是否通过 GUI 运行它,如果是这样,它不检查键盘,而是使用访问功能检查文件是否存在,所以当 GUI 想要告诉它时停止,它只是写一个停止文件。如果我不必通过文件进行交流,我会感觉好一点,但我们已经做到了。 【参考方案1】:

我遇到了同样的问题,并且能够使用SendKeys 让它工作。如果您有 WPF 应用程序,只需添加对 System.Windows.Forms 的引用。

对于我使用的进程StartInfo

newProcess.StartInfo.UserShellExecute = false; 
newProcess.StartInfo.CreateNoWindow = false;
newProcess.StartInfo.RedirectStandardInput = false;
newProcess.StartInfo.RedirectStandardOutput = true; 
newProcess.StartInfo.RedirectStatndardError = true; 
newProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
newProcess.OutputDataReceived += new DataReceivedHandler(gotData);

CreatNoWindow设置为false的原因是你可以在Spy++中找到Window。 ProcessWindowStyle.Hidden 在窗口弹出片刻后隐藏窗口。

RedirectStatndardInput 必须为 false,因为我们使用 SendKeys 来模拟隐藏窗口的键盘输入。

使用SendKeys.waitSend("commandENTER");,我能够向使用_kbhit()getc() 输入的控制台应用程序发送命令。

【讨论】:

【参考方案2】:

您是否尝试过查看 C 程序在写入文件时是否以及多快?

还有其他方式(在 Windows 中)进行进程间通信。

    命名管道(类似于 TCP) 内存映射文件(在这里可能是一个不错的选择 - 类似于您的 其他有效的实验) TCP/IP(按照您的建议。)

就 TCP/IP 而言,它不受限于使用相同语言和工具构建的软件。您的 C 程序将是 TCP 服务器,而您的 C# 程序将是 TCP 客户端。如果您知道如何使用任何一种语言执行此操作,您就会得到答案。

【讨论】:

【参考方案3】:

您可以使用 Process 对象来终止生成的进程: (假设 C 程序有一个处理程序在收到“CloseMainWindow()”信号后进行清理)

/// <summary>
/// Close the shelled process, if there is any
/// </summary>
/// <param name="reason">why closing?</param>
public static void shellTerminate(string reason)

    Process p = shelledProcess;

    try
    
        if (p == null)
        
            o3(reason + ". No shelled process.");
        
        else if (p.HasExited)
        
            o3(reason + ". Process has exited already.");
        
        else
        
            //Process is still running.
            //Test to see if the process is hung up.
            if (p.Responding)
            
                //Process was responding; close the main window.
                o3(reason + ". Process is being closed gracefully.");
                if (p.CloseMainWindow())
                
                    //Process was not responding; force the process to close.
                    o3(reason + ". Process is being killed.");
                    p.Kill();
                    p.Close();
                    p = null;
                
            

            if (p != null)
            
                //Process was not responding; force the process to close.
                o3(reason + ". Process is being killed.");
                p.Kill();
            

            p.Close();
        

        if (shellOut != null)
        
            shellOut.Close();
            shellOut = null;
        

        shelledProcess = null;
    
    catch (Exception ex)
    
        o("Exception in shellTerminate: " + ex.Message);
    

【讨论】:

以上是关于C#-C 进程间通信的主要内容,如果未能解决你的问题,请参考以下文章

一起talk C栗子吧(第八十七回:C语言实例--使用管道进行进程间通信概述)

Linux C语言高级编程之使用消息队列实现进程间通信!重点内容!!!

C#-C 进程间通信

在 C 中为多个进程之间的进程间通信创建管道

linux c之通过管道实现兄弟间进程通信:

C/C++ 进程间通信 管道