본문 바로가기
Delphi Tip/유닛

프로그램 중복 실행 방지

by MonoSoft 2021. 12. 30.
728x90
반응형

프로그램 중복 실행 방지

 

프로그램의 중복실행을 방지하는 방법으로는 CreateMutex가 많이 쓰이는 것 같습니다.

저는 조금 고전적이지만 이해하기 쉬운 Global Atom Table을 이용한 방법을 소개합니다.

실은 10년전쯤에 컴포넌트로 만든 것을 컴포넌트 설치과정 없이

바로 이용할 수 있도록 단순한 유니트로 바꾼 것입니다. 

 

이용법은 프로그램 소스 내용 중 상수로 정의된

Author와 RunProgram 값을 올바르게 고친 후 프로젝트가 위치한 

폴더에 복사해 두고,

아래와 같이 프로젝트 소스화일(*.dpr)의 uses절에 제일 먼저 RunOne을 등록만 하면 됩니다. 

 

  uses RunOne, 

            Forms, . . .  .

 

그리고 RunOne은 실행하고자 하는 프로그램이

이미 실행중일 경우 최소화 상태이면 원래 크기로, 최상위

윈도우가 아니면 최상위 윈도우로 변경하여 사용자가

이전에 이미 실행 중이었다는 것을 바로 인식할 수 있도록 해 줍니다.

 

아래는 RunOne.pas 소스입니다.

 

unit RunOne;

 

interface

 

uses WinTypes, SysUtils, Forms;

 

const

  Author = 'Silhwan Hyun';  // 저자명 : 실행여부를 검사하기 위한 검색어를 구성함.

  RunProgram = 'TClock';    // 프로그램명 :    

       "

 

implementation

 

var

  AtomText: array[0..63] of Char;

  AtomSaved : boolean = false;

  MyClassName    : array[0..255] of Char;

  FoundPrevInst  : boolean = false;

  PrevInstHandle : HWnd = 0;

  FoundAtom      : TAtom;

  NewAtom : TAtom;

  MyPopup : HWnd;

function LookAtAllWindows(Handle: HWnd; Temp: Longint): BOOL; stdcall;

var

  ClassName : array[0..255] of Char;

begin

  LookAtAllWindows := true;

  if GetClassName(Handle, ClassName, SizeOf(ClassName)) > 0 then

  begin

    if StrComp(ClassName, MyClassName) = 0 then // 동일 window class ?

    begin

    // 중복실행여부를 조사하기 위한 검색어 생성

       StrPCopy(AtomText, Author + RunProgram + IntToStr(Handle));

    // 검색어가 Global Atom Table에 등록되어 있는지 확인

       FoundAtom := GlobalFindAtom(AtomText);

       if FoundAtom <> 0 then  // Global Atom Table에 등록되어 있으면

       begin

          FoundPrevInst  := true;    // 이미 실행 중인 것으로 표시

          PrevInstHandle := Handle;  // 실행 중인 어플리케이션 윈도우 핸들

          LookAtAllWindows := false; // enumeration 함수를 종료시킨다

       end;

    end;

  end;

end;

 

initialization

 // 프로그램의 클래스명을 알아낸다.   

  GetClassName(Application.Handle, MyClassName, SizeOf(MyClassName));

 // 윈도우를 검색하여 중복실행이 아닌지 확인한다

  EnumWindows(@LookAtAllWindows, 0);

  if FoundPrevInst then   // 이미 실행 중이면

  begin

     MyPopup := GetLastActivePopup(PrevInstHandle);

     BringWindowToTop(PrevInstHandle);

     if IsIconic(MyPopup) then

     begin

        ShowWindow(MyPopup, SW_RESTORE);  // 최소화 상태이면 원래 크기로

     end else

        BringWindowToTop(MyPopup);        // 최상위 윈도우로

    SetForegroundWindow(MyPopup);      // 포커스를 준다.    *** Added ***

 

     Halt(0);  // 새로 실행한 프로그램은 강제로 종료시킨다

  end else

  begin

   // 실행중이 아니면 검색어를 Global Atom Table에 등록한다

     StrPCopy(AtomText, Author + RunProgram + IntToStr(Application.Handle));

     NewAtom := GlobalAddAtom(AtomText);

     if NewAtom <> 0 then   // Global Atom Table에 등록성공이면

        AtomSaved := true;

  end;

finalization

  // 프로그램 종료시는 Global Atom Table에 등록해 둔 검색어를 해제한다.

  if AtomSaved then

  begin

     FoundAtom := GlobalFindAtom(AtomText);

     if FoundAtom <> 0 then

        GlobalDeleteAtom(FoundAtom);

  end;

end.

 

댓글 중~ 

단지...

BringWindowToTop 다음에

     SetForegroundWindow(MyPopup);

이것을 추가하는것이 더 편할것 같습니다.

어차피 실행할려고 한것이니 최상위 및 원복 후 포커스를 주는것이 좋을듯 합니다. ^^ 

 

728x90
반응형

댓글