.NET에서 특정 앱의 여러 인스턴스를 방지 하시겠습니까?


123

.NET에서 앱의 여러 인스턴스가 동시에 실행되는 것을 방지하는 가장 좋은 방법은 무엇입니까? "최상의"기술이없는 경우 각 솔루션에 대해 고려해야 할 몇 가지주의 사항은 무엇입니까?

답변:


151

Mutex를 사용하십시오. GetProcessByName을 사용하는 위의 예제 중 하나에는 많은주의 사항이 있습니다. 다음은 주제에 대한 좋은 기사입니다.

http://odetocode.com/Blogs/scott/archive/2004/08/20/401.aspx

[STAThread]
static void Main() 
{
   using(Mutex mutex = new Mutex(false, "Global\\" + appGuid))
   {
      if(!mutex.WaitOne(0, false))
      {
         MessageBox.Show("Instance already running");
         return;
      }

      Application.Run(new Form1());
   }
}

private static string appGuid = "c0a76b5a-12ab-45c5-b9d9-d693faa6e7b9";

1
뮤텍스를 사용하는 것은 .net이 아닌 코드에서도 작동합니다 (구문은 다를 수 있음)
crashmstr

8
다음은 좋은 의견과 함께 약간 더 채워진 버전입니다. stackoverflow.com/questions/229565/…
Richard Watson

2
@ClarkKent : Mutex 이름이 다른 응용 프로그램의 이름과 충돌하지 않도록 임의의 문자열입니다.
jgauffin 2013-07-03

이 역시 특정 수의 인스턴스로 제한 할 수 있습니까?
Alejandro del Río

3
앱 GUID를 버전 관리하거나 변경하는 동안 더 나은 제어를 위해 다음 string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), true)[0]).Value;을 사용할 수 있습니다. 실행중인 어셈블리의 GUID를 가져옵니다.
ciosoriog

22
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1)
{
  AppLog.Write("Application XXXX already running. Only one instance of this application is allowed", AppLog.LogMessageType.Warn);
  return;
}

1
: 나는이 참조해야한다고 생각 odetocode.com/blogs/scott/archive/2004/08/20/...
SubmarineX

@SubmarineX이 기사가 정확하다고 어떻게 확신합니까? 여전히 뮤텍스 간의 논쟁이다 codeproject.com/Articles/4975/...
존 응우 엔

당신의 시간과 노력에 대한 놀라운 그냥 완벽한 감사
아흐메드 마흐무드

2
-1 이것은 빠른 해결책이지만 a.exe가 b.exe로 이름이 바뀌고 둘 다 실행되는 것을 피하는 것도 매우 쉽습니다. + 이것이 의도 한대로 작동하지 않는 다른 경우. 주의해서 사용하십시오!
Lars Nielsen

단일 개발에서는 작동하지 않습니다. Windows 환경에서는 훌륭하게 작동합니다.
Tono Nam

20

다음은 하나의 인스턴스 만 실행되도록하는 데 필요한 코드입니다. 이것은 명명 된 뮤텍스를 사용하는 방법입니다.

public class Program
{
    static System.Threading.Mutex singleton = new Mutex(true, "My App Name");

    static void Main(string[] args)
    {
        if (!singleton.WaitOne(TimeSpan.Zero, true))
        {
            //there is already another instance running!
            Application.Exit();
        }
    }
}

2
WPF 애플리케이션의 경우 Application.Current.Shutdown (); 이 방법은 매력처럼 작동합니다. 고마워요 Terrapin.
Jeff

여기서 가장 중요한 것은 뮤텍스를 정적으로 만드는 것입니다. 다른 경우와 마찬가지로 GC에서 수집합니다.
Oleksii 2015

나는 Mutex라는 이름의 단순성과 명확성을 즐겼습니다. 이 코드는 간결하고 효과적입니다.
Chad

7

Hanselman 은이를 위해 Microsoft.VisualBasic 어셈블리의 WinFormsApplicationBase 클래스를 사용하는 것에 대한 게시물 을 가지고 있습니다.


나는 그것을 몇 년 동안 사용해 왔지만 지금은 Mutex 기반 솔루션으로 변경하려고합니다. 이 문제를보고하는 고객이 있으며 Remoting을 사용하여이를 수행하고있는 것 같습니다.
Richard Watson

5

