VBAでRedisに接続 その3 [完結編]
何回目かのVBAでRedisを使うポストですが、ようやく今回で無事VBAからのRedisアクセスができるようになりました。
C#でVBAのDLLを作成する方法
VBAから他の言語で書かれたDLLを作成する場合、2パターンあります。
- COMインターフェースを持つDLLを環境設定で追加して使用する。
- 通常のDLLをDllImportして使用する。
今回は勉強がてらCOMインターフェースを持つDLLを作成します。
COMインターフェースで作れば、インテリセンスも効くしヒントも表示されるので使いやすくなります。
COMインターフェースとは
COMインターフェースCOMインターフェースと言っていますがそもそもCOMインターフェースって何?
なところがあったので調べてみました。
Component Object Modelとは、マイクロソフトが提唱するソフトウェアの再利用を目的とした技術のことである。
アプリケーションソフトウェア間の通信や、OSとアプリケーションソフトウェアとのAPIに用いられる。
Component Object Model - Wikipedia
主にWindowsで使われるライブラリの基盤的なもの、という感じかな。
現在は殆どが.Net Frameworkに移行しているけど、C++では現役バリバリ、だそうだ。
VBAはそもそもが.Net以前のVBをベースにした言語なので、COMとは相性が良いんでしょう。
StackExchange.RedisにCOM設定を入れてビルドする
早速、StackExchange.Redisの設定でCOM参照を追加…等やってみてビルドします。
そうは問屋がおろしまへんで!とばかりにビルドエラーが発生しました。
ビルドエラーの原因
ビルドエラー内容を見ると、ジェネリック型はCOMインターフェースで使えないようです。
このジェネリック型、ですがC#とJavaにある機能で、型が違うけど同じような処理を実装する時にに使えるものです。
C++には似たようなテンプレートと言う機能があります。
動的型付け言語のRubyでは特にこういった機能はなかった気がします。
別dllファイルとしてラッパーdllを作成する
ジェネリック型を含むコードをビルドしてdllを作成する場合、COMインターフェースの実装ができないので、ジェネリック型を使わない
COMインターフェース用のラッパーDLLを作成してVBAからはそのラッパーDLLを経由したアクセスを行う方針で作成することにしました。
NugetでStackExchange.Redisをインストール
VisualStudioには、RubyのGemとかMacのHomeBrewのようなNugetというパッケージマネージャーがあり、それで開発環境にStackExchange.Redisを含めることが出来ます。
実はVisualStudio4年使っていて初めてVisualStudioにもNugetがあることを知りました
StackExchange.RedisのReadmeにある通りNugetのパッケージマネージャーコンソールを開いて、以下を入力します。
PM> Install-Package StackExchange.Redis
これで環境へStackExchange.Redisが準備できるので、プロジェクトのプロパティでCOM関係の設定をした後、COMインターフェースと空のクラスを作って、COM公開用の属性などを追加してビルドします。
よっしゃこれでよかろ!とおもったらビルドエラー。
なんでや!?と思ってエラーメッセージを見ると、レジストリにアクセス出来ませんでした…とあります。
COMインターフェースアセンブリを登録するためにはレジストリに登録する必要があるようで、
一般ユーザ権限でVisualStudioを起動しているときのビルドだと、レジストリに登録する権限がないので正常にCOMインターフェースが登録出来ない、ということみたいですね。
というわけで、VisualStudioを管理者モードとして起動してビルドすることで正常にビルドが通りました。
とりあえず基本的な読み書きだけやってみる
前回作成したBasicUsageを見ると、ConnectionMultiplexer
クラスのConnect
,GetDatabase
、そしてIDatabase
インターフェースのStringGet
,StringSet
があれば基本的な読み書きはできそうです。
というわけで、2つのクラスのCOMインターフェースとラッパークラスを作成したものをビルドします。
ConnectionMultiPlexer.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Runtime.InteropServices; using System.ComponentModel; using StackExchange.Redis; namespace StackExchange.Redis_COM { [ComVisible(true)] public interface IConnectionMultiplexer { [Description("Create a new ConnectionMultiplexer instance")] ConnectionMultiplexer Connect(string configuration); [Description("Obtain an interactive connection to a database inside redis")] Database GetDatabase(int db = -1); } [ComVisible(true)] [ClassInterface(ClassInterfaceType.None)] public class ConnectionMultiplexer : IConnectionMultiplexer { private Redis.ConnectionMultiplexer ConnectionMultiplexerInstance; public ConnectionMultiplexer Connect(string configuration) { ConnectionMultiplexerInstance = Redis.ConnectionMultiplexer.Connect(configuration); return this; } public Database GetDatabase(int db = -1) { return new Database(ConnectionMultiplexerInstance.GetDatabase(db)); } } }
Database.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Runtime.InteropServices; namespace StackExchange.Redis_COM { [ComVisible(true)] public interface IDatabase { void StringSet(string key, string value); string StringGet(string key); } [ComVisible(true)] [ClassInterface(ClassInterfaceType.None)] public class Database : IDatabase { private Redis.IDatabase IDatabaseInstance; public Database(Redis.IDatabase IDatabase) { IDatabaseInstance = IDatabase; } public void StringSet(string key, string value) { IDatabaseInstance.StringSet(key, value); } public string StringGet(string key) { return IDatabaseInstance.StringGet(key); } } }
VBAで使ってみる
作成したCOMインターフェースをVBEの環境設定で使う用に設定して、BasicUsageをVBAで書いてみます。
Option Explicit Public Sub Redis_BasicUsage() Dim Connection_Dummy As New Redis_COM.ConnectionMultiplexer Dim Connection As Redis_COM.ConnectionMultiplexer Set Connection = Connection_Dummy.Connect("localhost") Dim Redis As Redis_COM.Database Set Redis = Connection.GetDatabase Redis.StringSet "mykey", "foo" Debug.Print Redis.StringGet("mykey") End Sub
実行結果
結果、無事Redisにアクセスしてデータを設定、取得ができました。
あとがき
今回作成したRedisのCOMインターフェースはGitHubに上げました。
github.com
examplesディレクトリにVBAでの使用例を保存してあります。
せっかくなのでC#を勉強がてら、実用的なレベルまで作成した後、Redisのクライアント一覧に登録までやっちゃおうかなと思います。