开发者

C#-C Interprocess communication

Okay, so I have a program written in c# that starts up a process running another program, this one written in C. Now I already worked out redirecting the stdout from the C program and picking it up on the C# side, and it works great. But I need a way for the C# program to tell the C program to end. My first thought, was that since the C program originally was controlled through testing kbhit from conio.h, that I could just redirect stdin and streamwrite something and it would detect a key hit, but that didn't work (I'm guessing kbhit doesn't lend itself to redirection), so I searched around and a lot of people kept suggesting PeekConsoleInput(), because I'm writing this program exclusively for windows (in fact a specific machine). So I changed the c program to use PeekConsoleInput instead of kbhit and redirected stdin and it still didn't detect anything I sent to it. For example in 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;
}

and a snippet from the C# code...

ProcessStartInfo 开发者_C百科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");

The C program executes by itself, but when the C# program runs it, it never reaches "Hit Detected". I also delayed the s.WriteLine("Q") by a few seconds to see if it was a timing issue and it still didn't work.

Ideally, I wanted the C program to be able to run by itself, or be run by the C# program, but even if you couldn't run the C program by itself, that wouldn't be so bad.

One thing I tried that worked, was to have the C# program just write a file, and have the C program just poll with fopen's until it successfully opens it, but one of the main purposes of this C program is to write to data to disk really fast, and I worry that polling the disk may be slowing it down.

Another thing that kinda worked was just closing the process. But that's messy because the C program needs to clean up some stuff before it closes (unless there's some way to get the C program to execute some code before it shuts down, but I'm not sure if you can do that).

Other ways to get this done would be sockets, pipes, etc. but it seems like a lot of work for just a one bit signal. Also, all the examples I could find about how to do that all seemed to be how to get two C# programs to communicate or how to get two C programs to communicate, never two different programs in two different languages.

So, firstly, is there any way to get this stdin redirection thing working? and if not, what's the easiest solution to tell the C process that it needs to exit?


I ran into the same problem and was able to get it to work using SendKeys. Just add a reference to System.Windows.Forms if you have a WPF app.

For the processes StartInfo I used:

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);

The reason for setting CreatNoWindow to false is that you can find the Window in Spy++. ProcessWindowStyle.Hidden hides the window after it pops up for a brief moment.

RedirectStatndardInput must be false because we are using SendKeys to simulated keyboard input to the hidden window.

Using SendKeys.waitSend("command{ENTER}"); I was able to send a command to the console app that uses _kbhit() and getc() for input.


Have you tried to see if and by how much the C program is faster at writing files?

There are other ways (in Windows) to do interprocess communication.

  1. Named Pipes (similar to TCP)
  2. Memory mapped files (might be a good option here - similar to your other experiment which worked)
  3. TCP/IP (as you've suggested.)

As far as TCP/IP is concerned it is not constrained to works with software build using the same language and tool. Your C program will be the TCP server and your C# program will be the TCP client. If you know how to do this in either of the languages you've got your answer.


You could use the Process object to kill the spawned process: (assuming that the C program has a handler to do its cleanup after receiving the "CloseMainWindow()" signal)

/// <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);
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