지금까지 제안 된 3 가지 기본 기술이있는 것 같습니다.

  1. Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase 클래스에서 파생하고 IsSingleInstance 속성을 true로 설정합니다. (여기서 경고는 WPF 응용 프로그램에서 작동하지 않는다는 것입니다.)
  2. 명명 된 뮤텍스를 사용하고 이미 생성되었는지 확인합니다.
  3. 실행중인 프로세스 목록을 가져오고 프로세스 이름을 비교합니다. (이는 주어진 사용자의 컴퓨터에서 실행되는 다른 프로세스에 비해 고유 한 프로세스 이름을 요구한다는 경고가 있습니다.)

내가 놓친 경고가 있습니까?


3
저는 3이 매우 효율적이라고 생각하지 않습니다. 나는 Mutex에 투표하고 문제없이 여러 번 사용했습니다. 나는 당신이 C #에있을 때 어떻게 날아가는 지 확실하지 않은 항목 1을 사용한 적이 없습니다.
typemismatch

2
옵션 1은 여전히 ​​WPF에서 작동하지만 약간 더 복잡합니다. msdn.microsoft.com/en-us/library/ms771662.aspx
Graeme Bradbury

5

1-program.cs에 참조 만들기->

using System.Diagnostics;

2- void Main()코드의 첫 번째 줄로 입력->

 if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length >1)
                return;

그게 다야.


이것의 차이점은 무엇입니까 Mutex? 캐치가 있습니까?
Harambe Attack Helicopter

프로세스의 이름을 사용하고 있습니다. 이름이 반복되면 거짓 플래그가 생성됩니다. 다른 경우에는 뮤텍스보다 깨끗합니다
magallanes

4

실행 파일에 대한 프로젝트를 만들 때 Visual Studio 2005 또는 2008을 사용하면 "응용 프로그램"패널 내의 속성 창에 "단일 인스턴스 응용 프로그램 만들기"라는 확인란이 있으며 단일 인스턴스 응용 프로그램에서 응용 프로그램을 변환하기 위해 활성화 할 수 있습니다. .

다음은 제가 말하는 창을 캡처 한 것입니다. 여기에 이미지 설명 입력 이것은 Visual Studio 2008 Windows 응용 프로그램 프로젝트입니다.


3
내 C # / WPF 앱에 대해 언급 한이 확인란을 찾았지만 아무것도 없습니다.
HappyNomad 2010-01-05

3
내 VS 2008 C # / WinForms 앱의 속성에서도 볼 수 없습니다.
Jesse McGrew

VS2005에서도 마찬가지입니다. 그는 오래된 VB 스튜디오를 언급하고있을 것입니다.
nawfal

예, 옵션이 있습니다.이 옵션을 찾을 수있는 창의 캡처를 추가하기 위해 게시물을 수정했습니다.
Doliveras

6
이 옵션은 C #이 아닌 VB.NET 응용 프로그램에만 존재합니다. 분명히 옵션 자체는 Microsoft.VisualBasic 어셈블리의 WinFormsApplicationBase 클래스를 사용합니다.
amolbk 2011

4

여기에서 모든 솔루션을 시도했지만 C # .net 4.0 프로젝트에서 아무것도 작동하지 않았습니다. 여기 누군가가 나를 위해 일한 솔루션을 돕고 싶습니다.

주요 클래스 변수 :

private static string appGuid = "WRITE AN UNIQUE GUID HERE";
private static Mutex mutex;

앱이 이미 실행 중인지 확인해야하는 경우 :

bool mutexCreated;
mutex = new Mutex(true, "Global\\" + appGuid, out mutexCreated);
if (mutexCreated)
    mutex.ReleaseMutex();

if (!mutexCreated)
{
    //App is already running, close this!
    Environment.Exit(0); //i used this because its a console app
}

일부 조건에서만 다른 istance를 닫을 필요가 있었는데 이것은 내 목적에 잘 맞았습니다.


실제로 뮤텍스를 획득하고 해제 할 필요가 없습니다. 알아야 할 것은 다른 앱이 이미 객체를 생성했는지 여부입니다 (즉, 커널 참조 횟수> = 1).
Michael Goldshteyn 2014


3

여러 솔루션을 시도한 후 질문입니다. 나는 여기 에 WPF에 대한 예제를 사용했습니다 . http://www.c-sharpcorner.com/UploadFile/f9f215/how-to-restrict-the-application-to-just-one-instance/

