WPF单一实例的最佳实践 [英] WPF Single Instance Best Practices

查看:149
本文介绍了WPF单一实例的最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的代码工作迄今已创造了单一实例WPF应用程序:

This is the code I implemented so far to create a single instance WPF application:

#region Using Directives
using System;
using System.Globalization;
using System.Reflection;
using System.Threading;
using System.Windows;
using System.Windows.Interop;
#endregion

namespace MyWPF
{
    public partial class MainApplication : Application, IDisposable
    {
        #region Members
        private Int32 m_Message;
        private Mutex m_Mutex;
        #endregion

        #region Methods: Functions
        private IntPtr HandleMessages(IntPtr handle, Int32 message, IntPtr wParameter, IntPtr lParameter, ref Boolean handled)
        {
            if (message == m_Message)
            {
                if (MainWindow.WindowState == WindowState.Minimized)
                    MainWindow.WindowState = WindowState.Normal;

                Boolean topmost = MainWindow.Topmost;

                MainWindow.Topmost = true;
                MainWindow.Topmost = topmost;
            }

            return IntPtr.Zero;
        }

        private void Dispose(Boolean disposing)
        {
            if (disposing && (m_Mutex != null))
            {
                m_Mutex.ReleaseMutex();
                m_Mutex.Close();
                m_Mutex = null;
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion

        #region Methods: Overrides
        protected override void OnStartup(StartupEventArgs e)
        {
            Assembly assembly = Assembly.GetExecutingAssembly();
            Boolean mutexCreated;
            String mutexName = String.Format(CultureInfo.InvariantCulture, "Local\\{{{0}}}{{{1}}}", assembly.GetType().GUID, assembly.GetName().Name);

            m_Mutex = new Mutex(true, mutexName, out mutexCreated);
            m_Message = NativeMethods.RegisterWindowMessage(mutexName);

            if (!mutexCreated)
            {
                m_Mutex = null;

                NativeMethods.PostMessage(NativeMethods.HWND_BROADCAST, m_Message, IntPtr.Zero, IntPtr.Zero);

                Current.Shutdown();

                return;
            }

            base.OnStartup(e);

            MainWindow window = new MainWindow();
            MainWindow = window;
            window.Show(); 

            HwndSource.FromHwnd((new WindowInteropHelper(window)).Handle).AddHook(new HwndSourceHook(HandleMessages));
        }

        protected override void OnExit(ExitEventArgs e)
        {
            Dispose();
            base.OnExit(e);
        }
        #endregion
    }
}



一切完美......但我对此有些怀疑,我希望收到你对我的做法如何改进的建议。

Everything works perfectly... but I have some doubts about it and I would like to receive your suggestions about how my approach could be improved.

1)有人问我代码分析,因为我是用的IDisposable 成员(实施的IDisposable 接口互斥)。是我的的Dispose()执行不够好?我应该避免它,因为它永远不会被调用?

1) I was asked by Code Analysis to implement IDisposable interface because I was using IDisposable members (the Mutex). Is my Dispose() implementation good enough? Should I avoid it because it's never going to be called?

2),这是更好地使用 m_Mutex =新的Mutex(真实的,mutexName,出mutexCreated ); 和检查的结果或使用 m_Mutex =新的Mutex(假,mutexName); 然后检查 m_Mutex.WaitOne(TimeSpan.Zero,FALSE); ?在多线程的情况下,我的意思是...

2) It's better to use m_Mutex = new Mutex(true, mutexName, out mutexCreated); and check for the result or to use m_Mutex = new Mutex(false, mutexName); and then check for m_Mutex.WaitOne(TimeSpan.Zero, false); ? In case of multithreading I mean...

3) RegisterWindowMessage API调用应该返回 UInt32的 ...但 HwndSourceHook 只接受的Int32 作为消息的价值......应我担心的意外行为(如结果比 Int32.MaxValue 大)?

3) RegisterWindowMessage API call should return UInt32... but HwndSourceHook is only accepting Int32 as message value... should I be worried about unexpected behaviors (like a result bigger than Int32.MaxValue)?

4) OnStartup 覆盖......我应该执行 base.OnStartup(E); 即使另一个实例已在运行,我要关闭应用程序?

4) In OnStartup override... should I execute base.OnStartup(e); even if another instance is already running and I'm going to shutdown the application?

5)有没有更好的方式,使现有的实例,这并不需要设置顶部朵蒙特价值?也许启动()

