在WIX中,CustomAction用来在安装过程中执行自定义行为。比如注册、修改文件、触发其他可执行文件等。这一节主要是介绍一下CustomAction的7种用法。 在此之前要了解InstallExecuteSequence,它是一个Action的执行序列。 Installer会按照默认顺序来执行这些Action。通过字面意思也大概知道这些Action的目的。这些方法不是每次一都执行,分安装和卸载。如果CustomAction没有指定,很可能会安装卸载的时候都会执行一次。

• AppSearch
• LaunchConditions
• ValidateProductId
• CostInitialize
• FileCost
• CostFinalize
• InstallValidate
• InstallInitialize
• ProcessComponents
• UnpublishFeatures
• RemoveRegistryValues
• RemoveShortcuts
• RemoveFiles
• InstallFiles
• CreateShortcuts
• WriteRegistryValues
• RegisterUser
• RegisterProduct
• PublishFeatures
• PublishProduct
• InstallFinalize

一、设置变量

Custom Action本身是分很多类型,这里是用到的是Type 51 Custom Action。用来设置变量的值。详情请看Custom Action Types

<CustomAction Id="rememberInstallDir"  Property="ARPINSTALLLOCATION"  Value="[INSTALLLOCATION]" />

这个例子用内置的ARPINSTALLLOCATION变量保存了安装路径,value是用方括号包括目录ID。同样的方式你可以设置你的自定义变量。然后加入执行序列。

<InstallExecuteSequence>
<Custom Action="rememberInstallDir" After="InstallValidate"/>
</InstallExecuteSequence>

我们可以获取这些变量,比如在卸载的时候通过C#程序获取变量的值,稍后会介绍。

ProductInstallation install =new ProductInstallation(session["ProductCode"]);
string installDir = install.InstallLocation;

还有第二种方法,Custom Action的简便方式:使用SetProperty 元素 ,例如在InstallInitialize 执行完成后我们将自定义的变量MyDir 的值设置成123.

<SetProperty Id="MyDir"  Value="123" After="InstallInitialize" Sequence="execute" />

记录日志:

session.Log("installDir:"+installDir);
session.Log("ARPINSTALLLOCATION:" + session["ARPINSTALLLOCATION"]);
session.Log("MyDir:" + session["MyDir"]);

奇怪Install.InstallLocation方式获取到的installDir为空(看来书上的有问题),但直接获取变量,我们发现ARPINSTALLLOCATIONMyDir确实被赋值了。

二、设置安装目录

类型35的自定义Action用来设置一个Directory元素的路径。示例:

<CustomAction Id="SetAppDataDir" Directory="DataDir" Value="[CommonAppDataFolder]MyProduct" />

那这个句子会将ID为DataDir的目录在XP系统下设置为“C:\Documents and Settings\All Users\Application Data”,WIN7下的 C:\ ProgramData  然后这个Action需要在InstallFiles之前执行。

同样这也有第二种方法设置Directory的值。

<SetDirectory Id="DataDir" Value="[CommonAppDataFolder]MyProduct"  Sequence="execute" />

加入序列:

<InstallExecuteSequence>
<Custom Action="SetAppDataDir" Before="InstallFiles" />
</InstallExecuteSequence>

记录日志:(Directory 本质也是Property)

session.Log("DataDir:" + session["DataDir"]);

结果正确。

三、运行嵌入的VBScript和JScript

类型37和类型38的Custom Action可以执行嵌入的脚本。通过Script属性来指定是vbscript还是jscript. 下面的示例是弹出两个提示框。

   <CustomAction Id="testVBScript" Script="vbscript" Execute="immediate" >
<![CDATA[
msgbox "this is embedded code..."
msgbox "myProperty: " & Session.Property("myProperty")
]]>
</CustomAction>

注意到可以通过Session.Property的方式获取到已经存在的变量。 这个session对象控制着安装进程,它打开了包含安装表格和数据的的数据库。从而可以通过这个上下文对象可以获取和修改安装的变量和参数。更多信息可以参考Session Object

加入序列

<InstallUISequence>
<Custom Action="testVBScript" After="LaunchConditions" />
</InstallUISequence>
<Property Id="myProperty" Value="2" />

执行结果:

  

下面是一些有用的示例:

<CustomAction Id="testVBScript" Script="vbscript"
Execute="immediate" >
<![CDATA[
' 写入一条安装日志
Dim rec
Set rec = Session.Installer.CreateRecord(0)
rec.StringData(0) = "My log message"
Session.Message &H04000000, rec
'改变安装level
Session.SetInstallLevel(1000)
' 获取Product元素的属性。
Dim productName
productName = Session.ProductProperty("ProductName")
' 改变Directory元素的路径
Dim installFolder
installFolder = Session.TargetPath("INSTALLFOLDER")
]]>
</CustomAction>

