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》的翻譯和測試。但願對你有幫助。

相關文章
相關標籤/搜索