2

さて、私はCで書かれた別のプログラムを実行するプロセスを起動するC#で書かれたプログラムを持っています。これで、CプログラムからstdoutをリダイレクトしてC#側でそれを取得することをすでに解決しました。 . しかし、C# プログラムが C プログラムに終了を伝える方法が必要です。私が最初に考えたのは、C プログラムはもともと conio.h から kbhit をテストすることで制御されていたので、stdin をリダイレクトして何かをストリームライトするだけで、キー ヒットを検出できるということでしたが、それは機能しませんでした (kbhit を推測しています)。リダイレクトには向いていません)、私は周りを検索しましたが、多くの人が PeekConsoleInput() を提案し続けました。そこで、kbhit の代わりに PeekConsoleInput を使用するように c プログラムを変更し、標準入力をリダイレクトしましたが、送信したものはまだ検出されませんでした。たとえば、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#コードからのスニペット...

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# プログラムが実行されると、「ヒット検出」に達することはありません。また、s.WriteLine("Q") を数秒遅らせて、タイミングの問題であり、それでも機能しないかどうかを確認しました。

理想的には、C プログラムを単独で実行できるようにするか、C# プログラムで実行できるようにしたかったのですが、C プログラムを単独で実行できなくても、それほど悪くはありません。

私が試みたものの1つは、C#プログラムにファイルを書き込むだけで、Cプログラムが正常に開くまでfopenでポーリングすることでしたが、このCプログラムの主な目的の1つは、データをディスクに書き込むことです非常に高速で、ディスクをポーリングすると速度が低下するのではないかと心配しています。

ちょっとうまくいったもう1つのことは、プロセスを閉じることでした。しかし、Cプログラムは閉じる前にいくつかのものをクリーンアップする必要があるため、面倒です(シャットダウンする前にCプログラムにコードを実行させる方法がない限り、それができるかどうかはわかりません)。

これを実現する他の方法は、ソケット、パイプなどですが、1 ビットの信号だけでは大変な作業のように思えます。また、それを行う方法について私が見つけたすべての例は、2 つの C# プログラムを通信させる方法、または 2 つの C プログラムを通信させる方法であり、2 つの異なる言語で 2 つの異なるプログラムを使用することはありませんでした。

まず、この stdin リダイレクトを機能させる方法はありますか? そうでない場合、Cプロセスに終了する必要があることを伝える最も簡単な解決策は何ですか?

4

3 に答える 3

1

私は同じ問題に遭遇し、 SendKeysを使用して動作させることができました。System.Windows.FormsWPF アプリがある場合は、への参照を追加するだけです。

私が使用したプロセスについて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);

falseに設定する理由CreatNoWindowは、Spy++ でウィンドウを見つけることができるためです。ProcessWindowStyle.Hiddenウィンドウが一瞬ポップアップした後、ウィンドウを非表示にします。

RedirectStatndardInput非表示ウィンドウへのキーボード入力をシミュレートするために SendKeys を使用しているため、false にする必要があります。

を使用して、入力用のandSendKeys.waitSend("command{ENTER}");を使用するコンソール アプリにコマンドを送信できました。_kbhit()getc()

于 2011-07-14T18:22:45.363 に答える
0

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);
    }
}
于 2012-12-22T18:45:31.207 に答える
0

ファイルの書き込みが C プログラムの方が速いかどうか、またどの程度速いかを調べてみましたか?

プロセス間通信を行う (Windows の) 方法は他にもあります。

  1. 名前付きパイプ (TCP に類似)
  2. メモリマップファイル(ここでは良いオプションかもしれません - うまくいった他の実験と同様です)
  3. TCP/IP(あなたが提案したように。)

TCP/IP に関する限り、同じ言語とツールを使用して構築されたソフトウェアで動作するという制約はありません。C プログラムが TCP サーバーになり、C# プログラムが TCP クライアントになります。いずれかの言語でこれを行う方法を知っていれば、答えが得られます。

于 2011-03-01T03:55:20.900 に答える