Tutorial: Creación de un instalador personalizado para una aplicación ClickOnce
Cualquier aplicación ClickOnce basada en un archivo .exe se puede instalar y actualizar silenciosamente mediante un instalador personalizado. Un instalador personalizado puede implementar la experiencia de usuario personalizada durante la instalación, incluidos los cuadros de diálogo personalizados para las operaciones de seguridad y mantenimiento. Para realizar operaciones de instalación, el instalador personalizado usa la clase InPlaceHostingManager. En este tutorial se muestra cómo crear un instalador personalizado que instala silenciosamente una aplicación ClickOnce.
Nota
La clase ApplicationDeployment y las API del espacio de nombres System.Deployment.Application no se admiten en .NET Core y .NET 5 y versiones posteriores. En .NET 7 se admite un nuevo método de acceso a las propiedades de implementación de aplicaciones. Para obtener más información, consulte Acceso a las propiedades de implementación de ClickOnce en .NET. .NET 7 no admite el equivalente de los métodos ApplicationDeployment.
Requisitos previos
Para crear un instalador de aplicación ClickOnce personalizado
En la aplicación ClickOnce, agregue referencias a System.Deployment y System.Windows.Forms.
Agregue una nueva clase a la aplicación y especifique cualquier nombre. Este tutorial usa el nombre
MyInstaller
.Agregue las directivas
Imports
ousing
siguientes a la parte superior de la nueva clase.Agregue los métodos siguientes a su clase.
Estos métodos llaman a los métodos InPlaceHostingManager para descargar el manifiesto de implementación, declarar los permisos adecuados, pedir al usuario permiso para instalar y, a continuación, descargar e instalar la aplicación en la caché de ClickOnce. Un instalador personalizado puede especificar que una aplicación ClickOnce es de confianza previa o puede aplazar la decisión de confianza a la llamada al método AssertApplicationRequirements. Este código confía previamente en la aplicación.
Nota
Los permisos asignados por confianza previa no pueden superar los permisos del código del instalador personalizado.
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 }
Para intentar la instalación desde el código, llame al método
InstallApplication
. Por ejemplo, si ha llamado a la claseMyInstaller
, puede llamar aInstallApplication
de la siguiente manera.
Pasos siguientes
Una aplicación ClickOnce también puede agregar lógica de actualización personalizada, incluida una interfaz de usuario personalizada para mostrarse durante el proceso de actualización. Para obtener más información, vea UpdateCheckInfo. Una aplicación ClickOnce también puede suprimir la entrada de menú Inicio estándar, el acceso directo y la entrada Agregar o quitar programas mediante un elemento <customUX>
. Para más información, consulte <Elemento entryPoint>y ShortcutAppId.