我有一个 Windows 应用程序(C#),我需要将它配置为当时从应用程序运行一个实例,这意味着一个用户单击了 .exe 文件并且应用程序运行并且用户没有关闭第一个实例正在运行的应用程序需要运行下一个实例,因此它应该出现在第一个实例中,而不是打开新实例。
谁能帮我怎么做?
提前致谢
我经常通过检查其他同名进程来解决这个问题。这样做的优点/缺点是您(或用户)可以通过重命名 exe 来“避开”检查。如果您不希望这样,您可能会使用返回的 Process-object。
string procName = Process.GetCurrentProcess().ProcessName;
if (Process.GetProcessesByName(procName).Length == 1)
{
...code here...
}
这取决于您的需要,我认为绕过检查而不重新编译很方便(它是一个服务器进程,有时作为服务运行)。
VB.Net 团队已经实施了一个解决方案。您将需要依赖 Microsoft.VisualBasic.dll,但如果这不打扰您,那么恕我直言,这是一个很好的解决方案。请参阅以下文章的结尾:单实例应用程序
以下是文章的相关部分:
1) 添加对 Microsoft.VisualBasic.dll 的引用 2) 将以下类添加到您的项目中。
public class SingleInstanceApplication : WindowsFormsApplicationBase
{
private SingleInstanceApplication()
{
base.IsSingleInstance = true;
}
public static void Run(Form f, StartupNextInstanceEventHandler startupHandler)
{
SingleInstanceApplication app = new SingleInstanceApplication();
app.MainForm = f;
app.StartupNextInstance += startupHandler;
app.Run(Environment.GetCommandLineArgs());
}
}
打开 Program.cs 并添加以下 using 语句:
using Microsoft.VisualBasic.ApplicationServices;
将类更改为以下内容:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
SingleInstanceApplication.Run(new Form1(), StartupNextInstanceEventHandler);
}
public static void StartupNextInstanceEventHandler(object sender, StartupNextInstanceEventArgs e)
{
MessageBox.Show("New instance");
}
}
我们遇到了完全相同的问题。我们尝试了进程方法,但如果用户无权阅读有关其他进程的信息,即非管理员,则此方法失败。所以我们实现了下面的解决方案。
基本上我们尝试打开一个文件进行独占阅读。如果这失败了(因为另一个实例已经这样做了),我们会得到一个异常并且可以退出应用程序。
bool haveLock = false;
try
{
lockStream = new System.IO.FileStream(pathToTempFile,System.IO.FileMode.Create,System.IO.FileAccess.ReadWrite,System.IO.FileShare.None);
haveLock = true;
}
catch(Exception)
{
System.Console.WriteLine("Failed to acquire lock. ");
}
if(!haveLock)
{
Inka.Controls.Dialoge.InkaInfoBox diag = new Inka.Controls.Dialoge.InkaInfoBox("App has been started already");
diag.Size = new Size(diag.Size.Width + 40, diag.Size.Height + 20);
diag.ShowDialog();
Application.Exit();
}
编辑:在问题被修改为包含 c# 之后。我的答案仅适用于 vb.net 应用程序
选中Make single instance application复选框以防止用户运行您的应用程序的多个实例。此复选框的默认设置被清除,允许运行应用程序的多个实例。
您可以从项目 -> 属性 -> 应用程序选项卡执行此操作
假设您使用的是 C#
static Mutex mx;
const string singleInstance = @"MU.Mutex";
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
try
{
System.Threading.Mutex.OpenExisting(singleInstance);
MessageBox.Show("already exist instance");
return;
}
catch(WaitHandleCannotBeOpenedException)
{
mx = new System.Threading.Mutex(true, singleInstance);
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
我会Mutex
在这种情况下使用 a 。或者, aSemaphore
也可以工作(但 aMutex
似乎更合适)。
这是我的示例(来自 WPF 应用程序,但相同的原则应适用于其他项目类型):
public partial class App : Application
{
const string AppId = "MY APP ID FOR THE MUTEX";
static Mutex mutex = new Mutex(false, AppId);
static bool mutexAccessed = false;
protected override void OnStartup(StartupEventArgs e)
{
try
{
if (mutex.WaitOne(0))
mutexAccessed = true;
}
catch (AbandonedMutexException)
{
//handle the rare case of an abandoned mutex
//in the case of my app this isn't a problem, and I can just continue
mutexAccessed = true;
}
if (mutexAccessed)
base.OnStartup(e);
else
Shutdown();
}
protected override void OnExit(ExitEventArgs e)
{
if (mutexAccessed)
mutex?.ReleaseMutex();
mutex?.Dispose();
mutex = null;
base.OnExit(e);
}
}
我找到了这段代码,它的工作!
/// <summary>
/// The main entry point for the application.
/// Limit an app.to one instance
/// </summary>
[STAThread]
static void Main()
{
//Mutex to make sure that your application isn't already running.
Mutex mutex = new System.Threading.Mutex(false, "MyUniqueMutexName");
try
{
if (mutex.WaitOne(0, false))
{
// Run the application
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
else
{
MessageBox.Show("An instance of the application is already running.",
"An Application Is Running", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Application Error 'MyUniqueMutexName'",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
finally
{
if (mutex != null)
{
mutex.Close();
mutex = null;
}
}
}