プロセス起動、終了後にイベントを発生させるには

解決


Fusa  2008-12-08 22:50:53  No: 32844

こんにちは。
.NETの話を持ち出して恐縮なんですが

「.NETプログラミング研究」のメールマガジンの
http://dobon.net/vb/melma/dotnet1.txt
ここでは、objProcessというものをつかって
プロセスを起動したあとに
そのプロセスが終了したときにイベントが発生するような
コーディングを行っています。

これと同じようなことをするにはどのような
クラスを作ればよいでしょうか?

クラス内にスレッドを持てばよさそうな気はしますが
スレッド以外にもよいやり方はないでしょうか?

知ってましたら教えてください。
よろしくお願いします。


とおりすがり  2008-12-09 00:07:21  No: 32845

>これと同じようなことをするにはどのような
>クラスを作ればよいでしょうか?

API の  CreateProcess() WaitForSingleObject() GetExitCodeProcess() の機能を
ラップしたクラスをつくればいいかと。

>クラス内にスレッドを持てばよさそうな気はしますが
>スレッド以外にもよいやり方はないでしょうか?

この質問は意味不明です。


とおりすがり  2008-12-09 00:11:24  No: 32846

>この質問は意味不明です。

終了するのを待つのではなくイベントにするのでしたら、たしかに待つための
スレッドを作る必要がありますね。失礼しました。


Fusa  2008-12-09 00:16:10  No: 32847

そうなんですよ。
せっかくなら、.NETと同じことをできるようにはしておきたいと思っています。

コールバックとか、ApplicationProcessMessageで上手に作れないかな、など、思ってみたりですが。

スレッドは少し苦手なのです。


KHE00221  2008-12-10 09:31:54  No: 32848

VBも.NETもよく知らんけど

>http://dobon.net/vb/melma/dotnet1.txt
って

>'[VB.NET]・・・・・・・・・・・・・・・・・・・・・・・・・・
>'ファイルを開いて終了まで待機する
>Dim objProcess As System.Diagnostics.Process = _
>    System.Diagnostics.Process.Start("C:\test.txt")
>objProcess.WaitForExit()
>'ここを次のようにすると最大10秒間待機だけする
>'objProcess.WaitForExit(10000)
>MsgBox("終了。")

でプロセス呼んでWaitForSingleObject()で待つ
でもフリーズみたくなるから

>'[VB.NET]・・・・・・・・・・・・・・・・・・・・・・・・・・
>Private Sub Button1_Click(ByVal sender As System.Object, _
>        ByVal e As System.EventArgs) Handles Button1.Click
>    'ファイルを開いて終了まで待機する
>    Dim objProcess As System.Diagnostics.Process = _
>        System.Diagnostics.Process.Start("notepad.exe")
>    'プロセスが終了したときに Exited イベントを発生させる
>    objProcess.EnableRaisingEvents = True
>    'イベントハンドラの追加
>    AddHandler objProcess.Exited, AddressOf OnExited
>End Sub
>
>Private Sub OnExited(ByVal sender As Object, _
>        ByVal e As EventArgs)
>    'プロセスが終了したときに実行される
>    MsgBox("終了しました。")
>End Sub

Application.ProcessMessageいれて非同期で待機する
(非同期というか待機中にメッセージ処理してるだけ?)
そしてOnExited(イベントというか他の関数)を呼んでるだけじゃないのか?


KHE00221  2008-12-10 09:34:31  No: 32849

下のやつ  objProcess.WaitForExit()  ないからそのまま抜けるのか・・・


KHE00221  2008-12-10 09:52:08  No: 32850

スレッドなら
スレッドの Execute 内で CreateProcess で実行して

WaitForSingleObject(ProcessInfo.hProcess, $FFFFFFFF);
で終了まで待つだけで

プロセスが終了するとスレッドが終了するので 
OnTerminateがスレッド終了のイベントとなる

  TProcessThread = class(TThread)
  private
  public
    procedure Execute;override;
  private
  end;

procedure TForm8.ProcessOnTerminate(Sender: TObject);
begin
    //スレッド終了 = プロセス終了
end;

procedure TProcessThread.Execute;
var
    ret: Boolean;
    ecode: Integer;
    StartupInfo: TStartupInfo;
    ProcessInfo: TProcessInformation;
begin

    with StartupInfo do
    begin
      cb := SizeOf(TStartupInfo);
      dwX := 0;
      dwY := 0;
      dwXSize := 640;
      dwYSize := 480;
      wShowWindow := SW_SHOWNORMAL;
      dwFlags := STARTF_USESHOWWINDOW or STARTF_USESIZE or STARTF_USEPOSITION;
      lpReserved := nil;
      lpDesktop  := nil;
      lpTitle    := nil;
      cbReserved2 := 0;
      lpReserved2 := nil;
    end;

    ret := CreateProcess(
      nil,                        // 実行ファイル名
      'notepad.exe',              // コマンドライン
      nil,                        // プロセスのセキュリティ属性
      nil,                        // スレッドのセキュリティ属性
      False,                      // 親プロセスからハンドルを継承するか
      CREATE_DEFAULT_ERROR_MODE,  // 優先順位とプロセスの制作制御
      nil,                        // 環境変数ブロックへのポインタ
      nil,                        // カレントディレクトリ
      StartupInfo,                // ウィンドウの属性
      ProcessInfo                 // 新しいプロセスの情報を受け取る構造体
    );

    WaitForSingleObject(ProcessInfo.hProcess, $FFFFFFFF);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
    ProcessThread := TProcessThread.Create(True);
    ProcessThread.OnTerminate := ProcessOnTerminate;
    ProcessThread.Resume;
end;


KHE00221  2008-12-10 09:58:16  No: 32851

procedure TForm8.ProcessOnTerminate(Sender: TObject);

TForm1 ね


KHE00221  2008-12-10 18:55:08  No: 32852

スレッド使用しないならタイマーで監視かな?

procedure TForm8.Timer1Timer(Sender: TObject);
var
    ExitCode: Cardinal;
begin
    if ProcessInfo.hProcess <> 0 then
    begin
      ExitCode := $FFFFFFFF;
      if GetExitCodeProcess(ProcessInfo.hProcess,ExitCode) = True then
      begin
        case ExitCode of
          0:
          begin
            //終了
            Caption := '終了';
          end;
          1:
          begin
            Caption := '異常終了';
          end;
          259:
          begin
            //起動中
            Caption := '起動中';
          end;
        end;
      end;
    end;
end;


Fusa  2008-12-11 22:08:27  No: 32853

おおお!なるほど。
スレッドというとそれだけで敬遠してしまっていたのですが

こうやって使うとすごく短いコードで実現できてしまうのですね。

タイマーの例まで出していただいてありがとうございます。
勉強になります。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加