2014-12-08 2 views
5

이전에이 방법을 사용했지만 어떻게 기억 하는지를 알 수 없습니다.Delphi 명령 줄 매개 변수를 기반으로 한 프로그램의 단일 인스턴스 제한

실행 파일 이름에 뮤텍스를 사용하여 싱글 톤을 실행하도록 설정 한 프로그램이 있습니다. unit GlobalSU;

interface 
function IsAppRunning: Boolean; 

implementation 

uses 
Windows, SysUtils, Forms; 

function IsAppRunning: Boolean; 
var 
rtn : Cardinal; 
begin 
    result := False; 
    CreateMutex(nil, False, PWideChar(ExtractFileName(Application.ExeName))); 
    rtn := GetLastError; 
    if rtn = ERROR_ALREADY_EXISTS then 
    result := True; 
end; 

프로그램은 어떤 데이터를 처리할지 지정하는 특정 명령 줄 매개 변수를 허용합니다. 동일한 명령 행 인수로 실행되는 프로그램의 인스턴스가 두 개 이상은 필요하지 않습니다. 하지만 저는 다른 주장을 가지고 두 번째 인스턴스를 시작할 수 있기를 원합니다.

약 1 년 전에 이것을했으나 어떻게 기억하지 못합니다. DPR에서 명령 줄 매개 변수로 이름을 수정 한 다음 뮤텍스로 테스트합니다.

Application.ExeName의 이름을 바꾸려고했지만 읽기 전용이므로 뭔가 다른 것을 변경해야합니다.

다음은 컴파일하지 않고 추가하려는 코드입니다. 은 BTW - 당신은 잘못된 접근 방식을 사용하고있는 '##은 "항상 세번째 매개 변수의 처음 두 문자입니다하지만 난 정규식으로 테스트

program EPRmailer; 

uses 
    Vcl.Forms, 
    uMainMailer in 'uMainMailer.pas' {frmMainMailer}, 
    configXML in 'configXML.pas', 
    GlobalSU in 'GlobalSU.pas', 
    CVUtils in 'CVUtils.pas', 
    QMConst in 'QMConst.pas', 
    ServerAttachmentDMu in 'ServerAttachmentDMu.pas'; 

{$R *.res} 
var 
    i : integer; 
begin 

    for i := 0 to ParamCount do 
    if TestParam('##', ParamStr(i)) then 
    Application.ExeName := Application.ExeName + '-' + ParamStr(i); 

    if IsAppRunning then exit; 

    Application.Initialize; 
    ReportMemoryLeaksOnShutdown := DebugHook <> 0; 
    Application.MainFormOnTaskbar := false; 
    Application.CreateForm(TfrmMainMailer, frmMainMailer); 
    frmMainMailer.RunEPR; 

end. 
+1

해야하는 응용 프로그램'에서 foo.exe -a -b'에서 foo.exe '와 동일한 것으로 처리 - b -a'와'foo.exe -B -a'? –

+2

뮤텍스의 이름에 대한 매개 변수는 'MAX_PATH' 길이 이하 여야합니다. 약을 지나치는 경우. 250 문자 길이 ('MAX_PATH - 'EPRmailer') 명령 행 매개 변수. 이 경우 뮤텍스 생성은 실패하지만 'ERROR_ALREADY_EXISTS' 오류 때문에 실패하지 않고 함수에서 잘못된 값을 반환합니다. 이것을 방지하기 위해 여기서 매개 변수를 정렬 한 후 해시를 생각할 것입니다. – TLama

+0

Application.Title이 충분히 고유하면 Application.ExeName 대신 사용할 수 있습니다. Application.ExeName은 훨씬 짧으며 '\'문자를 포함하지 않기 때문입니다. –

답변

8

대신 Application.ExeName 이름을 변경, 당신은 구성 문자열을 보내야합니다.. 함수에 중복 된 응용 프로그램에 대한 테스트가.이 응용 프로그램이 종료 될 때까지 활성 상태로 유지하는 뮤텍스를 할당 한 다음 Windows 자동으로 닫힙니다 뮤텍스 핸들입니다.

,536 때문에

function CreateSingleInstance(const InstanceName: string): boolean; 
var 
    MutexHandle: THandle; 
begin 
    MutexHandle := CreateMutex(nil, false, PChar(InstanceName)); 
    // if MutexHandle created check if already exists 
    if (MutexHandle <> 0) then 
    begin 
     if GetLastError = ERROR_ALREADY_EXISTS then 
     begin 
      Result := false; 
      CloseHandle(MutexHandle); 
     end 
     else Result := true; 
    end 
    else Result := false; 
end; 

var 
    MyInstanceName: string; 
begin 
    Application.Initialize; 
    // Initialize MyInstanceName here 
    ... 
    if CreateSingleInstance(MyInstanceName) then 
    begin 
     // Form creation 
     ... 
    end 
    else Application.Terminate; 
end. 

기능 CreateSingleInstance는 응용 프로그램에서 한 번 사용하기위한 것입니다

참고 :MyInstanceName 경우는 MAX_PATH자를 초과 또는 백 슬래시 '\' 문자 기능이 실패합니다 포함

CreateMutex documentation

+0

이 함수는'MAX_PATH' 긴'InstanceName' 값 이상을 전달하면 항상 False를 반환합니다. 또한'PWideChar' 캐스트는 오래된 Delphi 버전에는 좋지 않습니다 ;-) 사실, 결과 : = (CreateMutex (nil, False, PChar (InstanceName)) <> 0) 및 (GetLastError = ERROR_ALREADY_EXISTS) 하지만 뮤텍스 이름 길이를 초과 할 위험이 남아 있습니다. – TLama

+0

뮤텍스가 닫히지 않았기 때문에'IsAppRunning() '을 한 번만 호출하면 이후 호출이'ERROR_ALREADY_EXISTS'를 (를) 탐지 할 수 있습니다. –

+0

@TLama 코드를 변경했지만 함수가 앱 시작에만 사용되는 경우 뮤텍스 핸들을 닫는 것을 포함하여 더 자세히 볼 수 있도록 좀 더 복잡한 체크를 추가했습니다. –