四、调用外部的脚本文件(VBScript / JScript)

类型5(JScript)和类型6(VBScript)的自定义Action可以调用外部脚本文件的函数。我们定义一个myScript.vbs的文件,它包含一个myFunction的函数:

Function myFunction()
If Session.Property("myProperty") = "" Then
msgbox "Property is 1. Returning success!"
myFunction =
Exit Function
End If
msgbox "Property not 1. Returning failure."
myFunction =
Exit Function
End Function

返回1意味着调用成功,返回3意味着调用失败,而且会终止安装。另外我们需要用一个Binary元素来保存我们的vbs文件。

<Binary Id="myScriptVBS" SourceFile="myScript.vbs" />

然后通过我们的CustomAction和的BinaryKey和VBScriptCall(或者JScriptCall如果是JScript文件)来调用函数:

<CustomAction Id="myScript_CA" BinaryKey="myScriptVBS" VBScriptCall="myFunction" Execute="immediate" Return="check" />

加入序列:

<InstallUISequence>
<Custom Action="myScript_CA" After="LaunchConditions" />
</InstallUISequence>

五、调用动态链接库中的方法

类型1的自定义Action可以调用dll中的方法,VS提供了下面的模板。

我们将编写一个C#的dll,技术上讲,类型1的Custom Action需要非托管的C/C++的dll,Windows Installer 本身不支持.Net下的自定义Action。不过我们使用的模板会将我们的托管代码编译成c/c++的dll。使用.Net的时候要注意.Net的版本,当然也有C++的Custom Action 供选择。

创建一个C# Custom Action Project 之后,我们会得到一个引用了Microsoft.Deployment.WindowsInstaller 的源文件。这个命名空间可以让我们获取properties ,features 和 components 。

using Microsoft.Deployment.WindowsInstaller;
namespace CustomAction
{
public class CustomActions
{
[CustomAction]
public static ActionResult CustomAction1(Session session)
{
session.Log("Begin CustomAction1"); return ActionResult.Success;
}
}
}

ActionResult 用来说明custom action 的调用是成功还是失败。单个的.Net 程序集之前只能定义16个CustomAction。wix3.6以后提高到128个。如果超过了这个,你只能再定义一个程序集了(没有测试过...)。这些都是来自Deployment Tools Foundation(DTF)的支持,DTF是一个让我们写.Net代码的类库,并且支持低级的Windows Installer技术。它提供了很多有用的类。 工程编译之后,我们会得到两个文件,一个是.dll 另外一个是 .CA.dll ,只有后者的才能被MSI识别。

有两种方法引用这个dll。

1.直接复制到Wix 工程目录,然后用Binary 元素引用它。

<Binary Id="myCustomActionsDLL"  SourceFile="CustomAction.CA.dll" />

2.就是引用工程,再用变量指向工程的输出目录。

   <Binary Id="myCustomActionsDLL"  SourceFile="$(var.CustomAction.TargetDir)CustomAction.CA.dll" />

示例:在安装结束后,修改应用程序中的配置参数

 public class CustomActions
{
[CustomAction]
public static ActionResult SetDevLanguage(Session session)
{
Record record = new Record();
record[] = "开始执行!";
session.Message(InstallMessage.Info, record);
session.Log("Begin CustomAction SetDevLanguage"); string xmlDoc = Path.Combine(session["INSTALLFOLDER"], "DVStudio.exe.config");
session.Log("安装目录:" + session["INSTALLDIR"]);
session.Log("配置文件:" + xmlDoc);
if (File.Exists(xmlDoc))
{
session.Log("config文件存在!");
session.Log("安装包语言是" + session["ProductLanguage"]);
string strContent = File.ReadAllText(xmlDoc);
strContent = Regex.Replace(strContent, "zh-CHT", lanDictionary[session["ProductLanguage"]]);
session.Log("语言修改为" + lanDictionary[session["ProductLanguage"]]);
File.WriteAllText(xmlDoc, strContent);
}
else
{
session.Log("config文件没有找到!");
}
return ActionResult.Success;
} private static Dictionary<string, string> lanDictionary = new Dictionary<string, string>()
{
{"","zh-CN"},
{"","zh-CHT"},
{"","en-US"},
};
}

定义Custom Action 并加入序列

    <CustomAction Id="CA_myCustomAction" BinaryKey="myCustomActionsDLL" DllEntry="SetDevLanguage" Execute="immediate" Return="check" />
      <Custom Action="CA_myCustomAction" After="InstallFiles"  Overridable="yes"  />

