Odpowiedzi:
Użyj Mutex. Jeden z powyższych przykładów użycia GetProcessByName ma wiele zastrzeżeń. Oto dobry artykuł na ten temat:
http://odetocode.com/Blogs/scott/archive/2004/08/20/401.aspx
[STAThread]
static void Main()
{
using(Mutex mutex = new Mutex(false, "Global\\" + appGuid))
{
if(!mutex.WaitOne(0, false))
{
MessageBox.Show("Instance already running");
return;
}
Application.Run(new Form1());
}
}
private static string appGuid = "c0a76b5a-12ab-45c5-b9d9-d693faa6e7b9";
string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), true)[0]).Value;który dostanie wykonującemu Zgromadzenia guid
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1)
{
AppLog.Write("Application XXXX already running. Only one instance of this application is allowed", AppLog.LogMessageType.Warn);
return;
}
Oto kod, którego potrzebujesz, aby upewnić się, że działa tylko jedna instancja. Jest to metoda korzystania z nazwanego muteksu.
public class Program
{
static System.Threading.Mutex singleton = new Mutex(true, "My App Name");
static void Main(string[] args)
{
if (!singleton.WaitOne(TimeSpan.Zero, true))
{
//there is already another instance running!
Application.Exit();
}
}
}
Hanselman ma post dotyczący używania klasy WinFormsApplicationBase z zestawu Microsoft.VisualBasic do tego.
Wygląda na to, że do tej pory zasugerowano 3 podstawowe techniki.
Jakieś zastrzeżenia, które przegapiłem?
1 - Utwórz odniesienie w program.cs ->
using System.Diagnostics;
2 - Wstaw void Main()jako pierwszą linię kodu ->
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length >1)
return;
Otóż to.
Mutex? Czy jest jakiś haczyk?
Korzystając z programu Visual Studio 2005 lub 2008 podczas tworzenia projektu dla pliku wykonywalnego, w oknach właściwości w panelu „Aplikacja” znajduje się pole wyboru o nazwie „Utwórz aplikację z pojedynczą instancją”, które można aktywować, aby przekonwertować aplikację na aplikację z pojedynczym wystąpieniem .
Oto zrzut okna, o którym mówię:
To jest projekt aplikacji Windows Visual Studio 2008.
Wypróbowałem wszystkie rozwiązania tutaj i nic nie działało w moim projekcie C # .net 4.0. Mam nadzieję, że pomogę komuś w rozwiązaniu, które zadziałało dla mnie:
Jako główne zmienne klasowe:
private static string appGuid = "WRITE AN UNIQUE GUID HERE";
private static Mutex mutex;
Kiedy musisz sprawdzić, czy aplikacja już działa:
bool mutexCreated;
mutex = new Mutex(true, "Global\\" + appGuid, out mutexCreated);
if (mutexCreated)
mutex.ReleaseMutex();
if (!mutexCreated)
{
//App is already running, close this!
Environment.Exit(0); //i used this because its a console app
}
Musiałem zamknąć inne poziomy tylko pod pewnymi warunkami, to działało dobrze w moim celu
http://en.csharp-online.net/Application_Architecture_in_Windows_Forms_2.0 --Single-Instance_Detection_and_Management
Po wypróbowaniu wielu rozwiązań zadaję pytanie. Skończyło się na tym, że użyłem przykładu WPF tutaj: http://www.c-sharpcorner.com/UploadFile/f9f215/how-to-restrict-the-application-to-just-one-instance/
public partial class App : Application
{
private static Mutex _mutex = null;
protected override void OnStartup(StartupEventArgs e)
{
const string appName = "MyAppName";
bool createdNew;
_mutex = new Mutex(true, appName, out createdNew);
if (!createdNew)
{
//app is already running! Exiting the application
Application.Current.Shutdown();
}
}
}
W załączniku xaml:
x:Class="*YourNameSpace*.App"
StartupUri="MainWindow.xaml"
Startup="App_Startup"
W tym artykule wyjaśniono, w jaki sposób można utworzyć aplikację systemu Windows z kontrolą liczby jej instancji lub uruchomić tylko jedną instancję. Jest to bardzo typowa potrzeba aplikacji biznesowej. Istnieje już wiele innych możliwych sposobów kontrolowania tego.
http://www.openwinforms.com/single_instance_application.html
To jest kod dla VB.Net
Private Shared Sub Main()
Using mutex As New Mutex(False, appGuid)
If Not mutex.WaitOne(0, False) Then
MessageBox.Show("Instance already running", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
End If
Application.Run(New Form1())
End Using
End Sub
To jest kod dla C #
private static void Main()
{
using (Mutex mutex = new Mutex(false, appGuid)) {
if (!mutex.WaitOne(0, false)) {
MessageBox.Show("Instance already running", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
Application.Run(new Form1());
}
}
Musisz użyć System.Diagnostics.Process.
Sprawdź: http://www.devx.com/tips/Tip/20044
(Uwaga: to fajne rozwiązanie! Działa, ale wykorzystuje zły projekt GDI +, aby to osiągnąć).
Umieść obraz w aplikacji i załaduj go podczas uruchamiania. Przytrzymaj, aż aplikacja zostanie zamknięta. Użytkownik nie będzie mógł uruchomić drugiej instancji. (Oczywiście rozwiązanie mutex jest znacznie czystsze)
private static Bitmap randomName = new Bitmap("my_image.jpg");
Main()metody, która jest sprzeczna z tym, jak powinien działać WPF.
[STAThread]
static void Main() // args are OK here, of course
{
bool ok;
m = new System.Threading.Mutex(true, "YourNameHere", out ok);
if (! ok)
{
MessageBox.Show("Another instance is already running.");
return;
}
Application.Run(new Form1()); // or whatever was there
GC.KeepAlive(m); // important!
}
Z: zapewnienie pojedynczego wystąpienia aplikacji .NET
i: Mutex aplikacji pojedynczej instancji
Ta sama odpowiedź co @Smink i @Imjustpondering z niespodzianką:
Jon Skeet's FAQ on C #, aby dowiedzieć się, dlaczego GC.KeepAlive ma znaczenie
Po prostu używając, a co StreamWriterpowiesz na to?
System.IO.File.StreamWriter OpenFlag = null; //globally
i
try
{
OpenFlag = new StreamWriter(Path.GetTempPath() + "OpenedIfRunning");
}
catch (System.IO.IOException) //file in use
{
Environment.Exit(0);
}
Zwykle odbywa się to za pomocą nazwanego Mutex (użyj nowego Mutexu („nazwa Twojej aplikacji”, prawda) i sprawdź wartość zwracaną), ale jest też kilka klas obsługi w Microsoft.VisualBasic.dll, które mogą to zrobić za Ciebie .
To działało dla mnie w czystym C #. try / catch ma miejsce, gdy prawdopodobnie proces z listy kończy działanie podczas pętli.
using System.Diagnostics;
....
[STAThread]
static void Main()
{
...
int procCount = 0;
foreach (Process pp in Process.GetProcesses())
{
try
{
if (String.Compare(pp.MainModule.FileName, Application.ExecutablePath, true) == 0)
{
procCount++;
if(procCount > 1) {
Application.Exit();
return;
}
}
}
catch { }
}
Application.Run(new Form1());
}
Pamiętaj, aby wziąć pod uwagę bezpieczeństwo podczas ograniczania aplikacji do jednej instancji:
Cały artykuł: https://blogs.msdn.microsoft.com/oldnewthing/20060620-13/?p=30813
Używamy nazwanego muteksu o stałej nazwie, aby wykryć, czy działa inna kopia programu. Ale oznacza to również, że osoba atakująca może najpierw utworzyć muteks, uniemożliwiając w ten sposób działanie naszego programu! Jak mogę zapobiec tego typu atakom typu „odmowa usługi”?
...
Jeśli osoba atakująca działa w tym samym kontekście bezpieczeństwa, w którym działa (lub miałby) Twój program, nie możesz nic zrobić. Niezależnie od tego, jaki „tajny uścisk dłoni” wymyślisz w celu ustalenia, czy działa inna kopia programu, osoba atakująca może ją naśladować. Ponieważ działa w odpowiednim kontekście bezpieczeństwa, może zrobić wszystko, co potrafi „prawdziwy” program.
...
Oczywiście nie możesz zabezpieczyć się przed intruzem działającym z tym samym przywilejem bezpieczeństwa, ale nadal możesz chronić się przed nieuprzywilejowanymi atakującymi korzystającymi z innych uprawnień bezpieczeństwa.
Spróbuj ustawić DACL w swoim muteksie, oto sposób .NET: https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.mutexsecurity(v=vs.110).aspx
Żadna z tych odpowiedzi nie zadziałała dla mnie, ponieważ potrzebowałem tego do pracy pod Linuksem przy użyciu monodevelop. To działa świetnie dla mnie:
Wywołaj tę metodę, przekazując jej unikalny identyfikator
public static void PreventMultipleInstance(string applicationId)
{
// Under Windows this is:
// C:\Users\SomeUser\AppData\Local\Temp\
// Linux this is:
// /tmp/
var temporaryDirectory = Path.GetTempPath();
// Application ID (Make sure this guid is different accross your different applications!
var applicationGuid = applicationId + ".process-lock";
// file that will serve as our lock
var fileFulePath = Path.Combine(temporaryDirectory, applicationGuid);
try
{
// Prevents other processes from reading from or writing to this file
var _InstanceLock = new FileStream(fileFulePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
_InstanceLock.Lock(0, 0);
MonoApp.Logger.LogToDisk(LogType.Notification, "04ZH-EQP0", "Aquired Lock", fileFulePath);
// todo investigate why we need a reference to file stream. Without this GC releases the lock!
System.Timers.Timer t = new System.Timers.Timer()
{
Interval = 500000,
Enabled = true,
};
t.Elapsed += (a, b) =>
{
try
{
_InstanceLock.Lock(0, 0);
}
catch
{
MonoApp.Logger.Log(LogType.Error, "AOI7-QMCT", "Unable to lock file");
}
};
t.Start();
}
catch
{
// Terminate application because another instance with this ID is running
Environment.Exit(102534);
}
}