Używając C # i WPF w .NET (zamiast Windows Forms lub konsoli), jaki jest właściwy sposób na stworzenie aplikacji, którą można uruchomić tylko jako jedną instancję?
Wiem, że ma to coś wspólnego z mityczną rzeczą zwaną mutex, rzadko mogę znaleźć kogoś, kto będzie chciał się zatrzymać i wyjaśnić, co to jest.
Kod musi również informować działającą już instancję, że użytkownik próbował uruchomić drugą, a także może przekazać wszelkie argumenty wiersza polecenia, jeśli takie istnieją.
Odpowiedzi:
Oto bardzo dobry artykuł dotyczący rozwiązania Mutex. Podejście opisane w artykule jest korzystne z dwóch powodów.
Po pierwsze, nie wymaga zależności od zestawu Microsoft.VisualBasic. Gdyby mój projekt był już zależny od tego zestawu, prawdopodobnie zalecałbym użycie podejścia pokazanego w innej odpowiedzi . Ale w tej chwili nie używam zestawu Microsoft.VisualBasic i wolałbym nie dodawać niepotrzebnej zależności do mojego projektu.
Po drugie, artykuł pokazuje, jak przenieść istniejącą instancję aplikacji na pierwszy plan, gdy użytkownik próbuje uruchomić inną instancję. To bardzo miły akcent, którego nie opisują inne opisane tutaj rozwiązania Mutex.
AKTUALIZACJA
Na dzień 8.01.2014 artykuł, do którego odsyłam, jest nadal aktywny, ale blog nie był przez jakiś czas aktualizowany. Martwi mnie to, że ostatecznie może zniknąć, a wraz z nim zalecane rozwiązanie. Powielam tutaj treść artykułu dla potomności. Słowa należą wyłącznie do właściciela bloga w Sanity Free Coding .
źródło
Mutex
konstruktor po prostu wymaga łańcucha, abyś mógł podać dowolną nazwę łańcucha, np. „This Is My Mutex”. Ponieważ „Mutex” jest obiektem systemowym dostępnym dla innych procesów, zwykle chcesz, aby nazwa była unikalna, aby nie kolidowała z innymi nazwami „Mutex” w tym samym systemie. W artykule tajemniczo wyglądającym ciągiem jest „Guid”. Możesz wygenerować to programowo, dzwoniącSystem.Guid.NewGuid()
. W przypadku tego artykułu użytkownik prawdopodobnie wygenerował go za pomocą Visual Studio, jak pokazano tutaj: msdn.microsoft.com/en-us/library/ms241442(VS.80).aspxMożesz użyć klasy Mutex, ale wkrótce przekonasz się, że będziesz musiał zaimplementować kod, aby przekazać argumenty i tym podobne. Cóż, nauczyłem się sztuczki podczas programowania w WinForm, kiedy czytałem książkę Chrisa Sella . Ta sztuczka wykorzystuje logikę, która jest już dla nas dostępna w ramach. Nie wiem o tobie, ale kiedy dowiaduję się o rzeczach, mogę ponownie użyć w ramie, zwykle taką drogę wybieram zamiast wymyślać koło. Chyba że oczywiście nie robi wszystkiego, czego chcę.
Kiedy dostałem się do WPF, wymyśliłem sposób użycia tego samego kodu, ale w aplikacji WPF. To rozwiązanie powinno zaspokoić twoje potrzeby w oparciu o twoje pytanie.
Najpierw musimy stworzyć naszą klasę aplikacji. W tej klasie przesłonimy zdarzenie OnStartup i stworzymy metodę o nazwie Activate, która zostanie wykorzystana później.
Po drugie, musimy stworzyć klasę, która będzie zarządzać naszymi instancjami. Zanim to przejdziemy, faktycznie ponownie wykorzystamy kod z zestawu Microsoft.VisualBasic. Ponieważ używam C # w tym przykładzie, musiałem odwołać się do zestawu. Jeśli korzystasz z VB.NET, nie musisz nic robić. Klasa, której będziemy używać, to WindowsFormsApplicationBase i dziedziczy po niej naszego menedżera instancji, a następnie wykorzystuje właściwości i zdarzenia do obsługi pojedynczego wystąpienia.
Zasadniczo używamy bitów VB do wykrywania pojedynczych instancji i odpowiedniego przetwarzania. OnStartup zostanie uruchomiony po załadowaniu pierwszej instancji. Program OnStartupNextInstance jest uruchamiany po ponownym uruchomieniu aplikacji. Jak widać, mogę dostać się do tego, co zostało przekazane w wierszu poleceń, za pomocą argumentów zdarzenia. Ustawiam wartość na pole instancji. Możesz parsować tutaj wiersz poleceń lub przekazać go do aplikacji przez konstruktor i wywołanie metody Activate.
Po trzecie, czas stworzyć nasz EntryPoint. Zamiast odświeżać aplikację tak, jak normalnie, skorzystamy z naszego narzędzia SingleInstanceManager.
Mam nadzieję, że będziesz w stanie śledzić wszystko i będziesz mógł korzystać z tej implementacji i dostosować ją do własnych potrzeb.
źródło
Od tutaj .
Powszechnym zastosowaniem w wielu procesach Mutex jest zapewnienie, że jednocześnie może być uruchomiona tylko instancja programu. Oto jak to się robi:
Dobrą cechą Mutex jest to, że jeśli aplikacja zakończy działanie bez uprzedniego wywołania ReleaseMutex, CLR automatycznie zwolni Mutex.
źródło
MSDN faktycznie ma przykładową aplikację dla C # i VB, która wykonuje dokładnie to: http://msdn.microsoft.com/en-us/library/ms771662(v=VS.90).aspx
'Another instance of the app is running. Bye'
, jakbyś nie był bardzo szczęśliwym użytkownikiem. Po prostu MUSISZ (w aplikacji GUI) przejść do tej aplikacji i przekazać podane argumenty - lub jeśli parametry wiersza poleceń nie mają znaczenia, musisz wyskoczyć z aplikacji, która mogła zostać zminimalizowana.Framework ma już na to wsparcie - po prostu ten idiota nazwał DLL
Microsoft.VisualBasic
i nie został wprowadzonyMicrosoft.ApplicationUtils
lub coś takiego. Pokonaj go - lub otwórz Odbłyśnik.Wskazówka: Jeśli zastosujesz to podejście dokładnie tak, jak jest, i masz już plik App.xaml z zasobami itp ., Również powinieneś się tym przyjrzeć .
źródło
Ten kod powinien przejść do głównej metody. Spójrz tutaj, aby uzyskać więcej informacji na temat głównej metody WPF.
Metoda 2
Uwaga: powyższe metody zakładają, że proces / aplikacja ma unikalną nazwę. Ponieważ używa nazwy procesu, aby sprawdzić, czy istnieją istniejące procesory. Jeśli więc aplikacja ma bardzo popularną nazwę (np. Notatnik), powyższe podejście nie będzie działać.
źródło
ProcessName
zwraca nazwę pliku wykonywalnego minusexe
. Jeśli utworzysz aplikację o nazwie „Notatnik”, a Notatnik systemu Windows będzie działał, wykryje ją jako działającą.Cóż, mam do tego jednorazową klasę, która z łatwością działa w większości przypadków użycia:
Użyj tego w ten sposób:
Oto on:
źródło
Nowym, który korzysta z Mutex i IPC, a także przekazuje argumenty wiersza poleceń do działającej instancji, jest aplikacja pojedynczej instancji WPF .
źródło
Kod C # .NET Aplikacja pojedynczego wystąpienia która jest odnośnikiem do zaznaczonej odpowiedzi, jest świetnym początkiem.
Stwierdziłem jednak, że nie radzi sobie zbyt dobrze z przypadkami, gdy instancja, która już istnieje, ma otwarte okno dialogowe modalne, niezależnie od tego, czy jest to okno zarządzane (jak inny formularz, np. O polu), czy niezarządzane (takie jak OpenFileDialog nawet przy użyciu standardowej klasy .NET). W przypadku oryginalnego kodu aktywowana jest główna forma, ale modalna pozostaje nieaktywna, co wygląda dziwnie, a użytkownik musi ją kliknąć, aby móc nadal korzystać z aplikacji.
Tak więc utworzyłem klasę narzędzi użytkowych SingleInstance do obsługi tego wszystkiego dość automatycznie dla aplikacji Winforms i WPF.
Winforms :
1) zmodyfikuj klasę Programu w następujący sposób:
2) zmodyfikuj klasę głównego okna w następujący sposób:
WPF:
1) zmodyfikuj stronę aplikacji w ten sposób (i upewnij się, że ustawiłeś akcję kompilacji na stronę, aby móc ponownie zdefiniować metodę główną):
2) zmodyfikuj klasę głównego okna w następujący sposób:
A oto klasa użyteczności:
źródło
Oto przykład, który pozwala mieć jedną instancję aplikacji. Po załadowaniu nowych instancji przekazują swoje argumenty do działającej instancji głównej.
źródło
Tylko kilka przemyśleń: zdarzają się sytuacje, w których wymaga się, aby tylko jedna instancja aplikacji nie była „kiepska”, jak niektórzy by chcieli. Aplikacje bazodanowe itp. Są o rząd wielkości trudniejsze, jeśli pozwala się na dostęp do bazy danych wielu wystąpieniom aplikacji dla jednego użytkownika (wszystko to aktualizuje wszystkie rekordy, które są otwarte w wielu wystąpieniach aplikacji na użytkownikach) maszyna itp.). Po pierwsze, w przypadku „kolizji nazw” nie używaj nazwy czytelnej dla człowieka - zamiast tego użyj identyfikatora GUID lub, nawet lepiej, identyfikatora GUID + nazwy czytelnej dla człowieka. Szanse kolizji nazwy spadły z radaru, a Mutex nie ma znaczenia Jak ktoś zauważył, atak DOS byłby do bani, ale gdyby złośliwa osoba zadała sobie trud uzyskania nazwy mutexu i włączenia jej do swojej aplikacji, i tak jesteś raczej celem i będziesz musiał zrobić DUŻO więcej, aby się bronić, niż po prostu bawić się mutexem. Ponadto, jeśli użyjesz wariantu: new Mutex (true, „GUID plus Name”, obecnie AIsFirstInstance), masz już wskaźnik tego, czy Mutex jest pierwszą instancją.
źródło
Tak wiele odpowiedzi na tak pozornie proste pytanie. Wystarczy trochę potrząsnąć tutaj, jest moim rozwiązaniem tego problemu.
Utworzenie Muteksu może być kłopotliwe, ponieważ JIT-er widzi, że używasz go tylko do niewielkiej części kodu i chce oznaczyć go jako gotowy do wyrzucania elementów bezużytecznych. Praktycznie chce obezwładnić cię myśląc, że nie będziesz używać tego Mutexa tak długo. W rzeczywistości chcesz trzymać się tego Mutexa tak długo, jak długo aplikacja jest uruchomiona. Najlepszym sposobem, aby powiedzieć śmieciarzowi, aby zostawił cię Mutex w spokoju, jest powiedzenie mu, aby utrzymał go przy życiu przez różne generacje kolekcji garażowych. Przykład:
Podniosłem pomysł z tej strony: http://www.ai.uga.edu/~mc/SingleInstance.html
źródło
Wygląda na to, że istnieje naprawdę dobry sposób na poradzenie sobie z tym:
Aplikacja pojedynczego wystąpienia WPF
Zapewnia to klasę, którą można dodać, która zarządza wszystkimi muteksami i wątkami komunikacyjnymi, aby uprościć implementację do tego stopnia, że jest to po prostu trywialne.
źródło
Poniższy kod to moje rozwiązanie nazwane potokami WCF do rejestracji aplikacji z pojedynczą instancją. To miłe, ponieważ wywołuje także zdarzenie, gdy inna instancja próbuje się uruchomić, i otrzymuje wiersz komendowy drugiej instancji.
Jest nastawiony na WPF, ponieważ wykorzystuje
System.Windows.StartupEventHandler
klasę, ale można to łatwo zmodyfikować.Ten kod wymaga odniesienia do
PresentationFramework
iSystem.ServiceModel
.Stosowanie:
Kod źródłowy:
źródło
Nigdy nie należy używać nazwanego muteksu do implementacji aplikacji z pojedynczą instancją (a przynajmniej nie do kodu produkcyjnego). Złośliwy kod może łatwo zrobić DoS ( Denial of Service ) tyłek ...
źródło
Spójrz na poniższy kod. Jest to świetne i proste rozwiązanie, aby zapobiec wielu wystąpieniom aplikacji WPF.
źródło
Oto czego używam. Połączono wyliczanie procesów w celu wykonania przełączania i muteksu w celu zabezpieczenia przed „aktywnymi modułami klikającymi”:
źródło
Znalazłem prostsze rozwiązanie, podobne do Dale Ragana, ale nieco zmodyfikowane. Robi praktycznie wszystko, czego potrzebujesz, w oparciu o standardową klasę Microsoft WindowsFormsApplicationBase.
Po pierwsze, tworzysz klasę SingleInstanceController, której możesz używać we wszystkich innych aplikacjach z pojedynczą instancją, które używają Windows Forms:
Następnie możesz użyć go w swoim programie w następujący sposób:
Zarówno program, jak i rozwiązanie SingleInstanceController_NET powinny odwoływać się do Microsoft.VisualBasic. Jeśli chcesz ponownie aktywować działającą aplikację jako normalne okno, gdy użytkownik próbuje zrestartować uruchomiony program, drugi parametr w SingleInstanceController może mieć wartość NULL. W podanym przykładzie okno jest zmaksymalizowane.
źródło
Aktualizacja 2017-01-25. Po wypróbowaniu kilku rzeczy, zdecydowałem się na VisualBasic.dll, jest łatwiejszy i działa lepiej (przynajmniej dla mnie). Podaję moją poprzednią odpowiedź jako odniesienie ...
Jako odniesienie, tak zrobiłem bez przekazywania argumentów (co nie mogę znaleźć żadnego powodu, aby to zrobić ... Mam na myśli pojedynczą aplikację z argumentami, które mają być przekazywane z jednej instancji do drugiej). Jeśli wymagane jest powiązanie plików, aplikacja powinna (zgodnie ze standardowymi oczekiwaniami użytkowników) zostać utworzona dla każdego dokumentu. Jeśli musisz przekazać argumenty do istniejącej aplikacji, myślę, że użyłbym vb dll.
Nie przekazując argumentów (tylko aplikacja z pojedynczym wystąpieniem), wolę nie rejestrować nowej wiadomości Windows i nie zastępować pętli wiadomości, jak zdefiniowano w Matt Davis Solution. Chociaż dodanie dll VisualBasic nie jest niczym wielkim, ale wolę nie dodawać nowego odwołania tylko po to, aby zrobić aplikację z pojedynczą instancją. Wolę też zaimplementować nową klasę z Main zamiast wywoływać Shutdown z App.Startup override, aby zapewnić jak najszybsze wyjście.
Mam nadzieję, że każdemu się spodoba ... lub trochę zainspiruje :-)
Klasę uruchamiania projektu należy ustawić jako „SingleInstanceApp”.
WindowHelper:
źródło
Jednak nie używając Mutex, prosta odpowiedź:
Umieść w środku
Program.Main()
.Przykład :
Możesz dodać
MessageBox.Show
doif
-statement i umieścić „Aplikacja już działa”.To może być komuś pomocne.
źródło
Podejścia oparte na muteksach nie są wieloplatformowe, ponieważ nazwane muteksy nie są globalne w Mono. Podejścia oparte na wyliczaniu procesów nie mają żadnej synchronizacji i mogą powodować nieprawidłowe zachowanie (np. Wiele procesów uruchomionych w tym samym czasie może zakończyć się samoczynnie w zależności od czasu). Podejścia oparte na systemie okienkowym nie są pożądane w aplikacji konsolowej. To rozwiązanie, oparte na odpowiedzi Divina, rozwiązuje wszystkie te problemy:
źródło
Używam Mutex w swoim rozwiązaniu do zapobiegania wielu wystąpieniom.
źródło
Użyj rozwiązania mutex:
źródło
Oto lekkie rozwiązanie, którego używam, które pozwala aplikacji przenieść istniejące okno na pierwszy plan bez uciekania się do niestandardowych komunikatów systemu Windows lub ślepego wyszukiwania nazw procesów.
Edycja: Możesz także przechowywać i inicjować muteks i utworzony Nowy statycznie, ale będziesz musiał jawnie pozbyć się / zwolnić muteks, gdy skończysz. Osobiście wolę utrzymywać muteks lokalny, ponieważ zostanie on automatycznie zutylizowany, nawet jeśli aplikacja zostanie zamknięta bez osiągania końca Main.
źródło
Możesz także użyć CodeFluent Runtime, który jest bezpłatnym zestawem narzędzi. Zapewnia klasę SingleInstance do implementacji aplikacji z pojedynczą instancją.
źródło
Dodałem metodę sendMessage do klasy NativeMethods.
Najwyraźniej metoda postmessage nie działa, jeśli aplikacja nie jest wyświetlana na pasku zadań, jednak zastosowanie metody sendmessage rozwiązuje ten problem.
źródło
Oto ta sama rzecz zaimplementowana przez Event.
źródło
[Podałem przykładowy kod dla aplikacji konsoli i wpf poniżej.]
Musisz tylko sprawdzić wartość
createdNew
zmiennej (przykład poniżej!) Po utworzeniu nazwanej instancji Mutex.Wartość logiczna
createdNew
zwróci false:Wartość logiczna
createdNew
zwróci wartość prawda:Aplikacja konsoli - przykład:
Przykład WPF:
źródło
Oszczędzające czas rozwiązanie dla C # Winforms ...
Program.cs:
źródło
Sprawdź proponowane rozwiązanie stąd które używa semafora, aby ustalić, czy istniejąca instancja już działa, działa dla aplikacji WPF i może przekazywać argumenty z drugiej instancji do pierwszej już działającej instancji za pomocą TcpListener i TcpClient:
Działa również dla .NET Core, nie tylko dla .NET Framework.
źródło
Nie mogę znaleźć tutaj krótkiego rozwiązania , więc mam nadzieję, że komuś się spodoba:
AKTUALIZACJA 2018-09-20
Umieść ten kod w swoim
Program.cs
:źródło