测试发现,after InstallFiles有的时候并不能检测到config文件,可能是安装文件和执行Action存在一定的延时,修改为InstallFinalize(最后一个Action)后,没有出现找不到文件的情况。

另外需要说明的是Session.Message 类型为Info的时候只是记录到日志,修改为Warning会弹出提示框。

六、触发可执行文件

有两种方法可以通过custom Action运行一个可执行文件(.exe)。类型2的Custom Action是用Binary元素来保存文件。类似上面的脚本文件的做法。所有这些Binary中的文件都不会拷贝到用户的电脑上去。我们创建一个exe并放到工程目录下。

<Binary Id="myProgramEXE" SourceFile="$(sys.SOURCEFILEDIR)Demo.exe" />

这里的$(sys.SOURCEFILEDIR)是WIX定义的系统变量,代表的是工程目录。

定义一个CustomAction:

 <CustomAction Id="myProgramEXE_CA" BinaryKey="myProgramEXE" Impersonate="yes" Execute="deferred" ExeCommand="" Return="check" />

CustomAction的Impersonate属性告诉Installer是否模拟用户去触发这个Exe,它的默认值是no,意味着以LocalSystem 用户(功能强大的内置账户,拥有改变用户电脑参数的权限)去执行。如果你不需要,就设置为Yes,以当前用户的身份去运行。而ExeCommand属性可以传递命令行参数到可执行文件。即使是内容为空,也需要定义它。

然后加入序列:

<InstallExecuteSequence>
<Custom Action="myProgramEXE_CA" Before="InstallFinalize" />
</InstallExecuteSequence>

另外一种方式是类型18的Custom Action是直接调用的安装了的文件。

<DirectoryRef Id="INSTALLLOCATION">
<Component Id="CMP_MainAppEXE" Guid="7AB5216B-2DB5-4A8A-9293-F6711FFAAA83">
<File Id="mainAppEXE" Source="Demo.exe" KeyPath="yes" />
</Component>
</DirectoryRef>

而Custom action 通过ID获取到文件

<CustomAction Id="RunMainApp" FileKey="mainAppEXE" ExeCommand="" Execute="commit" Return="ignore" />

如果不想运行的程序显示界面,也就是静默执行,需要使用WixUtilExtension下的QtEexc action .WIX文档中也有这么一节: Quiet Execution Custom Action

另外类型34的Custom action 可以通过目录获取文件,并传递了参数。

<CustomAction Id="RunMainApp" Directory="INSTALLLOCATION" ExeCommand="[INSTALLLOCATION]Main_App.exe –myArg 123" Execute="commit"  Return="ignore" />

七、发送错误终止安装

类型19的自定义action使用Error属性,来发送一个错误并终止安装。

<Property Id="myProperty" Value="0" />
<CustomAction Id="ErrorCA" Error="Ends the installation!" />
<InstallUISequence>
<Custom Action="ErrorCA" Before="ExecuteAction">
<![CDATA[
myProperty <> 1
]]>
</Custom>
</InstallUISequence>

在Custom元素内部有一个条件表达式,当myproperty不为1的时候触发。(注意到这个action是在InstallUISequence中触发的)

小结:CustomAction给我们提供了可以自己编程的窗口,可以去触发bat,修改配置文件,触发exe。文章大部分内容是来自《Packtpub.WiX.3.6.A.Developers.Guide.to.Windows.Installer.XML.Dec.2012》的翻译和测试。希望对你有帮助。

