.NETで特定のアプリの複数のインスタンスを防止しますか?


123

.NETで、アプリの複数のインスタンスが同時に実行されるのを防ぐための最良の方法は何ですか?そして、「最良の」手法がない場合、各ソリューションで考慮すべき注意点は何ですか?

回答:


151

Mutexを使用します。GetProcessByNameを使用した上記の例の1つには、多くの警告があります。これは主題に関する良い記事です:

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
mutexの使用は、.net以外のコードでも機能します(構文は異なります)
crashmstr

8
これは、いくつかの良いコメントを含む、もう少し記入されたバージョンです。stackoverflow.com
Richard Watson

2
@ClarkKent:Mutex名が別のアプリケーションの名前と衝突しないように、ランダムな文字列。
jgauffin 2013

これも特定の数のインスタンスに制限できますか?
アレハンドロデルリオ

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/…の
John Nguyen

あなたの時間と努力に対するすばらしい完璧な感謝
Ahmed Mahmoud '20

2
-1これは迅速な解決策ですが、a.exeの名前をb.exeに変更すれば、非常に簡単に回避でき、どちらも実行されます。+これが単に意図したとおりに機能しない他のケース。注意して使用してください!
Lars Nielsen

これはmono-developでは機能しません。ただし、Windows環境では問題なく動作します。
遠野ナム

20

以下は、1つのインスタンスのみが実行されていることを確認するために必要なコードです。これは、名前付きミューテックスを使用する方法です。

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();を使用します。この方法は魅力のように機能します。テラピン、ありがとう。
ジェフ

ここで重要なのは、ミューテックスを静的にすることです。他の場合と同様に、GCが収集します。
Oleksii 2015

名前付きミューテックスのシンプルさと明快さを楽しんだ。このコードは簡潔で効果的です。
チャド

7

Hanselmanは、Microsoft.VisualBasicアセンブリのWinFormsApplicationBaseクラスを使用してこれを行う方法についての投稿を持っています。


私はこれを数年間使用してきましたが、現在、Mutexベースのソリューションへの変更を検討しています。私はこれに関して問題を報告している顧客がいて、それを行うためにRemotingを使用していると思います。
リチャードワトソン

5

これまでに提案されてきた3つの基本的なテクニックがあるようです。

  1. Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBaseクラスから派生し、IsSingleInstanceプロパティをtrueに設定します。(ここでの警告は、これがWPFアプリケーションでは機能しないことです。)
  2. 名前付きミューテックスを使用して、それがすでに作成されているかどうかを確認します。
  3. 実行中のプロセスのリストを取得し、プロセスの名前を比較します。(これには、プロセス名が特定のユーザーのマシンで実行されている他のプロセスに対して一意である必要があるという警告があります。)

私が見逃した警告はありますか?


3
3は非常に効率的ではないと思います。Mutexに投票し、問題なく何度も使用しました。私はアイテム1を使用したことがありません。
typemismatch 2008

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アタックヘリコプター

プロセスの名前を使用しています。名前が繰り返されると、偽のフラグが生成されます。それ以外の場合は、mutexよりもきれいです
magallanes

4

実行可能ファイルのプロジェクトを作成するときにVisual Studio 2005または2008を使用すると、[アプリケーション]パネル内のプロパティウィンドウに、[単一インスタンスアプリケーションを作成する]というチェックボックスがあり、これをアクティブにして、単一インスタンスアプリケーションでアプリケーションを変換できます。 。

ここに画像の説明を入力してください これが私が話しているウィンドウのキャプチャです: これはVisual Studio 2008のウィンドウアプリケーションプロジェクトです。


3
私のC#/ WPFアプリについて、このチェックボックスを探しましたが、何もありません。
HappyNomad

3
VS 2008 C#/ WinFormsアプリのプロパティにも表示されません。
Jesse McGrew、2010

VS2005にもありません。彼は古いVBスタジオについて言及しているに違いありません。
nawfal 2011

はい、オプションは存在します。投稿を変更して、このオプションを見つけることができるウィンドウのキャプチャを追加しました。
Doliveras 2011

6
このオプションはVB.NETアプリケーションにのみ存在し、C#には存在しません。どうやらオプション自体は、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
}

私はいくつかの条件でのみ他のインスタンスを閉じる必要がありました、これは私の目的のためにうまくいきました


実際にmutexを取得して解放する必要はありません。知っておく必要があるのは、別のアプリがすでにオブジェクトを作成したかどうか(つまり、そのカーネル参照カウント> = 1)だけです。
Michael Goldshteyn


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


リンクが壊れています。
チャド

2

VB.NETを使用してください!いいえ:本当に;)

Microsoft.VisualBasic.ApplicationServicesを使用します。

VB.NetのWindowsFormsApplicationBaseは、 "SingleInstace"プロパティを提供します。これは、他のインスタンスを決定し、1つのインスタンスのみを実行できるようにします。


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 +デザインを使用しています。)

アプリに画像を入れて、起動時にロードします。アプリが終了するまで押し続けます。ユーザーは2番目のインスタンスを開始できません。(もちろん、mutexソリューションはよりクリーンです)

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

これは実際にはその単純さに優れており、画像だけでなく、ほとんどすべての種類のファイルで機能します。ミューテックスのソリューションは「クリーン」にはほど遠いように感じます。これは非常に複雑であり、「正しく」実行しないために失敗する方法はたくさんあるようです。また、Main()WPFの動作方法に反する方法も必要です。
カイルデラニー

これは、バグのようなものです。それは動作しますが、その目的のために作られていません。私はそれを専門家として使用しません。
Bitterblue 2018

ええ、残念ながら、例外に頼らずにこれほど効果的で簡単な解決策はありません。
カイルデラニー

正確にはバグではありませんが。.NETは意図したとおりに動作しています。
カイルデラニー

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が重要である理由を見つけるためのC#に関するJon SkeetのFAQ


-1。mutexでusingブロックを使用できないため、KeepAliveが不要になります。そして、はい、私はジョン・スキートがこれを間違っていたと思います。この場合、ミューテックスを破棄することがなぜ間違っているのかについて、彼は詳しく述べていません。

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

通常は名前付きミューテックスで行われます(新しいミューテックス(「アプリ名」、trueを使用して戻り値を確認))が、Microsoft.VisualBasic.dllにサポートクラスがいくつかあります


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

Linuxでは、monodevelopを使用して作業するためにこれが必要だったため、この回答はどれもうまくいきませんでした。これは私にとってはうまくいきます:

一意の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.