平时使用 msiexec.exe 习惯了,所以最直接的想法就是在一个子进程中执行:
这样固然是能够完成任务,但是不是太简陋了? 安装开始后我们想取消这次安装怎么办? 或者我们还想要拿到一些安装进度的信息。
其实可以通过调用三个 windows API 轻松搞定这个事儿!下面的 C# demo 用一个自定义 Form 来指示多个 MSI 文件的安装过程。Form 上放的是一个滚动条,并且配合一个不断更新的 label。先看看 demo 长什么样子。
下面是安装过程中的 UI:
点击 Cancel 按钮取消安装后的 UI:
我们先来了解一下主要用到的几个 win32 API。
首先是 MsiSetInternalUI 方法:
在调用 msiexec.exe 时,我们通过指定 /q 参数让安装过程显示不同的 UI。如果不显示UI的话就要使用参数 /qn 。MsiSetInternalUI 方法就是干这个事儿的。通过下面的调用就可以去掉 msi 中自带的 UI:
接下来是 MsiSetExternalUI 方法:
MsiSetExternalUI 函数允许指定一个用户定义的外部 UI handler 用来处理安装过程中产生的消息。这个外部的 UI handler 会在内部的 UI handler 被调用前调用。 如果在外部的 UI handler 中返回非 0 的值,就说明这个消息已经被处理。
这个外部的 UI handler 就是 MsiSetExternalUI 方法的第一个参数,我们通过实现这个 handler 来处理自己感兴趣的消息, 比如当安装进度变化后去更新进度条。或者通过它传递我们的消息给 msi,比如说告诉 msi,停止安装,执行 cancel 操作。使用这个方法需要注意的是,当你完成安装后一定要把原来的 handler 设回去。否则以后执行 msi 安装包可能会出问题。
MSDN 上有一个 MsiInstallUIHandler 的 demo,感兴趣的同学可以去看看。
下面是 MsiInstallProduct 方法:
正如其名,这个是真正干活儿的方法。
实在忍不住要介绍第四个方法,虽然它对实现当前的功能来说是可选的,但对一个产品来说,它却是用来救命的。
这个方法会把安装 log 保存到你传递给它的文件路径。有了它生活就会 happy 很多,很多… 否则当用户告诉你安装失败时,你一定会抓狂的。
好了,下面是 MyInstaller demo 的主要代码:
简单说明一下,用户定义的 UI 运行在主线程中,使用 BackgroundWorker 执行安装任务。在安装进行的过程中可以把 cancel 信息传递给 MsiProgressHandler,当MsiProgressHandler 检测到 cancel 信息后通过返回值告诉 msi 的执行引擎,执行 cancel 操作(msi的安装过程是相当严谨的,可不能简单的杀掉安装进程了事!)。
这样,一个支持 cancel 的自定义 UI 的安装控制程序就 OK了(demo哈)。如果要安装多个 msi 只需在 Install 方法中循环就可以了。
本文转自xmgdc51CTO博客,原文链接:http://blog.51cto.com/12953214/1942277 ,如需转载请自行联系原作者