Excel VBA 第11回 別マクロの呼び出し（ライブラリ化）

# はじめに
Excel VBAのプログラムが増えてくると、同じようなソースコードを何度も書いたりしてしまいます。
ソースコードは再利用したほうが効率的であるため、ライブラリ化したくなります。
汎用ソースコードをExportして、別のマクロでそれをImportして使うといったことをよくします。
これはこれでいいんですが、そうすると少しずつ改変されていくと次第にソースコードが枝分かれしていきます。
また、共通のソースが複数のマクロに入るのは、複数マクロ起動するときにファイル読み込み時間がもったいなあと思ったりもします。
ということで、ライブラリとしていつでも使えるようにしておきたいと思いまして、ずいぶん前にライブラリ的なものを実現していたのですが、しばらくVBAから離れていたらそんなライブラリのことを忘れて、上に書いたようなImport、Exportを始めており、なんだかもったいなあと再び思い、そういえばライブラリ的なことやっていたようなと思い出しました。
ということで、備忘のためにまとめておこうと思います。

共通ライブラリは、それはそれでメンテナンスが大変だったりするので、本当に必要な時に必要なものを使うようにはしています。

# 今回実施する内容
![イメージ図.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/59cd648b-dc01-31ae-ef67-8535e2455ae2.jpeg)

共通ライブラリとなるアドインを作成して、それをMacroA、およびMacroBから呼び出しを行います。
青枠は、私は普段あまり意識しないですが、VBAのプロジェクト名です。プロジェクト名は違ったほうが参照設定で分かりやすいため示しておきます。

# ソースコード(Git Hub)
[VBA_11_OtherMacro](https://github.com/Build-Mount/VBA_11_OtherMacro)

# 環境
OS:Windows 10 JP
Excel: Excel 2021 (64bit)

# 参考
[事前バインディングと遅延バインディング](https://docs.microsoft.com/ja-jp/dotnet/visual-basic/programming-guide/language-features/early-late-binding/)
事前バインディングと遅延バインディングの説明です。

[クラス (object) を、宣言されている VBA プロジェクトの外部から使用する方法](https://docs.microsoft.com/ja-jp/previous-versions/office/troubleshoot/office-developer/set-up-vb-project-using-class)
がうぶからマクロを実行する方法が記載されています。

# 用語

# CommonLib.xlamの作成
今回は簡単な例として、CommonLib.xlamは、FunctionとClassを実装します。
- Function
    - ShowMessage
        - 設定したメッセージを表示する。
    - CreateClsEmployee
        - Cls_Employeeのインスタンスを生成する。 
- Class
    - Cls_Employee
        - 従業員の名前をプロパティで設定、取得するクラス。

## ソース
CommonLib.xlamは、以下の標準モジュールとクラスモジュールを作成します。
```VisualBasic:Module1.bas
Option Explicit

Public Function ShowMessage(strMsg As String)
    Call MsgBox(strMsg)
End Function

Public Function CreateClsEmployee() As Cls_Employee
    Set CreateClsEmployee = New Cls_Employee
End Function

```

```VisualBasic:Cls_Employee.cls
Option Explicit

Private G_strName As String

Property Get Name() As String
    Name = G_strName
End Property

Property Let Name(strName As String)
    G_strName = strName
End Property
```

## 設定
上記ソースを作ったら別のマクロから呼び出しするために少し設定が必要です。
- プロジェクト名の設定
    - 必須ではないのですが、事前バインディングをするときに、参照設定を行う場合、プロジェクト名で設定します。プロジェクト名はデフォルトでは、「VBAProject」だと思いますが、これだとその他多くあるプロジェクトと識別できなくて困るため、今回はプロジェクト名を「CommonLib」にします。
    - VBEの「ツール」→「VBAProjectのプロパティ」を選択して、プロジェクト名を「CommonLib」に設定します。
- クラスのインスタンス化の許可
    - Cls_Employee.clsはデフォルトでは、「Private」であり、外部からインスタンスを生成することができません。これを変更します。
    - Cls＿Employee.clsを選択して、プロパティ画面のInstancingの値を「PublicNotCreatable」に変更します。
    - これで外部から参照できるようになりますが、インスタンスは作れないため、CreateClsEmployee関数でインスタンスを生成するわけです。

# MacroA.xlsmの作成（事前バインディング）
MacroA.xlsmとMacroB.xlsmからCommonLib.xlamから呼び出しますが、せっかくなので、事前バインディングと遅延バインディングで試そうと思います。
MacroA.xlsmは事前バインディングで実装します。

## ソース
```VisualBasic:MacroA.xlsm
Option Explicit

Public Sub MacroA()
    Dim strMsg As String
    Dim ClsEmployee As Cls_Employee
    
    Call ShowMessage("CommonLibの関数を実行")

    Set ClsEmployee = CreateClsEmployee()
    ClsEmployee.Name = "従業員A"
    
    Call ShowMessage(ClsEmployee.Name)

End Sub
```
ソースはいたってシンプルで、CommonLib.xlamで実装した関数をそのまま実行するだけです。
ただ、事前バインディングが必要ですから、VB Editorの「ツール」→「参照設定」で、CommonLibをチェックしておく必要があります。
アドインは通常「%appdata%Microsoft\AddIns\」配下に置きます。そこに置いた場合「参照可能なライブラリファイル」にCommonLibが表示されてチェックするだけですが、今回は展開用に作成したため、「参照」ボタンで「C:\11_別マクロの呼び出し\CommonLib.xlam」を参照するようにしました。

# MacroB.xlsmの作成（遅延バインディング）
MacroB.xlsmは遅延バインディングで実装します。

## ソース
```VisualBasic:MacroB.xlsm
Option Explicit

Private Const COMMON_LIB_PATH As String = "'C:\11_別マクロの呼び出し\CommonLib.xlam'!"

Private Function CreateObject(strObjName As String) As Object
    Dim strFullPath As String
    
    strFullPath = COMMON_LIB_PATH & strObjName
    
    Set CreateObject = Application.Run(strFullPath)
End Function

Private Function RunFunction(strFuncName As String, Optional strArg1 As String)
    Dim strFullPath As String

    strFullPath = COMMON_LIB_PATH & strFuncName
    
    Call Application.Run(strFullPath, strArg1)
End Function

Public Sub MacroB()
    Dim strMsg As String
    Dim ClsEmployee As Object
    
    Set ClsEmployee = CreateObject("CreateClsEmployee")
    
    Call RunFunction("ShowMessage", "CommonLibの関数を実行")
    
    ClsEmployee.Name = "従業員B"
    
    Call RunFunction("ShowMessage", ClsEmployee.Name)
End Sub
```
Application.Runを実行してCommonLibの関数を呼び出します。
関数名のリンク先を明示するために、COMMON_LIB_PATHを定義し、関数名をつなげて、Application.Runで実行します。
クラスの場合は、戻り値でインスタンスを戻し、CreateObjectという関数名とし、関数実行は今回は戻り値がなかったため、RunFunctionというものを作りました。

# おわりに
今回は、別マクロを呼び出す方法をまとめました。
事前バインディングと遅延バインディングの2種類で実装しましたが、事前バインディングのほうが別マクロの呼び出しは簡単で使いやすいと思います。