Visual Studio 2019 によるExcelアドインの作成 - VBAからアドイン内のメソッドを呼び出す

# Visual Studio 2019 によるExcelアドインの作成 - VBAからアドイン内のメソッドを呼び出す
## 内容
[【前回の記事】](https://qiita.com/rhene/items/dd2cf0667f7ca0fd15a8)でVisual StudioでExcelのアドインを実装することが出来ました。
本記事ではアドイン内で定義したメソッドを公開して、VBAから呼び出せるようにします。

なお、本記事は下記の内容を参考に実装しました。
[【他の Office ソリューションから VSTO アドインのコードを呼び出す】- Microsoft](https://docs.microsoft.com/ja-jp/visualstudio/vsto/calling-code-in-vsto-add-ins-from-other-office-solutions?view=vs-2019)


## 概要
本記事の手順は主に以下となります。

1. 公開用クラスの追加
- RequestComAddInAutomationService メソッドのオーバーライド
- デバッグ (公開メソッドの呼び出し)

なお、本記事は以下の環境で動作を確認しています。

- Windows 10 Professional
- Visual Studio Professional 2019 (Visual Studio Community 2019 及び Professional 2017 でも確認済み)
- Excel 2013以降 (VS2017ではExcel2010向けアドインも開発可能)

なお、本記事では前回の記事で作成したソリューションをそのまま流用する想定です。

## 【1. 公開用クラスの追加】
まずは [前回の記事](https://qiita.com/rhene/items/dd2cf0667f7ca0fd15a8) で作成したソリューションに公開用のクラスを追加します。
プロジェクトを右クリックし[追加]から[クラス]を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454012/23e643c2-30a2-9698-3c15-749f7d7160a5.png)

「クラス」が選択された状態で「新しい項目の追加」ダイアログが表示されます。
ここで公開用のクラス名を指定します。
今回は「PublicClass」としました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454012/e4eaa3f3-a08d-7f36-5c6d-89e483f6ea69.png)

作成された `PublicClass.cs` の内容を以下のコードに編集してください。

```C#:PublicClass.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Excel = Microsoft.Office.Interop.Excel;

namespace ExcelAddIn1
{
    [ComVisible(true)]
    public interface IPublicClass
    {
        void FillData(Excel.Range range, string text);
    }


    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    public class PublicClass: IPublicClass
    {
        /// <summary>
        /// 指定されたRangeを指定された文字列で埋めます
        /// </summary>
        /// <param name="range">埋めるRange</param>
        /// <param name="text">埋める文字列</param>
        public void FillData(Excel.Range range, string text)
        {
            range.Value2 = text;
        }
    }
}
```
コードの概要は以下の通り。

- インターフェースを公開 (public interface IPublicClass)
- インターフェースの実装 (public class PublicClass: IPublicClass)
- `ComVisible` 属性を `true` に指定

詳しくは [参考記事](https://docs.microsoft.com/ja-jp/visualstudio/vsto/calling-code-in-vsto-add-ins-from-other-office-solutions?view=vs-2019) を参照してください。

なお、本コードでは公開用のメソッドとして `FillData` を実装して公開しています。
メソッド `FillData` は第一引数にExcel.Range、第二引数にstringを渡すことで、指定されたRangeを第二引数の文字列で埋めます。

`PublicClass.cs` の編集が完了すると、以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454012/ae79652c-4c7d-23e6-ae69-4e3fa1a5ac49.png)


## 【2. RequestComAddInAutomationService メソッドのオーバーライド】
続いて `ThisAddIn` クラスのRequestComAddInAutomationService メソッドをオーバライドします。
具体的には `ThisAddIn.cs` 内の `ThisAddIn` クラスに以下のコードを追加します。

```C#:ThisAddin.cs
        private PublicClass utilities;
        protected override object RequestComAddInAutomationService()
        {
            if (utilities == null)
                utilities = new PublicClass();

            return utilities;
        }
```
なお、 `PublicClass` と記述されている部分は、上記で作成した公開用のクラス名を指定してください。
編集が完了すると、以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454012/16e427bd-da31-7b8f-ed10-f43cfc5cf016.png)

以上で公開メソッドの準備は整いました。


## 【3. デバッグ】
[デバッグ]メニューから [デバッグの開始] を実行するか F5 キーを押します。
アドインのビルドが走り、実行が開始されるとExcelが起動し新しいワークブックが開きます。
新しいワークブックが開かない場合、起動されたExcel上で「空白のブック」を選択してください。

新しいワークブックが開いたら「Alt+F11」を押してVBAのコードエディタを開き、 `ThisWorkbook` をダブルクリックし、開いたエディタに以下のコードをコピペします。

```VB:ThisWorkbook
Sub CallVSTOMethod()
    Dim addIn As COMAddIn
    Dim automationObject As Object

    ' アドインの読み込み
    Set addIn = Application.COMAddIns("ExcelAddIn1")

    ' アドイン内の公開クラスの読み込み
    ' アドイン内で RequestComAddInAutomationService をオーバライドしてないと Nothing が返ります
    Set automationObject = addIn.Object
    
    ' 【公開メソッドの呼び出し】
    ' 指定したRangeを指定した文字列で埋める
    Call automationObject.FillData(ActiveSheet.Range("A1:C3"), "テスト テキスト")
End Sub
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454012/0cb78626-8b64-b26a-6a9d-cfdc281650c3.png)

準備ができたら「F5」を押して実行してみます。
エラーがなければアクティブセルの「A1:C3」が「テスト テキスト」という文字列で埋められます。

【公開メソッド「FillData」動作イメージ】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454012/d0a167bf-16a5-d86d-d970-9fbc880397a2.png)

引数を変更することで、処理範囲や埋めるテキストを変更することができるので試してみてください。


## 最後に
アドイン内のメソッドを公開することで、複雑な処理はアドイン内で処理できるようになりました。
多少の手順は必要ですが、比較的簡単に実装することが可能でした。
あとはゴリゴリ実装していくだけです。

ちなみに、本当はアドインからイベントを発報してVBA側で受け取りたかったのですが、どうやら無理なようです。
アドイン内で非同期処理を行いステータスの変更や処理の完了をイベントで通知したいと思っており、クラスライブラリ(COMオブジェクト)であれば可能なので、アドインでも可能かなと思っていたのですが残念です。