Tək nümunəvi proqram yaratmaq üçün doğru yol nədir?

.NET-də C # və WPF ( Windows Formaları və ya konsol əvəzinə) istifadə edərək, bir nümunə kimi istifadə edə biləcək bir proqram yaratmaq üçün nə uyğun yol var?

Bilindim ki, bir muteks adlı bəzi mifik əşyalarla bir əlaqəsi var, duran və nə olduğunu açıqlayan kimsə tapmaq çox nadirdir.

Kod həmçinin istifadəçinin ikinci birinə başlamağa çalışdığını və mövcud olduqda hər hansı bir command line arqumentini də keçirməyə başlamışdır.

562
21 авг. Nidonocu 21 avqustda təyin etdi . 2008-08-21 03:33 '08 at 3:33 pm 2008-08-21 03:33
@ 35 cavab
  • 1
  • 2

Burada Mutex həllində çox yaxşı bir məqalə var. Yazıda təsvir olunan yanaşma iki səbəbdən də faydalıdır.

Birincisi, Microsoft.VisualBasic məclisində asılılıq tələb etmir. Layihəm artıq bu quruluşa asılılıq etmişsə, ehtimalla qəbul edilmiş cavabda göstərilən yanaşmadan istifadə etməliyəm. Ancaq bu olduğundan, mən Microsoft.VisualBasic toplantısını istifadə etmirəm və mənim layihə üçün lazımsız asılılığı əlavə etməməyi xahiş edirəm.

İkincisi, məqalədə bir istifadəçi başqa bir nümunə açmağa çalışdıqda tətbiqin mövcud nüsxəsini ön planda necə gətirəcəyini göstərir. Burada təsvir olunan digər Mutex həllərinin ələ alınmaması çox xoşdur.


ƏLAVƏ OLUNUB

2014-cü il 8/1 tarixindən etibarən yuxarıda göstərilən məqalə hələ də aktivdir, lakin bir müddətdən sonra blog yenilənməyib. Bu məni narahat edir ki, sonunda yox ola bilər və bununla da etibarlı bir həlldir. Məqalənin məzmununu buradakı övlad üçün buraxıram. Sözlər yalnız Sanity Free Coding- də blog sahibinə aiddir.

Bu gün mənim ərizəmimi bir neçə nüsxədə işləməyə qadağan edən bəzi kodları yenidən təşkil etmək istəmişdim.

System.Diagnostics.Process'i proseslər siyahısında mənim my.exe faylının bir nümunəsini axtarmaq üçün istifadə edirdilər. Bu işə baxmayaraq, bir çox yük daşıyır və təmiz bir şey istəmişəm.

Bunun üçün mütləq istifadə edə biləcəyimi bilirəm (amma heç vaxt əvvəl bunu etməmişəm), kodumu kəsib həyatımı asanlaşdırmağa qərar verdim.

Mənim əsas tətbiqim sinifində, Mutex adlı bir statik yaratdıq :

 static class Program { static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}"); [STAThread] ... } 

Adlandırılmış bir mutexa sahib olduğumuz, mənim aradığım sehrli bir neçə mövzu və prosesin sinxronizasiyasını sinxronizasiya etməyə imkan verir.

Mutex.WaitOne , bizə gözləmə müddəti müəyyən edən aşırı yükə malikdir. Bizim kodu sinxronizasiya etmək istəmədiyimizə görə (daha çox sadəcə istifadə olunur olub-olmadığını yoxlamaq), biz iki parametrlə yüklənməni istifadə edirik: Mutex.WaitOne (Timeout timeout, bool exitContext) . Qəbul edildikdə və ya olmadıqda saxta olduqdan sonra gözləyin. Bu vəziyyətdə biz gözləmək istəmirik; Bizim mutex istifadə edilərsə, onu atlayın və hərəkət edin, beləliklə, biz TimeSpan.Zero (0 millisaniyəni gözləyin) və exitContext parametresini true olaraq təyin edirik ki, biz kiliddən istifadə etməzdən əvvəl sinxronizasiya edə bilərik. Bununla belə, bizim kimi bir şey daxilində Application.Run kodunu ləğv edirik:

 static class Program { static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}"); [STAThread] static void Main() { if(mutex.WaitOne(TimeSpan.Zero, true)) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); mutex.ReleaseMutex(); } else { MessageBox.Show("only one instance at a time"); } } } 

