在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爲空(看來書上的有問題),但直接獲取變量,咱們發現ARPINSTALLLOCATION和MyDir確實被賦值了。函數
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》的翻譯和測試。但願對你有幫助。