精华内容
下载资源
问答
  • WPF应用程序开发实例

    2011-05-03 19:32:24
    WPF设计的播放器实例,更好地去学习WPF开发
  • WpfSingletonAppBase:为WPF提供单实例应用程序基础
  • 一个Application类包装器,它为WPF程序提供通用功能和单实例支持。
  • 如果我们不希望用户打开两个应用程序实例, 可以通过下面的方式来实现此目的 首先, 删除 App.xaml 文件, 新建一个 App.cs 文件 完成之后项目的结构 : 因为要在 App 类之前执行一些代码, 所以不能使用 App.xaml ...

    本文最后更新于 2019年 5月 6号 凌晨 2点 07分,并同步发布于 :


    如果我们不希望用户打开两个应用程序实例, 可以通过下面的方式来实现此目的


    首先, 删除 App.xaml 文件, 新建一个 App.cs 文件
    完成之后项目的结构 :

    因为要在 App 类之前执行一些代码, 所以不能使用 App.xaml 文件

    然后添加引用 Microsoft.VisualBasic

    然后开始编写代码


    需要的 using 指令组 :

    由于 Microsoft.VisualBasic.ApplicationServicesSystem.Windows 这两个命名空间都定义了我们即将使用的 StartupEventArgs 类型, 所以分别对这两个命名空间设置一个别名


    首先编写 App 类, 并设置启动时的窗口

    然后创建一个继承自 WindowsFormsApplicationBase 的类

    OnStartup() 方法中创建 App 类, 并调用 Run() 方法
    OnStartupNextInstance() 方法中, 激活一个窗口, 提示用户, 程序已经在运行了

    最后手动编写 Main() 方法, 创建一个 SingleInstanceApp 对象并调用 Run() 方法


    —END—

    展开全文
  • WPF实例应用程序

    2017-10-19 16:31:16
    WPF,每次只能启动一个程序,再次启动则激活已有窗体,不创建新窗体。
  • 一个简单的例子就是大家在使用很多应用程序,例如在使用Microsoft Word 时会遇到一种情况,不管你打开多少个文档,... 对于创建单实例应用程序WPF本身没有提供自带的解决方法,但可以通过变通的方式来实现—...

      一个简单的例子就是大家在使用很多应用程序,例如在使用Microsoft Word 时会遇到一种情况,不管你打开多少个文档,系统一次只能加载一个winword.exe 实例。当打开新文档时,文档在新窗口显示,但是始终只有一个应用程序控制所有文档窗口;如:可以提供平铺当前所有文档中相邻窗口的文档的特性。

      对于创建单实例的应用程序,WPF本身没有提供自带的解决方法,但可以通过变通的方式来实现——思路是当触发ApplicationStartup事件时,检查另一个实例是否在运行。方法是通过使用全局的mutex对像(mutex是操做系统中提供的用于进程间通信的同步方法)。虽然简单,但功能有限,如新实例无法与已经存在的实例进行通信。尤其是对于基于文档的用于程序而言,这确实是一个问题,如果新实例需要告诉已经存在的实例打开一个新的文档或者该文档是通过命令行参数传递的情况,那该使用什么方法来解决问题呢??

      WPF团队推荐我们一种最简单的方法就是:使用Windows  窗体提供的内置支持,该内置支持最初是用于VisualBasic 应用程序的,使用Window窗体和VisualBasic 的这一特新来开发基于C#的WPF程序会存在一个新旧应用程序之分,本质上旧式应用程序充当了WPF应用程序的封装器。流程是:当启动程序时将创建旧式应用程序,旧式应用程序接着创建WPF应用程序,旧式应用程序处理实例管理,而WPF应用程序处理正真的应用。

      下面我们通过一个实例来演示创建单实例应用程序的具体步骤:

     

        一.创建WPF窗体项目,并添加Microsoft.VisualBasic.dll 引用。

        

        二.首先创建一个Document.xaml,和 DocumentList.xaml 窗口文件,使用定义的类DocumentReference 表示对Document引用。

    DocumentReference :

     1 public class DocumentReference
     2     {
     3         private Document document;
     4         public Document Document
     5         {
     6             get { return document; }
     7             set { document = value; }
     8         }
     9 
    10         private string name;
    11         public string Name
    12         {
    13             get { return name; }
    14             set { name = value; }
    15         }
    16 
    17         public DocumentReference(Document document, string name)
    18         {
    19             Document = document;
    20             Name = name;
    21         }
    22     }
    View Code

        Document.LoadFile() 通过文件名读取文档内容,Document.OnClosed() 事件在文档窗体关闭时触发,用于从动态集合移除实例。

     public partial class Document : Window
        {
            private DocumentReference docRef;
    
            public Document()
            {
                InitializeComponent();
            }
    
            public void LoadFile(DocumentReference docRef)
            {
                this.docRef = docRef;
                this.Content = File.ReadAllText(docRef.Name);
                this.Title = docRef.Name;
            }
    
            protected override void OnClosed(EventArgs e)
            {
                base.OnClosed(e);
                ((WpfApp)Application.Current).Documents.Remove(docRef);
            }
    
        }
    View Code

      DocumentList 窗体放置一个 <ListBox Name="lstDocuments"></ListBox> 的 lstDocuments控件,用于显示当前文档列表。

     1 public partial class DocumentList : Window
     2     {
     3         public DocumentList()
     4         {
     5             InitializeComponent();
     6 
     7             lstDocuments.DisplayMemberPath = "Name";
     8             lstDocuments.ItemsSource = ((WpfApp)Application.Current).Documents;
     9         }       
    10     }
    View Code

        三.接着创建一个自定义的WPF类WpfApp.cs,该类继承于Windows.Application。在这里每当通过命令行参数传递给SingleInstanceApplication 类文件名时,会触发 SingleInstanceApplication 类的 OnStartupNextInstance 方法,并调用自定义的 ShowDocument() 方法为指定的文档加载文档窗体。

    WpfApp:

     1  public class WpfApp : Application
     2     {
     3         private ObservableCollection<DocumentReference> documents =
     4             new ObservableCollection<DocumentReference>();
     5         public ObservableCollection<DocumentReference> Documents
     6         {
     7             get { return documents; }
     8             set { documents = value; }
     9         }        
    10 
    11         protected override void OnStartup(System.Windows.StartupEventArgs e)
    12         {
    13             base.OnStartup(e);
    14             //WpfApp.Current = this;
    15 
    16             DocumentList list = new DocumentList();
    17             this.MainWindow = list;
    18             list.Show();
    19 
    20             // Load the document that was specified as an argument.
    21             if (e.Args.Length > 0) ShowDocument(e.Args[0]);
    22 
    23         }
    24 
    25         public void ShowDocument(string fileName)
    26         {
    27             try
    28             {
    29                 Document doc = new Document();
    30                 DocumentReference docRef = new DocumentReference(doc, fileName);
    31                 doc.LoadFile(docRef);
    32                 doc.Owner = this.MainWindow;
    33                 doc.Show();
    34                 doc.Activate();
    35                 Documents.Add(docRef);
    36             }
    37             catch
    38             {
    39                 MessageBox.Show("Could not load document.");
    40             }
    41         }
    42     }
    View Code

      四.创建继承于WindowsFormsApplicationBase 的自定义类 SingleInstanceApplication.cs 该类将提供3个用于管理实例的重要成员。

    • IsSingleInstance 用于确定此应用程序是否为单实例应用程序,在构造函数中设置值为true。
    • 重写 OnStartup(),程序启动时,重写该方法并创建WPF应用程序对象。
    • 重写 OnStartupNextInstance(),当另一个应用程序启动时触发该方法,该方法提供了访问命令行的参数的功能。此时可以调用WPF应用程序类的方法来创建窗口,但不能创建另一个应用程序对象。

         SingleInstanceApplication:

     1 public class SingleInstanceApplication : WindowsFormsApplicationBase
     2     {
     3         private WpfApp App;
     4         public SingleInstanceApplication()
     5         {
     6             this.IsSingleInstance = true;
     7         }
     8 
     9         protected override bool OnStartup(Microsoft.VisualBasic.ApplicationServices.StartupEventArgs eventArgs)
    10         {
    11             string extension = ".testDoc";
    12             string title = "SingleInstanceApplication";
    13             string extensionDescription = "A Test Document";
    14 
    15             //return base.OnStartup(eventArgs);
    16             App = new WpfApp();
    17             App.Run();
    18             return false;
    19         }
    20 
    21         protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
    22         {
    23             //base.OnStartupNextInstance(eventArgs);
    24             if (eventArgs.CommandLine.Count > 0)
    25                 App.ShowDocument(eventArgs.CommandLine[0]);
    26         }
    27     }
    View Code

       五. 由于应用程序需要在APP类之前就要创建SingleInstanceApplication 类,所以这里就需要同过传统的Main方法作为启动入口。

     public class Startup
        {
            [STAThread]
            public static void Main(string[] args)
            {
                SingleInstanceApplication wrapper = new SingleInstanceApplication();
                wrapper.Run(args);
            }
        }
    

     六,为了测试单例程序,需要使用Window文件扩展名与程序相关联,将其文件类型注册。运行结果如下:

      

     

    转载于:https://www.cnblogs.com/mschen/p/4303944.html

    展开全文
  • 一 重写程序启动OnStartup方法 protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); Mutex mutex = new Mutex(true,"单实例程序",out bool isNewInstance); ...

    一 重写程序启动OnStartup方法

      protected override void OnStartup(StartupEventArgs e)
            {
                base.OnStartup(e);
                Mutex mutex = new Mutex(true,"单实例程序",out bool isNewInstance); 
                if(isNewInstance!=true)
                {
                   	IntPtr intPtr = FindWindowW(null, "单实例应用程序Title");
                    if(intPtr!=IntPtr.Zero)
                    {
                        SetForegroundWindow(intPtr);
                    }
    				Shutdown();
                }
            }
    

    二 调用Win32 API

    [DllImport("User32", CharSet = CharSet.Unicode)]
    static extern IntPtr FindWindowW(String lpClassName,String lpWindowName);
    [DllImport("User32", CharSet = CharSet.Unicode)]
    static extern Boolean SetForegroundWindow(IntPtr hWnd);
            
    
    展开全文
  • 在.NET(而不是Windows Forms或控制台)下使用C#和WPF,创建只能作为单个实例运行的应用程序的正确方法是什么? 我知道它与某种称为互斥量的神话事物有关,我很少能找到一个烦人的

    .NET(而不是Windows Forms或控制台)下使用C#和WPF,创建只能作为单个实例运行的应用程序的正确方法是什么?

    我知道它与某种称为互斥量的神话事物有关,我很少能找到一个烦人的人来阻止并解释其中的一个。

    该代码还需要告知已经运行的实例用户试图启动第二个实例,并且还可能传递任何命令行参数(如果存在)。


    #1楼

    看下面的代码。 这是防止WPF应用程序的多个实例的绝佳解决方案。

    private void Application_Startup(object sender, StartupEventArgs e)
    {
        Process thisProc = Process.GetCurrentProcess();
        if (Process.GetProcessesByName(thisProc.ProcessName).Length > 1)
        {
            MessageBox.Show("Application running");
            Application.Current.Shutdown();
            return;
        }
    
        var wLogin = new LoginWindow();
    
        if (wLogin.ShowDialog() == true)
        {
            var wMain = new Main();
            wMain.WindowState = WindowState.Maximized;
            wMain.Show();
        }
        else
        {
            Application.Current.Shutdown();
        }
    }
    

    #2楼

    通常,这是我用于单实例Windows Forms应用程序的代码:

    [STAThread]
    public static void Main()
    {
        String assemblyName = Assembly.GetExecutingAssembly().GetName().Name;
    
        using (Mutex mutex = new Mutex(false, assemblyName))
        {
            if (!mutex.WaitOne(0, false))
            {
                Boolean shownProcess = false;
                Process currentProcess = Process.GetCurrentProcess();
    
                foreach (Process process in Process.GetProcessesByName(currentProcess.ProcessName))
                {
                    if (!process.Id.Equals(currentProcess.Id) && process.MainModule.FileName.Equals(currentProcess.MainModule.FileName) && !process.MainWindowHandle.Equals(IntPtr.Zero))
                    {
                        IntPtr windowHandle = process.MainWindowHandle;
    
                        if (NativeMethods.IsIconic(windowHandle))
                            NativeMethods.ShowWindow(windowHandle, ShowWindowCommand.Restore);
    
                        NativeMethods.SetForegroundWindow(windowHandle);
    
                        shownProcess = true;
                    }
                }
    
                if (!shownProcess)
                    MessageBox.Show(String.Format(CultureInfo.CurrentCulture, "An instance of {0} is already running!", assemblyName), assemblyName, MessageBoxButtons.OK, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1, (MessageBoxOptions)0);
            }
            else
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form());
            }
        }
    }
    

    本机组件在哪里:

    [DllImport("User32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern Boolean IsIconic([In] IntPtr windowHandle);
    
    [DllImport("User32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern Boolean SetForegroundWindow([In] IntPtr windowHandle);
    
    [DllImport("User32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern Boolean ShowWindow([In] IntPtr windowHandle, [In] ShowWindowCommand command);
    
    public enum ShowWindowCommand : int
    {
        Hide                   = 0x0,
        ShowNormal             = 0x1,
        ShowMinimized          = 0x2,
        ShowMaximized          = 0x3,
        ShowNormalNotActive    = 0x4,
        Minimize               = 0x6,
        ShowMinimizedNotActive = 0x7,
        ShowCurrentNotActive   = 0x8,
        Restore                = 0x9,
        ShowDefault            = 0xA,
        ForceMinimize          = 0xB
    }
    

    #3楼

    以下代码是我的WCF命名管道解决方案,用于注册单实例应用程序。 很好,因为当另一个实例尝试启动时,它还会引发一个事件,并接收另一个实例的命令行。

    它面向WPF,因为它使用System.Windows.StartupEventHandler类,但是可以轻松对其进行修改。

    此代码需要对PresentationFrameworkSystem.ServiceModel的引用。

    用法:

    class Program
    {
        static void Main()
        {
            var applicationId = new Guid("b54f7b0d-87f9-4df9-9686-4d8fd76066dc");
    
            if (SingleInstanceManager.VerifySingleInstance(applicationId))
            {
                SingleInstanceManager.OtherInstanceStarted += OnOtherInstanceStarted;
    
                // Start the application
            }
        }
    
        static void OnOtherInstanceStarted(object sender, StartupEventArgs e)
        {
            // Do something in response to another instance starting up.
        }
    }
    

    源代码:

    /// <summary>
    /// A class to use for single-instance applications.
    /// </summary>
    public static class SingleInstanceManager
    {
      /// <summary>
      /// Raised when another instance attempts to start up.
      /// </summary>
      public static event StartupEventHandler OtherInstanceStarted;
    
      /// <summary>
      /// Checks to see if this instance is the first instance running on this machine.  If it is not, this method will
      /// send the main instance this instance's startup information.
      /// </summary>
      /// <param name="guid">The application's unique identifier.</param>
      /// <returns>True if this instance is the main instance.</returns>
      public static bool VerifySingleInstace(Guid guid)
      {
        if (!AttemptPublishService(guid))
        {
          NotifyMainInstance(guid);
    
          return false;
        }
    
        return true;
      }
    
      /// <summary>
      /// Attempts to publish the service.
      /// </summary>
      /// <param name="guid">The application's unique identifier.</param>
      /// <returns>True if the service was published successfully.</returns>
      private static bool AttemptPublishService(Guid guid)
      {
        try
        {
          ServiceHost serviceHost = new ServiceHost(typeof(SingleInstance));
          NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
          serviceHost.AddServiceEndpoint(typeof(ISingleInstance), binding, CreateAddress(guid));
          serviceHost.Open();
    
          return true;
        }
        catch
        {
          return false;
        }
      }
    
      /// <summary>
      /// Notifies the main instance that this instance is attempting to start up.
      /// </summary>
      /// <param name="guid">The application's unique identifier.</param>
      private static void NotifyMainInstance(Guid guid)
      {
        NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
        EndpointAddress remoteAddress = new EndpointAddress(CreateAddress(guid));
        using (ChannelFactory<ISingleInstance> factory = new ChannelFactory<ISingleInstance>(binding, remoteAddress))
        {
          ISingleInstance singleInstance = factory.CreateChannel();
          singleInstance.NotifyMainInstance(Environment.GetCommandLineArgs());
        }
      }
    
      /// <summary>
      /// Creates an address to publish/contact the service at based on a globally unique identifier.
      /// </summary>
      /// <param name="guid">The identifier for the application.</param>
      /// <returns>The address to publish/contact the service.</returns>
      private static string CreateAddress(Guid guid)
      {
        return string.Format(CultureInfo.CurrentCulture, "net.pipe://localhost/{0}", guid);
      }
    
      /// <summary>
      /// The interface that describes the single instance service.
      /// </summary>
      [ServiceContract]
      private interface ISingleInstance
      {
        /// <summary>
        /// Notifies the main instance that another instance of the application attempted to start.
        /// </summary>
        /// <param name="args">The other instance's command-line arguments.</param>
        [OperationContract]
        void NotifyMainInstance(string[] args);
      }
    
      /// <summary>
      /// The implementation of the single instance service interface.
      /// </summary>
      private class SingleInstance : ISingleInstance
      {
        /// <summary>
        /// Notifies the main instance that another instance of the application attempted to start.
        /// </summary>
        /// <param name="args">The other instance's command-line arguments.</param>
        public void NotifyMainInstance(string[] args)
        {
          if (OtherInstanceStarted != null)
          {
            Type type = typeof(StartupEventArgs);
            ConstructorInfo constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
            StartupEventArgs e = (StartupEventArgs)constructor.Invoke(null);
            FieldInfo argsField = type.GetField("_args", BindingFlags.Instance | BindingFlags.NonPublic);
            Debug.Assert(argsField != null);
            argsField.SetValue(e, args);
    
            OtherInstanceStarted(null, e);
          }
        }
      }
    }
    

    #4楼

    作为标记答案的参考,代码C#.NET单一实例应用程序是一个很好的开始。

    但是,我发现当已经存在的实例打开一个模式对话框时,无论该对话框是托管对话框(例如另一种窗体,如“关于”框)还是非托管对话框(例如,即使使用标准的.NET类,也可以使用OpenFileDialog。 使用原始代码,主窗体被激活,但是模态窗体保持不活动状态,这看起来很奇怪,此外用户必须单击它才能继续使用该应用程序。

    因此,我已经创建了SingleInstance实用程序类来为Winforms和WPF应用程序自动处理所有这些。

    Winforms

    1)像这样修改Program类:

    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)像这样修改主窗口类:

    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)像这样修改App页面(并确保将其构建操作设置为page以能够重新定义Main方法):

    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)像这样修改主窗口类:

    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;
        }
    

    这是实用程序类:

    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);
            }
        }
    }
    

    #5楼

    这里

    跨进程Mutex的常见用法是确保一次只能运行程序实例。 这是完成的过程:

    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的一个好功能是,如果应用程序在不首先调用ReleaseMutex的情况下终止,则CLR将自动释放Mutex。


    #6楼

    只是有些想法:在某些情况下,仅要求应用程序的一个实例不像某些人所相信的那样是“ lam脚的”。 如果一个数据库允许单个用户访问该应用程序的多个实例,那么数据库应用程序等的难度将增加一个数量级(您知道,所有这些操作都会更新在该用户的多个应用程序实例中打开的所有记录机器等)。 首先,对于“名称冲突”,不要使用人类易读的名称-而是使用GUID,或者甚至更好的GUID +人类易读的名称。名称冲突的可能性刚刚被忽略,互斥体不在乎正如某人所指出的那样,DOS攻击会很烂,但是如果恶意软件人冒了获取互斥量名称并将其合并到他们的应用程序中的麻烦,那么无论如何您几乎都是目标,并且必须做更多的事情来保护此外,如果有人使用互斥量名称的变体:new Mutex(true,“ some GUID plus Name”,AIsFirstInstance输出),您已经有了关于Mutex是否是第一个实例的指示符。


    #7楼

    您可以使用Mutex类,但是很快您将发现您将需要实现代码以自己传递参数。 好吧,当我阅读Chris Sell的书时,我在WinForms中进行编程时学到了一个技巧。 这个技巧使用了框架中已经可用的逻辑。 我不了解您,但是当我了解到一些东西后,我便可以在框架中重用,这通常是我走的路,而不是重新发明轮子。 除非它当然不能满足我的所有需求。

    当我进入WPF时,我想出了一种在WPF应用程序中使用相同代码的方法。 该解决方案应根据您的问题满足您的需求。

    首先,我们需要创建我们的应用程序类。 在此类中,我们将重写OnStartup事件,并创建一个称为Activate的方法,该方法将在以后使用。

    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();
        }
    }
    

    其次,我们将需要创建一个可以管理实例的类。 在进行此操作之前,我们实际上将重用Microsoft.VisualBasic程序集中的某些代码。 由于在此示例中使用的是C#,因此必须对程序集进行引用。 如果您使用的是VB.NET,则无需执行任何操作。 我们将使用的类是WindowsFormsApplicationBase,并继承其实例管理器,然后利用属性和事件来处理单个实例。

    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();
        }
    }
    

    基本上,我们使用VB位来检测单个实例并进行相应处理。 第一个实例加载时将触发OnStartup。 再次重新运行该应用程序时,将触发OnStartupNextInstance。 如您所见,我可以了解事件参数在命令行中传递的内容。 我将值设置为实例字段。 您可以在此处解析命令行,也可以通过构造函数和对Activate方法的调用将其传递给应用程序。

    第三,是时候创建我们的EntryPoint了。 无需像通常那样更新应用程序,我们将利用SingleInstanceManager。

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

    好吧,我希望您能够了解所有内容并能够使用此实现并将其实现为自己的实现。


    #8楼

    使用互斥锁解决方案:

    using System;
    using System.Windows.Forms;
    using System.Threading;
    
    namespace OneAndOnlyOne
    {
    static class Program
    {
        static String _mutexID = " // generate guid"
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
    
            Boolean _isNotRunning;
            using (Mutex _mutex = new Mutex(true, _mutexID, out _isNotRunning))
            {
                if (_isNotRunning)
                {
                    Application.Run(new Form1());
                }
                else
                {
                    MessageBox.Show("An instance is already running.");
                    return;
                }
            }
        }
    }
    }
    

    #9楼

    这是我使用的一种轻量级解决方案,它允许应用程序将现有的窗口带到前台,而无需诉诸自定义窗口消息或盲目搜索进程名称。

    [DllImport("user32.dll")]
    static extern bool SetForegroundWindow(IntPtr hWnd);
    
    static readonly string guid = "<Application Guid>";
    
    static void Main()
    {
        Mutex mutex = null;
        if (!CreateMutex(out mutex))
            return;
    
        // Application startup code.
    
        Environment.SetEnvironmentVariable(guid, null, EnvironmentVariableTarget.User);
    }
    
    static bool CreateMutex(out Mutex mutex)
    {
        bool createdNew = false;
        mutex = new Mutex(false, guid, out createdNew);
    
        if (createdNew)
        {
            Process process = Process.GetCurrentProcess();
            string value = process.Id.ToString();
    
            Environment.SetEnvironmentVariable(guid, value, EnvironmentVariableTarget.User);
        }
        else
        {
            string value = Environment.GetEnvironmentVariable(guid, EnvironmentVariableTarget.User);
            Process process = null;
            int processId = -1;
    
            if (int.TryParse(value, out processId))
                process = Process.GetProcessById(processId);
    
            if (process == null || !SetForegroundWindow(process.MainWindowHandle))
                MessageBox.Show("Unable to start application. An instance of this application is already running.");
        }
    
        return createdNew;
    }
    

    编辑:您还可以静态存储和初始化互斥锁和createdNew,但是一旦完成处理,就需要显式处理/释放互斥锁。 就个人而言,我更喜欢将互斥锁保持在本地,因为即使应用程序关闭而没有到达Main的末尾,它也会被自动丢弃。


    #10楼

    更新2017年1月25日。 在尝试了几件事之后,我决定使用VisualBasic.dll,它更容易且效果更好(至少对我而言)。 我让以前的回答作为参考...

    就像参考一样,这是我不传递参数的方式(我找不到任何理由……我的意思是单个应用程序的参数要从一个实例传递到另一个实例)。 如果需要文件关联,则应为每个文档实例化一个应用程序(按用户标准期望)。 如果您必须将args传递给现有应用程序,我想我会使用vb dll。

    不传递args(仅单实例应用程序),我更喜欢不注册新的Window消息,并且不覆盖Matt Davis解决方案中定义的消息循环。 尽管添加VisualBasic dll没什么大不了的,但是我宁愿不要仅仅为了做单实例应用而添加新的引用。 此外,我确实更喜欢使用Main实例化一个新类,而不是从App.Startup重写调用Shutdown以确保尽快退出。

    希望任何人都会喜欢它...或会有所启发:-)

    项目启动类应设置为“ SingleInstanceApp”。

    public class SingleInstanceApp
    {
        [STAThread]
        public static void Main(string[] args)
        {
            Mutex _mutexSingleInstance = new Mutex(true, "MonitorMeSingleInstance");
    
            if (_mutexSingleInstance.WaitOne(TimeSpan.Zero, true))
            {
                try
                {
                    var app = new App();
                    app.InitializeComponent();
                    app.Run();
    
                }
                finally
                {
                    _mutexSingleInstance.ReleaseMutex();
                    _mutexSingleInstance.Close();
                }
            }
            else
            {
                MessageBox.Show("One instance is already running.");
    
                var processes = Process.GetProcessesByName(Assembly.GetEntryAssembly().GetName().Name);
                {
                    if (processes.Length > 1)
                    {
                        foreach (var process in processes)
                        {
                            if (process.Id != Process.GetCurrentProcess().Id)
                            {
                                WindowHelper.SetForegroundWindow(process.MainWindowHandle);
                            }
                        }
                    }
                }
            }
        }
    }
    

    WindowHelper:

    using System;
    using System.Runtime.InteropServices;
    using System.Windows;
    using System.Windows.Interop;
    using System.Windows.Threading;
    
    namespace HQ.Util.Unmanaged
    {
        public class WindowHelper
        {
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool SetForegroundWindow(IntPtr hWnd);
    

    #11楼

    好吧,我为此有一个可弃用的类,在大多数情况下都可以轻松使用:

    像这样使用它:

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

    这里是:

    /// <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)
            {
                /* Release unmanaged ressources */
    
                if (disposing)
                {
                    /* Release managed ressources */
                    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
    }
    

    #12楼

    您还可以使用CodeFluent Runtime ,它是一组免费工具。 它提供了SingleInstance类来实现单个实例应用程序。


    #13楼

    这个看似简单的问题有这么多答案。 我只是想在这里稍作改动,这就是我对这个问题的解决方案。

    创建Mutex可能会很麻烦,因为JIT-er仅看到您将其用于代码的一小部分,并希望将其标记为可进行垃圾回收。 它非常想让您以为您不会再使用该Mutex这么长的时间了。 实际上,只要您的应用程序运行,您就希望挂在此Mutex上。 告诉垃圾收集器让您自己离开Mutex的最好方法是告诉它,使其在不同年代的车库收集中保持活力。 例:

    var m = new Mutex(...);
    ...
    GC.KeepAlive(m);
    

    我从以下页面提出了这个想法: http : //www.ai.uga.edu/~mc/SingleInstance.html


    #14楼

    我向NativeMethods类添加了sendMessage方法。

    显然,如果任务栏中未显示该应用程序,则postmessage方法可以工作,但是使用sendmessage方法可以解决此问题。

    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.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
        [DllImport("user32")]
        public static extern int RegisterWindowMessage(string message);
    }
    

    #15楼

    WPF单实例应用程序是一种使用Mutex和IPC东西,并且还将任何命令行参数传递给正在运行的实例的新方法。


    #16楼

    这是我用的。 它结合了过程枚举来执行切换和互斥,以防止“活动的点击器”:

    public partial class App
    {
        [DllImport("user32")]
        private static extern int OpenIcon(IntPtr hWnd);
    
        [DllImport("user32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);
    
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            var p = Process
               .GetProcessesByName(Process.GetCurrentProcess().ProcessName);
                foreach (var t in p.Where(t => t.MainWindowHandle != IntPtr.Zero))
                {
                    OpenIcon(t.MainWindowHandle);
                    SetForegroundWindow(t.MainWindowHandle);
                    Current.Shutdown();
                    return;
                }
    
                // there is a chance the user tries to click on the icon repeatedly
                // and the process cannot be discovered yet
                bool createdNew;
                var mutex = new Mutex(true, "MyAwesomeApp", 
                   out createdNew);  // must be a variable, though it is unused - 
                // we just need a bit of time until the process shows up
                if (!createdNew)
                {
                    Current.Shutdown();
                    return;
                }
    
                new Bootstrapper().Run();
            }
        }
    

    #17楼

    通常,每当我们执行一个.exe时,它每次都会创建一个具有自己的地址空间,资源等的单独的Windows进程。 但是我们不希望使用此标准,因为这将阻止我们创建单个流程。 可以使用C#中的Mutex创建单实例应用程序,本文将对此进行讨论。

    此外,如果我们想将应用程序放在首位,我们可以使用

     [DllImport("user32")]
     static extern IntPtr SetForegroundWindow(IntPtr hWnd);
    

    #18楼

    MSDN实际上为C#和VB都提供了一个示例应用程序来完全做到这一点: http : //msdn.microsoft.com/zh-cn/library/ms771662(v=VS.90).aspx

    开发单实例检测的最常见,最可靠的技术是使用Microsoft .NET Framework远程处理基础结构(System.Remoting)。 Microsoft .NET Framework(2.0版)包括WindowsFormsApplicationBase类型,该类型封装了必需的远程处理功能。 要将这种类型合并到WPF应用程序中,需要从该类型派生一个类型,并将其用作应用程序静态入口点方法Main和WPF应用程序的Application类型之间的垫片。 填充程序检测何时首次启动应用程序以及何时尝试进行后续启动,并让WPF Application Type类型确定控制如何处理启动。

    • 对于C#,人们深吸一口气,然后忽略整个“我不想包含VisualBasic DLL”。 正因为如此Scott Hanselman所说的话 ,事实是,这几乎是解决问题的最干净的方法,并且是由比您更了解框架的人设计的。
    • 从可用性的角度来看,事实是用户是否正在加载应用程序并且该应用程序已经打开,并且向他们显示了错误消息,例如'Another instance of the app is running. Bye' 'Another instance of the app is running. Bye'那么他们将不会是一个非常高兴的用户。 您只需(在GUI应用程序中)切换到该应用程序并传递提供的参数-否则,如果命令行参数没有意义,则必须弹出可能已最小化的应用程序。

    该框架已经对此提供了支持-只是那个白痴叫DLL Microsoft.VisualBasic ,它并没有放入Microsoft.ApplicationUtils或类似的东西。 克服它-或打开Reflector。

    提示:如果完全按原样使用此方法,并且已经具有包含资源等的App.xaml,那么您也将要对此进行研究


    #19楼

    这是一个解决方案:

    Protected Overrides Sub OnStartup(e As StartupEventArgs)
        Const appName As String = "TestApp"
        Dim createdNew As Boolean
        _mutex = New Mutex(True, appName, createdNew)
        If Not createdNew Then
            'app is already running! Exiting the application
            MessageBox.Show("Application is already running.")
            Application.Current.Shutdown()
        End If
        MyBase.OnStartup(e)
    End Sub
    

    #20楼

    这是通过Event实现的同一件事。

    public enum ApplicationSingleInstanceMode
    {
        CurrentUserSession,
        AllSessionsOfCurrentUser,
        Pc
    }
    
    public class ApplicationSingleInstancePerUser: IDisposable
    {
        private readonly EventWaitHandle _event;
    
        /// <summary>
        /// Shows if the current instance of ghost is the first
        /// </summary>
        public bool FirstInstance { get; private set; }
    
        /// <summary>
        /// Initializes 
        /// </summary>
        /// <param name="applicationName">The application name</param>
        /// <param name="mode">The single mode</param>
        public ApplicationSingleInstancePerUser(string applicationName, ApplicationSingleInstanceMode mode = ApplicationSingleInstanceMode.CurrentUserSession)
        {
            string name;
            if (mode == ApplicationSingleInstanceMode.CurrentUserSession)
                name = $"Local\\{applicationName}";
            else if (mode == ApplicationSingleInstanceMode.AllSessionsOfCurrentUser)
                name = $"Global\\{applicationName}{Environment.UserDomainName}";
            else
                name = $"Global\\{applicationName}";
    
            try
            {
                bool created;
                _event = new EventWaitHandle(false, EventResetMode.ManualReset, name, out created);
                FirstInstance = created;
            }
            catch
            {
            }
        }
    
        public void Dispose()
        {
            _event.Dispose();
        }
    }
    

    #21楼

    这就是我最终处理此问题的方式。 请注意,调试代码仍在进行测试。 此代码在App.xaml.cs文件的OnStartup中。 (WPF)

            // Process already running ? 
            if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1)
            {
    
                // Show your error message
                MessageBox.Show("xxx is already running.  \r\n\r\nIf the original process is hung up you may need to restart your computer, or kill the current xxx process using the task manager.", "xxx is already running!", MessageBoxButton.OK, MessageBoxImage.Exclamation);
    
                // This process 
                Process currentProcess = Process.GetCurrentProcess();
    
                // Get all processes running on the local computer.
                Process[] localAll = Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName);
    
                // ID of this process... 
                int temp = currentProcess.Id;
                MessageBox.Show("This Process ID:  " + temp.ToString());
    
                for (int i = 0; i < localAll.Length; i++)
                {
                    // Find the other process 
                    if (localAll[i].Id != currentProcess.Id)
                    {
                        MessageBox.Show("Original Process ID (Switching to):  " + localAll[i].Id.ToString());
    
                        // Switch to it... 
                        SetForegroundWindow(localAll[i].MainWindowHandle);
    
                    }
                }
    
                Application.Current.Shutdown();
    
            }
    

    这可能有我尚未发现的问题。 如果遇到任何问题,我将更新我的答案。


    #22楼

    虽然不使用Mutex,简单的答案是:

    System.Diagnostics;    
    ...
    string thisprocessname = Process.GetCurrentProcess().ProcessName;
    
    if (Process.GetProcesses().Count(p => p.ProcessName == thisprocessname) > 1)
                    return;
    

    将其放在Program.Main()
    范例

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Diagnostics;
    
    namespace Sample
    {
        static class Program
        {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main()
            {
                //simple add Diagnostics namespace, and these 3 lines below 
                string thisprocessname = Process.GetCurrentProcess().ProcessName;
                if (Process.GetProcesses().Count(p => p.ProcessName == thisprocessname) > 1)
                    return;
    
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Sample());
            }
        }
    }
    

    您可以将MessageBox.Show添加到if -statement并将“应用程序已在运行”。
    这可能对某人有帮助。


    #23楼

    基于命名互斥的方法不是跨平台的,因为命名互斥在Mono中不是全局的。 基于流程枚举的方法没有任何同步,并且可能导致错误的行为(例如,同一时间启动的多个流程可能全部随时间自行终止)。 在控制台应用程序中,不希望基于窗口系统的方法。 该解决方案基于Divin的答案,解决了所有这些问题:

    using System;
    using System.IO;
    
    namespace TestCs
    {
        public class Program
        {
            // The app id must be unique. Generate a new guid for your application. 
            public static string AppId = "01234567-89ab-cdef-0123-456789abcdef";
    
            // The stream is stored globally to ensure that it won't be disposed before the application terminates.
            public static FileStream UniqueInstanceStream;
    
            public static int Main(string[] args)
            {
                EnsureUniqueInstance();
    
                // Your code here.
    
                return 0;
            }
    
            private static void EnsureUniqueInstance()
            {
                // Note: If you want the check to be per-user, use Environment.SpecialFolder.ApplicationData instead.
                string lockDir = Path.Combine(
                    Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
                    "UniqueInstanceApps");
                string lockPath = Path.Combine(lockDir, $"{AppId}.unique");
    
                Directory.CreateDirectory(lockDir);
    
                try
                {
                    // Create the file with exclusive write access. If this fails, then another process is executing.
                    UniqueInstanceStream = File.Open(lockPath, FileMode.Create, FileAccess.Write, FileShare.None);
    
                    // Although only the line above should be sufficient, when debugging with a vshost on Visual Studio
                    // (that acts as a proxy), the IO exception isn't passed to the application before a Write is executed.
                    UniqueInstanceStream.Write(new byte[] { 0 }, 0, 1);
                    UniqueInstanceStream.Flush();
                }
                catch
                {
                    throw new Exception("Another instance of the application is already running.");
                }
            }
        }
    }
    

    #24楼

    永远不要使用命名的互斥体来实现单实例应用程序(或者至少不用于生产代码)。 恶意代码可以轻易地您的资产进行DoS( 拒绝服务 )...


    #25楼

    我在这里找不到简短的解决方案 ,因此希望有人会喜欢这样:

    更新于2018-09-20

    (顺便说一句,将代码放在“ Program.cs”中

        using System.Diagnostics;
    
        static void Main()
        {
            Process ThisProcess = Process.GetCurrentProcess();
            Process[] AllProcesses = Process.GetProcessesByName(ThisProcess.ProcessName);
            if (AllProcesses.Length > 1)
            {
                //Don't put a MessageBox in here because the user could spam this MessageBox.
                return;
            }
    

    //可选代码。 如果您不希望有人运行,请使用其他名称的“ .exe”:

            string exeName = AppDomain.CurrentDomain.FriendlyName;
            if (exeName != "the name of you're executable.exe") // If you try that in debug mode, don't forget that u don't use ur normal .exe. Debug uses the .vshost.exe.
            {// You can add here a MessageBox if you want. To point users that the name got changed and maybe what the name should be or something like that^^ 
                MessageBox.Show("The executable name should be \"the name of you're executable.exe\"", 
                "Wrong executable name", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
    
            //Following Code is default code:
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
        }
    

    #26楼

    这是有关Mutex解决方案的非常好的文章 。 该文章描述的方法有两个方面的优势。

    首先,它不需要依赖于Microsoft.VisualBasic程序集。 如果我的项目已经依赖于该程序集,那么我可能会提倡使用另一个答案中所示的方法。 但实际上,我不使用Microsoft.VisualBasic程序集,而我不想在项目中添加不必要的依赖项。

    其次,本文介绍了当用户尝试启动另一个实例时如何将应用程序的现有实例置于前台。 这是这里描述的其他Mutex解决方案无法解决的一个很好的方面。


    更新

    截至2014年8月1日,我上面链接的文章仍处于活动状态,但该博客已有一段时间没有更新。 这使我担心,最终它可能会消失,并且随之而来的是所倡导的解决方案。 我在此转载本文的内容,以供后代参考。 这些单词仅属于Sanity Free Coding的博客所有者。

    今天,我想重构一些禁止我的应用程序运行其自身多个实例的代码。

    以前,我曾使用System.Diagnostics.Process在进程列表中搜索myapp.exe的实例。 虽然这样做有效,但会带来很多开销,我想要更清洁的东西。

    知道我可以为此使用互斥锁(但以前从未做过),因此着手缩减代码并简化生活。

    在我的应用程序主类中,我创建了一个名为Mutex的静态变量

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

    拥有一个已命名的互斥锁可以使我们在多个线程和进程之间进行堆栈同步,这正是我要寻找的魔术。

    Mutex.WaitOne有一个重载,它指定了我们等待的时间。 由于我们实际上并不想同步代码(更多的是检查当前是否在使用它),我们将重载与两个参数一起使用: Mutex.WaitOne(Timespan timeout,bool exitContext) 。 如果可以输入,则等待返回true,否则返回false。 在这种情况下,我们根本不想等待; 如果正在使用我们的互斥锁,请跳过它并继续前进,以便我们传入TimeSpan.Zero(等待0毫秒),并将exitContext设置为true,以便在尝试获取对其的锁定之前可以退出同步上下文。 使用此代码,我们将Application.Run代码包装在如下代码中:

    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");
            }
        }
    }
    

    因此,如果我们的应用程序正在运行,WaitOne将返回false,我们将收到一个消息框。

    我没有显示消息框,而是选择使用一个小的Win32来通知正在运行的实例有人忘记了它已经在运行(通过将自身置于所有其他窗口的顶部)。 为此,我使用PostMessage将自定义消息广播到每个窗口(该自定义消息已由运行的应用程序注册到RegisterWindowMessage中 ,这意味着只有我的应用程序知道它是什么),然后退出第二个实例。 正在运行的应用程序实例将接收该通知并对其进行处理。 为了做到这一点,我以主要形式覆盖了WndProc ,并收听了自定义通知。 当我收到该通知时,我将表单的TopMost属性设置为true,以将其置于顶部。

    我最终得到的是:

    • 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(正面部分)
    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;
        }
    }
    

    #27楼

    我找到了更简单的解决方案,类似于Dale Ragan的解决方案,但略有修改。 它实际上基于标准的Microsoft WindowsFormsApplicationBase类,可以满足您的所有需求。

    首先,创建SingleInstanceController类,该类可在所有其他使用Windows窗体的单实例应用程序中使用:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using Microsoft.VisualBasic.ApplicationServices;
    
    
    namespace SingleInstanceController_NET
    {
        public class SingleInstanceController
        : WindowsFormsApplicationBase
        {
            public delegate Form CreateMainForm();
            public delegate void StartNextInstanceDelegate(Form mainWindow);
            CreateMainForm formCreation;
            StartNextInstanceDelegate onStartNextInstance;
            public SingleInstanceController(CreateMainForm formCreation, StartNextInstanceDelegate onStartNextInstance)
            {
                // Set whether the application is single instance
                this.formCreation = formCreation;
                this.onStartNextInstance = onStartNextInstance;
                this.IsSingleInstance = true;
    
                this.StartupNextInstance += new StartupNextInstanceEventHandler(this_StartupNextInstance);                      
            }
    
            void this_StartupNextInstance(object sender, StartupNextInstanceEventArgs e)
            {
                if (onStartNextInstance != null)
                {
                    onStartNextInstance(this.MainForm); // This code will be executed when the user tries to start the running program again,
                                                        // for example, by clicking on the exe file.
                }                                       // This code can determine how to re-activate the existing main window of the running application.
            }
    
            protected override void OnCreateMainForm()
            {
                // Instantiate your main application form
                this.MainForm = formCreation();
            }
    
            public void Run()
            {
                string[] commandLine = new string[0];
                base.Run(commandLine);
            }
        }
    }
    

    然后可以在程序中使用它,如下所示:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows.Forms;
    using SingleInstanceController_NET;
    
    namespace SingleInstance
    {
        static class Program
        {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            static Form CreateForm()
            {
                return new Form1(); // Form1 is used for the main window.
            }
    
            static void OnStartNextInstance(Form mainWindow) // When the user tries to restart the application again,
                                                             // the main window is activated again.
            {
                mainWindow.WindowState = FormWindowState.Maximized;
            }
            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);            
                SingleInstanceController controller = new SingleInstanceController(CreateForm, OnStartNextInstance);
                controller.Run();         
            }
        }
    }
    

    程序和SingleInstanceController_NET解决方案都应引用Microsoft.VisualBasic。 如果您只想在用户尝试重新启动正在运行的程序时将正常运行的应用程序重新激活为正常窗口,则SingleInstanceController中的第二个参数可以为null。 在给定的示例中,窗口被最大化。


    #28楼

    我在解决方案中使用Mutex来防止多个实例。

    static Mutex mutex = null;
    //A string that is the name of the mutex
    string mutexName = @"Global\test";
    //Prevent Multiple Instances of Application
    bool onlyInstance = false;
    mutex = new Mutex(true, mutexName, out onlyInstance);
    
    if (!onlyInstance)
    {
      MessageBox.Show("You are already running this application in your system.", "Already Running..", MessageBoxButton.OK);
      Application.Current.Shutdown();
    }
    

    #29楼

    这是一个允许您拥有一个应用程序实例的示例。 加载任何新实例时,它们会将其参数传递给正在运行的主实例。

    public partial class App : Application
    {
        private static Mutex SingleMutex;
        public static uint MessageId;
    
        private void Application_Startup(object sender, StartupEventArgs e)
        {
            IntPtr Result;
            IntPtr SendOk;
            Win32.COPYDATASTRUCT CopyData;
            string[] Args;
            IntPtr CopyDataMem;
            bool AllowMultipleInstances = false;
    
            Args = Environment.GetCommandLineArgs();
    
            // TODO: Replace {00000000-0000-0000-0000-000000000000} with your application's GUID
            MessageId   = Win32.RegisterWindowMessage("{00000000-0000-0000-0000-000000000000}");
            SingleMutex = new Mutex(false, "AppName");
    
            if ((AllowMultipleInstances) || (!AllowMultipleInstances && SingleMutex.WaitOne(1, true)))
            {
                new Main();
            }
            else if (Args.Length > 1)
            {
                foreach (Process Proc in Process.GetProcesses())
                {
                    SendOk = Win32.SendMessageTimeout(Proc.MainWindowHandle, MessageId, IntPtr.Zero, IntPtr.Zero,
                        Win32.SendMessageTimeoutFlags.SMTO_BLOCK | Win32.SendMessageTimeoutFlags.SMTO_ABORTIFHUNG,
                        2000, out Result);
    
                    if (SendOk == IntPtr.Zero)
                        continue;
                    if ((uint)Result != MessageId)
                        continue;
    
                    CopyDataMem = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Win32.COPYDATASTRUCT)));
    
                    CopyData.dwData = IntPtr.Zero;
                    CopyData.cbData = Args[1].Length*2;
                    CopyData.lpData = Marshal.StringToHGlobalUni(Args[1]);
    
                    Marshal.StructureToPtr(CopyData, CopyDataMem, false);
    
                    Win32.SendMessageTimeout(Proc.MainWindowHandle, Win32.WM_COPYDATA, IntPtr.Zero, CopyDataMem,
                        Win32.SendMessageTimeoutFlags.SMTO_BLOCK | Win32.SendMessageTimeoutFlags.SMTO_ABORTIFHUNG,
                        5000, out Result);
    
                    Marshal.FreeHGlobal(CopyData.lpData);
                    Marshal.FreeHGlobal(CopyDataMem);
                }
    
                Shutdown(0);
            }
        }
    }
    
    public partial class Main : Window
    {
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            HwndSource Source;
    
            Source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
            Source.AddHook(new HwndSourceHook(Window_Proc));
        }
    
        private IntPtr Window_Proc(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam, ref bool Handled)
        {
            Win32.COPYDATASTRUCT CopyData;
            string Path;
    
            if (Msg == Win32.WM_COPYDATA)
            {
                CopyData = (Win32.COPYDATASTRUCT)Marshal.PtrToStructure(lParam, typeof(Win32.COPYDATASTRUCT));
                Path = Marshal.PtrToStringUni(CopyData.lpData, CopyData.cbData / 2);
    
                if (WindowState == WindowState.Minimized)
                {
                    // Restore window from tray
                }
    
                // Do whatever we want with information
    
                Activate();
                Focus();
            }
    
            if (Msg == App.MessageId)
            {
                Handled = true;
                return new IntPtr(App.MessageId);
            }
    
            return IntPtr.Zero;
        }
    }
    
    public class Win32
    {
        public const uint WM_COPYDATA = 0x004A;
    
        public struct COPYDATASTRUCT
        {
            public IntPtr dwData;
            public int    cbData;
            public IntPtr lpData;
        }
    
        [Flags]
        public enum SendMessageTimeoutFlags : uint
        {
            SMTO_NORMAL             = 0x0000,
            SMTO_BLOCK              = 0x0001,
            SMTO_ABORTIFHUNG        = 0x0002,
            SMTO_NOTIMEOUTIFNOTHUNG = 0x0008
        }
    
        [DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
        public static extern uint RegisterWindowMessage(string lpString);
        [DllImport("user32.dll")]
        public static extern IntPtr SendMessageTimeout(
            IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam,
            SendMessageTimeoutFlags fuFlags, uint uTimeout, out IntPtr lpdwResult);
    }
    

    #30楼

    看起来有一个非常好的方法可以解决此问题:

    WPF单实例应用程序

    这提供了一个您可以添加的类,该类可以管理所有互斥量和消息传递异常,从而将实现简化到简单的程度。


    #31楼

    此代码应转到main方法。 在此处查看有关WPF中主要方法的更多信息。

    [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; 
        }
    }
    

    方法二

    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(...);
        }
    }
    

    注意:以上方法假定您的进程/应用程序具有唯一的名称。 因为它使用进程名称来查找是否存在任何现有处理器。 因此,如果您的应用程序有一个非常通用的名称(即:记事本),则上述方法将行不通。

    展开全文
  • WPF应用程序的“最近文件”菜单。 自动显示文件图标。 可为每种语言定制。 有自己的(异步)持久性机制。 同步同一程序的多个线程和多个实例之间的访问。 实现一个接口,以支持依赖关系反转和单元测试(可模拟...
  • WPF只运行一个应用程序实例的方法 运行前检测是否已运行,如果已运行则激活已启动的程序 修改App.xaml.cs using System.Diagnostics; using System.Reflection; using System.Runtime.InteropServices; using System...
  • 1,新建一个wpf项目,找到App.xmal.cs打开后插入如下代码: namespace ElectronicNeedleTherapySystem { /// &amp;lt;summary&amp;gt; /// App.xaml 的交互逻辑 /// &amp;lt;/summary&amp;gt...
  • 使用一个已命名的(操作系统范围的)互斥量。...因为是操作系统范围的,所以需要确定参数uniqueName指定的名字不会被其他应用程序使用。   http://blog.csdn.net/cs_oldhorse/article/details/6803569
  • 静默更新的单实例WPF ClickOnce应用程序
  • 实例应用程序即该应用程序只允许运行一个实例,说白了就是不能同时运行两个相同的程序。 主体框架为3个自定义类: Startup、 SimpleInstanceAppWrapper、 App // Startup.cs using System; using System.Windows;...
  • 如何将Word、Excel、PowerPoint嵌入WPF应用程序?大部分人应该都记得可以将Excel图表嵌入到Word文档中的OLE技术,但该技术并不支持所有的Microsoft Office文档。它不支持表单中的多个MS Word实例。而Edraw office ...
  • 1.自定义SingletonWindow类(此方法也适合于传统winform程序) using System;using System.Linq; namespace NetWorld{ public class SingletonWindow { public static System.Diagnostics.Process Process() //...
  • 在实际应用中,因为涉及到数据访问、消息连接等问题,经常需要实现应用程序的单例运行。 这里采用System.Threading.Mutex来实现应用程序的单例。参考:WPF 只允许运行一个程序(单例)。 在App.xaml.cs中重写启动...
  • WPF连接数据库实例源码

    热门讨论 2009-03-25 17:15:23
    WPF连接数据库实例源码,开发WPF应用程序实例
  • 为 windows presentation foundation (WPF) 应用程序提供一个启动屏幕。 url:http://msdn.microsoft.com/zh-cn/library/system.windows.splashscreen.aspx 实例 public partial ...
  • 所谓单实例应用程序就是只能开启一个进程的应用程序,通常未做处理的WPF程序可以多次点击exe程序,每次点击,系统都会分配一个... 1、创建一个简单的WPF应用程序,没做任何处理。如下图所示:  2、不采用调试...
  • WPF-单实例程序

    2018-06-08 11:08:42
    二、添加新类,单实例应用程序包装器SingleInstanceApplicationWrapper类,这里我将App.xaml的启动方式删除,使用自己创建的启动代码,下面附上。 using System; using System.Collections.Generic; using System....
  • 实例应用程序指的是有些应用...本节主要介绍如何利用WPF创建单实例应用程序。 首先我们新建一个WPF程序,将原来的App删除,新建一个WPFapp类,对启动响应函数进行重写。 class WPFapp : Application { protect
  • 基于 Microsoft.VisualBasic.dll
  • 最近有同事问道在应用程序启动之后,再次双击应用程序,如何保证不再启动新的应用程序,而是弹出之前已经启动的进程,本质上这就是创建一个单实例WPF应用程序。在VS的工程树中有一个App.xaml和App.xaml.cs(这两个...
  • WPF只开启一个应用程序运行实例

    千次阅读 2018-04-16 10:25:45
    #region Using Directives using System; using System.Globalization; using System.Reflection; using System.Threading; using System.Windows;...using System.Windows.Interop;...namespace MyWPF { ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 480
精华内容 192
关键字:

wpf应用程序实例