【发布时间】:2013-01-08 12:11:18
【问题描述】:
这是我迄今为止实现的用于创建单实例 WPF 应用程序的代码:
#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
}
}
一切都很完美......但我对此有些怀疑,我希望收到您关于如何改进我的方法的建议。
1) 代码分析要求我实现IDisposable 接口,因为我使用的是IDisposable 成员(Mutex)。我的Dispose() 实现是否足够好?我应该避免它,因为它永远不会被调用吗?
2) 最好使用m_Mutex = new Mutex(true, mutexName, out mutexCreated); 并检查结果还是使用m_Mutex = new Mutex(false, mutexName); 然后检查m_Mutex.WaitOne(TimeSpan.Zero, false);?在多线程的情况下,我的意思是......
3) RegisterWindowMessage API 调用应该返回 UInt32... 但 HwndSourceHook 只接受 Int32 作为消息值... 我应该担心意外行为(例如大于 Int32.MaxValue 的结果)?
4) 在OnStartup 覆盖...即使另一个实例已经在运行并且我要关闭应用程序,我是否应该执行base.OnStartup(e);?
5) 有没有更好的方法将现有实例置于顶部而不需要设置Topmost 值?也许Activate()?
6) 你能看出我的方法有什么缺陷吗?关于多线程、不良异常处理之类的东西?例如...如果我的应用程序在OnStartup 和OnExit 之间崩溃会发生什么?
【问题讨论】:
-
好问题。但是,它同时包含很多问题,因此codereview.stackexchange.com 可能更合适。
-
你检查过微软的实现吗? elegantcode.com/wp-content/uploads/2011/03/…
-
从远程 IPC 管理它对我来说似乎有点太多了。这就像用核弹杀死一只苍蝇。
-
从那个链接和上面的其他链接,我喜欢这个答案stackoverflow.com/a/1904772/3225