15

単一インスタンス アプリケーションが必要ですが (この回答に従って)、クリック ワンスでデプロイする必要があります。

問題は、アプリケーションの実行中に更新を自動的に検出せず、新しいバージョンをロードしようとする試みを 1 回クリックする必要があることです。実行中の場合は、他のインスタンスをアクティブにする必要があります。通常、クリック ワンス リンクを選択すると、最初に行われるのは更新プログラムの検索です。これをインターセプトし、通常の更新プロセスを開始するに、すでに実行中のインスタンスを確認したいと考えています。

Click Once 展開シナリオでこれがどのように可能になるかを知っている人はいますか?

4

4 に答える 4

22

この問題に取り組むために、次の2つの機能を備えたプロトタイプアプリケーションを作成しました。

  1. 1台のPC上の複数のインスタンスが無効になります。シングルインスタンスアプリケーションは、clickonceを介してデプロイされます。ユーザーがアプリの2番目のインスタンスを起動しようとすると、「別のインスタンスが既に実行されています」というメッセージがポップアップ表示されます。

  2. 更新を非同期でチェックし、更新が存在する場合はインストールします。ユーザーが新しいインスタンスを実行したときに利用可能な更新がある場合、「更新が利用可能です」というメッセージがポップアップ表示されます。

デモアプリケーションを構築するプロセスは次のとおりです。

手順1: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() );
        }
    }
}

ステップ2:プログラムで更新を処理する

その前に、ClickOnceの自動更新チェックを無効にする必要があります([公開]-[更新...]ダイアログで)。

次に、UpdateProgressとmainFormの2つのフォームを作成します。ここで、UpdateProgressはダウンロードの進行状況を示し、mainFormはメインアプリケーションを表します。

ユーザーがアプリケーションを実行すると、最初にupdateProgressが起動され、更新を確認します。更新が完了すると、mainFormが起動し、updateProgressが非表示になります。

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();
            }
        }
    }
}

アプリケーションはうまく機能し、問題の良い解決策になることを願っています。ソースコードを提供してくれたTimothyWalters
に特に感謝します

于 2008-11-27T05:16:26.293 に答える
5

確かに- ClickOnce の自動更新チェックを無効にして ([発行] -> [更新] ダイアログで)、System.Deployment.Application名前空間のオブジェクトとコマンドを使用して、更新を実用的にチェックすることができます。

チェックアウト:

更新がある場合は、実際に更新する前に、以下を呼び出して単一インスタンス アプリケーションのチェックを行うことができます。

于 2008-10-29T23:53:16.123 に答える
0

実行前のチェックはコードの外部にあるため、このようにすることはできないと思います。

ただし、clickonce デプロイ オプションを変更して、コードの実行中に更新を確認することができます。

さらに制御が必要な場合は、ApplicationDeployment UpdateまたはCheckForUpdateメソッドを使用して、更新プロセスを完全に制御できます。

于 2008-10-29T23:04:14.040 に答える