Delphi Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
델파이 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
FreePascal/Lazarus
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
델마당
볼랜드포럼 광고 모집

델파이 팁&트릭
Delphi Programming Tip&Tricks
[357] 프로그램 재실행
첫눈 [hadugo] 441 읽음    2016-12-16 16:54
이미 실행된 프로그램을 또 실행되지 않게 하기 위해 사용하는 가장 일반적인 방법이
MUTEX를 이용한 방법입니다.

이 방법은 프로그램이 실행될때
이미 생성된 MUTEX가 생성되어 있으면 그냥 종료하고
MUTEX가 없으면 새로 생성한 후 실행되도록 하는 방식입니다.

이 방식 이외에 몇가지 방법이 더 있긴 하지만 이 방법이 가장 많이 사용되는 방법입니다.


하지만 전 이미 실행된 프로그램이 있으면 그냥 종료되는게 아니고
이미 실행된 프로세스를 강제로 종료시키고 재실행되도록 하는 방법이 필요했습니다.


소스코드는 다음과 같습니다.

Procedure GetPIDsByProgramName(AProcessName: string; IncludeSelf: Boolean; ResultList: TStringList);
var
  isFound: boolean;
  AHandle, AhProcess: THandle;
  ProcEntry32: TProcessEntry32;
  APath: array[0..MAX_PATH] of char;
begin
  AProcessName := ExtractFileName(AProcessName);
  ResultList.Clear;

  try
    AHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    ProcEntry32.dwSize := Sizeof(TProcessEntry32);
    isFound := Process32First(AHandle, ProcEntry32);

    while isFound do
    begin
      AhProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, ProcEntry32.th32ProcessID);
      GetModuleFileNameEx(AhProcess, 0, @APath[0], sizeof(APath));
      CloseHandle(AhProcess);

      if (UpperCase(StrPas(APath)) <> UpperCase(AProcessName)) AND
         (UpperCase(StrPas(ProcEntry32.szExeFile)) <> UpperCase(AProcessName)) then
      begin
        isFound := Process32Next(AHandle, ProcEntry32);
        Continue;
      end;

      if ProcEntry32.th32ProcessID = GetCurrentProcessId then
      Begin
        if NOT IncludeSelf then
        begin
          isFound := Process32Next(AHandle, ProcEntry32);
          Continue;
        end;
      End;

      ResultList.Add(IntToStr(ProcEntry32.th32ProcessID));
      isFound := Process32Next(AHandle, ProcEntry32);
    end;
  finally
    CloseHandle(AHandle);
  end;
end;


Function KillProcessByPIDList(PIDList: TStringList): Boolean;
Var
  KillProcessParam : String;
  I: Integer;
  CmdPID : PDWORD;
Begin
  Result := True;
  KillProcessParam := '/F /T ';
  for I := 0 to PIDList.Count - 1 do
  Begin
    KillProcessParam := KillProcessParam + '/PID ' + PIDList[I];
  End;
  ShellExecute(0, 'Open', 'TaskKill.exe', PChar(KillProcessParam), '', SW_HIDE);
End;


Function KillProcessByProgramName(AProcessName: String = ''; IncludeSelf: Boolean = False): Boolean;
Var
  PIDList : TStringList;
Begin
  Result := True;
  if AProcessName = '' then
  Begin
    AProcessName := Application.ExeName;
  End;
  AProcessName := ExtractFileName(AProcessName);

  PIDList := TStringList.Create;
  GetPIDsByProgramName(AProcessName, IncludeSelf, PIDList);
  while PIDList.Count > 0 do
  Begin
    KillProcessByPIDList(PIDList);
    PIDList.Clear;
    GetPIDsByProgramName(AProcessName, IncludeSelf, PIDList);
  End;
  FreeAndNil(PIDList);
End;



이렇게 했으면 이제 프로젝트 소스코드에 이 함수를 사용하시면 됩니다.
  Application.Initialize;

  KillProcessByProgramName;

  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;



참고로 프로세스를 강제종료하는 부분을 보면
  ShellExecute(0, 'Open', 'TaskKill.exe', PChar(KillProcessParam), '', SW_HIDE);
이렇게 TaskKill.exe를 사용했습니다.

SendMessage를 이용하여 WM_Close 메세지를 전송하여 창을 닫는 방법도 있고

TerminateProcess함수를 사용하여 프로세스를 강제로 종료하는 방법도 있는데
굳이 ShellExecute를 이용하여 외부프로그램을 사용한데는 이유가 있습니다.


같은 프로그램을 빠른 속도로 계속 재실행 시키다 보면
SendMessage를 이용하여 WM_Close 메세지를 전송하면 창은 닫히지만 프로세스가 남아 있는 경우가 발생합니다.

그리고 TerminateProcess함수를 이용하면
빠른 속도로 프로그램을 계속 재실행하는 경우 약 50번 정도 재실행 되기 전에 반드시 에러메세지가 나타납니다.

하지만 TaskKil.exe를 이용하여 프로그램을 강제종료 시키면 약 5천번을 빠른 속도로 연속 재실행해도 에러가 없었습니다.


+ -

관련 글 리스트
357 프로그램 재실행 첫눈 441 2016-12-16
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.