C#でctrl + cをcmd.exeプロセスに送信する
質問
私は現在、小さなC#バックアッププログラムを書いています。インターフェイスに標準のWindowsフォームを使用し、cmd.exeを新しいプロセスとして呼び出してから、この新しいプロセス内からXCOPYを使用しています。最後に追加したい機能(操作を中断する機能)を除き、すべてがうまく機能しています。
ネイティブコマンドプロンプトからctrl + cを使用してこれをきれいに行うことができますが、winformsおよびプロセスアプローチを使用してこの機能を複製することはできません。標準入力をリダイレクトし、それを使用してconsolespecialkeys.ControlCをプロセスに送信しようとしました。また、他のフォーラム投稿で読んだ0x03と" / x03"の両方を送信しようとしました。 c。ただし、送信するものは何も登録されておらず、プロセスを終了するとユーザーインターフェイスは強制終了されますが、xcopy.exeはバックグラウンドで動作します。 xcopy.exeを手動で強制終了すると、コマンドプロンプトでctrl + cを使用して発生したものではなく、コピー中のファイルが半分コピーされて破損したままになります。
目がくらむほど明らかな何かを見逃していますか?私はC#に慣れていないので、手を挙げて、これが遅いか、プロセスがcmd.exeでどのように機能するかを誤解している可能性が高いことを認めます。ただし、プロセスは標準の入力リダイレクトをサポートしているため、少なくとも私には動作するはずです。私がどこで混乱しているかを特定するのに役立つ場合のために、コードの基本的な概要を以下に示しました。
string XCopyArguments = "\"" + dir.FullName + "\" \"" + destination + "\" /D /S /I /E";
Process XCopyProcess = new Process();
ProcessStartInfo XCopyStartInfo = new ProcessStartInfo();
XCopyStartInfo.FileName = "CMD.exe ";
XCopyStartInfo.RedirectStandardError = true;
XCopyStartInfo.RedirectStandardOutput = true;
XCopyStartInfo.RedirectStandardInput = true;
XCopyStartInfo.UseShellExecute = false;
XCopyStartInfo.CreateNoWindow = true;
XCopyStartInfo.Arguments = " /D /c XCOPY " + XCopyArguments;
XCopyProcess.EnableRaisingEvents = true;
XCopyProcess.StartInfo = XCopyStartInfo;
XCopyProcess.Start();
XCopyProcess.WaitForExit(15000);
int ExitCode = XCopyProcess.ExitCode;
if (ExitCode > 0 & !XCopyProcess.HasExited)
{
XCopyProcess.Kill();
}
XCopyProcess.Dispose();
誰でも提供できるヘルプに感謝します。
解決
私は盗聴者にはなりたくありませんが、プログラム内でコピーを行う方がはるかに良いと思います。 System.IO名前空間のFile、Directory、およびその他のクラスを使用するのは非常に簡単で、進行状況の報告、操作のキャンセルなどを完全に制御できます。
他のヒント
はい、.NETで操作を行う方が簡単です。しかし、ctrl-cもプロセスに送信する必要があり、そのオプションはありません。
では、この質問への回答をいただけますか?
編集:回答を得るために複製を投稿する必要がありますか?いいえ、@ j0rd4nは質問に答えませんでした。
他の人が言ったように、その特定のタスクを達成するより良い方法があります。しかし、それはあなたの質問には答えません。さまざまなタスクを自動化するためにここで示したものと同様の手法を使用しており、非常に便利です。時には物事が非常に悪くなり、物事が悪化する前にプロセスを救済したい場合があります。 ; p
例の問題は次のとおりです。
XCopyStartInfo.CreateNoWindow = true;
falseに設定すると、XCopyProcess.CloseMainWindow()およびXCopyProcess.Close()が処理されます。 Kill()を使用するよりもずっときれいです。
サブディレクトリとファイルをループして1つずつコピーするために必要なコード行が少なくなり、別のプロセスを制御する必要がなくなります...
VB.NETにあります。
Declare Function GenerateConsoleCtrlEvent Lib "kernel32" ( _
ByVal dwCtrlEvent As Integer, _
ByVal dwProcessGroupId As Integer _
) As Integer
Private Const CTRL_C_EVENT As Integer = 0
Private Sub SendCtrlC()
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)
' send a Ctrl-C to this process
GenerateConsoleCtrlEvent(CTRL_C_EVENT, currentpid)
' send a Ctrl-C to the cmd process
GenerateConsoleCtrlEvent(CTRL_C_EVENT, cmdpid)
End Sub
CTRL_Cの組み合わせを、SW_HIDEで作成されたcmd.exeプロセス、つまり非表示のcmd.exeウィンドウに正常に送信しました。
手法は、EnumWindowsを使用してプロセスを識別し、そのウィンドウハンドルを取得することでした(表示されていなくても、メッセージを処理するためのハンドルを保持しています)。
次に、PostMessageを使用してctrl-cの組み合わせをプロセスに投稿しました。これは、ウィンドウがアクティブなときにユーザーが「ctrl-c」を押した場合と同じ効果がありました。
C#からこれを行うには、おそらく http://pinvoke.net/ にアクセスしてください-命の恩人C#でWin32 API関数プロトタイプを作成する場合。
この方法でコピーを処理する場合は、プロセスを手動で強制終了する必要があります。上記のコードでは、XCopyProcess.WaitForExit(...)を呼び出しています。これはブロッキング呼び出しであるため、子プロセスが終了するか、時間間隔が経過するまで、親C#プロセスはその時点で停止します。
ブロックする代わりに、ユーザーがC#UIを介してプロセスの強制終了を要求しているかどうかを定期的にチェックするループでスリープすることができます。このイベントを受け取った場合、プロセスを明示的に強制終了します。それ以外の場合は、プロセスが完了するまで別の間隔を待ちます。
編集:ただし、他のコメントにも同意します。 xcopyを使用する代わりに、.NETフレームワークから直接コピーします。