一、前言
自定义协议是什么?这么突然问起来可能不太会有人想起来,但如果给你看以下几个地址,你们应该会马上反应过来:
- tencent://xxxxxxxxxx……
- thunder://xxxxxxxxxx……
- qqdl://xxxxxxxxxx……
- aliim://xxxxxxxxxx……
是的,上面四个地址分别就是QQ、迅雷、QQ旋风、阿里旺旺的自定义协议。
如果我们在网页上单击这些自定义协议的超链接后,对应的客户端就会被唤起,非常的方便。
那我们能不能为自己的.net Framework程序设计并注册一个自定义协议呢?答案当然是可以。
二、操作
关于注册自定义协议,微软的MSDN上专门有一篇文章讲述如何操作:《Registering an Application to a URI Scheme》,这篇文章告诉我们,如果需要注册自定义协议,可以通过在注册表指定位置添加键值,MSDN文章中以注册“Alert://”协议为例(下面步骤中项名和值名均不含中文引号):
1.在注册表 HKEY_CLASSES_ROOT 基项中新建项,项名为协议名(“Alert://”协议的协议名就是“Alert”);
2.设置协议项的默认值为“URL:协议名 Protocol”;
3.在协议项下新建字符串值,值名称要求为“URL Protocol”;值为空
4.(可选)在协议项下新建新子项,名称为“DefaultIcon”,其子项默认值为“响应程序路径,1”
5.在协议项下新建子项,子项名为“shell”
6.在“shell”项下新建子项,子项名为“open”
7.在“open”项下新建子项,子项名为“command”
8.修改“command”项默认值为“"响应程序路径" "%1"”
大功告成。可能看的比较烦或者看不懂,具体可以参考下图:
三、代码
总感觉以后应该可能会用,所以直接就做成了一个Helper辅助类,代码如下:
(注意:这里需要操作注册表,Windows Vista平台及以上请注意申请UAC权限)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
using Microsoft.Win32; using System; namespace Yume.Common { /// <summary> /// 协议辅助类 /// <para>在Windows Vista及以上平台调用时,请注意先申请UAC管理员权限。</para> /// </summary> public static class ProtocolHelper { #region 判断指定协议名是否有效 + public static bool IsProtocol(string protocolName) /// <summary> /// 判断指定协议名是否有效 /// </summary> /// <param name="protocolName">协议名称</param> /// <returns>判断结果</returns> public static bool IsProtocol(string protocolName) { bool result = false; RegistryKey protocolKey = Registry.ClassesRoot.OpenSubKey(protocolName); if (protocolKey != null) { if (protocolKey.GetValue("URL Protocol") != null) result = true; protocolKey.Dispose(); } return result; } #endregion #region 判断指定协议名是否存在 + public static bool ProtocolNameExists(string protocolName) /// <summary> /// 判断指定协议名是否存在 /// </summary> /// <param name="protocolName">协议名称</param> /// <returns>判断结果</returns> public static bool ProtocolNameExists(string protocolName) { bool result = false; RegistryKey protocolKey = Registry.ClassesRoot.OpenSubKey(protocolName); if (protocolKey != null) { result = true; protocolKey.Dispose(); } return result; } #endregion #region 向当前系统申请注册协议 + public static void Register(string protocolName, string applicationPath) /// <summary> /// 向当前系统申请注册协议 /// <para>类似于“协议名://”;仅限于Windows平台。</para> /// </summary> /// <param name="protocolName">协议名</param> /// <param name="applicationPath">可执行程序路径</param> public static void Register(string protocolName, string applicationPath) { if (ProtocolNameExists(protocolName)) throw new InvalidOperationException("此协议名已被占用。"); RegistryKey protocolKey = Registry.ClassesRoot.CreateSubKey(protocolName); protocolKey.SetValue(string.Empty, string.Format("URL:{0} Protocol", protocolName)); protocolKey.SetValue("URL Protocol", applicationPath); RegistryKey defaultIconKey = protocolKey.CreateSubKey("DefaultIcon"); defaultIconKey.SetValue(string.Empty, string.Format("{0},1", applicationPath)); defaultIconKey.Dispose(); RegistryKey shellKey = protocolKey.CreateSubKey("shell"); RegistryKey openKey = shellKey.CreateSubKey("open"); RegistryKey commandKey = openKey.CreateSubKey("command"); commandKey.SetValue(string.Empty, string.Format("\"{0}\" \"%1\"", applicationPath)); commandKey.Dispose(); openKey.Dispose(); shellKey.Dispose(); protocolKey.Dispose(); } #endregion #region 取消协议注册 + public static void UnRegister(string protocolName) /// <summary> /// 取消协议注册 /// <para>注意:此方法将直接删除HKEY_CLASSES_ROOT根下对应子键。</para> /// </summary> /// <param name="protocolName">协议名</param> public static void UnRegister(string protocolName) { if (!ProtocolNameExists(protocolName)) return; else if (!IsProtocol(protocolName)) throw new InvalidOperationException("协议名无效。"); //删除协议键 Registry.ClassesRoot.DeleteSubKeyTree(protocolName); } #endregion } } |
四、实践
在用户通过鼠标单击超链接或其他操作从而触发了自定义协议后,Windows会自动唤醒响应程序,并将用户单击的协议链接作为启动参数。
启动参数大家都懂,可以在修改Main函数为:
1 2 3 4 |
static void Main(string[] args) { } |
此时args数组即为程序启动时被赋予的启动参数。
除此以外也可以用
1 |
System.Environment.CommandLine |
这个属性和
1 |
System.Environment.GetCommandLineArgs() |
这个办法获得。
我这里做了一个简单的示范程序,首先我们注册一个“Chunfeng”协议(程序默认将自己作为响应程序):
之后我们随便去一个浏览器试试我们的Chunfeng协议有没有生效(一般浏览器为了安全,都会进行二次确认):
完美(前面的“1.”是我自己添加的):
示范程序源码下载:
链接:http://pan.baidu.com/s/1o7Cdj9g 密码:uzmw
五、写在最后
最后的最后,还是要提醒这么一点。在微软MSDN文章里有这么一段:
Security Warning: Applications that handle URI schemes must consider how to respond to malicious data. Because handler applications can receive data from untrusted sources, the URI and other parameter values passed to the application may contain malicious data that attempts to exploit the handling application.
响应程序必须考虑如何处理恶意数据,因为应用程序可以可以从不信任的源接受数据。
小柊
2017年2月13日 22:50:59
4 条评论发布于 “C# WinForm注册自定义协议”