什么是创造了单实例应用程序的正确方法是什么? [英] What is the correct way to create a single instance application?

查看:517
本文介绍了什么是创造了单实例应用程序的正确方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用C#和WPF在.NET下(而不是WindowsForms或控制台),什么是创建一个只能运行一个单一实例的应用程序的正确方法是什么?我知道它是与一些神秘的东西叫一个互斥体,很少我可以找人困扰停下来解释其中之一是。

在code需要还告知已经运行的实例,用户试图启动第二个一个,也许还通过任何命令行参数如果任何存在。

解决方案

下面是关于一个非常好的文章互斥的解决方案。本文所描述的方法是有利的,原因有两个。

首先,它不要求对Microsoft.VisualBasic程序组件的依赖关系。如果我的项目已经有上装配的依赖,我可能会主张使用公认的答案显示的方式。但因为它是,我不使用Microsoft.VisualBasic程序集,我宁愿不不必要的依赖关系添加到我的项目。

二,文章展示了如何当用户试图启动另一个实例使应用程序的现有实例置于前台。这是一个非常良好的感觉,这里描述的其他互斥方案没有解决。


更新

截至2014年8月1日,我联系到上面的文章仍然是积极的,但博客一直没有在一段时间更新。这让我担心,它最终可能会消失,有了它,所提倡的解决方案。我再现文章的内容在这里为后人。这句话属于纯粹的博客的主人在理智自由编码

  

今天,我想重构了禁止我的应用程序的一些code   运行其自身的多个实例。

     

previously我不得不使用<一个href="http://msdn.microsoft.com/en-us/library/system.diagnostics.process(v=vs.110).aspx">System.Diagnostics.Process以搜索   比如我在进程列表程序myapp.exe的。虽然这工作,它   带来了很多的开销,和我想要的东西更清洁。

     

知道,我可以用一个互斥这个(但从未做过   之前),我开始着手削减我的code和简化了我的生活。

     

在班级我的应用程序主要的我创建了一个静态命名的互斥

 静态类节目
{
    静态互斥互斥=新的mutex(真的,{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F});
    [STAThread]
    ...
}
 

  

有一个名为互斥使我们能够跨越叠加同步   多线程和进程这就是我要找的魔力   为

     

Mutex.WaitOne 具有过载,指定金额时间对我们来说   等待。由于我们没有真正想同步我们的code   (更多只是检查是否正在使用中),我们使用的超负荷   两个参数: Mutex.WaitOne(时间跨度超时,布尔exitContext) 。   等待,如果它能够进入,否则为false没有一个返回true。   在这种情况下,我们不希望等待所有;如果我们的互斥体是被   使用时,跳过它,继续前进,所以我们传递的TimeSpan.Zero(等待0   毫秒),并设置exitContext为true,这样我们就可以退出   同步上下文之前,我们试图在它的AQUIRE锁。运用   这一点,我们总结里这样的事情我们Application.Run code:

 静态类节目
{
    静态互斥互斥=新的mutex(真的,{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F});
    [STAThread]
    静态无效的主要(){
        如果(mutex.WaitOne(TimeSpan.Zero,真)){
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(假);
            Application.Run(新Form1中());
            mutex.ReleaseMutex();
        } 其他 {
            的MessageBox.show(在同一时间只有一个实例);
        }
    }
}
 

  

所以,如果我们的应用程序正在运行,了WaitOne将返回false,我们将得到一个   消息框。

     而不是显示一个消息框的

,我选择使用一个小的Win32到   通知我正在运行的实例,有人忘了,它已经   运行(通过使自身的所有其他窗口的顶部)。至   做到这一点我用<一个href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms644944(v=vs.85).aspx">PostMessage广播自定义消息,每   窗口(自定义邮件注册<一个href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms644947(v=vs.85).aspx">RegisterWindowMessage   我的应用程序运行,这意味着只有我的应用程序知道什么   这是)那么我的第二个实例退出。正在运行的应用程序实例   会收到通知,并进行处理。为了做到这一点,我   压倒<一href="http://msdn.microsoft.com/en-us/library/system.windows.forms.form.wndproc(v=vs.110).aspx">WndProc在我的主要形式,并听取了我的自定义   通知。当我收到通知,我设置窗体的   TopMost属性为true,使其达到顶部。

     

下面是我结束了:

     
      
  • 的Program.cs
  •   

 静态类节目
{
    静态互斥互斥=新的mutex(真的,{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F});
    [STAThread]
    静态无效的主要(){
        如果(mutex.WaitOne(TimeSpan.Zero,真)){
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(假);
            Application.Run(新Form1中());
            mutex.ReleaseMutex();
        } 其他 {
            //把我们的Win32消息,使当前运行的实例
            //跳在所有其他窗口的顶部
            NativeMethods.PostMessage(
                (IntPtr的)NativeMethods.HWND_BROADCAST,
                NativeMethods.WM_SHOWME,
                IntPtr.Zero,
                IntPtr.Zero);
        }
    }
}
 

  
      
  • NativeMethods.cs
  •   

  //这个类只是包装一些Win32的东西,我们要使用
