DOBON.NETプログラミング道掲示板

ツリー一括表示

Nomalアイコン Processクラスからbatファイル実行後、KILLできない /あばば無人君 (24/01/13(Sat) 05:19) #35573
Nomalアイコン Re[1]: Processクラスからbatファイル実行後、KILLできない /Azulean (24/01/13(Sat) 14:01) #35574
  └Nomalアイコン Re[2]: Processクラスからbatファイル実行後、KILLできない /あばば無人君 (24/01/13(Sat) 17:01) #35575 解決み!


親記事 / ▼[ 35574 ]
■35573 / 親階層)  Processクラスからbatファイル実行後、KILLできない
□投稿者/ あばば無人君 一般人(1回)-(2024/01/13(Sat) 05:19:30)
  • アイコン環境/言語:[Windows10(64bit/Home/22H2)、NET Framework-4.8.1、C#] 
    分類:[.NET] 

    約3年ぶりの投稿となります。宜しくお願いします。

    掲題の件ですが、WinFormアプリを新規で用意し、
    画面に開始ボタン(button1)と停止ボタン(button2)を配置しました。

    開始ボタンを押下するとProcessクラスでbatファイルを実行し、
    その処理が終わる前に停止ボタンを押下するとProcessクラスの
    KILLを実行して強制終了させる、というシンプルなアプリです。

    その実装は以下となります。
    001 public partial class Form1 : Form
    002 {
    003 private Process myProcess;
    004
    005 public Form1()
    006 {
    007 InitializeComponent();
    008
    009 this.button1.Click += this.button1_Click;
    010
    011 this.button2.Click += this.button2_Click;
    012 this.button2.Enabled = false;
    013 }
    014
    015 private void button1_Click(object sender, EventArgs e)
    016 {
    017 // 開始ボタン:非活性 / 停止ボタン:活性
    018 SwitchButtonEnable(false);
    019
    020 // 10秒間スリープするだけのバッチを指定
    021 this.myProcess = new Process();
    022 this.myProcess.StartInfo.FileName = @".\Sample.bat";
    023
    024 // バッチ処理の終了時に発生させるイベント処理を指定
    025 // ※SynchronizingObjectプロパティに当画面のインスタンスを指定することで
    026 // このイベント処理はGUIスレッドで動作する
    027 this.myProcess.Exited += button2_Click;
    028 this.myProcess.EnableRaisingEvents = true;
    029 this.myProcess.SynchronizingObject = this;
    030
    031 // 開始
    032 this.myProcess.Start();
    033 }
    034
    035 private void button2_Click(object sender, EventArgs e)
    036 {
    037 // すでに当処理が実施済みなら何もしない
    038 if (this.myProcess == null) { return; }
    039
    040 // バッチ処理の終了時に発生させるイベント処理を削除
    041 this.myProcess.Exited -= button2_Click;
    042 this.myProcess.EnableRaisingEvents = false;
    043
    044 if (!this.myProcess.HasExited)
    045 {
    046 try
    047 {
    048 this.myProcess.Kill();
    049 }
    050 catch
    051 {
    052 // 停止ボタン押下直後にプロセスが終了したケースを想定
    053 // よって例外をキャッチしても何もしていない
    054 }
    055 }
    056
    057 // 怒涛のインスタンス開放
    058 this.myProcess.Refresh();
    059 this.myProcess.Close();
    060 this.myProcess.Dispose();
    061 using (this.myProcess) { }
    062
    063 // 閉じるボタン押下とプロセス終了イベントがほぼ同時に発生した時、
    064 // 当関数の処理が2回実行されない様にnullを設定しておく
    065 this.myProcess = null;
    066
    067 // 開始ボタン:活性 / 停止ボタン:非活性
    068 SwitchButtonEnable(true);
    069 }
    070
    071 private void SwitchButtonEnable(bool isEnable)
    072 {
    073 button1.Enabled = isEnable;
    074
    075 button2.Enabled = !isEnable;
    076 }
    077 }

    以上を踏まえて、このアプリ、停止ボタンを押下しても
    起動したbatが終了しません。
    コード22行目で指定している「Sample.bat」は
     timeout /T 10
    というスリープ処理が1行あるだけの物となっています。

    しかもコード22行目の起動対象ファイルを
    ・メモ帳 "C:\Windows\System32\notepad.exe"
    ・エクセルファイル ".\適当.xlsx"
    などにした場合は期待通り終了します。

    ここから質問ですが、
    @batだけ終了しないのは何故か?
    Abatを終了させる方法はあるか?
    が分かる方、いらっしゃいましたらお力添えいただきたいです。
    ※特にAが知りたいです

    長くなりましたが宜しくお願い致します。


違反を報告
[ □ Tree ] 返信 削除キー/

▲[ 35573 ] / ▼[ 35575 ]
■35574 / 1階層)  Re[1]: Processクラスからbatファイル実行後、KILLできない
□投稿者/ Azulean 大御所(545回)-(2024/01/13(Sat) 14:01:27)
  • アイコンNo35573に返信(あばば無人君さんの記事)
    > コード22行目で指定している「Sample.bat」は
    >  timeout /T 10
    > というスリープ処理が1行あるだけの物となっています。

    たとえば、バッチファイルを「pause」として入力待ちだけにすれば、このコードでも問題なく動作すると思います。

    timeout の場合、cmd.exe とは別に timeout.exe プロセスが立ち上がります。
    今回のコードでは cmd.exe は終了できますが、子プロセスである timeout.exe は生き残っていますので、止まりません。


    ご自身で子プロセスの列挙と停止といった処理を作る必要があるそうです。
    https://stackoverflow.com/a/32405627
違反を報告
[ 親 35573 / □ Tree ] 返信 削除キー/

▲[ 35574 ] / 返信無し
■35575 / 2階層)  Re[2]: Processクラスからbatファイル実行後、KILLできない
□投稿者/ あばば無人君 一般人(2回)-(2024/01/13(Sat) 17:01:14)
  • アイコンNo35574に返信(Azuleanさんの記事)

    > ■No35573に返信(あばば無人君さんの記事)
    > たとえば、バッチファイルを「pause」として入力待ちだけにすれば、このコードでも問題なく動作すると思います。
    >
    > timeout の場合、cmd.exe とは別に timeout.exe プロセスが立ち上がります。
    > 今回のコードでは cmd.exe は終了できますが、子プロセスである timeout.exe は生き残っていますので、止まりません。

    ご記載のとおり、pauseコマンドですと期待通り終了しましたし、
    FTPコマンド(ftp.exe)だとtimeoutと同じく終了しませんでした。

    なるほど、別プロセスですか。盲点でした。


    > ご自身で子プロセスの列挙と停止といった処理を作る必要があるそうです。
    > https://stackoverflow.com/a/32405627

    参考リンク、ありがとうございます。時間ができたらサンプルを作ってみます。

    今回は客先指定のアプリが手元に無かったのでbatのtimeoutで代用していましたが、
    客先指定のアプリがKILLで終了するのは分かっているので
    本件はこれで解決とさせていただきます。

    ご回答ありがとうございました。

解決み!
違反を報告
[ 親 35573 / □ Tree ] 返信 削除キー/


Mode/  Pass/


- Child Tree -