如果已经有实例运行,我的应用程序在加载时需要略微不同。
我理解如何使用互斥锁来阻止其他实例加载,但这并不能完全解决我的问题。
例如:
有什么想法吗?值得庆幸的是,它不需要处理多个用户帐户或类似的东西。
(C#,桌面应用程序)
编辑:为了澄清,应用程序不需要限制在单个实例上,只要执行另一个已经运行的实例,就执行稍微不同的启动操作。多个实例都很好(并且是预期的)。
答案 0 :(得分:12)
这可能会做你想要的。它具有很好的附加功能,可以使已经运行的实例前进。
编辑:更新了代码以自动确定应用程序标题。
using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
static void Main()
{
if (!EnsureSingleInstance())
{
return;
}
//...
}
static bool EnsureSingleInstance()
{
Process currentProcess = Process.GetCurrentProcess();
var runningProcess = (from process in Process.GetProcesses()
where
process.Id != currentProcess.Id &&
process.ProcessName.Equals(
currentProcess.ProcessName,
StringComparison.Ordinal)
select process).FirstOrDefault();
if (runningProcess != null)
{
ShowWindow(runningProcess.MainWindowHandle, SW_SHOWMAXIMIZED);
SetForegroundWindow(runningProcess.MainWindowHandle);
return false;
}
return true;
}
[DllImport("user32.dll", EntryPoint = "SetForegroundWindow")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow);
private const int SW_SHOWMAXIMIZED = 3;
答案 1 :(得分:2)
答案 2 :(得分:1)
尝试使用信号量而不是互斥锁
答案 3 :(得分:0)
您是否可以在使用GetLastError()
创建互斥锁后查看CreateMutex()
?如果它返回ERROR_ALREADY_EXISTS
,则表示您的应用程序正在运行另一个实例。
根据http://msdn.microsoft.com/en-us/library/ms682411%28VS.85%29.aspx,
如果互斥锁是一个命名的互斥锁,那么 对象在此函数之前存在 调用,返回值是句柄 现有对象GetLastError 返回ERROR_ALREADY_EXISTS, bInitialOwner被忽略了 调用线程未被授予 所有权。但是,如果来电者有 有限的访问权限,功能 将失败,ERROR_ACCESS_DENIED和 调用者应该使用OpenMutex 功能
编辑:刚刚意识到这是一个C#/ .Net问题,抱歉。
在.Net中,使用返回createdNew标志的Mutex构造函数http://msdn.microsoft.com/en-us/library/bwe34f1k%28VS.80%29.aspx:
public Mutex (
bool initiallyOwned,
string name,
out bool createdNew
)
答案 4 :(得分:0)
一个好方法是使用Sandor解决方案,但使用WMI获取进程列表,如下所述:C#: How to get the full path of running process?(Jeff的解决方案)。这样,您还可以检查其他正在运行的实例是否与路径和远程终端会话ID匹配:
static bool EnsureSingleInstance()
{
Process currentProcess = Process.GetCurrentProcess();
var wmiQueryString = "SELECT ProcessId, ExecutablePath, CommandLine FROM Win32_Process";
using (var searcher = new ManagementObjectSearcher(wmiQueryString))
using (var results = searcher.Get())
{
var query = from p in Process.GetProcesses()
join mo in results.Cast<ManagementObject>()
on p.Id equals (int)(uint)mo["ProcessId"]
select new
{
Process = p,
Path = (string)mo["ExecutablePath"],
CommandLine = (string)mo["CommandLine"],
};
var runningProcess = (from process in query
where
process.Process.Id != currentProcess.Id &&
process.Process.ProcessName.Equals(
currentProcess.ProcessName,
StringComparison.Ordinal) &&
process.Path == currentProcess.MainModule.FileName &&
process.Process.SessionId == currentProcess.SessionId
select process).FirstOrDefault();
return runningProcess == null;
}
}