逐步解說:為 ClickOnce 應用程式建立自訂安裝程式

任何以 .exe 檔案為基礎的 ClickOnce 應用程式都可以由自訂安裝程式以無訊息方式安裝及更新。 自訂安裝程式可以在安裝期間實作自訂使用者體驗,包括安全性和維護作業的自訂對話方塊。 若要執行安裝作業,自訂安裝程式會使用類別 InPlaceHostingManager。 本逐步解說示範如何建立自訂安裝程式,以無訊息方式安裝 ClickOnce 應用程式。

注意

.NET Core 和 .NET 5 和更新版本中不支援 System.Deployment.Application 命名空間中的 ApplicationDeployment 類別和 API。 .NET 7 支援存取應用程式部署屬性的新方法。 如需詳細資訊,請參閱在 .NET 中存取 ClickOnce 部署屬性。 .NET 7 不支援 ApplicationDeployment 方法的同等項。

必要條件

建立自訂 ClickOnce 應用程式安裝程式

  1. 在您的 ClickOnce 應用程式中,新增 System.Deployment 和 System.Windows.Forms 的參考。

  2. 將新類別新增至您的應用程式,並指定任何名稱。 這個逐步解說使用的名稱為 MyInstaller

  3. 將下列 Importsusing 指示詞新增至新類別的頂端。

    using System.Deployment.Application;
    using System.Windows.Forms;
    
  4. 將下列方法加入類別。

    這些方法會呼叫 InPlaceHostingManager 方法來下載部署資訊清單、判斷提示適當的權限、要求使用者安裝權限,然後將應用程式下載並安裝到 ClickOnce 快取中。 自訂安裝程式可以指定 ClickOnce 應用程式是預先信任的,也可以將信任決策延遲至 AssertApplicationRequirements 方法呼叫。 此程式碼會預先信任應用程式。

    注意

    預先信任指派的權限不能超過自訂安裝程式程式碼的權限。

    InPlaceHostingManager iphm = null;
    
    public void InstallApplication(string deployManifestUriStr)
    {
        try
        {
            Uri deploymentUri = new Uri(deployManifestUriStr);
            iphm = new InPlaceHostingManager(deploymentUri, false);
        }
        catch (UriFormatException uriEx)
        {
            MessageBox.Show("Cannot install the application: " + 
                "The deployment manifest URL supplied is not a valid URL. " +
                "Error: " + uriEx.Message);
            return;
        }
        catch (PlatformNotSupportedException platformEx)
        {
            MessageBox.Show("Cannot install the application: " + 
                "This program requires Windows XP or higher. " +
                "Error: " + platformEx.Message);
            return;
        }
        catch (ArgumentException argumentEx)
        {
            MessageBox.Show("Cannot install the application: " + 
                "The deployment manifest URL supplied is not a valid URL. " +
                "Error: " + argumentEx.Message);
            return;
        }
    
        iphm.GetManifestCompleted += new EventHandler<GetManifestCompletedEventArgs>(iphm_GetManifestCompleted);
        iphm.GetManifestAsync();
    }
    
    void iphm_GetManifestCompleted(object sender, GetManifestCompletedEventArgs e)
    {
        // Check for an error.
        if (e.Error != null)
        {
            // Cancel download and install.
            MessageBox.Show("Could not download manifest. Error: " + e.Error.Message);
            return;
        }
    
        // bool isFullTrust = CheckForFullTrust(e.ApplicationManifest);
    
        // Verify this application can be installed.
        try
        {
            // the true parameter allows InPlaceHostingManager
            // to grant the permissions requested in the applicaiton manifest.
            iphm.AssertApplicationRequirements(true) ; 
        }
        catch (Exception ex)
        {
            MessageBox.Show("An error occurred while verifying the application. " +
                "Error: " + ex.Message);
            return;
        }
    
        // Use the information from GetManifestCompleted() to confirm 
        // that the user wants to proceed.
        string appInfo = "Application Name: " + e.ProductName;
        appInfo += "\nVersion: " + e.Version;
        appInfo += "\nSupport/Help Requests: " + (e.SupportUri != null ?
            e.SupportUri.ToString() : "N/A");
        appInfo += "\n\nConfirmed that this application can run with its requested permissions.";
        // if (isFullTrust)
        // appInfo += "\n\nThis application requires full trust in order to run.";
        appInfo += "\n\nProceed with installation?";
    
        DialogResult dr = MessageBox.Show(appInfo, "Confirm Application Install",
            MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
        if (dr != System.Windows.Forms.DialogResult.OK)
        {
            return;
        }
    
        // Download the deployment manifest. 
        iphm.DownloadProgressChanged += new EventHandler<DownloadProgressChangedEventArgs>(iphm_DownloadProgressChanged);
        iphm.DownloadApplicationCompleted += new EventHandler<DownloadApplicationCompletedEventArgs>(iphm_DownloadApplicationCompleted);
    
        try
        {
            // Usually this shouldn't throw an exception unless AssertApplicationRequirements() failed, 
            // or you did not call that method before calling this one.
            iphm.DownloadApplicationAsync();
        }
        catch (Exception downloadEx)
        {
            MessageBox.Show("Cannot initiate download of application. Error: " +
                downloadEx.Message);
            return;
        }
    }
    
    /*
    private bool CheckForFullTrust(XmlReader appManifest)
    {
        if (appManifest == null)
        {
            throw (new ArgumentNullException("appManifest cannot be null."));
        }
    
        XAttribute xaUnrestricted =
            XDocument.Load(appManifest)
                .Element("{urn:schemas-microsoft-com:asm.v1}assembly")
                .Element("{urn:schemas-microsoft-com:asm.v2}trustInfo")
                .Element("{urn:schemas-microsoft-com:asm.v2}security")
                .Element("{urn:schemas-microsoft-com:asm.v2}applicationRequestMinimum")
                .Element("{urn:schemas-microsoft-com:asm.v2}PermissionSet")
                .Attribute("Unrestricted"); // Attributes never have a namespace
    
        if (xaUnrestricted != null)
            if (xaUnrestricted.Value == "true")
                return true;
    
        return false;
    }
    */
    
    void iphm_DownloadApplicationCompleted(object sender, DownloadApplicationCompletedEventArgs e)
    {
        // Check for an error.
        if (e.Error != null)
        {
            // Cancel download and install.
            MessageBox.Show("Could not download and install application. Error: " + e.Error.Message);
            return;
        }
    
        // Inform the user that their application is ready for use. 
        MessageBox.Show("Application installed! You may now run it from the Start menu.");
    }
    
    void iphm_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
    {
        // you can show percentage of task completed using e.ProgressPercentage
    }
    
  5. 若要嘗試從程式碼安裝,請呼叫 InstallApplication 方法。 例如,如果您將類別 MyInstaller 命名,您可能會以下列方式呼叫 InstallApplication

    MyInstaller installer = new MyInstaller();
    installer.InstallApplication(@"\\myServer\myShare\myApp.application");
    MessageBox.Show("Installer object created.");
    

下一步

ClickOnce 應用程式也可以新增自訂更新邏輯,包括自訂使用者介面,以在更新處理序期間顯示。 如需詳細資訊,請參閱UpdateCheckInfo。 ClickOnce 應用程式也可以使用 <customUX> 元素來抑制標準 [開始] 功能表項目、快捷方式和 [新增或移除程式] 項目。 如需詳細資訊,請參閱 <entryPoint> 元素ShortcutAppId