啊哈哈,我又出来诈尸啦! 也是又重新用起了 Typecho ,因为自己写博客程序的话完全没时间啊魂淡! 但是网站的其他部分呢,还是会用不同的语言/技术实现。

所谓的自定义 scheme ,就是自定义 URI 协议。举个例子来说,在 Steam 上购买游戏之后,就可以看到具有这样 URI 格式的链接,点击就可以启动 Steam 客户端安装游戏。

Steam scheme

这样做的好处显而易见:如果有些事情在浏览器里无法完成,那么用客户端软件进行辅助是非常有必要的,而自定义 scheme 可能是打通浏览器和客户端软件最便捷的一条通道。Windows 、 OSX 和 Linux 都支持这种方式调用客户端软件,但是使用的方法不一样。现在只探讨 Windows 下的实现,其他平台我用到的话会更新文章的。

根据 MSDN 上的说明: Registering an Application to a URI Scheme ,为一个应用程序注册一种 URI scheme ,需要在注册表的 HKCR 键下( HKEY_CLASSES_ROOT )写入一系列值和子键。总体来说是下面这样的结构。

HKEY_CLASSES_ROOT
   alert
      (Default) = "URL:scheme_name Protocol"
      URL Protocol = ""
      DefaultIcon
         (Default) = "icon_path"
      shell
         open
            command
               (Default) = "Drive:\path\to\you\program.exe" "%1"

首先来看一下 Steam 的实现,马上就可以理解。

Steam URI Scheme Registry 1 Steam URI Scheme Registry 2 Steam URI Scheme Registry 3 Steam URI Scheme Registry 4 Steam URI Scheme Registry 5

这样应该很容易看懂了。

如果你使用 InnoSetup 打包程序的话,实现注册自定义的 URI scheme 很简单,只需要四行代码(放在安装包编译配置文件的 [Registry] section 里)。

Root: HKCR; Subkey: "app_name"; ValueType: string; ValueName: ""; ValueData: "URL:scheme_name protocol"; Flags:noerror deletevalue uninsdeletevalue;
Root: HKCR; Subkey: "app_name"; ValueType: string; ValueName: "URL Protocol"; ValueData: ""; Flags:noerror deletevalue uninsdeletevalue;
Root: HKCR; Subkey: "app_name\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName}"; Flags:noerror deletevalue uninsdeletevalue;
Root: HKCR; Subkey: "app_name\Shell\Open\Command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags:noerror deletevalue uninsdeletevalue;

然后在你的程序入口(接受参数的地方,对于 Python 打包的程序来说是入口文件的启动语句处使用 sys.argv 获取参数),加入对参数的解析。

Windows 下是这样的:假设要注册一个名字叫 test 的 URI scheme ,那么浏览器访问 test: 就会启动你的程序,跟在 test: 之后的字符串都会作为参数传递给你的程序;例如 test://start 相当于终端运行 "path_to_your_app.exe" "//start" 。只要解析好入口处的参数,就可以实现对应的功能了。

2014 年 11 月 21 日修正

Windows 平台下:浏览器访问 test: 就会启动你的程序,包括 scheme 在内的所有字符串将被当作参数传递给你的程序。例如 test://start 相当于终端运行 "path_to_your_app.exe" "test://start" 。在程序入口处解析好参数就可以实现对应的功能。