最近在基于node-webkit(以下简称NW)开发windows桌面app,里面有个类似于软件市场的功能,后台管理员提供一些软件,可以从该app上进行下载、安装、卸载、升级等等。

安装或升级可以直接通过把下载好的zip包解压出来然后执行里面的exe程序安装就好,但是卸载相对来说比较麻烦,几乎每个第三方exe在安装后的目录里面都有一个uninstall.exe,但是我们不知道这个软件具体安装在哪,所以要卸载也无从下手,这时候就想到了注册表,通过注册表可以获取到某个软件的安装目录,所以可以先把当前注册表的目录取得,再去相应目录下找卸载该软件的那个exe并执行。

由于NW是基于nodejs的,所以可以通过一些第三方的npm包来操作,在这里主要主要用到的包是winreg,首先我们先分析下注册表:

注册表分析

可以看到根下面有5个大项(HKEY_CLASSES_ROOT、HKEY_CURRENT_USER、HKEY_LOCAL_MACHINE、HKEY_USERS、HKEY_CURRENT_CONFIG),第三方软件基本上都是在HKEY_LOCAL_MACHINE下面的,所以读取的时候就从HKEY_LOCAL_MACHINE下面开始找,这里以搜狗输入法为例:

搜狗输入法分析

从上图中看到该项的全路径为”HKEY_LOCAL_MACHINE\SOFTWARE\SogouInput”,注册项里的第一项就是安装路径,对应的名称是默认,所以我们读取的时候从就可以读取刚才的那个路径,下面是主要的实现:

const Registry = require("winreg"),
    child_process = require("child_process"),
    path = require("path"),
    key = new Registry({
        //  打开HKEY_LOCAL_MACHINE这个大类
        //  一共有5个属性,分别是'HKLM', 'HKCU', 'HKCR', 'HKU', 'HKCC'
        //  就是上面那5大项的简称
        hive: Registry.HKLM,
        //  反斜杠前面需要加"\"进行转义
        key: "\\SOFTWARE\\SogouInput"
    });

let pre, end, cur, target;

//  获取到注册项中中所有配置项,以键值对的形式返回
//  每一小项分别包含(host、hive、key、name、type、value、arch)这几个属性
key.values((err, res) => {
    if (err) {
        console.log(err);
    } else {
        for(var i in res) {
            cur = res[i];
            //  判断当前项的名称是否包含default或者version
            if (/default/gi.test(cur.name)) {
                pre = cur.value;
            } else if (/^version$/gi.test(cur.name)) {
                end = cur.value;
            }
        }

        //  拼接软件的安装全路径
        target = `${pre}\\${end}`;

        //  结合nodejs中子进程模块中的execFile方法执行卸载的exe
        child_process.execFile(path.join(target, "Uninstall.exe"), (err, res) => {
            if (err) {
                console.log("卸载失败,请重试!");
            }
        });
    }
});

最后执行写好的js文件,就会顺利打开相关卸载窗口:

卸载窗口

当然这只是一个简单的实现,是分析好了软件安装目录下的卸载文件在什么地方去调用它的,肯定不能应用于所有场景,应该遍历该软件安装的根目录和子目录搜索卸载程序所在的最终目录来执行并进行卸载。

记在2017-03-30

今天尝试用昨天的写法来实现软件卸载,发现实现起来并不是那么简单,而且遍历文件的话面临一个性能问题,层级一多,递归循环就可能导致需要等好久才能开始卸载,所以又深入研究了下注册表,真是得来全不费工夫,注册表里面就给我们提供了某个软件的卸载路径,具体位置在

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\

这边都是我们安装的所有软件,需要注意的是在64位系统中该路径有所不同,大问题解决了,我们又面临一个其他问题,就是有些软件在安装后,卸载那一级的最后一层并不是它自己的名字,而是一串花括号开始花括号结尾的字符串,类似于下图所示:

卸载id

于是又在好几种不同版本的windows电脑上进行尝试,发现这个id始终是唯一的,最后和需求商量决定后台管理员在提供软件的时候把这个id也带上,这样就解决了问题,这样唯一的不好就是后台管理员的工作可能会稍微繁琐点。