public partial class App : Application  
{  
    private static Mutex _mutex = null;  

    protected override void OnStartup(StartupEventArgs e)  
    {  
        const string appName = "MyAppName";  
        bool createdNew;  

        _mutex = new Mutex(true, appName, out createdNew);  

        if (!createdNew)  
        {  
            //app is already running! Exiting the application  
            Application.Current.Shutdown();  
        }  

    }          
}  

App.xaml에서 :

x:Class="*YourNameSpace*.App"
StartupUri="MainWindow.xaml"
Startup="App_Startup"

2

이 문서에서는 인스턴스 수를 제어하는 ​​Windows 애플리케이션을 생성하거나 단일 인스턴스 만 실행하는 방법을 간단히 설명합니다. 이것은 비즈니스 애플리케이션의 매우 일반적인 요구 사항입니다. 이를 제어 할 수있는 다른 많은 솔루션이 이미 있습니다.

http://www.openwinforms.com/single_instance_application.html


링크가 끊어졌습니다.
Chad

2

VB.NET을 사용하십시오! 아니요 : 정말;)

Microsoft.VisualBasic.ApplicationServices 사용;

VB.Net의 WindowsFormsApplicationBase는 다른 인스턴스를 결정하고 하나의 인스턴스 만 실행할 수있는 "SingleInstace"속성을 제공합니다.


2

이것은 VB.Net의 코드입니다.

Private Shared Sub Main()
    Using mutex As New Mutex(False, appGuid)
        If Not mutex.WaitOne(0, False) Then
              MessageBox.Show("Instance already running", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error)
            Return
        End If

        Application.Run(New Form1())
    End Using
End Sub

이것은 C #의 코드입니다.