5) Is there a better way to bring the existing instance to the top that doesn't need to set Topmost value? Maybe Activate()?

6)你可以看到我的做法的缺陷?关于多线程的东西,不好的例外处理和类似的东西?例如......会发生什么,如果 OnStartup OnExit

6) Can you see any flaw in my approach? Something concerning multithreading, bad exceptions handling and something like that? For example... what happens if my application crashes between OnStartup and OnExit?

推荐答案

1),它看起来像一个标准的实施处置我。这是不是真的有必要(见第6点),但它不会做任何伤害。 (在关闭它清理有点像烧下来之前打扫屋子,恕我直言,但对此事的看法有所不同。)

1) It looks like a standard Dispose implementation to me. It is not really necessary (see point 6) but it does not do any harm. (Cleanup on closing it's a bit like cleaning the house before burning it down, IMHO, but opinions on the matter differs..)

无论如何,为什么不使用处置作为清理方法的名称,即使它不会直接叫什么名字?你可以把它称为清理,但记住,你还编写代码对人类和处置看起来很熟悉和.NET的人了解什么是它。所以,去为处置

Anyway, why not using "Dispose" as the name of the cleanup method, even if it does not get called directly? You could have called it "Cleanup", but remember you also write code for humans, and Dispose looks familiar and anyone on .NET understands what is it for. So, go for "Dispose".

2)我一直看到 m_Mutex =新的Mutex(假,mutexName); 我觉得这更是一个惯例,技术优势,但是

2) I have always seen m_Mutex = new Mutex(false, mutexName); I think it's more a convention that a technical advantage, however.

3)从MSDN:

如果该消息被成功注册,返回值是到0xFFFF范围内0xC000时的邮件标识符。

If the message is successfully registered, the return value is a message identifier in the range 0xC000 through 0xFFFF.

所以我不担心。通常情况下,这个类的功能,UINT不用于它不适合诠释,让我们使用UINT所以我们有更多的东西,但澄清合同函数永远不会返回一个负值。

So I would not worry. Usually, for this class of functions, UInt is not used for "it does not fit in Int, let's use UInt so we have something more" but to clarify a contract "function never returns a negative value".

4)我想避免调用它,如果你将关闭,原因同#1

4) I would avoid calling it if you will shutdown, same reason as #1

5)有一对夫妇的方式正在做。在Win32中最简单的方法就是让第二个实例进行调用SetForegroundWindow(看看这里:的 http://blogs.msdn.com/b/oldnewthing/archive/2009/02/20/9435239.aspx );但是,我不知道是否有一个等效WPF功能,或者,如果你需要的PInvoke它。

5) There are a couple of ways of doing it. The easiest way in Win32 is simply to have the second instance make the call to SetForegroundWindow (Look here: http://blogs.msdn.com/b/oldnewthing/archive/2009/02/20/9435239.aspx); however, I don't know if there is an equivalent WPF functionality or if you need to PInvoke it.

6)

例如......会发生什么,如果OnStartup和OnExit之间我的应用程序崩溃?

For example... what happens if my application crashes between OnStartup and OnExit?

这是确定的:当一个进程终止时,该进程拥有的所有句柄被释放;互斥体被释放为好。

It's OK: when a process terminates, all handles owned by the process are released; the mutex is released as well.

在总之,我的建议:


  • 我会使用基于一种方法命名的同步对象:它是更windows平台(S)上建立。 (考虑一个多用户系统时,如终端服务器小心!命名的同步对象,也许,用户名/ SID和应用程序名称的组合)

  • 使用Windows API来提高以前的实例(见我在#5点链接),或WPF等价物。

  • 您可能不担心崩溃(内核将减少对内核对象裁判计数器为您服务;做一个小测试反正),但如果我可以建议的改进:如果你的第一个应用程序实例不会崩溃什么,而是挂起? (与Firefox偏偏..我敢肯定它发生在你身上!无窗,FF过程中,你不能打开一个新的)。在这种情况下,它可能是好的,如果应用程序/窗口响应的另一种技术或两者结合起来,以一个)测试; B)找到挂起实例,并终止

例如,你可以使用你的技术(尝试发送/发布消息窗口 - 如果不回嘴它卡),加上MSK技术,发现并终止旧进程。然后正常启动。

For example, you can use your technique (trying to send/post a message to the window - if does not answer back it is stuck), plus MSK technique, to find and terminate the old process. Then start normally.

这篇关于WPF单一实例的最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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