いろんなものはつながっている

VBAからC#のDLLを使う

市販のソフトウェアを付属のマクロ機能で操作する必要がでてきた(マクロはVBAで記述する)。

できれば既存のライブラリを使いたいので、VBAからC++やC#で作成した自作のライブラリを呼び出したいと考えていたが、以前に行ったC++で作成した「関数」をエクセルのVBAから呼び出す方法では「クラス」を呼び出すことはできないようだ。

ただ、C#で作成した.NETのマネージドDLLをCOMのインターフェースを介してVBAから呼び出すことができるようだ。

このサイトを参考に以下のようなC#のクラスを作成した。

using System;
using System.Text;
using System.Net;
using System.Runtime.InteropServices;

namespace DLLforVBA
{
    [Guid(Base.ClassId)] 
    public class Base
    {
        public const string ClassId = "1A26B1FF-F693-43c6-9318-F1EFB0638A29";
         
        public virtual string GetMessage() { return "In Base Class"; }
    }
    
    [Guid(Derived1.ClassId1)]
    public class Derived1 : Base
    {
        public const string ClassId1 = "E04A8181-2A65-4140-8FD3-EDE875584942";

        public override string GetMessage() { return "In Derived1 Class"; }
    }

    [Guid(Derived2.ClassId2)]
    public class Derived2 : Base
    {
        public const string ClassId2 = "912591B0-538E-4fd6-85E2-A948EE993078";

        public override string GetMessage() { return "In Derived2 Class"; }
    }

    [Guid(Factory.ClassId)]
    public class Factory
    {
        public const string ClassId = "BC801173-B9A1-47da-B06C-C7CFCC8E436C";

        public string GetMessage() { return "In Factory"; }

        public Base Create(string type)
        { 
            switch (type){
                case "Derived1":
                    {
                        return new Derived1();
                    }
                case "Derived2":
                    {
                        return new Derived2();
                    }
                default:
                    {
                        return new Base();
                    }
            }
        }

    }

}

GUIDを発生させるのにVisual Studioのツールを利用した。ただし、Visual Studio Expressでは[ツール]-[GUID作成]がないのでGUIDを作成するツールをマイクロソフトのサイトからダウンロードした。

一方、作成したDLLを呼び出す側では

Public Sub test()

    Dim testFactory As New DLLforVBA.Factory
    Dim baseClass As New DLLforVBA.Base
    Set baseClass = testFactory.Create("Derived1")
    
    Debug.Print baseClass.GetMessage()
    
End Sub

といった要領でC#で作成したDLLを呼び出すことができる。

DLLをビルドしたマシンでVBAからDLLを使用するには特に追加の作業は必要ない。なぜならばVisual Studioがビルドの際にCOM仕様準拠のDLLを作成しCOMとしてレジストリに登録してくれるから。しかし、ビルドしたマシン以外でDLLを使う場合はそのマシンにDLLをCOMとして登録する必要がある。

登録は以下のコマンドを実行すればよい。
regasm MyClass.dll /tlb:MyClass.tlb

今回のケースでは、私の開発環境は32ビットで、市販ソフトウェアの環境は64ビットであり、かつ、市販ソフトウェアのVBAはWOW64で実行されている。その違いが原因で市販ソフトウェア環境へのDLLの登録ではまった。

はまった原因その1:プラットフォームスイッチ

Visual Studioのデフォルトのプラットフォームスイッチの設定はAny CPUになっている。これは、CLRがMSILをCPUにあわせてネイティブコードに変換するするという設定。今回の場合、CPUは64bitであるがソフトウェアは32bitなのでプラットフォームスイッチがAny CUPでは都合が悪い。明示的にx86にしてやる必要がある。このあたりのはことはここを参考にした。

はまった原因その2:32bitバージョンと64bitバージョンのRegasmがある

これでうまくいくと思いきや実際にRegasmで登録してみてもうまくいかない。調べてみるとRegasmにも32bitバージョンと64bitバージョンがあり、32bitのマネージドDLLを64bit環境で使用するには、32bitのRegasm(C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe)を使用する必要があるようだ。

以上で無事にC#で作成したクラスのDLLをVBAから呼び出すことができた。

関連記事

コメント

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

スポンサード リンク

カテゴリー

スポンサード リンク