Belə ki, tətbiqimiz işə yararsa, WaitOne saxta qayıdır və biz bir mesaj qutusuna sahibik.

Bir mesaj qutusunu göstərmək əvəzinə, bəzilərinin artıq olduğunu (bütün digər pəncərələrin üstünə aparan) unutduğum iş nümunəsini bildirmək üçün bir az Win32 istifadə etməyə qərar verdim. Bunu etmək üçün hər bir istifadəçi mesajını (bir istifadəçi mesajı, qeydiyyatdan keçirdiyimWindowMessage ilə işləyən tətbiqdə qeydiyyatdan keçdi) istifadə etmək üçün PostMessage istifadə etdim, yəni mənim tətbiqimin nə olduğunu bilir, sonra ikinci nüsxəm çıxır. Orijinal ərizə forması bu bildirişi alacaq və onu işləyəcəkdir. Bunu etmək üçün, WndProc'u ana formumda aşdım və bildirim ayarlarımı dinlədim. Bu bildirişi aldığımda formu TopMost Əmlakına düzəltdim.

Budur bitirdiğim şey:

  • Program.cs
 static class Program { static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}"); [STAThread] static void Main() { if(mutex.WaitOne(TimeSpan.Zero, true)) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); mutex.ReleaseMutex(); } else { // send our Win32 message to make the currently running instance // jump on top of all the other windows NativeMethods.PostMessage( (IntPtr)NativeMethods.HWND_BROADCAST, NativeMethods.WM_SHOWME, IntPtr.Zero, IntPtr.Zero); } } } 
  • NativeMethods.cs
 // this class just wraps some Win32 stuff that we're going to use internal class NativeMethods { public const int HWND_BROADCAST = 0xffff; public static readonly int WM_SHOWME = RegisterWindowMessage("WM_SHOWME"); [DllImport("user32")] public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam); [DllImport("user32")] public static extern int RegisterWindowMessage(string message); } 
  • Form1.cs (qismən ön tərəf)
 public partial class Form1 : Form { public Form1() { InitializeComponent(); } protected override void WndProc(ref Message m) { if(m.Msg == NativeMethods.WM_SHOWME) { ShowMe(); } base.WndProc(ref m); } private void ShowMe() { if(WindowState == FormWindowState.Minimized) { WindowState = FormWindowState.Normal; } // get our current "TopMost" value (ours will always be false though) bool top = TopMost; // make our form jump to the top of everything TopMost = true; // set it back to whatever it was TopMost = top; } } 
453
07 февр. Cavab Matt Davis tərəfindən verilir 07 fevral. 2009-02-07 04:18 '09 da 4:18 'də 2009-02-07 04:18

Mutex sinifindən istifadə edə bilərsiniz, amma tezliklə siz arqumentləri və özünüzü keçmək üçün kod tətbiq etməlisiniz. Yaxşı, Chris Sell'i oxuduğumda WinForms'ta proqramlaşdırma edərkən bir oyun öyrəndim. Bu hiylə artıq çərçivədə bizə aid olan məntiqdən istifadə edir. Mən səni tanıyıram, amma bir çərçivədə istifadə edə biləcəyim şeylərdən danışdığımda, bu, çarxı təkrarlamağa əvəzinə götürdüyü marşrutdur. Əlbəttə ki, istədiyim hər şeyi edir.

WPF'ye daxil olduğumda, eyni kodu istifadə etmək üçün bir yolla gəldim, ancaq WPF tətbiqində. Bu həll sizin sualınız əsasında ehtiyaclarınıza cavab verməlidir.

Birincisi, tətbiqi sinifimizi yaratmalıyıq. Bu sinifdə, OnStartup hadisəsini qüvvədə saxlayırıq və daha sonra istifadə ediləcək Activate adlı bir metod yaradırıq.

 public class SingleInstanceApplication : System.Windows.Application { protected override void OnStartup(System.Windows.StartupEventArgs e) { // Call the OnStartup event on our base class base.OnStartup(e); // Create our MainWindow and show it MainWindow window = new MainWindow(); window.Show(); } public void Activate() { // Reactivate the main window MainWindow.Activate(); } } 

İkincisi, nümunələri idarə edə biləcək bir sinif yaratmalıyıq. Bunu düşünməzdən əvvəl, biz Microsoft.VisualBasic məclisində olan kodu yenidən istifadə etmək niyyətindəyik. C # -dən istifadə etdiyim nümunədən bəri məclisə keçid etmək lazımdır. VB.NET istifadə edirsinizsə, bir şey etmək lazım deyil. Biz istifadə edəcəyimiz sinif WindowsFormsApplicationBase və nümunə meneceri devralır və sonra bir nümunəni idarə etmək üçün xüsusiyyətləri və hadisələrdən istifadə edir.

border=0
 public class SingleInstanceManager : Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase { private SingleInstanceApplication _application; private System.Collections.ObjectModel.ReadOnlyCollection<string> _commandLine; public SingleInstanceManager() { IsSingleInstance = true; } protected override bool OnStartup(Microsoft.VisualBasic.ApplicationServices.StartupEventArgs eventArgs) { // First time _application is launched _commandLine = eventArgs.CommandLine; _application = new SingleInstanceApplication(); _application.Run(); return false; } protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs) { // Subsequent launches base.OnStartupNextInstance(eventArgs); _commandLine = eventArgs.CommandLine; _application.Activate(); } } 

Əsasən, VB bitlərini sırasıyla bir nümunə və prosesi aşkar etmək üçün istifadə edirik. İlk instansiya yükləndikdə OnStartup çalışacaq. OnStartupNextInstance tətbiqi yenidən başladıldığında başlayır. Gördüyünüz kimi, hadisə arqumentləri ilə əmr xəttinə keçdiyimə gedə bilərəm. Nümunə sahəsində dəyəri təyin etdim. Komut satırını burada analiz edə bilərsiniz və ya konstruktor vasitəsilə tətbiqə keçə və Aktivləşdirmə üsuluna zəng edə bilərsiniz.

Üçüncüsü, EntryPoint yaratmaq vaxtıdır. Tətbiqə başlamağın əvəzinə, adi olaraq, biz SingleInstanceManager istifadə edəcəyik.

 public class EntryPoint { [STAThread] public static void Main(string[] args) { SingleInstanceManager manager = new SingleInstanceManager(); manager.Run(args); } } 

Bəli, ümid edirəm ki, hər şeyi izləyə və bu tətbiqdən istifadə edə və onu özünüz edə bilərsiniz.

94
21 авг. Dale Ragan'a 21 Avqust cavab verildi . 2008-08-21 07:17 '08 at 7:17 pm 2008-08-21 07:17

Buradan .

Cross prosesinin Mutex üçün ümumi istifadə proqramın yalnız bir nümunəsi eyni anda işlədilməsini təmin etməkdir. İşdə necə edilir:

 class OneAtATimePlease { // Use a name unique to the application (eg include your company URL) static Mutex mutex = new Mutex (false, "oreilly.com OneAtATimeDemo"); static void Main() { // Wait 5 seconds if contended – in case another instance // of the program is in the process of shutting down. if (!mutex.WaitOne(TimeSpan.FromSeconds (5), false)) { Console.WriteLine("Another instance of the app is running. Bye!"); return; } try { Console.WriteLine("Running - press Enter to exit"); Console.ReadLine(); } finally { mutex.ReleaseMutex(); } } } 

Mutex'in yaxşı bir xüsusiyyəti, bir tətbiqin ReleaseMutex çağırmadan sona çatması halında, CLR avtomatik olaraq Mutex'i aradan qaldırır.

76
21 авг. jason saldo tərəfindən verilmiş cavab 21 avqust. 2008-08-21 03:47 '08 saat 03:47 'da 2008-08-21 03:47

MSDN həqiqətən C # və VB üçün bir nümunə proqrama malikdir: http://msdn.microsoft.com/en-us/library/ms771662(v=VS.90).aspx

Tək nümunəvi algılamanın inkişafı üçün ən ümumi və etibarlı metod Microsoft .NET Framework uzaqdan istifadə infrastrukturunun (System.Remoting) istifadə edilməsidir. Microsoft .NET Framework (versiya 2.0), lazımlı remoting funksiyasını əhatə edən bir WindowsFormsApplicationBase növü ehtiva edir. Bu növü bir WPF proqramına daxil etmək üçün, növündən əldə olunmalı və tətbiqin statik giriş nöqtəsi metodu, əsas ərizə və WPF tətbiqinin tətbiqi arasında bir conta kimi istifadə edilməlidir. Conta tətbiqi ilk dəfə tətbiq edildikdə və növbəti başlanğıc cəhdləri edildikdə və WPF tətbiqinin növbənin necə idarə olunacağının müəyyənləşdirilməsinə nəzarət etmək üçün imkan verir.

  • C # adamları üçün yalnız dərin nəfəs al və bütövlükdə unutma: "VisualBasic DLL faylını daxil etmək istəmirəm." Bu səbəbdən və Scott Hanselman'ın dediyi və bu problemin ən təmiz həlli olduğu və quruluşu haqqında daha çox bilən insanlar tərəfindən inkişaf etdirdiyi bir gerçəkdir.
  • Kullanışlılık baxımından, istifadəçi proqramı yüklədir və artıq açıqdır və onlara bir səhv mesajı verirsiniz, məsələn, 'Another instance of the app is running. Bye' 'Another instance of the app is running. Bye' 'Another instance of the app is running. Bye' 'Another instance of the app is running. Bye' sonra onlar çox xoşbəxt istifadəçi olmayacaq. Siz sadəcə (GUI ərizəsində) bu tətbiqə keçin və təqdim olunan dəlilləri ötürün - ya da əmr xəttinin parametrləri mənalı deyilsə, ən azı saxlanıla bilən proqramı açmalısınız.

Zəmanət zaten bunun üçün dəstək verir - yalnız Microsoft.VisualBasic DLL deyilən bir səhvdir və Microsoft.ApplicationUtils və ya bir şeyə daxil olmadı. Onu arxaya oturun və ya yansıtıcıyı açın.

Şurası Əgər bu yanaşmanı tam olaraq istifadə edirsinizsə və zaten resursları və s. İlə App.xaml var, siz də baxmaq istəyirəm.

49
28 сент. Simon_Weaver tərəfindən verilmiş cavab Sep 28 2010-09-28 00:48 '10 at 0:48 2010-09-28 00:48

Bu kod əsas üsula keçməlidir. WPF əsas metodu haqqında daha ətraflı məlumat üçün buraya baxın.

 [DllImport("user32.dll")] private static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow); private const int SW_SHOWMAXIMIZED = 3; static void Main() { 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); return; } } 

Metod 2

 static void Main() { string procName = Process.GetCurrentProcess().ProcessName; // get the list of all processes by that name Process[] processes=Process.GetProcessesByName(procName); if (processes.Length > 1) { MessageBox.Show(procName + " already running"); return; } else { // Application.Run(...); } } 

Qeyd . Yuxarıda göstərilən üsullar sizin prosesinizin / proqramınızın unikal bir adın olduğunu düşünür. Mövcud prosessorları tapmaq üçün proses adını istifadə edir. Belə ki, ərizəinizdə çox ümumi ad (məsələn, "Notepad") varsa, yuxarıda göstərilən yanaşma işləməyəcəkdir.

21
25 авг. CharityJ tərəfindən verilmiş cavabı 25 Avqust. 2011-08-25 01:48 '11 at 1:48 2011-08-25 01:48

Bunun üçün bir çox vaxt üçün asanlıqla işləyən bir dəfə bir sinif var:

Aşağıdakı kimi istifadə edin:

 static void Main() { using (SingleInstanceMutex sim = new SingleInstanceMutex()) { if (sim.IsOtherInstanceRunning) { Application.Exit(); } // Initialize program here. } } 

Burada:

 /// <summary> /// Represents a <see cref="SingleInstanceMutex"/> class. /// </summary> public partial class SingleInstanceMutex : IDisposable { #region Fields /// <summary> /// Indicator whether another instance of this application is running or not. /// </summary> private bool isNoOtherInstanceRunning; /// <summary> /// The <see cref="Mutex"/> used to ask for other instances of this application. /// </summary> private Mutex singleInstanceMutex = null; /// <summary> /// An indicator whether this object is beeing actively disposed or not. /// </summary> private bool disposed; #endregion #region Constructor /// <summary> /// Initializes a new instance of the <see cref="SingleInstanceMutex"/> class. /// </summary> public SingleInstanceMutex() { this.singleInstanceMutex = new Mutex(true, Assembly.GetCallingAssembly().FullName, out this.isNoOtherInstanceRunning); } #endregion #region Properties /// <summary> /// Gets an indicator whether another instance of the application is running or not. /// </summary> public bool IsOtherInstanceRunning { get { return !this.isNoOtherInstanceRunning; } } #endregion #region Methods /// <summary> /// Closes the <see cref="SingleInstanceMutex"/>. /// </summary> public void Close() { this.ThrowIfDisposed(); this.singleInstanceMutex.Close(); } public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (!this.disposed) {  if (disposing) {  this.Close(); } this.disposed = true; } } /// <summary> /// Throws an exception if something is tried to be done with an already disposed object. /// </summary> /// <remarks> /// All public methods of the class must first call this. /// </remarks> public void ThrowIfDisposed() { if (this.disposed) { throw new ObjectDisposedException(this.GetType().Name); } } #endregion } 
15
19 февр. Oliver Friedrich 19 Feb. 2010-02-19 13:39 '10 at 13:39 2010-02-19 13:39

Mutex və IPC materialı istifadə edən yeni, həmçinin hər hansı bir əmr satırı argusunu çalışan bir misal üçün, bir fazalı WPF tətbiqinə keçir .

12
28 мая '10 в 22:58 2010-05-28 22:58 Cavay 28 may 'da saat 10: 58-da huseyint tərəfindən verilmişdir 2010-05-05 22:58

Əlavə C # .Net Single Instance, qeyd olunan bir cavab üçün bir əlaqədir, böyük bir başlanğıcdır.

Buna baxmayaraq, o, dialoqun nəzarət altına alınmadığına (məsələn, başqa forma, məsələn, sahə haqqında) və ya idarə edilmədən (məsələn, OpenFileDialog standart .NET sinifi istifadə edərkən də). Mənbə kodu ilə əsas forma aktivdir, lakin modal qəribə görünən effektiv olaraq qalır, üstəlik istifadəçi proqramı istifadə etməyə davam etmək üçün üzərinə basmalıdır.

Beləliklə WinForms və WPF applications üçün olduqca avtomatik olaraq idarə etmək üçün SingleInstance kommunal sinfi yaradıldı.

Winforms :

1) proqramın sinifini aşağıdakı kimi dəyişdirin:

 static class Program { public static readonly SingleInstance Singleton = new SingleInstance(typeof(Program).FullName); [STAThread] static void Main(string[] args) { // NOTE: if this always return false, close  restart Visual Studio // this is probably due to the vshost.exe thing Singleton.RunFirstInstance(() => { SingleInstanceMain(args); }); } public static void SingleInstanceMain(string[] args) { // standard code that was in Main now goes here Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } 

2) əsas pəncərənin sinfini aşağıdakı kimi dəyişdirin:

 public partial class Form1 : Form { public Form1() { InitializeComponent(); } protected override void WndProc(ref Message m) { // if needed, the singleton will restore this window Program.Singleton.OnWndProc(this, m, true); // TODO: handle specific messages here if needed base.WndProc(ref m); } } 

WPF:

1) tətbiqi səhifəni bu şəkildə dəyişdirin (və əsas metoddan kənarlaşdırmaq üçün bir səhifəə qurma hərəkətini təyin etdiyinizə əmin olun):

 public partial class App : Application { public static readonly SingleInstance Singleton = new SingleInstance(typeof(App).FullName); [STAThread] public static void Main(string[] args) { // NOTE: if this always return false, close  restart Visual Studio // this is probably due to the vshost.exe thing Singleton.RunFirstInstance(() => { SingleInstanceMain(args); }); } public static void SingleInstanceMain(string[] args) { // standard code that was in Main now goes here App app = new App(); app.InitializeComponent(); app.Run(); } } 

2) əsas pəncərənin sinfini aşağıdakı kimi dəyişdirin:

 public partial class MainWindow : Window { private HwndSource _source; public MainWindow() { InitializeComponent(); } protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); _source = (HwndSource)PresentationSource.FromVisual(this); _source.AddHook(HwndSourceHook); } protected virtual IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { // if needed, the singleton will restore this window App.Singleton.OnWndProc(hwnd, msg, wParam, lParam, true, true); // TODO: handle other specific message return IntPtr.Zero; } 

Və burada faydalı bir sinifdir:

 using System; using System.ComponentModel; using System.Runtime.InteropServices; using System.Threading; namespace SingleInstanceUtilities { public sealed class SingleInstance { private const int HWND_BROADCAST = 0xFFFF; [DllImport("user32.dll")] private static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam); [DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern int RegisterWindowMessage(string message); [DllImport("user32.dll")] private static extern bool SetForegroundWindow(IntPtr hWnd); public SingleInstance(string uniqueName) { if (uniqueName == null) throw new ArgumentNullException("uniqueName"); Mutex = new Mutex(true, uniqueName); Message = RegisterWindowMessage("WM_" + uniqueName); } public Mutex Mutex { get; private set; } public int Message { get; private set; } public void RunFirstInstance(Action action) { RunFirstInstance(action, IntPtr.Zero, IntPtr.Zero); } // NOTE: if this always return false, close  restart Visual Studio // this is probably due to the vshost.exe thing public void RunFirstInstance(Action action, IntPtr wParam, IntPtr lParam) { if (action == null) throw new ArgumentNullException("action"); if (WaitForMutext(wParam, lParam)) { try { action(); } finally { ReleaseMutex(); } } } public static void ActivateWindow(IntPtr hwnd) { if (hwnd == IntPtr.Zero) return; FormUtilities.ActivateWindow(FormUtilities.GetModalWindow(hwnd)); } public void OnWndProc(IntPtr hwnd, int m, IntPtr wParam, IntPtr lParam, bool restorePlacement, bool activate) { if (m == Message) { if (restorePlacement) { WindowPlacement placement = WindowPlacement.GetPlacement(hwnd, false); if (placement.IsValid  placement.IsMinimized) { const int SW_SHOWNORMAL = 1; placement.ShowCmd = SW_SHOWNORMAL; placement.SetPlacement(hwnd); } } if (activate) { SetForegroundWindow(hwnd); FormUtilities.ActivateWindow(FormUtilities.GetModalWindow(hwnd)); } } } #if WINFORMS // define this for Winforms apps public void OnWndProc(System.Windows.Forms.Form form, int m, IntPtr wParam, IntPtr lParam, bool activate) { if (form == null) throw new ArgumentNullException("form"); if (m == Message) { if (activate) { if (form.WindowState == System.Windows.Forms.FormWindowState.Minimized) { form.WindowState = System.Windows.Forms.FormWindowState.Normal; } form.Activate(); FormUtilities.ActivateWindow(FormUtilities.GetModalWindow(form.Handle)); } } } public void OnWndProc(System.Windows.Forms.Form form, System.Windows.Forms.Message m, bool activate) { if (form == null) throw new ArgumentNullException("form"); OnWndProc(form, m.Msg, m.WParam, m.LParam, activate); } #endif public void ReleaseMutex() { Mutex.ReleaseMutex(); } public bool WaitForMutext(bool force, IntPtr wParam, IntPtr lParam) { bool b = PrivateWaitForMutext(force); if (!b) { PostMessage((IntPtr)HWND_BROADCAST, Message, wParam, lParam); } return b; } public bool WaitForMutext(IntPtr wParam, IntPtr lParam) { return WaitForMutext(false, wParam, lParam); } private bool PrivateWaitForMutext(bool force) { if (force) return true; try { return Mutex.WaitOne(TimeSpan.Zero, true); } catch (AbandonedMutexException) { return true; } } } // NOTE: don't add any field or public get/set property, as this must exactly map to Windows' WINDOWPLACEMENT structure [StructLayout(LayoutKind.Sequential)] public struct WindowPlacement { public int Length { get; set; } public int Flags { get; set; } public int ShowCmd { get; set; } public int MinPositionX { get; set; } public int MinPositionY { get; set; } public int MaxPositionX { get; set; } public int MaxPositionY { get; set; } public int NormalPositionLeft { get; set; } public int NormalPositionTop { get; set; } public int NormalPositionRight { get; set; } public int NormalPositionBottom { get; set; } [DllImport("user32.dll", SetLastError = true)] private static extern bool SetWindowPlacement(IntPtr hWnd, ref WindowPlacement lpwndpl); [DllImport("user32.dll", SetLastError = true)] private static extern bool GetWindowPlacement(IntPtr hWnd, ref WindowPlacement lpwndpl); private const int SW_SHOWMINIMIZED = 2; public bool IsMinimized { get { return ShowCmd == SW_SHOWMINIMIZED; } } public bool IsValid { get { return Length == Marshal.SizeOf(typeof(WindowPlacement)); } } public void SetPlacement(IntPtr windowHandle) { SetWindowPlacement(windowHandle, ref this); } public static WindowPlacement GetPlacement(IntPtr windowHandle, bool throwOnError) { WindowPlacement placement = new WindowPlacement(); if (windowHandle == IntPtr.Zero) return placement; placement.Length = Marshal.SizeOf(typeof(WindowPlacement)); if (!GetWindowPlacement(windowHandle, ref placement)) { if (throwOnError) throw new Win32Exception(Marshal.GetLastWin32Error()); return new WindowPlacement(); } return placement; } } public static class FormUtilities { [DllImport("user32.dll")] private static extern IntPtr GetWindow(IntPtr hWnd, int uCmd); [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr SetActiveWindow(IntPtr hWnd); [DllImport("user32.dll")] private static extern bool IsWindowVisible(IntPtr hWnd); [DllImport("kernel32.dll")] public static extern int GetCurrentThreadId(); private delegate bool EnumChildrenCallback(IntPtr hwnd, IntPtr lParam); [DllImport("user32.dll")] private static extern bool EnumThreadWindows(int dwThreadId, EnumChildrenCallback lpEnumFunc, IntPtr lParam); private class ModalWindowUtil { private const int GW_OWNER = 4; private int _maxOwnershipLevel; private IntPtr _maxOwnershipHandle; private bool EnumChildren(IntPtr hwnd, IntPtr lParam) { int level = 1; if (IsWindowVisible(hwnd)  IsOwned(lParam, hwnd, ref level)) { if (level > _maxOwnershipLevel) { _maxOwnershipHandle = hwnd; _maxOwnershipLevel = level; } } return true; } private static bool IsOwned(IntPtr owner, IntPtr hwnd, ref int level) { IntPtr o = GetWindow(hwnd, GW_OWNER); if (o == IntPtr.Zero) return false; if (o == owner) return true; level++; return IsOwned(owner, o, ref level); } public static void ActivateWindow(IntPtr hwnd) { if (hwnd != IntPtr.Zero) { SetActiveWindow(hwnd); } } public static IntPtr GetModalWindow(IntPtr owner) { ModalWindowUtil util = new ModalWindowUtil(); EnumThreadWindows(GetCurrentThreadId(), util.EnumChildren, owner); return util._maxOwnershipHandle; // may be IntPtr.Zero } } public static void ActivateWindow(IntPtr hwnd) { ModalWindowUtil.ActivateWindow(hwnd); } public static IntPtr GetModalWindow(IntPtr owner) { return ModalWindowUtil.GetModalWindow(owner); } } } 
9
ответ дан Simon Mourier 13 мая '13 в 15:40 2013-05-13 15:40