Wix 安装部署教程(十五) --CustomAction的七种用法的更多相关文章

  1. Wix 安装部署教程(十六) -- 自动生成多语言文件

    因为持续集成需要,所有项目编译完之后生成一个多语言的安装包.之前生成mst文件都是手动操作,而且mst文件必须每次重新和新的安装包“关联”,否则中文的安装包去调用英文的资源的时候就会报类似于“类型转换 ...

  2. Wix 安装部署教程(十二) -- 自动更新WXS文件

    上一篇分享了一个QuickWIX,用来对比两个工程前后的差异,但是这样还是很繁琐,而且昨天发现有Bug,目录对比有问题.这次改变做法,完全让程序自动去更新WXS文件,然后再用CCNet去自动编译,这样 ...

  3. Wix 安装部署教程(十) --来,用WPF做个漂亮的安装界面

    在上一篇中曾留下两个问题,.Net捆绑安装不触发以及路径选择的问题现在都已经解决,这段时间花的最多的地方还是WPF调样式上面,奈何WPF功力不够,暂时还是没有达到自己想要的效果.另外ViewModel ...

  4. Wix 安装部署教程(十四) -- 多语言安装包之用户许可协议

    在上一篇中,留下了许可协议的问题,目前已经解决.感谢网友武全的指点! 问题 一般我们是用WixVariable 来设定许可协议.如下所示: <WixVariable Id="WixUI ...

  5. Wix 安装部署教程 -CustomAction的七种用法

    在WIX中,CustomAction用来在安装过程中执行自定义行为.比如注册.修改文件.触发其他可执行文件等.这一节主要是介绍一下CustomAction的7种用法. 在此之前要了解InstallEx ...

  6. WIX 安装部署教程(六) 为你收集的七个知识点

    前段时间整理5篇WIX(Windows Installer XML)的安装教程,但还不够完善,这里继续整理了七个知识点分享给大家.WIX最新版本3.8,点击下载 WIX安装部署(一)同MSBuild自 ...

  7. Wix 安装部署教程(三)自定义安装界面和行为

    接上一篇自定义安装界面,这篇继续探索,首先介绍下,Wix为我们定义了五种风格,每种风格的UI都是有一定顺序的.我们可以改变安装顺序,也可以完全自定义一个Dialog插入其中.比如Wix_Mondo 风 ...

  8. Wix 安装部署教程(九) --用WPF做安装界面

    经常安装PC端的应用,特别是重装系统之后,大致分为两类.一类像QQ,搜狗输入法这样的.分三步走的:第一个页面可以自定义安装路径和软件许可.第二个页面显示安装进度条,第三个页面推荐其他应用.先不管人家怎 ...

  9. Wix 安装部署教程(四) 添加安装文件及快捷方式

    通过之前三篇的介绍,大家对wix的xml部署方式也应该有一些认识,今天天气不错,再来一发.主要介绍桌面,开始菜单,卸载等功能的如何添加.希望园友们支持! 一.如何添加文件 Demo打包程序很简单,就一 ...

随机推荐

  1. 移动开发tip

    input点击出现背景色和边框,加入样式 -webkit-tap-highlight-color: rgba(255,255,255,0); ios下按钮糊掉,样式表不怎么起作用,使用-webkit- ...

  2. C#数据结构选择

    选择一个合适的数据结构会对程序的性能有着显著的提高 线性表和链表: 1.LinkedList<T>:适合于元素数组不固定,存在大量列表的头尾添加动作场合.其它可使用List<T> ...

  3. mysql Statement violates GTID consistency 的坑

    今天项目迁移,重新换了一个数据库版本,然后问题来了,原本运行正常的程序迁移过来之后就是不能正常运行,后台报错如下: update tbl_user_info set -- 强制下架 mv_count ...

  4. Jmeter测试结果分析

    *.jtl文件内容: 请求发出的绝对时间,响应时间,请求的标签,返回码,返回消息,请求所属的线程,数据类型,是否成功,字节,             响应时间 1458294513309,   382 ...

  5. CS0234: 命名空间“System.Web.Mvc”中不存在类型或命名空间名称“Html、Ajax”(是否缺少程序集引用?)

    从SVN上down下来的程序,编译报了一大堆的错,发现是缺少引用,但是明明引用了,后来打开引用,发现system.web.mvc这个引用打着叹号,如图: 后来重新引用了本机的system.web.mv ...

  6. <%%>标签 什么意思

    <%%>是说这里面的文本不是普通直接输出到客户端的文本,而是需要服务器来解释的.不光是可以写JAVA脚本,这要看具体服务器端使用的是什么技术ASP/JSP/PHP/ASP.NET都使用相同 ...

  7. 拒绝try.catch泛滥,学习委托有感

    读了一位博友关于使用委托避免重复的try.catch的随笔(原文地址:http://www.cnblogs.com/foolishfox/archive/2010/07/30/1788416.html ...

  8. 1293. 3n+1数链问题 2016 12 23

    /* 1293. 3n+1数链问题 Constraints Time Limit: 1 secs, Memory Limit: 32 MB Description 在计算机科学上,有很多类问题是无法解 ...

  9. IIS报错 试图加载格式不正确 的程序集解决办法

    一般都是由于系统位数不一致导致的 方法:64位启用32应用程序兼容(推荐) 思路就是把程序池设置为对应的应用程序(即到底要不要启用32位应用程序)

  10. jQuery学习-css、class操作、动画方法的运用、jQ操作Dom节点

    css操作(设置单个/多个样式.获取样式) //修改单个属性:括号之中直接是需要修改的样式名,值 css(name,value) //例:$("#one").css("b ...