处理URL协议而不重启应用程序

时间:2012-01-31 13:01:01

标签: c# url protocols

我的问题是关于网址协议。

我已经注册了一个名为 mcm 的URL协议,但我注意到每次从任何Web浏览器运行它时,都会创建一个新的应用程序实例。有没有办法在已经运行的实例中处理协议请求?

例如,当uTorrent使用 torrent 协议时,它会立即处理请求,而无需再次运行应用程序。我真的找不到任何有趣的东西,所以我在这里问......

以下是我用来注册协议的代码:

private static void RegisterUrlProtocol()
{
    UnregisterUrlProtocol();

    RegistryKey rKey = Registry.ClassesRoot.OpenSubKey(UrlProtocol, true);
    if (rKey == null)
    {
        rKey = Registry.ClassesRoot.CreateSubKey(UrlProtocol);
        rKey.SetValue("", "URL: MazCraft Protocol");
        rKey.SetValue("URL Protocol", "");

        rKey = rKey.CreateSubKey(@"shell\open\command");
        rKey.SetValue("", "\"" + Application.ExecutablePath + "\" %1");
    }

    if (rKey != null)
    {
        rKey.Close();
    }
}

读取参数的代码:

private static bool CheckForProtocolMessage()
{
    string[] arguments = Environment.GetCommandLineArgs();

    if (arguments.Length > 1)
    {
        string[] args = arguments[1].Split(':');
        args[1] = args[1].Replace("//", "");

        if (args[0].Trim().ToUpper() == "MCM" && args.Length > 1)
        {
            string[] actionDetail = args[1].Split('=');

            if (actionDetail[0].Trim().ToUpper() == "INSTALL" && actionDetail.Length > 1)
            {
                string id = actionDetail[1].Trim().Replace("/", "");

                Funcs.ID = id;

                return true;
            }
        }
    }

    return false;
}

任何帮助将不胜感激:) 问候。

1 个答案:

答案 0 :(得分:6)

您可以使用Mutex检测已在运行的应用程序的实例,并通过命名管道将数据发送到现有实例。

希望以下示例有所帮助。 你可以换掉你喜欢的任何可序列化对象的命名管道对象(在本例中为字符串)。

NamedPipe.cs

    namespace SingleInstanceNP
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO.Pipes;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.Threading;
    using System.IO;


    public class NamedPipe<T> : IDisposable
    {
        #region Attribute and Properties

        private string _pipeName;
        private NamedPipeServerStream _pipeServer;
        private bool _disposed;
        private Thread _thread;
        private bool _started;

        #endregion

        #region Constructors

        public NamedPipe(NameTypes pipeType)
        {
            _disposed = false;
            _started = false;
            _pipeName = pipeType.ToString();
            _thread = new Thread(Main);
            _thread.SetApartmentState(ApartmentState.STA);
            _thread.Name = "NamePipe: " + pipeType.ToString() + " Thread";
            _thread.IsBackground = true;
        }

        ~NamedPipe()
        {
            Dispose();
        }

        #endregion

        #region Events

        public delegate void Request(T t);
        public event Request OnRequest;

        #endregion

        #region Public Methods

        public static void Send(NameTypes pipeType, T t)
        {
            using (var npc = new NamedPipeClientStream(".", pipeType.ToString(), PipeDirection.Out))
            {
                var bf = new BinaryFormatter();
                npc.Connect();
                bf.Serialize(npc, t);
            }
        }

        public static T Recieve(NameTypes pipeType)
        {
            using (var nps = new NamedPipeServerStream(pipeType.ToString(), PipeDirection.In))
            {
                return Recieve(nps);
            }
        }

        public void Start()
        {
            if (!_disposed && !_started)
            {
                _started = true;
                _thread.Start();
            }
        }

        public void Stop()
        {
            _started = false;

            if (_pipeServer != null)
            {
                _pipeServer.Close();
                // disposing will occur on thread
            }
        }

        public void Dispose()
        {
            _disposed = true;
            Stop();

            if (OnRequest != null)
                OnRequest = null;
        }

        #endregion

        private void Main()
        {
            while (_started && !_disposed)
            {
                try
                {
                    using (_pipeServer = new NamedPipeServerStream(_pipeName))
                    {
                        T t = Recieve(_pipeServer);

                        if (OnRequest != null && _started)
                            OnRequest(t);
                    }
                }
                catch (ThreadAbortException)
                { }
                catch (System.IO.IOException iox)
                {
                    Console.WriteLine("ERROR: {0}", iox.Message);
                    Thread.Sleep(TimeSpan.FromSeconds(30));
                }
                catch (Exception ex)
                {
                    Console.WriteLine("ERROR: {0}", ex.Message);
                    return;
                }
            }
        }

        private static T Recieve(NamedPipeServerStream nps)
        {
            var bf = new BinaryFormatter();

            try
            {
                nps.WaitForConnection();

                var obj = bf.Deserialize(nps);

                if (obj is T)
                    return (T)obj;
            }
            // Catch the IOException that is raised if the pipe is
            // broken or disconnected.
            catch (IOException e)
            {
                Console.WriteLine("ERROR: {0}", e.Message);
            }
            return default(T);
        }

        #region Enums

        public enum NameTypes
        {
            PipeType1
        }

        #endregion
    }
}

的Program.cs 请将APP GUID归功于What is a good pattern for using a Global Mutex in C#?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Threading;

namespace SingleInstanceNP
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            // get application GUID as defined in AssemblyInfo.cs
            string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value.ToString();

            // unique id for global mutex - Global prefix means it is global to the machine
            string mutexId = string.Format("Global\\{{{0}}}", appGuid);

            using (var mutex = new Mutex(false, mutexId))
            {
                try
                {
                    if (!mutex.WaitOne(0, false))
                    {
                        //signal existing app via named pipes

                        NamedPipe<string>.Send(NamedPipe<string>.NameTypes.PipeType1, "test");

                        Environment.Exit(0);
                    }
                    else
                    {
                        // handle protocol with this instance   
                        Application.Run(new Form1());

                    }
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
            }
        }
    }
}

Form1.cs的

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace SingleInstanceNP
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            // start listening for named pipe connections
            var namedPipeString = new NamedPipe<string>(NamedPipe<string>.NameTypes.PipeType1);
            namedPipeString.OnRequest += new NamedPipe<string>.Request(namedPipeString_OnRequest);
            namedPipeString.Start();
        }

        void namedPipeString_OnRequest(string t)
        {
            MessageBox.Show(t);
        }
    }
}