演练:使用自定义操作在安装时将二进制文件编译为本机代码
可定义自定义操作来指定完成安装后运行的命令。 例如,在本演练中,将定义一个自定义操作,并将 EXE 的路径名传递给**“CustomActionData”**属性,以便在安装应用程序后将可执行文件编译为本机代码。
提示
对于在以下说明中使用的某些 Visual Studio 用户界面元素,您的计算机可能会显示不同的名称或位置。这些元素取决于您所使用的 Visual Studio 版本和您所使用的设置。有关更多信息,请参见 Visual Studio 设置。
创建要部署的 Web 浏览器应用程序
在**“文件”菜单上指向“新建”,再单击“项目”**。
单击**“Windows 窗体应用程序”**。
对于**“名称”,键入“BrowserSample”,然后单击“确定”**。
在**“视图”菜单上单击“工具箱”**。
展开**“所有 Windows 窗体”,然后将一个“Panel”**控件拖到窗体的左上角。
在“窗体设计器”中,将一个**“TextBox”控件和一个“Button”控件拖动到“Panel”**控件中。
在“窗体设计器”中,将一个**“WebBrowser”控件拖动到“Panel”**下面。
扩展窗体的大小以适合所有控件。
在“窗体设计器”中,单击**“Panel”**控件。
在**“属性”窗口中,将“布局”下面的“Dock”属性更改为“Top”**。
在“窗体设计器”中,单击**“WebBrowser”**控件。
在**“属性”窗口中,将“布局”下面的“Dock”属性更改为“Fill”**。
在“窗体设计器”中,单击**“Button”**控件。
在**“属性”窗口中,将“外观”下面的“Text”**属性更改为“转到”。
根据自己的喜好,调整**“Form”、“Panel”、“Textbox”、“Button”和“WebBrowser”**的大小。
在“窗体设计器”中,双击**“转到”**按钮。
Form1 代码文件的代码视图将出现。
添加以下代码以便将 Web 浏览功能添加到应用程序中。 **“TextBox”控件中的文本为“WebBrowser”控件的地址栏,当单击“转到”**按钮时将进行此操作。
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click WebBrowser1.Navigate(TextBox1.Text) End Sub
private void button1_Click(object sender, EventArgs e) { webBrowser1.Navigate(textBox1.Text); }
若要测试浏览器,请按 F5。
将打开窗体。
在文本框中,键入“https://www.microsoft.com”,然后单击**“转到”**。
Microsoft 网站随即出现。
创建自定义操作类
在**“文件”菜单上指向“添加”,然后单击“新建项目”**。
在**“添加新项目”对话框中,单击“Windows”,再单击“类库”**。
在**“名称”框中,键入 NGenCustomAction,然后单击“确定”**。
在**“项目”菜单上,单击“添加新项”**。
在**“添加新项”对话框中,单击“常规”,然后单击“安装程序类”。 在“名称”框中,键入 NGenCustomAction,然后单击“添加”**。
提示
确保添加的是“安装程序类”;否则,代码文件将没有必要的 using 语句。
在**“解决方案资源管理器”**中删除 NGenCustomAction 项目中的 Class1 代码文件。
将代码添加到自定义操作中
右击**“解决方案资源管理器”中的 NGenCustomAction 代码文件(或设计图面),然后单击“查看代码”以打开“代码编辑器”**。 将下面的代码添加到模块的顶部。
Imports System.IO Imports System.Diagnostics
using System.IO; using System.Diagnostics;
更新类声明以便从 System.Configuration.Install.Installer 类中继承。
Inherits System.Configuration.Install.Installer
: System.Configuration.Install.Installer
在 NGenCustomAction 代码文件中添加以下帮助器方法,以便为任何程序集生成本机映像代码文件。
<System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)> _ Private Sub ngenCA(ByVal savedState As System.Collections.IDictionary, ByVal ngenCommand As String) Dim argsArray As [String]() If String.Compare(ngenCommand, "install", StringComparison.OrdinalIgnoreCase) = 0 Then Dim args As [String] = Context.Parameters("Args") If [String].IsNullOrEmpty(args) Then Throw New InstallException("No arguments specified") End If Dim separators As Char() = {";"c} argsArray = args.Split(separators) 'It is Ok to 'ngen uninstall' assemblies which were not installed savedState.Add("NgenCAArgs", argsArray) Else argsArray = DirectCast(savedState("NgenCAArgs"), [String]()) End If ' Gets the path to the Framework directory. Dim fxPath As String = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory() For i As Integer = 0 To argsArray.Length - 1 Dim arg As String = argsArray(i) ' Quotes the argument, in case it has a space in it. arg = """" & arg & """" Dim command As String = (ngenCommand & " ") + arg Dim si As New ProcessStartInfo(Path.Combine(fxPath, "ngen.exe"), command) si.WindowStyle = ProcessWindowStyle.Hidden Dim p As Process Try Context.LogMessage((">>>>" & Path.Combine(fxPath, "ngen.exe ")) + command) p = Process.Start(si) p.WaitForExit() Catch ex As Exception Throw New InstallException("Failed to ngen " & arg, ex) End Try Next End Sub
[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)] private void ngenCA(System.Collections.IDictionary savedState, string ngenCommand) { String[] argsArray; if (string.Compare(ngenCommand, "install", StringComparison.OrdinalIgnoreCase) == 0) { String args = Context.Parameters["Args"]; if (String.IsNullOrEmpty(args)) { throw new InstallException("No arguments specified"); } char[] separators = { ';' }; argsArray = args.Split(separators); savedState.Add("NgenCAArgs", argsArray); //It is Ok to 'ngen uninstall' assemblies which were not installed } else { argsArray = (String[])savedState["NgenCAArgs"]; } // Gets the path to the Framework directory. string fxPath = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(); for (int i = 0; i < argsArray.Length; ++i) { string arg = argsArray[i]; // Quotes the argument, in case it has a space in it. arg = "\"" + arg + "\""; string command = ngenCommand + " " + arg; ProcessStartInfo si = new ProcessStartInfo(Path.Combine(fxPath, "ngen.exe"), command); si.WindowStyle = ProcessWindowStyle.Hidden; Process p; try { Context.LogMessage(">>>>" + Path.Combine(fxPath, "ngen.exe ") + command); p = Process.Start(si); p.WaitForExit(); } catch (Exception ex) { throw new InstallException("Failed to ngen " + arg, ex); } } }
在 NGenCustomAction 代码文件中,添加以下过程以重写基类的 Install、Commit、Rollback 和 Uninstall 过程。
<System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)> _ Public Overloads Overrides Sub Install(ByVal savedState As System.Collections.IDictionary) MyBase.Install(savedState) Context.LogMessage(">>>> ngenCA: install") ngenCA(savedState, "install") End Sub <System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)> _ Public Overrides Sub Commit(ByVal savedState As System.Collections.IDictionary) MyBase.Commit(savedState) Context.LogMessage(">>>> ngenCA: commit") End Sub <System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)> _ Public Overloads Overrides Sub Uninstall(ByVal savedState As System.Collections.IDictionary) MyBase.Uninstall(savedState) Context.LogMessage(">>>> ngenCA: uninstall") ngenCA(savedState, "uninstall") End Sub <System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)> _ Public Overloads Overrides Sub Rollback(ByVal savedState As System.Collections.IDictionary) MyBase.Rollback(savedState) Context.LogMessage(">>>> ngenCA: rollback") ngenCA(savedState, "uninstall") End Sub
[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)] public override void Install(System.Collections.IDictionary savedState) { base.Install(savedState); Context.LogMessage(">>>> ngenCA: install"); ngenCA(savedState, "install"); } [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)] public override void Commit(IDictionary savedState) { base.Commit(savedState); Context.LogMessage(">>>> ngenCA: commit"); } [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)] public override void Uninstall(System.Collections.IDictionary savedState) { base.Uninstall(savedState); Context.LogMessage(">>>> ngenCA: uninstall"); ngenCA(savedState, "uninstall"); } [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand)] public override void Rollback(System.Collections.IDictionary savedState) { base.Rollback(savedState); Context.LogMessage(">>>> ngenCA: rollback"); ngenCA(savedState, "uninstall"); }
为浏览器示例应用程序添加部署项目
在**“文件”菜单上指向“添加”,然后单击“新建项目”**。
在**“添加新项目”对话框中,展开“其他项目类型”,展开“安装和部署项目”,单击“Visual Studio Installer”,然后再单击“安装项目”**。
在**“名称”框中,键入 Browser Sample Installer,再单击“确定”**。
在**“文件系统编辑器”中,选择“应用程序文件夹”。 在“操作”菜单上,单击“添加”**。
出现“添加项目输出组”对话框。
在“项目”下拉组合框中,选择“BrowserSample”,单击**“项目输出”,再单击“确定”**。
在**“文件系统编辑器”中,选择“应用程序文件夹”。 在“操作”菜单上,单击“添加”**。
出现“添加项目输出组”对话框。
在“项目”下拉组合框中,选择“NGenCustomAction”,单击**“项目输出”,再单击“确定”**。
向安装项目添加 NGEN 自定义操作
在**“解决方案资源管理器”中,单击“Browser Sample Installer”**项目。
在**“视图”菜单上指向“编辑器”,然后单击“自定义操作”**。
在**“自定义操作编辑器”中,选择“自定义操作”**节点。
在**“操作”菜单上,单击“添加自定义操作”**。
在**“选择项目中的项”对话框中,双击“应用程序文件夹”,单击“NGenCustomAction 的主输出(活动)”,再单击“确定”**。
将 NGEN 自定义操作添加到全部四个自定义操作节点。
在**“安装”节点中,单击“NGenCustomAction 的主输出(活动)”**。
在**“属性”窗口中,将“CustomActionData”**属性更改为 /Args="[TARGETDIR]BrowserSample.exe"。请在键入内容中包括引号。
提示
[TARGETDIR] 属性是已安装的可执行文件的位置。 此自定义操作使用 ngen.exe 将已安装的可执行文件转换为本机映像。
在**“解决方案资源管理器”中,单击“Browser Sample Installer”**安装项目。
在**“生成”菜单上,单击“生成 Browser Sample Installer”**。
验证本机代码生成
定位到安装文件夹,并查找 BrowserSample.exe 文件。 例如 %PROGRAMFILES%\CompanyName\Brower Sample Installer\BrowserSample.exe。
在 Visual Studio 命令提示符处,通过运行以下代码,验证是否已将可执行文件预编译为本机代码:
ngen.exe display FullPathToExe
例如,您可能运行以下命令:
ngen.exe display "C:\Program Files (x86)\Microsoft\Browser Sample Installer\BrowserSample.exe"
将显示命令输出。
Microsoft (R) CLR Native Image Generator - Version 4.0.21102.0 Copyright (c) Microsoft Corporation. All rights reserved. NGEN Roots: C:\Program Files (x86)\Microsoft\Browser Sample Installer\BrowserSample.exe NGEN Roots that depend on "c:\Program Files (x86)\Microsoft\Browser Sample Installer\BrowserSample.exe": C:\Program Files (x86)\Microsoft\Browser Sample Installer\BrowserSample.exe Native Images: BrowserSample, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null <debug>
提示
如果 ngen.exe 未显示本机映像,您可以在以下目录之一中查找 Ngen 日志:
%SystemRoot%\Microsoft.NET\Framework\v<CLR 版本> %SystemRoot%\Microsoft.NET\Framework64\v<CLR 版本>
ngen.log 文件是最新的疑难解答日志。