4

プログラムのインスタンスを生成し、一部のデータをその STDIN にパイプしてから、C++ を使用してプロセスの出力を読み取る関数を作成しようとしています。私はここにある MSDN の例を見てきましたが、これはややこしいものでした。この例を使用しようとすると、厄介なエラー コードが表示され、機能しません。

    HANDLE hWriteOUT, hReadOUT, hWriteIN, hReadIN;
    SECURITY_ATTRIBUTES saPipe = {0};
    PROCESS_INFORMATION procInfo = {0};
    STARTUPINFO procSi;
    DWORD dwWritten, dwRead;
    char buf[512];

    saPipe.nLength = sizeof(SECURITY_ATTRIBUTES);
    saPipe.bInheritHandle = TRUE;
    saPipe.lpSecurityDescriptor= NULL;
    CreatePipe(&hReadOUT, &hWriteOUT, &saPipe, 0);
    SetHandleInformation(hReadOUT, HANDLE_FLAG_INHERIT, 0);
    CreatePipe(&hReadIN, &hWriteIN, &saPipe, 0);
    SetHandleInformation(hReadIN, HANDLE_FLAG_INHERIT, 0);

    ZeroMemory(&procSi, sizeof(STARTUPINFO));
    procSi.cb = sizeof(STARTUPINFO);
    procSi.hStdError = hWriteOUT;
    procSi.hStdOutput = hWriteOUT;
    procSi.hStdInput = hReadIN;
    procSi.dwFlags |= STARTF_USESTDHANDLES;

    CreateProcess(NULL, "cmd", NULL, NULL, TRUE, 0, NULL, NULL, &procSi, &procInfo);
    //Gives me an error code of 18 but returns a 1 when a 0 indicates failure.

    WriteFile(hWriteIN, "notepad", sizeof("notepad"), &dwWritten, NULL);
    cout << GetLastError();  //This gives me error code 18 (ERROR_NO_MORE_FILES)
    ReadFile(hReadOUT, buf, 512, &dwRead, NULL);
    cout << buf;  //This prints "Microsoft Windows [version 6.1.7601]
    CloseHandle(hWriteIN);

このコードは、文字列 "notepad" を cmd.exe にパイプすることはできませんが、コマンド シェルの起動には成功しています。タスク マネージャーを見ると、コマンド プロンプトがいくつか表示されていますが、メモ帳は表示されていません。さらに、ReadFile()関数は機能しているように見えた唯一のものですが、パイプされたプロセス (生成されるはずだったメモ帳) からの読み取りではなく、CMD からの読み取りです。さらに悪いことに、読み取った最初の行以外はすべて切り捨てられます。(CMD は "Microsoft Windows....\n Copyright...\n C:\Users\Foo>...\n" を出力しますが、`ReadFile() は最初の行のみを取得します)

4

2 に答える 2

5

コードは期待どおりに動作しています。あなたが誤解しているように見えることがいくつかあります:

1) cmd.exe でコマンドを実行する場合は、コマンドの最後に ENTER ("\n") を送信する必要があります。通常は、 CreateProcessで実行するコマンドを指定することをお勧めします。たとえば、「cmd」だけでなく、「cmd /c notepad」をコマンド ラインとして指定することもできます。

2) パイプを cmd.exe プロセスの標準入力と標準出力に接続したので、もちろんそのプロセスからの出力が表示されます。cmd.exe からの出力を見たくない場合は、実行しないでください。必要なアプリケーションを直接実行します。たとえば、実行するコマンド ラインとして「メモ帳」を指定できます。

3) パイプから読み取る場合、ReadFileは一度に 1 つのデータ ブロックしか返さないため、ループで呼び出す必要があります。

4) メモ帳は GUI プロセスであるため、stdin や stdout は使用しません。おそらく、これは適切に選択されていない例であり、実際にコマンドライン アプリケーションを実行したいですか?

5) 特に文書化されている場合を除き、エラー コード ( GetLastErrorによって返される) は、関数が失敗した場合にのみ意味があります。使用している関数はいずれもこのケースの例外ではないため、関数が失敗したことを示すためにゼロを返さない限り、エラー コードをチェックしても意味がありません。

于 2012-04-12T21:32:48.680 に答える
2

この質問に答えるには遅すぎることはわかっていますが、コードには他にも問題があります。それは物事SetHandleInformation(hReadOUT, HANDLE_FLAG_INHERIT, 0);SetHandleInformation(hReadIN, HANDLE_FLAG_INHERIT, 0);壊すようです。理由はわかりませんが、コードを実行しようとした後、これらの 2 行を削除するまで、cmd はパイプから値を読み取ることができませんでした。

于 2012-10-25T14:50:08.383 に答える