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のクライアント一覧に登録までやっちゃおうかなと思います。
応用情報技術者試験に合格しました&勉強方法振り返り
先日、とうとう平成28年度秋季情報技術者試験の合格発表があり、
無事応用情報技術者試験に合格できました。
結果としては↓みたいな感じです。
以前、↓のような記事を書いたのですが
stonebeach-dakar.hatenablog.com
あらためて勉強方法をまとめなおしてみました。
私、Atomを卒業します。普通のVim使いになります!
私、Atomを卒業します。
普通の女の子になります!
普通のVim使いになります!
いや、真面目に、Atomを卒業します。
なんでかというと、「達人プログラマー」で2つのエディタを使っているような状況は良くないよ、
という話があったんです。
達人プログラマーに書いてあったこと
いくつか抜き出します。
1つのエディタを知り尽くしておき、コーディング、ドキュメント作成、メモ、システム管理といった編集作業は、全てそれを使用して行うことをお勧めします。
複数種類のエディタの使用によって、現代におけるバベルの塔の混乱に直面する可能性があるのです。
異なった編集規約やコマンドが個別にそんざいすると、それぞれの環境への熟達が難しいものとなってしますのです。
あなたは一芸に秀でている必要があります。
強力なエディタとあなたの指先を使えば、高い生産性を上げられるようになります。
もし1つのエディタをすべてのテキスト編集作業で使えるのであれば、テキスト操作のたびに立ち止まって考え込む必要もなくなり、反射的にキー入力が行えるようになります。
エディタは手の延長となり、軽やかなキー入力の音はテキストと指向の間を抜ける小道を渡る小鳥のさえずりのようになるのです。それが目標です。
達人プログラマー 第3章 パワーエディットより
- 作者: Andrew Hunt,David Thomas,村上雅章
- 出版社/メーカー: オーム社
- 発売日: 2016/10/20
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (3件) を見る
エディタはどんな操作をする時でも1種類だけにしてしまおう!という考え方です。
ただ、IDEに依存する言語(VBAやDelphi等)もあるので、そういった言語は除いていいと思います。
この考え方ですが、最近はMicrosoftもVSCode等でどのような言語でも使えるエディタをだしてきたりと、昨今のトレンドになっている気がします。
今まで使っていたエディタについて
AtomとVim。どちらもオープンソースのエディタです。
ターミナルからの開発はVim,デスクトップからはAtomの2本体勢を2年ぐらいやっていました。
プラグインを入れればお互いのキーバインドも近づけるのは知っていたんですが、余り気にしていなかったので両方のキーバインドを覚えるという効率が悪いことをやっていました。
そのせいで何方か一方しか使わない時期があるとすぐにキーバインドを混乱して使ってしまうこともありました。
なぜAtomを使っていたのか
まだCUIベースのVimに慣れていない時に出てきた新しいエディタで、色々なパッケージをつかうことで様々な言語に対応出来る!などの触れ込みが気になって使い始めました。
実際、当初は使いやすく色々な開発をこのAtomでやっていたのですが、最近はよくクラッシュするためもっぱらMarkDownとCSS、HTML専用エディタになっていました。
なぜVimを使っていたのか
最初、Vimを使い始めた理由は尊敬するプログラマの1人である@junichi_itoさんが紹介していたのがきっかけです。
@junichi_itoさんはもうVimをやめてRubyMineに移行したみたいですが
最初さわった時は何だこの使いにくいエディタは!?と思っていたのですが、
慣れてくると非常にテンポよくタイプできるので、もう手放せないエディタとなりました。
また、設定ファイルのVimrcをGitHubなどにアップしておけば家で使っている環境をそのまま会社のPCでも使える、というのがお気に入りでした。
そして、Rubyを書くとターミナルで動作確認をすることが多いので、キーボードから手を離すことなく動作確認が行えるため、Rubyの開発では重宝します。
ただ、プラグインを入れていないだけなのにいろんな理由をつけては余り使わなかった時期があり、その間にAtomを使っていた感じです。
最近、Vimを使う機会が増えたおかげで改めてVimのほうが使いやすいな!と気づきました。
なぜAtomをやめるのか
なんかね、よくクラッシュするんですよ。
自分の環境だけかもしれませんが。
そして、クラッシュするとプロジェクトフォルダや開いていたタブが全部消えるので、また設定して、開き直して…というのがめんどくさくなってきました。
そしてもう1つ、設定を様々なOSで共有できない、Rubyを書いているとターミナルで動きを確認、というのが多いんですね。
なので、Term3などのターミナルパッケージを使っていたんですが、Atomのターミナルってどれもイマイチな出来で、結局Atomとターミナルを同時起動して入力が終わったらマウスを持ってターミナルにフォーカスを当ててまたキーボードで入力・・・というプロセスを踏む必要があったんです。
これがまた面倒臭い。集中しているときはなかなかキーボードから手を離したくないんですよね。
ということで、ちゃんとしたターミナルが使える環境の上で動作するVimのほうがベストでは?と思いました。
Atomから完全にVimに移行するためにやったこと
ここから、Atomを完全にやめて完全なVimmerとなるためにやったことを書いていきます。
Atomをアンインストール
潔く消してしまいましょう。自らを背水の陣に追い込むのです!
Vimの操作を完全に覚える
Vimをそこそこ使っていたものの、基本的な操作を完全に覚えているわけではありませんでした。
これを機会にちゃんと覚えないと、と思いました。
これはVimチュートリアルが便利です。3回ぐらいで大分なれてきたかな、という感じでした。
ちなみに30分で終わる、と言われているのですが自分の場合、初回は1時間ぐらいかかっていたような気がします。
Atomを使っていた理由をなくす
AtomとVimを使い分けていた理由をなくしてしまえば
「こういうことがAtomで出来ていたのにVimはできない。やっぱAtom必要だ。」
なんてことがなくなります。
Vimは長い間世界中の人に愛されたエディタなのでそのプラグインの数はAtomよりずっと多くあり、他のエディタにあってVimにないプラグインはない、とまで言われています。
VimでMarkDownのプレビュー表示に対応する
AtomではMarkDownPreviewというプラグインでプレビュー表示をしつつMarkdownテキストをガリガリ書ける機能を付けていました。
これでブログなりQiita記事なりを書いていたのですが、これはターミナルで動くVimじゃ無理だろなー、と思っていたのですが、
調べてみたらやりようがあったと知って決めつけちゃっていたな〜と反省。
下のサイトとリポジトリのReadMeを参考に設定するだけでOKでした。これでVimでブログ記事が書ける!
実際に使ってみても非常に便利です。リアルタイムじゃないけど、リアルタイムプレビューはたいてい重くなりやすいので保存時のプレビュー反映のほうが使いやすい気がします。
VimでMarkdownの環境を整える | KEYPOINT – キー・ポイント株式会社 開発日誌
というわけでこの記事は、こんな感じでブラウザでプレビューしながらVimでガリガリ書きました。
RGB値からカラーのプレビュー表示できるようにする
Atomでは、プラグインを入れることでCSSなどに書かれた色設定のプレビューが表示される、等の機能がありました。
これはVimだと無理だろ〜なんて思ってましたがありました。
Vimすげぇ。
blog.scimpr.com
これから
今使っているvimrcは元々まだまだVimに慣れていない頃、ネットで紹介されたオススメ設定とかプラグインをどんどん入れていったものなので、ちょっとメチャクチャなところがあったり、使っていないプラグインがあったります。
完全にVimに移行したので、vimrcファイルをそのうち整理してより使いやすくしていきたいな〜と思います。
とりあえずVim本を買ってみたので読みながらよりVimを使いこなせるようやってきます。
- 作者: DrewNeil,新丈径
- 出版社/メーカー: KADOKAWA / アスキー・メディアワークス
- 発売日: 2014/01/28
- メディア: Kindle版
- この商品を含むブログ (4件) を見る
学生時代はEmacs使っていた人
クロージャを学ぶ その心は?
とある事を以前、職場の上司に言われた。
プログラマを何年もやっていてもわからないことは多い。
実は基本的なこともしらなかったこともあるしよくわかってなかった、と言うのは本当によくある。
大切なのはよくわからないまま放置しないことだ。
はい、わからないまま放置していること多いです!
というわけで、今回はよくわからない基本的なことの1つ、クロージャをお勉強。
クロージャって何?
Wiki先生に聞きましょう。
クロージャ(クロージャー、英語: closure)、関数閉包はプログラミング言語における関数オブジェクトの一種。
いくつかの言語ではラムダ式や無名関数で実現している。
引数以外の変数を実行時の環境ではなく、自身が定義された環境(静的スコープ)において解決することを特徴とする。関数とそれを評価する環境のペアであるともいえる。 主な利点としてはグローバル変数の削減が挙げられる。
クロージャ - Wikipedia
ちょっとよくわかりません。日本語でry
色々なサイトで勉強してみて、ようやく意味がつかめました。
下の2点がクロージャの特徴です。
引数以外の変数を実行時の環境ではなく、自身が定義された環境で(以下略)
これは、関数そのものをオブジェクトとして持って、引数以外の変数は前回実行時の状態を保存しておく、
ということです。
主な利点としてはグローバル変数の削減が挙げられる
上の前回その関数を実行した状態を保存しておく、という利点を使って、
その関数が実行された回数をわざわざグローバルで持たず関数オブジェクトで保持することが可能になります。
自分的には、クロージャとは
関数の状態を保存して、いつでもその状態で処理を始められる方法と解釈しました。
クロージャの実際の例
よくあるカウンタの例です。
#encoding : utf-8 def increase n = 0 -> { n += 5 } end 3.times { p increase.call } puts "===========" increase_proc = increase 3.times { p increase_proc.call }
この例についての解説は、@ITの記事を参照してください。
他のサイトも見たのですが、ここが詳細にかかれてわかりやすくなっています。
http://www.atmarkit.co.jp/ait/articles/1409/29/news035_3.html
自分がよくわからなかったところ
increase_procという関数オブジェクトを使うことで、nが5,10,15となっていくのはわかります。
でも、n=0の部分はなぜ無視されてしまうのか?これがよくわかりませんでした。
ちょっと悩んだ結果、以下のことに気づきました。
increaseメソッドの返り値は->{ n += 5 }、つまりProcクラス
つまり、increase_procはincreaseメソッドの関数オブジェクトと勘違いしてたわけです。
本当は上の通りProcオブジェクトの中身の関数オブジェクトだったということでした。
勘違いした原因
前職ではC++をやっていたのですが、そのC++に関数ポインタと言うものがありました。
この関数ポインタは、下のような感じで使います。
int Sum(int a, int b){ return a + b; } int (func*)(int, int); func = Sum;
※C++なら関数オブジェクトを使ったほうが良いです
func = Sumの下りが似てたんですね…
この場合、Sumという関数のポインタをfunc変数に保存する、と言う事になります。
なので、Sum関数全部が1つのfunc変数に入ってます。
C++に慣れてる人は気をつけてください!(こんな勘違いするのは自分だけ)
クロージャをどう使っていくか
上の特徴にある通り、グローバル変数を削減したいといったシチュエーションで使えると思います。
ただ、基本的に私はグローバル変数を使わない実装にしているので、使う機会は余りなさそうな。
これに関しては色々なサイトを見たり自分で使ったりして自分なりの使い方を見つけていく必要がありそうです。
参考文献・サイト
おまけ
このクロージャはメタプログラミングの技法の1つとされています。
RubyをRubyたらしめるのはこのメタプログラミング、ともいわれているのでメタプログラミングをしっかり勉強してみたいところです。
さしあたっては以下の本を読むところから始めないと。
- 作者: Paolo Perrotta,角征典
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/10/10
- メディア: 大型本
- この商品を含むブログ (2件) を見る