VSTOのClickOnceアプリではCheckForUpdateによる更新ができない

本記事の内容は2021年5月時点の情報に基づいています。

##はじめに
Visual Studio Tools for Office (VSTO) でExcelのアドインを開発し、ClickOnceで配布しています。

Excelの起動時、ClickOnceがアドインの更新をチェックし、更新があれば自動的に更新してから読み込まれます。

これが、外出時など、インターネット環境のない状態でExcelを起動した場合、ClickOnceの更新確認で時間がかかりExcelの起動に時間がかかる、という事象がありました。
![VSTO_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196121/2e947f32-b103-7caa-f4d0-de24b5acd6f3.png)


今回は、VSTOアドインのコードからの更新でハマった事をメモします。

## Windows Formsアプリケーションの場合
Windows FormsアプリケーションのClickOnceの場合、「アプリケーションの更新プログラムを確認する」をOFFにしておき、`ApplicationDeployment.CheckForUpdate`メソッドや`Update`メソッドを呼ぶことでコード上から更新確認と更新処理を行なう事が可能です。
https://docs.microsoft.com/ja-jp/visualstudio/deployment/how-to-check-for-application-updates-programmatically-using-the-clickonce-deployment-api

Windowsアプリケーションの発行-更新画面
![VSTO-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196121/374af30a-24ba-49eb-6307-cdf9b4b14c19.png)

## VSTOの場合
同じ事がVSTOでもできるかと思い、「更新の確認をしない」にして同じように実装してみました。
![VSTO-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196121/c73ff4ad-94dd-7e82-1a41-cc804e2777a1.png)

ところが、`CheckForUpdate`メソッドの呼び出しで以下のエラーが発生しました。

```
例外発生: System.Deployment.Application.TrustNotGrantedException: ユーザーは必要なアクセス許可をアプリケーションに与えることを拒否しました。
   場所 System.Deployment.Application.ApplicationTrust.RequestTrust(SubscriptionState subState, Boolean isShellVisible, Boolean isUpdate, ActivationContext actCtx, TrustManagerContext tmc)
   場所 System.Deployment.Application.DeploymentManager.DetermineTrustCore(Boolean blocking, TrustParams tp)
   場所 System.Deployment.Application.DeploymentManager.DetermineTrust(TrustParams trustParams)
   場所 System.Deployment.Application.ApplicationDeployment.CheckForDetailedUpdate(Boolean persistUpdateCheckResult)
   場所 System.Deployment.Application.ApplicationDeployment.CheckForUpdate()
場所 System.Deployment.Application.ApplicationTrust.RequestTrust(SubscriptionState subState, Boolean isShellVisible, Boolean isUpdate, ActivationContext actCtx, TrustManagerContext tmc)
   場所 System.Deployment.Application.DeploymentManager.DetermineTrustCore(Boolean blocking, TrustParams tp)
   場所 System.Deployment.Application.DeploymentManager.DetermineTrust(TrustParams trustParams)
   場所 System.Deployment.Application.ApplicationDeployment.CheckForDetailedUpdate(Boolean persistUpdateCheckResult)
   場所 System.Deployment.Application.ApplicationDeployment.CheckForUpdate()
```

## 調査結果
MSに問い合わせたところ、以下のような回答でした。

>ClickOnceがアプリケーションのインストールを試みた際に、通常は信頼プロンプトを表示し、ユーザーがインストールを明示的に許可することによって当該アプリケーションに「信頼」が付与されます。
VSTO アドインの更新時も同様の確認が行われますが、CheckForUpdate メソッドによる更新時は信頼プロンプトが表示されないため、信頼された発行元ストアに証明書がインストールされていない場合はアプリケーションに信頼を付与することができず、例外の発生に至ります。

解決策としては、ClickOnceマニフェストに署名した証明書の公開鍵を、クライアントにインストールしておく、という回答でしたが、既に数百台と展開している業務アプリだったため、各クライアントにインストールして回るのは無理でした。

>信頼された発行元ストアに証明書がインストールされていない場合、アプリケーションのインストールを試みた際に信頼プロンプトを表示し、ユーザーがインストールを明示的に許可することによって当該アプリケーションに信頼が付与されます。
信頼された発行元ストアに証明書がインストールされている場合は、信頼プロンプトは表示されずそのままアプリケーションのインストールが進みます。
VSTO アドインの更新時も同様の確認が行われますが、CheckForUpdate メソッドによる更新時は信頼プロンプトが表示されないため、信頼された発行元ストアに証明書がインストールされていない場合はアプリケーションに信頼を付与することができず、例外の発生に至ります。

また、VSTO以外との比較について
>標準の ClickOnce アプリケーションでは信頼プロンプトでインストールを許可して信頼済みとマークした際にレジストリに情報を保持していますが、VSTO アドインのインストール時には同レジストリ情報が保持されていないように見受けられます。

結論として、
>大変恐れ入りますが、VSTO では ApplicationDeployment.CheckForUpdate メソッドの動作が想定されておらず、ご利用いただくことができない状況でした。
ドキュメントに記載されておらず大変恐れ入りますが、今後変更される見通しはなく、このメソッドを利用してアプリケーション内から更新を行うことはできません。

という事でした。。

## 別案
別案として、VSTOInstaller.exeを呼ぶことで非同期に更新する事ができました。
但し、非同期のため新しいバージョンでの起動は次回起動時となります。更新があったらメッセージを表示し、ユーザーにExcelの再起動を促す必要があります。

```
VSTOInstaller.exe /install [URL] /silent
```

```C#:コード例
const string defaultInstallerPath = @"C:\Program Files\Common Files\Microsoft Shared\VSTO\10.0\VSTOInstaller.exe";
string installerPath = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\VSTO Runtime Setup\v4", "InstallerPath", defaultInstallerPath).ToString();
string deploymentUrl = "<https://***.***.jp/hoge.vsto";>
string arg = $"/install {deploymentUrl} /silent";
Process.Start(installerPath, arg);
```

## 結論
VSTOのClickOnceアプリはCheckForUpdateによる更新ができない。
代案として、VSTOInstaller.exeで非同期更新することができ、次回起動時に最新版が起動される。