private static void Main()
{
    using (Mutex mutex = new Mutex(false, appGuid)) {
        if (!mutex.WaitOne(0, false)) {
            MessageBox.Show("Instance already running", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return;
        }

        Application.Run(new Form1());
    }
}



1

(참고 : 이것은 재미있는 솔루션입니다! 작동하지만 잘못된 GDI + 디자인을 사용하여이를 달성합니다.)

앱에 이미지를 넣고 시작할 때로드합니다. 앱이 종료 될 때까지 누르고 있습니다. 사용자는 두 번째 인스턴스를 시작할 수 없습니다. (물론 뮤텍스 솔루션은 훨씬 깨끗합니다)

private static Bitmap randomName = new Bitmap("my_image.jpg");

이것은 실제로 단순함이 훌륭하며 이미지뿐만 아니라 거의 모든 종류의 파일에서 작동합니다. Mutex 솔루션이 "깨끗함"과는 거리가 먼 것 같습니다. 매우 복잡하고 "올바르게"하지 않아서 실패 할 수있는 방법이 많이 있습니다. 또한 Main()WPF가 작동 하는 방식에 반하는 방법이 필요합니다 .
Kyle Delaney

이것은 일종의 버그 사용과 같습니다. 작동하지만 그 목적으로 만들어진 것은 아닙니다. 나는 그것을 전문가로 사용하지 않을 것입니다.
Bitterblue

예, 불행히도 예외에 의존하지 않고 이렇게 효과적이고 간단한 해결책이 없습니다.
Kyle Delaney

정확히 버그는 아니지만. 여전히 .NET이 의도 한대로 작동합니다.
Kyle Delaney

1
[STAThread]
static void Main()                  // args are OK here, of course
{
    bool ok;
    m = new System.Threading.Mutex(true, "YourNameHere", out ok);

    if (! ok)
    {
        MessageBox.Show("Another instance is already running.");
        return;
    }

    Application.Run(new Form1());   // or whatever was there

    GC.KeepAlive(m);                // important!
}

From : .NET 응용 프로그램의 단일 인스턴스 보장

및 : 단일 인스턴스 애플리케이션 뮤텍스

@Smink 및 @Imjustpondering과 동일한 답변 :

GC.KeepAlive가 중요한 이유를 알아보기위한 Jon Skeet의 C # FAQ


-1, 뮤텍스와 함께 using 블록을 사용하지 않아 KeepAlive가 불필요 해지기 때문입니다. 그리고 네, 저는 John Skeet이 이것을 잘못했다고 생각합니다. 그는이 경우 뮤텍스를 폐기하는 것이 잘못된 이유를 설명하지 않습니다.

1

단순히를 사용 StreamWriter하면 어떻습니까?

System.IO.File.StreamWriter OpenFlag = null;   //globally

try
{
    OpenFlag = new StreamWriter(Path.GetTempPath() + "OpenedIfRunning");
}
catch (System.IO.IOException) //file in use
{
    Environment.Exit(0);
}


0

이것은 순수한 C #에서 나를 위해 일했습니다. try / catch는 루프 중에 목록의 프로세스가 종료되는 경우입니다.

using System.Diagnostics;
....
[STAThread]
static void Main()
{
...
        int procCount = 0;
        foreach (Process pp in Process.GetProcesses())
        {
            try
            {
                if (String.Compare(pp.MainModule.FileName, Application.ExecutablePath, true) == 0)
                {
                    procCount++;                        
                    if(procCount > 1) {
                       Application.Exit();
                       return;
                    }
                }
            }
            catch { }
        }
        Application.Run(new Form1());
}

0

애플리케이션을 단일 인스턴스로 제한 할 때 보안을 고려해야합니다.

전체 문서 : https://blogs.msdn.microsoft.com/oldnewthing/20060620-13/?p=30813

우리는 프로그램의 다른 복사본이 실행 중인지 감지하기 위해 고정 된 이름으로 명명 된 뮤텍스를 사용하고 있습니다. 그러나 이는 공격자가 먼저 뮤텍스를 생성하여 프로그램이 전혀 실행되지 않도록 할 수 있음을 의미합니다! 이러한 유형의 서비스 거부 공격을 어떻게 방지 할 수 있습니까?

...

공격자가 프로그램이 실행중인 (또는 실행될) 동일한 보안 컨텍스트에서 실행되고있는 경우 수행 할 수있는 작업이 없습니다. 프로그램의 다른 복사본이 실행 중인지 확인하기 위해 어떤 "비밀 핸드 셰이크"를 생성하든 공격자는이를 모방 할 수 있습니다. 올바른 보안 컨텍스트에서 실행되기 때문에 "실제"프로그램이 할 수있는 모든 작업을 수행 할 수 있습니다.

...

동일한 보안 권한으로 실행되는 공격자로부터 자신을 보호 할 수는 없지만 다른 보안 권한으로 실행되는 권한없는 공격자로부터 자신을 보호 할 수는 있습니다.

뮤텍스에서 DACL을 설정해보십시오. .NET 방식은 다음과 같습니다. https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.mutexsecurity(v=vs.110).aspx


0

monodevelop을 사용하여 Linux에서 작업하는 데 필요했기 때문에이 답변 중 어느 것도 나를 위해 일하지 않았습니다. 이것은 나를 위해 잘 작동합니다.

이 메서드를 호출하여 고유 한 ID를 전달합니다.

    public static void PreventMultipleInstance(string applicationId)
    {
        // Under Windows this is:
        //      C:\Users\SomeUser\AppData\Local\Temp\ 
        // Linux this is:
        //      /tmp/
        var temporaryDirectory = Path.GetTempPath();

        // Application ID (Make sure this guid is different accross your different applications!
        var applicationGuid = applicationId + ".process-lock";

        // file that will serve as our lock
        var fileFulePath = Path.Combine(temporaryDirectory, applicationGuid);

        try
        {
            // Prevents other processes from reading from or writing to this file
            var _InstanceLock = new FileStream(fileFulePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
            _InstanceLock.Lock(0, 0);
            MonoApp.Logger.LogToDisk(LogType.Notification, "04ZH-EQP0", "Aquired Lock", fileFulePath);

            // todo investigate why we need a reference to file stream. Without this GC releases the lock!
            System.Timers.Timer t = new System.Timers.Timer()
            {
                Interval = 500000,
                Enabled = true,
            };
            t.Elapsed += (a, b) =>
            {
                try
                {
                    _InstanceLock.Lock(0, 0);
                }
                catch
                {
                    MonoApp.Logger.Log(LogType.Error, "AOI7-QMCT", "Unable to lock file");
                }
            };
            t.Start();

        }
        catch
        {
            // Terminate application because another instance with this ID is running
            Environment.Exit(102534); 
        }
    }         
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.