内部类NativeMethods
{
    公共const int的HWND_BROADCAST = 0xFFFF的;
    公共静态只读INT WM_SHOWME = RegisterWindowMessage(WM_SHOWME);
    [的DllImport(USER32)]
    公共静态的extern BOOL PostMessage的(IntPtr的HWND,INT味精,IntPtr的WPARAM,IntPtr的LPARAM);
    [的DllImport(USER32)]
    公共静态外部INT RegisterWindowMessage(字符串消息);
}
 

  
      
  • 在Form1.cs中(前侧部分)
  •   

 公共部分类Form1中:形态
{
    公共Form1中()
    {
        的InitializeComponent();
    }
    保护覆盖无效的WndProc(参考消息M)
    {
        如果(m.Msg == NativeMethods.WM_SHOWME){
            给我看看();
        }
        base.WndProc(REF米);
    }
    私人无效SHOWME()
    {
        如果(的WindowState == FormWindowState.Minimized){
            的WindowState = FormWindowState.Normal;
        }
        //获取我们目前的最顶层的价值(我们将永远是假的,虽然)
        布尔顶部=最顶层;
        //使我们的形式跳转到一切的顶部
        最顶层=真;
        //设置回不管它是什么
        最顶层=顶部;
    }
}
 

Using C# and WPF under .net (rather than WindowsForms or console), what is the correct way to create an application that can only be run as a single instance? I know it has something to do with some mythical thing called a mutex, rarely can I find someone that bothers to stop and explain what one of these are.

The code needs to also inform the already running instance that the user tried to start a second one, and maybe also pass any command line arguments if any existed.

解决方案

Here is a very good article regarding the Mutex solution. The approach described by the article is advantageous for two reasons.

First, it does not require a dependency on the Microsoft.VisualBasic assembly. If my project already had a dependency on that assembly, I would probably advocate using the approach shown in the accepted answer. But as it is, I do not use the Microsoft.VisualBasic assembly, and I'd rather not add an unnecessary dependency to my project.

Second, the article shows how to bring the existing instance of the application to the foreground when the user tries to start another instance. That's a very nice touch that the other Mutex solutions described here do not address.


UPDATE

As of 8/1/2014, the article I linked to above is still active, but the blog hasn't been updated in a while. That makes me worry that eventually it might disappear, and with it, the advocated solution. I'm reproducing the content of the article here for posterity. The words belong solely to the blog owner at Sanity Free Coding.

Today I wanted to refactor some code that prohibited my application from running multiple instances of itself.

Previously I had use System.Diagnostics.Process to search for an instance of my myapp.exe in the process list. While this works, it brings on a lot of overhead, and I wanted something cleaner.

Knowing that I could use a mutex for this (but never having done it before) I set out to cut down my code and simplify my life.

In the class of my application main I created a static named Mutex:

static class Program
{
    static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}");
    [STAThread]
    ...
}

Having a named mutex allows us to stack synchronization across multiple threads and processes which is just the magic I'm looking for.

Mutex.WaitOne has an overload that specifies an amount of time for us to wait. Since we're not actually wanting to synchronizing our code (more just check if it is currently in use) we use the overload with two parameters: Mutex.WaitOne(Timespan timeout, bool exitContext). Wait one returns true if it is able to enter, and false if it wasn't. In this case, we don't want to wait at all; If our mutex is being used, skip it, and move on, so we pass in TimeSpan.Zero (wait 0 milliseconds), and set the exitContext to true so we can exit the synchronization context before we try to aquire a lock on it. Using this, we wrap our Application.Run code inside something like this:

static class Program
{
    static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}");
    [STAThread]
    static void Main() {
        if(mutex.WaitOne(TimeSpan.Zero, true)) {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
            mutex.ReleaseMutex();
        } else {
            MessageBox.Show("only one instance at a time");
        }
    }
}

So, if our app is running, WaitOne will return false, and we'll get a message box.

Instead of showing a message box, I opted to utilize a little Win32 to notify my running instance that someone forgot that it was already running (by bringing itself to the top of all the other windows). To achieve this I used PostMessage to broadcast a custom message to every window (the custom message was registered with RegisterWindowMessage by my running application, which means only my application knows what it is) then my second instance exits. The running application instance would receive that notification and process it. In order to do that, I overrode WndProc in my main form and listened for my custom notification. When I received that notification I set the form's TopMost property to true to bring it up on top.

Here is what I ended up with:

  • Program.cs

static class Program
{
    static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}");
    [STAThread]
    static void Main() {
        if(mutex.WaitOne(TimeSpan.Zero, true)) {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
            mutex.ReleaseMutex();
        } else {
            // send our Win32 message to make the currently running instance
            // jump on top of all the other windows
            NativeMethods.PostMessage(
                (IntPtr)NativeMethods.HWND_BROADCAST,
                NativeMethods.WM_SHOWME,
                IntPtr.Zero,
                IntPtr.Zero);
        }
    }
}

  • NativeMethods.cs

// this class just wraps some Win32 stuff that we're going to use
internal class NativeMethods
{
    public const int HWND_BROADCAST = 0xffff;
    public static readonly int WM_SHOWME = RegisterWindowMessage("WM_SHOWME");
    [DllImport("user32")]
    public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
    [DllImport("user32")]
    public static extern int RegisterWindowMessage(string message);
}

  • Form1.cs (front side partial)

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    protected override void WndProc(ref Message m)
    {
        if(m.Msg == NativeMethods.WM_SHOWME) {
            ShowMe();
        }
        base.WndProc(ref m);
    }
    private void ShowMe()
    {
        if(WindowState == FormWindowState.Minimized) {
            WindowState = FormWindowState.Normal;
        }
        // get our current "TopMost" value (ours will always be false though)
        bool top = TopMost;
        // make our form jump to the top of everything
        TopMost = true;
        // set it back to whatever it was
        TopMost = top;
    }
}

这篇关于什么是创造了单实例应用程序的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