What is the correct way to create a single-instance WPF application?

前端 未结 30 3089
耶瑟儿~
耶瑟儿~ 2020-11-21 05:14

Using C# and WPF under .NET (rather than Windows Forms or console), what is the correct way to create an application that can only be run as a single instance?

I kno

30条回答
  •  伪装坚强ぢ
    2020-11-21 05:54

    The following code is my WCF named pipes solution to register a single-instance application. It's nice because it also raises an event when another instance attempts to start, and receives the command line of the other instance.

    It's geared toward WPF because it uses the System.Windows.StartupEventHandler class, but this could be easily modified.

    This code requires a reference to PresentationFramework, and System.ServiceModel.

    Usage:

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

    Source Code:

    /// 
    /// A class to use for single-instance applications.
    /// 
    public static class SingleInstanceManager
    {
      /// 
      /// Raised when another instance attempts to start up.
      /// 
      public static event StartupEventHandler OtherInstanceStarted;
    
      /// 
      /// 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.
      /// 
      /// The application's unique identifier.
      /// True if this instance is the main instance.
      public static bool VerifySingleInstace(Guid guid)
      {
        if (!AttemptPublishService(guid))
        {
          NotifyMainInstance(guid);
    
          return false;
        }
    
        return true;
      }
    
      /// 
      /// Attempts to publish the service.
      /// 
      /// The application's unique identifier.
      /// True if the service was published successfully.
      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;
        }
      }
    
      /// 
      /// Notifies the main instance that this instance is attempting to start up.
      /// 
      /// The application's unique identifier.
      private static void NotifyMainInstance(Guid guid)
      {
        NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
        EndpointAddress remoteAddress = new EndpointAddress(CreateAddress(guid));
        using (ChannelFactory factory = new ChannelFactory(binding, remoteAddress))
        {
          ISingleInstance singleInstance = factory.CreateChannel();
          singleInstance.NotifyMainInstance(Environment.GetCommandLineArgs());
        }
      }
    
      /// 
      /// Creates an address to publish/contact the service at based on a globally unique identifier.
      /// 
      /// The identifier for the application.
      /// The address to publish/contact the service.
      private static string CreateAddress(Guid guid)
      {
        return string.Format(CultureInfo.CurrentCulture, "net.pipe://localhost/{0}", guid);
      }
    
      /// 
      /// The interface that describes the single instance service.
      /// 
      [ServiceContract]
      private interface ISingleInstance
      {
        /// 
        /// Notifies the main instance that another instance of the application attempted to start.
        /// 
        /// The other instance's command-line arguments.
        [OperationContract]
        void NotifyMainInstance(string[] args);
      }
    
      /// 
      /// The implementation of the single instance service interface.
      /// 
      private class SingleInstance : ISingleInstance
      {
        /// 
        /// Notifies the main instance that another instance of the application attempted to start.
        /// 
        /// The other instance's command-line arguments.
        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);
          }
        }
      }
    }
    

提交回复
热议问题