Question

Je dois disposer d'une application à instance unique (comme indiqué dans cette answer ), mais il doit être déployé par clic une fois.

Le problème est que j'ai besoin que clic une fois ne détecte pas automatiquement une mise à jour pour tenter de charger une version plus récente pendant que l'application est en cours d'exécution. Si elle est en cours d'exécution, il faut que l'autre instance soit activée. Habituellement, lorsque vous sélectionnez un lien Cliquez une fois, la première chose à faire est de tenter de trouver une mise à jour. Je souhaite intercepter ceci et rechercher une instance antérieure déjà en cours d'exécution pour lancer le processus de mise à jour normal.

Quelqu'un sait-il comment cela est possible dans un scénario de déploiement Click Once?

Était-ce utile?

La solution

Pour résoudre ce problème, nous avons créé un prototype d'application doté des deux fonctionnalités suivantes.

  1. Plusieurs instances sur un PC sont désactivées. Une application à instance unique est déployée via clickonce. Lorsqu'un utilisateur tente de démarrer une seconde instance de l'application, un message apparaît indiquant que "Une autre instance est déjà en cours d'exécution".

  2. Recherche une mise à jour de manière asynchrone et installe la mise à jour s'il en existe une. Un message: " Une mise à jour est disponible " apparaîtra si une mise à jour est disponible lorsqu'un utilisateur exécute une nouvelle instance.

Le processus de création de l'application de démonstration est le suivant:

Étape 1: Détectez une application d'instance active à l'aide de la classe Mutex.

namespace ClickOnceDemo
{
    static class Program
    {
        /// summary>
        /// The main entry point for the application.
        /// /summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault( false );
            bool ok;
            var m = new System.Threading.Mutex( true, "Application", out ok );
            if ( !ok )
            {
                MessageBox.Show( "Another instance is already running.", ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString() );
                return;
            }
           Application.Run( new UpdateProgress() );
        }
    }
}

Étape 2: gérez la mise à jour par programme

Avant cela, désactivons la vérification automatique des mises à jour de ClickOnce (dans la boîte de dialogue Publier - Mises à jour ...).

Ensuite, nous créons deux formulaires: UpdateProgress et mainForm, où UpdateProgress indique la progression du téléchargement et mainForm représente l'application principale.

Lorsqu'un utilisateur exécute l'application, updateProgress sera d'abord lancé pour rechercher les mises à jour. Lorsque la mise à jour est terminée, mainForm démarre et updateProgress est masqué.

namespace ClickOnceDemo
{
public partial class UpdateProgress : Form
 {
  public UpdateProgress()
        {
            InitializeComponent();
            Text = "Checking for updates...";

            ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
            ad.CheckForUpdateCompleted += OnCheckForUpdateCompleted;
            ad.CheckForUpdateProgressChanged += OnCheckForUpdateProgressChanged;

            ad.CheckForUpdateAsync();
       }

        private void OnCheckForUpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e)
        {
            lblStatus.Text = String.Format( "Downloading: {0}. {1:D}K of {2:D}K downloaded.", GetProgressString( e.State ), e.BytesCompleted / 1024, e.BytesTotal / 1024 );
            progressBar1.Value = e.ProgressPercentage;
        }

        string GetProgressString( DeploymentProgressState state )
        {
            if ( state == DeploymentProgressState.DownloadingApplicationFiles )
            {
                return "application files";
            }
            if ( state == DeploymentProgressState.DownloadingApplicationInformation )
            {
                return "application manifest";
            }
            return "deployment manifest";
        }

        private void OnCheckForUpdateCompleted(object sender, CheckForUpdateCompletedEventArgs e)
        {
            if ( e.Error != null )
            {
                MessageBox.Show( "ERROR: Could not retrieve new version of the application. Reason: \n" + e.Error.Message + "\nPlease report this error to the system administrator." );
                return;
            }
            if ( e.Cancelled )
            {
                MessageBox.Show( "The update was cancelled." );
            }

            // Ask the user if they would like to update the application now.
            if ( e.UpdateAvailable )
            {
                if ( !e.IsUpdateRequired )
                {
                    long updateSize = e.UpdateSizeBytes;
                    DialogResult dr = MessageBox.Show( string.Format("An update ({0}K) is available. Would you like to update the application now?", updateSize/1024), "Update Available", MessageBoxButtons.OKCancel );
                    if ( DialogResult.OK == dr )
                    {
                        BeginUpdate();
                    }
                }
                else
                {
                    MessageBox.Show( "A mandatory update is available for your application. We will install the update now, after which we will save all of your in-progress data and restart your application." );
                    BeginUpdate();
                }
            }
            else
            {
                ShowMainForm();
            }
        }

        // Show the main application form
        private void ShowMainForm()
        {
            MainForm mainForm = new MainForm ();
            mainForm.Show();
            Hide();
        }

        private void BeginUpdate()
        {
            Text = "Downloading update...";
            ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
            ad.UpdateCompleted += ad_UpdateCompleted;
            ad.UpdateProgressChanged += ad_UpdateProgressChanged;

            ad.UpdateAsync();
        }

        void ad_UpdateProgressChanged( object sender, DeploymentProgressChangedEventArgs e )
        {
            String progressText = String.Format( "{0:D}K out of {1:D}K downloaded - {2:D}% complete", e.BytesCompleted / 1024, e.BytesTotal / 1024, e.ProgressPercentage );
            progressBar1.Value = e.ProgressPercentage;
            lblStatus.Text = progressText;
        }

        void ad_UpdateCompleted( object sender, AsyncCompletedEventArgs e )
        {
            if ( e.Cancelled )
            {
                MessageBox.Show( "The update of the application's latest version was cancelled." );
                return;
            }
            if ( e.Error != null )
            {
                MessageBox.Show( "ERROR: Could not install the latest version of the application. Reason: \n" + e.Error.Message + "\nPlease report this error to the system administrator." );
                return;
            }

            DialogResult dr = MessageBox.Show( "The application has been updated. Restart? (If you do not restart now, the new version will not take effect until after you quit and launch the application again.)", "Restart Application", MessageBoxButtons.OKCancel );
            if ( DialogResult.OK == dr )
            {
                Application.Restart();
            }
            else
            {
                ShowMainForm();
            }
        }
    }
}

L’application fonctionne bien et nous espérons que c’est une bonne solution au problème.
Un merci spécial à Timothy Walters pour avoir fourni le code source

Autres conseils

Bien sûr : vous pouvez désactiver la vérification automatique de la mise à jour de ClickOnce (dans la boîte de dialogue Publier - > Mises à jour ..), puis utiliser les objets et les commandes de la Espace de noms System.Deployment.Application pour rechercher des mises à jour de manière pragmatique.

Départ:

S'il existe une mise à jour, vous pouvez effectuer les vérifications de votre application à instance unique avant la mise à jour effective en appelant:

Je ne pense pas que vous serez capable de le faire comme cela, car la vérification avant exécution est en dehors de votre code.

Toutefois, vous pouvez modifier les options de déploiement en cliquant une fois pour rechercher des mises à jour lors de l'exécution du code.

Si vous avez besoin de plus de contrôle, vous pouvez utiliser ApplicationDeployment Update ou CheckForUpdate méthodes à avoir absolu sur le processus de mise à jour.

J'ai utilisé http://wpfsingleinstance.codeplex.com/ dans mon application WPF ClickOnce avec un grand succès. Je n'ai rien eu à changer.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top