如何实现每台机器应用程序的单实例?

时间:2010-11-19 07:50:10

标签: c# .net mutex single-instance

我必须限制我的.net 4 WPF应用程序,以便每台计算机只能运行一次。请注意,我说每台机器,而不是每个会话 到目前为止,我使用简单的互斥锁实现了单实例应用程序,但不幸的是,每个会话都有这样的互斥锁。

有没有办法创建机器范围的互斥锁,还是有其他解决方案来实现每个机器应用程序的单个实例?

7 个答案:

答案 0 :(得分:14)

我会使用全局Mutex对象执行此操作,该对象必须在应用程序的生命周期内保留。

MutexSecurity oMutexSecurity;

//Set the security object
oMutexSecurity = new MutexSecurity();
oMutexSecurity.AddAccessRule(new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null), MutexRights.FullControl, AccessControlType.Allow));

//Create the global mutex and set its security
moGlobalMutex = new Mutex(True, "Global\\{5076d41c-a40a-4f4d-9eed-bf274a5bedcb}", bFirstInstance);
moGlobalMutex.SetAccessControl(oMutexSecurity);

如果这是全局运行的应用程序的第一个实例,则返回bFirstInstance。如果您省略了互斥锁的全局部分或将其替换为本地,那么互斥锁将仅针对每个会话(这可能是您当前代码的工作原理)。

我相信我首先从Jon Skeet获得了这项技术。

Mutex对象上的MSDN主题解释了Mutex对象的两个范围,并重点介绍了在使用终端服务时这一点很重要的原因(参见倒数第二页)。

答案 1 :(得分:3)

我认为您需要做的是使用system sempahore来跟踪应用程序的实例。

如果使用接受名称的构造函数创建Semaphore对象,则它与该名称的操作系统信号量相关联。

命名系统信号量在整个操作系统中都可见,可用于同步进程的活动。

编辑:请注意,我不知道此方法是否适用于计算机上的多个Windows会话。我认为它应该是一个操作系统级别的构造,但我无法肯定地说,因为我没有这样测试过。

编辑2:我不知道这一点但是在阅读了Stevo2000的答案之后,我也做了一些查找,我认为使该对象适用于全局命名空间的“Global \”前缀也适用于信号量和信号量,如果以这种方式创建,应该可以工作。

答案 2 :(得分:2)

你可以在%PROGRAMDATA%的某个地方打开一个拥有专有权的文件 启动的第二个实例将尝试打开同一个文件,如果它已经打开则会失败。

答案 3 :(得分:1)

使用注册表怎么样?

  1. 您可以创建registry entry under HKEY_LOCAL_MACHINE
  2. 如果应用程序已启动,请将值设为flag
  3. Encrypt the key使用一些标准symmetric key encryption方法,这样其他任何人都无法篡改该值。
  4. On application start-up check for the key并中止\相应地继续。
  5. 不要忘记执行此加密\解密部分的obfuscate your assembly,这样任何人都无法通过查看反射器中的代码来破解注册表中的密钥。

答案 4 :(得分:0)

我曾做过类似的事情。

在启动应用程序列表时,我检查了所有正在运行的进程,查找名称相同的进程,如果存在,我将不允许启动该程序。

当然,这不是防弹,因为如果另一个应用程序具有完全相同的进程名称,您的应用程序将永远不会启动,但如果您使用非通用名称,它可能会非常好。

答案 5 :(得分:0)

为了完整起见,我想补充一下我刚刚发现的以下内容:
这个web site在将Win32消息发送到其他进程时有一个有趣的方法。这将解决用户重命名程序集以绕过测试和其他具有相同名称的程序集的问题 他们正在使用该消息来激活其他进程的主窗口,但似乎该消息可能是一个虚拟消息,仅用于查看其他进程是否响应它以了解它是否是我们的进程。 / p>

请注意,我还没有测试过。

答案 6 :(得分:-1)

请参阅下文,了解如何在WPF 3.5中完成单个instace应用程序的完整示例

public class SingleInstanceApplicationWrapper :
Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase
{
public SingleInstanceApplicationWrapper()
{
// Enable single-instance mode.
this.IsSingleInstance = true;
}
// Create the WPF application class.
private WpfApp app;
protected override bool OnStartup(
Microsoft.VisualBasic.ApplicationServices.StartupEventArgs e)
{
app = new WpfApp();
app.Run();
return false;
}
// Direct multiple instances.
protected override void OnStartupNextInstance(
Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs e)
{
if (e.CommandLine.Count > 0)
{
app.ShowDocument(e.CommandLine[0]);
}
}
}

第二部分:

public class WpfApp : System.Windows.Application
{
protected override void OnStartup(System.Windows.StartupEventArgs e)
{
base.OnStartup(e);
WpfApp.current = this;
// Load the main window.
DocumentList list = new DocumentList();
this.MainWindow = list;
list.Show();
// Load the document that was specified as an argument.
if (e.Args.Length > 0) ShowDocument(e.Args[0]);
}
public void ShowDocument(string filename)
{
try
{
Document doc = new Document();
doc.LoadFile(filename);
doc.Owner = this.MainWindow;
doc.Show();
// If the application is already loaded, it may not be visible.
// This attempts to give focus to the new window.
doc.Activate();
}
catch
{
MessageBox.Show("Could not load document.");
}
}
}

第三部分:

 public class Startup
    {
    [STAThread]
    public static void Main(string[] args)
    {
    SingleInstanceApplicationWrapper wrapper =
    new SingleInstanceApplicationWrapper();
    wrapper.Run(args);
    }
    }

您可能需要添加soem引用并添加一些using语句,但它可以正常工作。

您还可以从here下载图书的源代码,下载VS示例完整解决方案。

摘自“2008年C#3中的Pro WPF,Apress,马修麦克唐纳”,买这本书就是黄金。我做到了。