I have an Excel VSTO add-in, which updates every 24 hours via ClickOnce. This works fine.
I would like to provide a button where the user can manually check for an update, immediately. I followed the instructions provided in the documentation. My code looks like this: (ignore the commented section for the moment)
Sub TryUpdateApp()
If (ApplicationDeployment.IsNetworkDeployed) Then
Dim Deployment As ApplicationDeployment = ApplicationDeployment.CurrentDeployment
Dim Info As UpdateCheckInfo = Nothing
'Try
' Dim AppIdentity As New ApplicationIdentity(Deployment.UpdatedApplicationFullName)
' Dim UnrestrictedPerms As New Security.PermissionSet(Security.Permissions.PermissionState.Unrestricted)
' Dim AppTrust As New Security.Policy.ApplicationTrust(AppIdentity) With {
' .DefaultGrantSet = New Security.Policy.PolicyStatement(UnrestrictedPerms),
' .IsApplicationTrustedToRun = True,
' .Persist = True
' }
' Security.Policy.ApplicationSecurityManager.UserApplicationTrusts.Add(AppTrust)
'Catch ex As Exception
' 'log error
'End Try
Try
Info = Deployment.CheckForDetailedUpdate()
Catch dde As DeploymentDownloadException
MsgBox($"The new version of App cannot be downloaded at this time.{vbNewLine}Please check your network connection, or try again later. Error: {dde.Message}", vbExclamation Or vbOKOnly)
Exit Sub
Catch ioe As InvalidOperationException
MsgBox($"This application cannot be updated. It is likely not a ClickOnce application. Error: {ioe.Message}", vbCritical Or vbOKOnly)
Exit Sub
End Try
Try
If (Info.UpdateAvailable) Then
Try
Deployment.Update()
MsgBox("App has been upgraded. Please restart Excel to apply changes.", vbInformation Or vbOKOnly)
Catch dde As DeploymentDownloadException
MsgBox($"Unable to install the latest version of App: download failed.{vbNewLine}Please check your network connection, or try again later.", vbCritical Or vbOKOnly)
Exit Sub
Catch tnge As TrustNotGrantedException
MsgBox("Unable to install the latest version of App: trust not granted.", vbExclamation Or vbOKOnly)
Exit Sub
End Try
Else
MsgBox("The latest version of App is already installed.", vbInformation Or vbOKOnly)
End If
Catch ex As Exception
MsgBox("Unable to install the latest version of App: unknown error.")
Exit Sub
End Try
Else
Throw New ApplicationException("Application is not network deployed.")
End If
End Sub
Whilst it would accurately indicate when "The latest version of App is already installed.", it would fail to update if necessary, throwing a TrustNotGrantedException: User has refused to grant required permissions to the application.
.
The first funny thing is that this exception is captured by "Unable to install the latest version of App: unknown error.", not "Unable to install the latest version of App: trust not granted.", as one would expect.
I thend found this thread, which corresponds to the commented part of the code above. When I uncomment and run the sub, it seems to work as I get "App has been upgraded. Please restart Excel to apply changes". However, when I then restart Excel and run the Sub once again, I get "Application is not network deployed".
How could I resolve this? (any C# code is fine)
After scratching my head for a while, I manage to find out why it was behaving that way and how to properly start an update manually.
The answer lies in this other SO answer, which links a MSDN forum post which itself links to an old Microsoft blog post.
I'll summarize the findings here, in case the links disappear.
The main thing to understand is that, while we can deploy VSTO as a ClickOnce app, it is actually NOT a fully compliant ClickOnce app since it is not an application, but an addin to an Office application! But it's not explicitly said anywhere in the docs! VSTO ClickOnce uses only a specific core part of ClickOnce, but not all!
I think this is the one thing that is bringing ton of confusion to everyone and explain why it's not simple to find an answer online. We are looking at how performing an update with ClickOnce and implementing it exactly as everyone is doing, but it's not working! Even though we clearly took the exact same code as in the docs or the myriad blog posts about it.
This is simply a case of mislabelling and reminds me how difficult it is to actually name things. If only Microsoft had named it "ClickOnceForOffice" or something, we may not have this issue.
Anyway.
The gist to get it working is twofold:
UpdateCheckInfo
) with lots of details.Here is the helper class I am using:
internal static class VstoHelper
{
// WARNING : VstoInstaller path actually depends on
// Office bitness : use "Program Files (x86)" if 32 bit Office
// Office version : use 10.0 for Office 2019 (not tested for other version)
private static string VstoInstallerPath = @"C:\Program Files\Common Files\Microsoft Shared\VSTO\10.0\VSTOInstaller.exe";
public static bool ApplyUpdate(bool applySilently = false)
{
if (!ApplicationDeployment.IsNetworkDeployed)
{
throw new InvalidOperationException();
}
using (var process = new Process())
{
process.StartInfo = new ProcessStartInfo()
{
FileName = VstoInstallerPath,
Arguments = $"{(applySilently ? "/S" : "")} /I \"{ApplicationDeployment.CurrentDeployment.UpdateLocation}\"",
UseShellExecute = false,
RedirectStandardOutput = false,
RedirectStandardError = false,
};
process.Start();
process.WaitForExit();
return process.ExitCode == 0;
}
}
public static UpdateCheckInfo CheckForUpdate()
{
if (!ApplicationDeployment.IsNetworkDeployed)
{
return null;
}
var deployment = ApplicationDeployment.CurrentDeployment;
var appId = new ApplicationIdentity(deployment.UpdatedApplicationFullName);
var unrestrictedPerms = new PermissionSet(PermissionState.Unrestricted);
var appTrust = new ApplicationTrust(appId)
{
DefaultGrantSet = new PolicyStatement(unrestrictedPerms),
IsApplicationTrustedToRun = true,
Persist = true
};
ApplicationSecurityManager.UserApplicationTrusts.Add(appTrust);
var info = deployment.CheckForDetailedUpdate();
return info;
}
}
I hope this will help someone in the future :-) Good luck!