演练:使用自定义操作在安装时将二进制文件编译为本机代码

可定义自定义操作来指定完成安装后运行的命令。 例如,在本演练中,将定义一个自定义操作,并将 EXE 的路径名传递给**“CustomActionData”**属性,以便在安装应用程序后将可执行文件编译为本机代码。

提示

对于在以下说明中使用的某些 Visual Studio 用户界面元素,您的计算机可能会显示不同的名称或位置。这些元素取决于您所使用的 Visual Studio 版本和您所使用的设置。有关更多信息,请参见 Visual Studio 设置

创建要部署的 Web 浏览器应用程序

  1. 在**“文件”菜单上指向“新建”,再单击“项目”**。

  2. 单击**“Windows 窗体应用程序”**。

  3. 对于**“名称”,键入“BrowserSample”,然后单击“确定”**。

  4. 在**“视图”菜单上单击“工具箱”**。

  5. 展开**“所有 Windows 窗体”,然后将一个“Panel”**控件拖到窗体的左上角。

  6. 在“窗体设计器”中,将一个**“TextBox”控件和一个“Button”控件拖动到“Panel”**控件中。

  7. 在“窗体设计器”中,将一个**“WebBrowser”控件拖动到“Panel”**下面。

  8. 扩展窗体的大小以适合所有控件。

  9. 在“窗体设计器”中,单击**“Panel”**控件。

  10. 在**“属性”窗口中,将“布局”下面的“Dock”属性更改为“Top”**。

  11. 在“窗体设计器”中,单击**“WebBrowser”**控件。

  12. 在**“属性”窗口中,将“布局”下面的“Dock”属性更改为“Fill”**。

  13. 在“窗体设计器”中,单击**“Button”**控件。

  14. 在**“属性”窗口中,将“外观”下面的“Text”**属性更改为“转到”。

  15. 根据自己的喜好,调整**“Form”“Panel”“Textbox”“Button”“WebBrowser”**的大小。

  16. 在“窗体设计器”中,双击**“转到”**按钮。

    Form1 代码文件的代码视图将出现。

  17. 添加以下代码以便将 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);
    }
    
  18. 若要测试浏览器,请按 F5。

    将打开窗体。

  19. 在文本框中,键入“https://www.microsoft.com”,然后单击**“转到”**。

    Microsoft 网站随即出现。

创建自定义操作类

  1. 在**“文件”菜单上指向“添加”,然后单击“新建项目”**。

  2. 在**“添加新项目”对话框中,单击“Windows”,再单击“类库”**。

  3. 在**“名称”框中,键入 NGenCustomAction,然后单击“确定”**。

  4. 在**“项目”菜单上,单击“添加新项”**。

  5. 在**“添加新项”对话框中,单击“常规”,然后单击“安装程序类”。 在“名称”框中,键入 NGenCustomAction,然后单击“添加”**。

    提示

    确保添加的是“安装程序类”;否则,代码文件将没有必要的 using 语句。

  6. 在**“解决方案资源管理器”**中删除 NGenCustomAction 项目中的 Class1 代码文件。

将代码添加到自定义操作中

  1. 右击**“解决方案资源管理器”中的 NGenCustomAction 代码文件(或设计图面),然后单击“查看代码”以打开“代码编辑器”**。 将下面的代码添加到模块的顶部。

    Imports System.IO
    Imports System.Diagnostics
    
    using System.IO;
    using System.Diagnostics;
    
  2. 更新类声明以便从 System.Configuration.Install.Installer 类中继承。

    Inherits System.Configuration.Install.Installer
    
    : System.Configuration.Install.Installer
    
  3. 在 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);
                    }
                }
            }
    
    
  4. 在 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");
    }
    

为浏览器示例应用程序添加部署项目

  1. 在**“文件”菜单上指向“添加”,然后单击“新建项目”**。

  2. 在**“添加新项目”对话框中,展开“其他项目类型”,展开“安装和部署项目”,单击“Visual Studio Installer”,然后再单击“安装项目”**。

  3. 在**“名称”框中,键入 Browser Sample Installer,再单击“确定”**。

  4. 在**“文件系统编辑器”中,选择“应用程序文件夹”。 在“操作”菜单上,单击“添加”**。

    出现“添加项目输出组”对话框。

  5. 在“项目”下拉组合框中,选择“BrowserSample”,单击**“项目输出”,再单击“确定”**。

  6. 在**“文件系统编辑器”中,选择“应用程序文件夹”。 在“操作”菜单上,单击“添加”**。

    出现“添加项目输出组”对话框。

  7. 在“项目”下拉组合框中,选择“NGenCustomAction”,单击**“项目输出”,再单击“确定”**。

向安装项目添加 NGEN 自定义操作

  1. 在**“解决方案资源管理器”中,单击“Browser Sample Installer”**项目。

  2. 在**“视图”菜单上指向“编辑器”,然后单击“自定义操作”**。

  3. 在**“自定义操作编辑器”中,选择“自定义操作”**节点。

  4. 在**“操作”菜单上,单击“添加自定义操作”**。

  5. 在**“选择项目中的项”对话框中,双击“应用程序文件夹”,单击“NGenCustomAction 的主输出(活动)”,再单击“确定”**。

    将 NGEN 自定义操作添加到全部四个自定义操作节点。

  6. 在**“安装”节点中,单击“NGenCustomAction 的主输出(活动)”**。

  7. 在**“属性”窗口中,将“CustomActionData”**属性更改为 /Args="[TARGETDIR]BrowserSample.exe"。请在键入内容中包括引号。

    提示

    [TARGETDIR] 属性是已安装的可执行文件的位置。 此自定义操作使用 ngen.exe 将已安装的可执行文件转换为本机映像。

  8. 在**“解决方案资源管理器”中,单击“Browser Sample Installer”**安装项目。

  9. 在**“生成”菜单上,单击“生成 Browser Sample Installer”**。

验证本机代码生成

  1. 定位到安装文件夹,并查找 BrowserSample.exe 文件。 例如 %PROGRAMFILES%\CompanyName\Brower Sample Installer\BrowserSample.exe。

  2. 在 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 文件是最新的疑难解答日志。

请参见

参考

CustomActionData 属性

Ngen.exe(本机映像生成器)

概念

托管执行过程

其他资源

部署中的自定义操作管理