我需要一个单一的实例应用程序(根据这个
answer),但它需要通过点击一次部署.
问题是我要求点击一次不会自动检测更新尝试在应用程序运行时加载较新版本.如果它正在运行,那么我需要另一个实例被激活.通常,当选择“点击一次”链接时,首先要尝试找到更新.我想拦截这个并检查一个已经运行的实例,然后再启动正常的更新过程.
有没有人知道如何在点击一次部署方案中实现这一点?
为了解决这个问题,我们构建了一个具有以下两个功能的原型应用程序.
>一个PC上的多个实例被禁用.通过clickonce部署单个实例应用程序.当用户尝试启动应用程序的第二个实例时,会弹出一条消息,指示“另一个实例已经在运行”.
>异步检查更新,并安装更新(如果存在).如果用户运行新实例时有可用的更新,则会弹出“可用更新”.
构建演示应用程序的过程如下:
步骤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,其中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.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(); } } } }
该应用程序运行良好,我们希望这是一个很好的解决方案.
特别感谢Timothy Walters 提供的源代码