Wix 安装部署教程(十五) --CustomAction的七种用法

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

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

  1、设置变量      c++

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#程序获取变量的值,稍后会介绍。windows

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

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

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

记录日志:ide

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

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

2、设置安装目录测试

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

<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"]);

结果正确。

3、运行嵌入的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>

 

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

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

Function myFunction()
If Session.Property("myProperty") = "2" Then
msgbox "Property is 1. Returning success!"
myFunction = 1
Exit Function
End If
msgbox "Property not 1. Returning failure."
myFunction = 3
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>

 5、调用动态连接库中的方法

类型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(0);
            record[0] = "开始执行!";
            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>()
        {
            {"2052","zh-CN"},
            {"1028","zh-CHT"},
            {"1033","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会弹出提示框。

6、触发可执行文件

有两种方法能够经过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" />

7、发送错误终止安装

 类型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》的翻译和测试。但愿对你有帮助。

相关文章
相关标签/搜索