2010年12月9日木曜日

プロセスの再起動

仕事で、プロセスを外部から強制的に再起動を
する必要があったのでとりあえずつくってみた。

停止させるプロセスは、仕様上一意性が保障されている
ので、コマンドライン引数に起動するプロセスの絶対パスを
与えて、そこからプロセスIDを求めています。

プロセスに停止メッセージ(メインウインドウのクローズ)を
ポストし、5秒まっても終了していなかったら
強制終了しています。

プロセスの起動には、JvCreateProcessコンポーネントを
使っています。
このコンポーネントは、非常に便利ですね。




  1. program RestartProcess;  
  2.   
  3. {$APPTYPE CONSOLE}  
  4.   
  5. uses  
  6.   SysUtils,Windows,TLHELP32,Messages,JvCreateProcess;  
  7.   
  8.   
  9. function GetProcessFromName(ProcessName :String) : Cardinal;  
  10. var  
  11.    ProcEntry : TProcessEntry32;  
  12.    SanpshotHandle : THandle;  
  13.    ListProcName : String;  
  14.   
  15. begin  
  16.    //Toolhelp32を使用する例  
  17.   Result := 0;  
  18.    SanpshotHandle := TlHelp32.CreateToolhelp32Snapshot(TlHelp32.TH32CS_SNAPPROCESS,0);  
  19.    if (SanpshotHandle <> -1then  
  20.       begin  
  21.          ProcEntry.dwSize := Sizeof(TProcessEntry32W);  
  22.          if (TlHelp32.Process32First(SanpshotHandle,ProcEntry)) Then  
  23.          begin  
  24.             repeat  
  25.               ListProcName := ProcEntry.szExeFile;  
  26.               if CompareText(ListProcName,ProcessName) = 0 then  
  27.               begin  
  28.                  Result := ProcEntry.th32ProcessID;  
  29.               end;  
  30.               //WriteLn(ListProcName);  
  31.           until (TlHelp32.Process32Next(SanpshotHandle,ProcEntry) = false);  
  32.        end;  
  33.     end;  
  34.     CloseHandle(SanpshotHandle);  
  35.   
  36. end;  
  37.   
  38.   
  39. function EnumWindowsProc(hwindow :HWnd; lparam :LPARAM):BOOL; stdcall;  
  40. var  
  41.   ProcessID : Cardinal;  
  42.   ThreadID : Cardinal;  
  43. begin  
  44.   
  45.    Result := True;  
  46.   
  47.    ThreadID := GetWindowThreadProcessId(hwindow, ProcessID);  
  48.   
  49.    If (ProcessID = lParam) Then  
  50.    begin  
  51.       PostMessage(hwindow, WM_CLOSE, 00);  
  52.      Result := true;  
  53.    End;  
  54. End;  
  55.   
  56.   
  57. function SendClose(ProcID : Cardinal) : Boolean;  
  58. begin  
  59.    Result := EnumWindows(@EnumWindowsProc, ProcID)  
  60. End;  
  61.   
  62. function StopProcess(ProcessName : String; Force : Boolean = false) : Integer;  
  63. var  
  64.    ProcessID : Cardinal;  
  65.   hProcess : THandle;  
  66. begin  
  67.    ProcessID := GetProcessFromName(ProcessName);  
  68.   if ProcessID = 0 then  
  69.   begin  
  70.      Result := -1;  
  71.   end  
  72.   else  
  73.   begin  
  74.      if (ProcessID > 0) Then  
  75.      begin  
  76.         if Force then  
  77.         begin  
  78.            hProcess := OpenProcess(PROCESS_TERMINATE, False, ProcessID);  
  79.            TerminateProcess(hProcess , 0 );  
  80.            CloseHandle(hProcess);  
  81.            Result := 0;  
  82.         end  
  83.         else  
  84.         begin  
  85.            Result := 1;  
  86.            if SendClose(ProcessID) then  
  87.            begin  
  88.               Result := 0;  
  89.            end;  
  90.         end;  
  91.      end;  
  92.   end;  
  93. end;  
  94.   
  95. var  
  96.    StopResult : Integer;  
  97.    JvCreateProcess: TJvCreateProcess;  
  98.   ExeName : String;  
  99.   ProcessID : Cardinal;  
  100.   
  101. begin  
  102.   try  
  103.   { TODO -oUser -cConsole Main : ここにコードを記述してください }  
  104.   
  105.      if ParamCount > 0 then  
  106.      begin  
  107.         ExeName := ExtractFileName(ParamStr(1));  
  108.          StopResult := StopProcess(ExeName);  
  109.   
  110.         //五秒まって停止イしたかどうかを確認する  
  111.         Sleep(5000);  
  112.   
  113.         ProcessID := GetProcessFromName(ExeName);  
  114.   
  115.         //プロセスが正常に停止できなかったので' +  
  116.         //強制終了する  
  117.         if ProcessID > 0 Then  
  118.         begin  
  119.            StopResult := StopProcess(ExeName,true);  
  120.            Sleep(10000);  
  121.         end;  
  122.   
  123.   
  124.         if StopResult <> 1 then  
  125.         begin  
  126.            JvCreateProcess := TJvCreateProcess.Create(nil);  
  127.            try  
  128.               JvCreateProcess.CommandLine := ParamStr(1);  
  129.               JvCreateProcess.WaitForTerminate := false;  
  130.               JvCreateProcess.Run;  
  131.            finally  
  132.               JvCreateProcess.Free;  
  133.             end;  
  134.         end;  
  135.      end;  
  136.      //ReadLn;  
  137.   except  
  138.     on E:Exception do  
  139.       Writeln(E.Classname, ': ', E.Message);  
  140.   end;  
  141. end.