演练:为 ClickOnce 应用程序创建自定义安装程序
基于 .exe 文件的任何 ClickOnce 应用程序均可通过一个自定义安装程序进行无提示安装和更新。自定义安装程序可以实现安装期间的自定义用户体验,包括用于安全和维护操作的自定义对话框。为了执行安装操作,自定义安装程序将使用 InPlaceHostingManager 类。本演练演示如何创建可进行 ClickOnce 应用程序的无提示安装的自定义安装程序。
创建自定义的 ClickOnce 应用程序安装程序
在 ClickOnce 应用程序中,添加对 System.Deployment 和 System.Windows.Forms 的引用。
向应用程序中添加一个新类,并指定任何名称。本演练使用名称 MyInstaller。
将以下 Imports 或 using 语句添加到新类的顶部。
Imports System.Deployment.Application Imports System.Windows.Forms
using System.Deployment.Application; using System.Windows.Forms;
将以下方法添加到类中。
这些方法调用 InPlaceHostingManager 方法以便下载部署清单,断言适当的权限,要求用户提供安装权限,然后将应用程序下载并安装到 ClickOnce 缓存中。自定义安装程序可以指定 ClickOnce 应用程序是预信任的,或者可以将信任决定推迟到调用 AssertApplicationRequirements 方法时。此代码预信任该应用程序。
说明 预信任分配的权限不能超越自定义安装程序代码的权限。
Dim WithEvents iphm As InPlaceHostingManager = Nothing Public Sub InstallApplication(ByVal deployManifestUriStr As String) Try Dim deploymentUri As New Uri(deployManifestUriStr) iphm = New InPlaceHostingManager(deploymentUri, False) MessageBox.Show("Created the object.") Catch uriEx As UriFormatException MessageBox.Show("Cannot install the application: " & _ "The deployment manifest URL supplied is not a valid URL." & _ "Error: " & uriEx.Message) Return Catch platformEx As PlatformNotSupportedException MessageBox.Show("Cannot install the application: " & _ "This program requires Windows XP or higher. " & _ "Error: " & platformEx.Message) Return Catch argumentEx As ArgumentException MessageBox.Show("Cannot install the application: " & _ "The deployment manifest URL supplied is not a valid URL." & _ "Error: " & argumentEx.Message) Return End Try iphm.GetManifestAsync() End Sub Private Sub iphm_GetManifestCompleted(ByVal sender As Object, ByVal e As GetManifestCompletedEventArgs) Handles iphm.GetManifestCompleted ' Check for an error. If (e.Error IsNot Nothing) Then ' Cancel download and install. MessageBox.Show("Could not download manifest. Error: " & e.Error.Message) Return End If ' Dim isFullTrust As Boolean = CheckForFullTrust(e.ApplicationManifest) ' Verify this application can be installed. Try ' the true parameter allows InPlaceHostingManager ' to grant the permissions requested in the application manifest. iphm.AssertApplicationRequirements(True) Catch ex As Exception MessageBox.Show("An error occurred while verifying the application. " & _ "Error text: " & ex.Message) Return End Try ' Use the information from GetManifestCompleted() to confirm ' that the user wants to proceed. Dim appInfo As String = "Application Name: " & e.ProductName appInfo &= ControlChars.Lf & "Version: " & e.Version.ToString() appInfo &= ControlChars.Lf & "Support/Help Requests: " If Not (e.SupportUri Is Nothing) Then appInfo &= e.SupportUri.ToString() Else appInfo &= "N/A" End If appInfo &= ControlChars.Lf & ControlChars.Lf & _ "Confirmed that this application can run with its requested permissions." ' If isFullTrust Then ' appInfo &= ControlChars.Lf & ControlChars.Lf & _ ' "This application requires full trust in order to run." ' End If appInfo &= ControlChars.Lf & ControlChars.Lf & "Proceed with installation?" Dim dr As DialogResult = MessageBox.Show(appInfo, _ "Confirm Application Install", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) If dr <> System.Windows.Forms.DialogResult.OK Then Return End If ' Download the deployment manifest. ' Usually, this shouldn't throw an exception unless ' AssertApplicationRequirements() failed, or you did not call that method ' before calling this one. Try iphm.DownloadApplicationAsync() Catch downloadEx As Exception MessageBox.Show("Cannot initiate download of application. Error: " & downloadEx.Message) Return End Try End Sub #If 0 Then Private Function CheckForFullTrust(ByVal appManifest As XmlReader) As Boolean Dim isFullTrust As Boolean = False If (appManifest Is Nothing) Then Throw New ArgumentNullException("appManifest cannot be null.") End If Dim xaUnrestricted As 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 Then If xaUnrestricted.Value = "true" Then Return True End If End If Return False End Function #End If Private Sub iphm_DownloadProgressChanged(ByVal sender As Object, ByVal e As DownloadProgressChangedEventArgs) Handles iphm.DownloadProgressChanged ' you can show percentage of task completed using e.ProgressPercentage End Sub Private Sub iphm_DownloadApplicationCompleted(ByVal sender As Object, ByVal e As DownloadApplicationCompletedEventArgs) Handles iphm.DownloadApplicationCompleted ' Check for an error. If (e.Error IsNot Nothing) Then ' Cancel download and install. MessageBox.Show("Could not download and install application. Error: " & e.Error.Message) Return End If ' Inform the user that their application is ready for use. MessageBox.Show("Application installed! You may now run it from the Start menu.") End Sub
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 }
若要尝试利用代码进行安装,请调用 InstallApplication 方法。例如,如果将类命名为 MyInstaller,则可以用下面的方法调用 InstallApplication。
Dim installer As New MyInstaller() installer.InstallApplication("\\myServer\myShare\myApp.application") MessageBox.Show("Installer object created.")
MyInstaller installer = new MyInstaller(); installer.InstallApplication(@"\\myServer\myShare\myApp.application"); MessageBox.Show("Installer object created.");
后续步骤
ClickOnce 应用程序还可以添加自定义更新逻辑,包括在更新过程中要显示的自定义用户界面。有关更多信息,请参见 UpdateCheckInfo。ClickOnce 应用程序还可以使用 <customUX> 元素来禁止显示标准的“开始”菜单项、快捷键和“添加或删除程序”项。有关更多信息,请参见 <entryPoint> 元素(ClickOnce 应用程序)和 ShortcutAppId。