Menggunakan C # dan WPF di bawah .NET (daripada Windows Forms atau konsol), apa cara yang benar untuk membuat aplikasi yang hanya dapat dijalankan sebagai satu contoh?
Saya tahu ini ada hubungannya dengan beberapa hal mistis yang disebut mutex, jarang saya dapat menemukan seseorang yang mau berhenti dan menjelaskan apa salah satunya.
Kode juga perlu menginformasikan contoh yang sudah berjalan bahwa pengguna mencoba memulai yang kedua, dan mungkin juga meneruskan argumen baris perintah jika ada.
Jawaban:
Berikut ini adalah artikel yang sangat bagus mengenai solusi Mutex. Pendekatan yang dijelaskan oleh artikel ini menguntungkan karena dua alasan.
Pertama, tidak memerlukan ketergantungan pada perakitan Microsoft.VisualBasic. Jika proyek saya sudah memiliki ketergantungan pada majelis itu, saya mungkin akan menganjurkan menggunakan pendekatan yang ditunjukkan dalam jawaban lain . Tapi apa adanya, saya tidak menggunakan perakitan Microsoft.VisualBasic, dan saya lebih suka tidak menambahkan ketergantungan yang tidak perlu untuk proyek saya.
Kedua, artikel menunjukkan bagaimana membawa instance aplikasi yang ada ke latar depan ketika pengguna mencoba untuk memulai instance lain. Itu adalah sentuhan yang sangat bagus yang tidak dijawab oleh solusi Mutex lainnya yang dijelaskan di sini.
MEMPERBARUI
Sampai 8/1/2014, artikel yang saya tautkan di atas masih aktif, tetapi blog belum diperbarui dalam beberapa saat. Itu membuat saya khawatir bahwa pada akhirnya itu akan hilang, dan dengan itu, solusi yang disarankan. Saya mereproduksi konten artikel di sini untuk anak cucu. Kata-kata itu sepenuhnya milik pemilik blog di Sanity Free Coding .
sumber
Mutex
konstruktor hanya memerlukan string, sehingga Anda dapat memberikan nama string yang Anda inginkan, misalnya, "This Is My Mutex". Karena 'Mutex' adalah objek sistem yang tersedia untuk proses lain, Anda biasanya ingin nama tersebut unik sehingga tidak berbenturan dengan nama 'Mutex' lain pada sistem yang sama. Dalam artikel tersebut, string yang tampak samar adalah 'Guid'. Anda dapat membuat ini secara terprogram dengan meneleponSystem.Guid.NewGuid()
. Dalam hal artikel, pengguna mungkin membuatnya melalui Visual Studio seperti yang ditunjukkan di sini: msdn.microsoft.com/en-us/library/ms241442(VS.80).aspxAnda bisa menggunakan kelas Mutex, tetapi Anda akan segera mengetahui bahwa Anda perlu mengimplementasikan kode untuk meneruskan argumen dan diri Anda sendiri. Yah, saya belajar trik ketika pemrograman di WinForms ketika saya membaca buku Chris Sell . Trik ini menggunakan logika yang sudah tersedia untuk kita dalam framework. Saya tidak tahu tentang Anda, tetapi ketika saya belajar tentang hal-hal yang dapat saya gunakan kembali dalam kerangka kerja, itu biasanya rute yang saya ambil alih-alih menciptakan kembali roda. Kecuali tentu saja itu tidak melakukan semua yang saya inginkan.
Ketika saya masuk ke WPF, saya menemukan cara untuk menggunakan kode yang sama, tetapi dalam aplikasi WPF. Solusi ini harus memenuhi kebutuhan Anda berdasarkan pertanyaan Anda.
Pertama, kita perlu membuat kelas aplikasi kita. Di kelas ini kita akan menimpa acara OnStartup dan membuat metode yang disebut Aktifkan, yang akan digunakan nanti.
Kedua, kita perlu membuat kelas yang dapat mengatur instance kita. Sebelum kita membahasnya, kita sebenarnya akan menggunakan kembali beberapa kode yang ada dalam perakitan Microsoft.VisualBasic. Karena, saya menggunakan C # dalam contoh ini, saya harus membuat referensi ke majelis. Jika Anda menggunakan VB.NET, Anda tidak perlu melakukan apa pun. Kelas yang akan kita gunakan adalah WindowsFormsApplicationBase dan mewarisi instance manager kita darinya dan kemudian memanfaatkan properti dan acara untuk menangani single instancing.
Pada dasarnya, kami menggunakan bit VB untuk mendeteksi instance tunggal dan memprosesnya. OnStartup akan diaktifkan ketika instance pertama dimuat. OnStartupNextInstance dipecat ketika aplikasi dijalankan kembali. Seperti yang Anda lihat, saya bisa mendapatkan apa yang diteruskan pada baris perintah melalui argumen event. Saya menetapkan nilai ke bidang contoh. Anda bisa menguraikan baris perintah di sini, atau Anda bisa meneruskannya ke aplikasi Anda melalui konstruktor dan panggilan ke metode Aktifkan.
Ketiga, saatnya untuk membuat EntryPoint kami. Alih-alih membuat aplikasi seperti yang biasa Anda lakukan, kami akan mengambil keuntungan dari SingleInstanceManager kami.
Yah, saya harap Anda bisa mengikuti semuanya dan bisa menggunakan implementasi ini dan menjadikannya milik Anda.
sumber
Dari sini .
Penggunaan umum untuk lintas proses Mutex adalah untuk memastikan bahwa hanya instance dari program yang dapat berjalan pada satu waktu. Begini cara melakukannya:
Fitur Mutex yang baik adalah bahwa jika aplikasi berhenti tanpa ReleaseMutex pertama kali dipanggil, CLR akan merilis Mutex secara otomatis.
sumber
MSDN sebenarnya memiliki contoh aplikasi untuk C # dan VB untuk melakukan hal ini: http://msdn.microsoft.com/en-us/library/ms771662(v=VS.90).aspx
'Another instance of the app is running. Bye'
maka mereka tidak akan menjadi pengguna yang sangat bahagia. Anda cukup HARUS (dalam aplikasi GUI) beralih ke aplikasi itu dan menyampaikan argumen yang diberikan - atau jika parameter baris perintah tidak memiliki arti maka Anda harus memunculkan aplikasi yang mungkin telah diminimalkan.Kerangka kerja sudah memiliki dukungan untuk ini - hanya saja beberapa orang idiot menamai DLL
Microsoft.VisualBasic
dan itu tidak dimasukkan ke dalamMicrosoft.ApplicationUtils
atau sesuatu seperti itu. Dapatkan lebih dari itu - atau buka Reflektor.Kiat: Jika Anda menggunakan pendekatan ini seperti apa adanya, dan Anda sudah memiliki App.xaml dengan sumber daya, dll. Anda juga ingin melihatnya .
sumber
Kode ini harus menuju ke metode utama. Lihat di sini untuk informasi lebih lanjut tentang metode utama dalam WPF.
Metode 2
Catatan: Metode di atas menganggap proses / aplikasi Anda memiliki nama unik. Karena menggunakan nama proses untuk mencari apakah ada prosesor yang ada. Jadi, jika aplikasi Anda memiliki nama yang sangat umum (yaitu: Notepad), pendekatan di atas tidak akan berfungsi.
sumber
ProcessName
mengembalikan nama file yang dapat dieksekusi dikurangiexe
. Jika Anda membuat aplikasi yang disebut "Notepad", dan notepad windows sedang berjalan, ia akan mendeteksinya saat aplikasi Anda berjalan.Yah, saya punya Kelas sekali pakai untuk ini yang bekerja dengan mudah untuk sebagian besar kasus penggunaan:
Gunakan seperti ini:
Ini dia:
sumber
Yang baru yang menggunakan hal Mutex dan IPC, dan juga meneruskan argumen baris perintah apa pun ke instance yang berjalan, adalah WPF Single Instance Application .
sumber
Kode C # .NET Single Instance Application yang merupakan referensi untuk jawaban yang ditandai adalah awal yang baik.
Namun, saya menemukan itu tidak menangani dengan baik kasus-kasus ketika contoh yang sudah ada memiliki dialog modal terbuka, apakah dialog itu dikelola (seperti Formulir lain seperti kotak tentang), atau yang tidak dikelola (seperti OpenFileDialog bahkan ketika menggunakan kelas .NET standar). Dengan kode asli, bentuk utama diaktifkan, tetapi modal yang tetap tidak aktif, yang terlihat aneh, ditambah pengguna harus mengkliknya untuk tetap menggunakan aplikasi.
Jadi, saya telah membuat kelas utilitas SingleInstance untuk menangani semua ini secara otomatis untuk aplikasi Winforms dan WPF.
Bentuk Win :
1) memodifikasi kelas Program seperti ini:
2) memodifikasi kelas jendela utama seperti ini:
WPF:
1) memodifikasi halaman App seperti ini (dan pastikan Anda mengatur action build-nya ke halaman untuk dapat mendefinisikan kembali metode Utama):
2) memodifikasi kelas jendela utama seperti ini:
Dan di sini adalah kelas utilitas:
sumber
Berikut adalah contoh yang memungkinkan Anda untuk memiliki satu instance aplikasi. Ketika instance baru dimuat, mereka meneruskan argumen mereka ke instance utama yang sedang berjalan.
sumber
Hanya beberapa pemikiran: Ada beberapa kasus ketika mengharuskan hanya satu contoh aplikasi tidak "lumpuh" karena beberapa orang akan Anda percaya. Aplikasi basis data, dll. Adalah urutan besarnya lebih sulit jika satu memungkinkan beberapa contoh aplikasi untuk satu pengguna untuk mengakses database (Anda tahu, semua itu memperbarui semua catatan yang terbuka dalam beberapa contoh aplikasi pada pengguna mesin, dll.). Pertama, untuk "masalah tabrakan nama, jangan gunakan nama yang dapat dibaca manusia - gunakan GUID sebagai gantinya atau, lebih baik GUID + nama yang dapat dibaca manusia. Peluang tabrakan nama baru saja lepas dari radar dan Mutex tidak peduli Seperti yang ditunjukkan oleh seseorang, serangan DOS akan menyedot, tetapi jika orang jahat telah kesulitan mendapatkan nama mutex dan memasukkannya ke dalam aplikasi mereka, Anda cukup banyak target dan harus melakukan JAUH lebih banyak untuk melindungi diri sendiri daripada hanya mengutak-atik nama mutex. Juga, jika seseorang menggunakan varian: Mutex baru (true, "some GUID plus Name", dari AIsFirstInstance), Anda sudah memiliki indikator untuk mengetahui apakah Mutex adalah instance pertama atau tidak.
sumber
Begitu banyak jawaban untuk pertanyaan yang tampaknya sederhana ini. Hanya untuk sedikit mengguncang di sini adalah solusi saya untuk masalah ini.
Membuat Mutex bisa menyusahkan karena JIT-er hanya melihat Anda menggunakannya untuk sebagian kecil kode Anda dan ingin menandainya sebagai siap untuk pengumpulan sampah. Cukup banyak yang ingin pintar Anda berpikir Anda tidak akan menggunakan Mutex selama itu. Pada kenyataannya Anda ingin bertahan di Mutex ini selama aplikasi Anda berjalan. Cara terbaik untuk memberi tahu pengumpul sampah untuk meninggalkan Anda Mutex sendirian adalah dengan memerintahkannya untuk tetap hidup meskipun keluar dari berbagai generasi pengumpulan garasi. Contoh:
Saya mengangkat ide dari halaman ini: http://www.ai.uga.edu/~mc/SingleInstance.html
sumber
Sepertinya ada cara yang sangat baik untuk menangani ini:
Aplikasi Instansi Tunggal WPF
Ini memberikan kelas yang dapat Anda tambahkan yang mengelola semua mutex dan pesan perpesanan untuk menyederhanakan implementasi Anda ke titik di mana itu hanya sepele.
sumber
Kode berikut adalah solusi pipa bernama WCF saya untuk mendaftarkan aplikasi satu contoh. Itu bagus karena itu juga memunculkan suatu peristiwa ketika instance lain mencoba untuk memulai, dan menerima baris perintah dari instance lainnya.
Ini diarahkan ke WPF karena menggunakan
System.Windows.StartupEventHandler
kelas, tetapi ini dapat dengan mudah dimodifikasi.Kode ini membutuhkan referensi ke
PresentationFramework
, danSystem.ServiceModel
.Pemakaian:
Kode sumber:
sumber
Anda tidak boleh menggunakan mutex yang bernama untuk mengimplementasikan aplikasi instance tunggal (atau setidaknya tidak untuk kode produksi). Kode berbahaya dapat dengan mudah DoS ( Denial of Service ) ...
sumber
Lihatlah kode berikut. Ini adalah solusi yang bagus dan sederhana untuk mencegah beberapa contoh aplikasi WPF.
sumber
Inilah yang saya gunakan. Ini menggabungkan proses penghitungan untuk melakukan peralihan dan mutex untuk melindungi dari "clickers aktif":
sumber
Saya menemukan solusi yang lebih sederhana, mirip dengan Dale Ragan, tetapi sedikit dimodifikasi. Ini praktis semua yang Anda butuhkan dan didasarkan pada kelas standar Microsoft WindowsFormsApplicationBase.
Pertama, Anda membuat kelas SingleInstanceController, yang dapat Anda gunakan di semua aplikasi instance tunggal lainnya, yang menggunakan Formulir Windows:
Maka Anda dapat menggunakannya dalam program Anda sebagai berikut:
Baik program dan solusi SingleInstanceController_NET harus referensi Microsoft.VisualBasic. Jika Anda hanya ingin mengaktifkan kembali aplikasi yang berjalan sebagai jendela normal ketika pengguna mencoba untuk me-restart program yang sedang berjalan, parameter kedua di SingleInstanceController bisa menjadi nol. Dalam contoh yang diberikan, jendela dimaksimalkan.
sumber
Pembaruan 2017-01-25. Setelah mencoba beberapa hal, saya memutuskan untuk menggunakan VisualBasic.dll lebih mudah dan berfungsi lebih baik (setidaknya untuk saya). Saya membiarkan jawaban saya sebelumnya hanya sebagai referensi ...
Sama seperti referensi, ini adalah bagaimana saya melakukannya tanpa melewati argumen (yang saya tidak dapat menemukan alasan untuk melakukannya ... Maksud saya satu aplikasi dengan argumen yang akan diteruskan dari satu contoh ke yang lain). Jika asosiasi file diperlukan, maka aplikasi harus (sesuai standar harapan pengguna) akan dipasang untuk setiap dokumen. Jika Anda harus meneruskan args ke aplikasi yang ada, saya pikir saya akan menggunakan vb dll.
Tidak lewat args (hanya aplikasi instance tunggal), saya lebih suka tidak mendaftarkan pesan Window baru dan tidak mengesampingkan loop pesan seperti yang didefinisikan dalam Matt Davis Solution. Meskipun bukan masalah besar untuk menambahkan VisualBasic dll, tapi saya lebih suka tidak menambahkan referensi baru hanya untuk melakukan aplikasi instance tunggal. Juga, saya lebih suka menginisiasi kelas baru dengan Main daripada memanggil Shutdown dari App.Startup menimpa untuk memastikan untuk keluar sesegera mungkin.
Dengan harapan siapa pun akan menyukainya ... atau akan sedikit menginspirasi :-)
Kelas startup proyek harus ditetapkan sebagai 'SingleInstanceApp'.
WindowHelper:
sumber
Tidak menggunakan Mutex, jawaban sederhana:
Letakkan di dalam
Program.Main()
.Contoh :
Anda dapat menambahkan
MessageBox.Show
ke-if
pernyataan dan menempatkan "Aplikasi sudah berjalan".Ini mungkin bermanfaat bagi seseorang.
sumber
Pendekatan berbasis-mutex tidak lintas-platform karena mutex bernama tidak global dalam Mono. Pendekatan berbasis proses-enumerasi tidak memiliki sinkronisasi dan dapat mengakibatkan perilaku yang salah (mis. Beberapa proses yang dimulai pada saat yang sama semua dapat berakhir sendiri tergantung pada waktu). Pendekatan berbasis sistem windowing tidak diinginkan dalam aplikasi konsol. Solusi ini, dibangun di atas jawaban Divin, mengatasi semua masalah ini:
sumber
Saya menggunakan Mutex dalam solusi saya untuk mencegah beberapa kejadian.
sumber
Gunakan solusi mutex:
sumber
Berikut ini adalah solusi ringan yang saya gunakan yang memungkinkan aplikasi untuk membawa jendela yang sudah ada ke latar depan tanpa menggunakan pesan jendela khusus atau secara membabi buta mencari nama proses.
Sunting: Anda juga dapat menyimpan dan menginisialisasi mutex dan dibuat Baru secara statis, tetapi Anda harus membuang / melepaskan mutex secara eksplisit setelah Anda selesai menggunakannya. Secara pribadi, saya lebih suka menjaga mutex lokal karena akan secara otomatis dibuang walaupun aplikasi ditutup tanpa pernah mencapai akhir Main.
sumber
Anda juga dapat menggunakan CodeFluent Runtime yang merupakan seperangkat alat gratis. Ini menyediakan kelas SingleInstance untuk mengimplementasikan aplikasi contoh tunggal.
sumber
Saya menambahkan Metode sendMessage ke Kelas NativeMethods.
Tampaknya dosis metode postmessage berfungsi, jika aplikasi tidak ditampilkan di taskbar, namun menggunakan metode sendmessage memecahkan ini.
sumber
Inilah hal yang sama diterapkan melalui Acara.
sumber
[Saya telah memberikan kode contoh untuk aplikasi konsol dan WPF di bawah ini.]
Anda hanya perlu memeriksa nilai
createdNew
variabel (contoh di bawah!), Setelah Anda membuat instance Mutex bernama.Boolean
createdNew
akan mengembalikan false:Boolean
createdNew
akan mengembalikan true:Aplikasi konsol - Contoh:
WPF-Contoh:
sumber
Solusi hemat waktu untuk C # Winforms ...
Program.cs:
sumber
Silakan periksa solusi yang diusulkan dari sini yang menggunakan semaphore untuk menentukan apakah instance yang sudah berjalan, berfungsi untuk aplikasi WPF dan dapat meneruskan argumen dari instance kedua ke instance yang sudah berjalan dengan menggunakan TcpListener dan TcpClient:
Ini juga berfungsi untuk .NET Core, tidak hanya untuk .NET Framework.
sumber
Saya tidak dapat menemukan solusi singkat di sini jadi saya harap seseorang akan menyukai ini:
DIPERBARUI 2018-09-20
Masukkan kode ini di
Program.cs
:sumber