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

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

问题描述

使用C#和.NET WPF下(而不是 Windows窗体或控制台),什么是创建正确的方法只能被运行作为单个实例的应用

我知道它是与一些所谓互斥神话的东西很少,我可以找人困扰停止并解释其中之一是。

在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)
  等待它是否能够进入,假如果没有一个返回true。
  在这种情况下,我们不希望等待在所有;如果我们的互斥体是被
  使用时,跳过它,继续前进,所以我们传递TimeSpan.Zero(等待0
  毫秒),并且exitContext设置为真,所以我们可以退出
  同步上下文之前,我们尝试在它的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的(HWND的IntPtr,诠释味精,IntPtr的WPARAM,LPARAM的IntPtr);
    函数[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 Windows Forms 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天全站免登陆