このドキュメントではVBAやVBScriptからCOM経由で.NETの処理を実行する方法について記述する。
環境
・Visual Studio2008 Pro
・.NET Framework 2.0 を対象とする。
・32ビットのOffice2010
.NETを使用したクラスモジュールをCOMにする方法
1.Visual Studio 2008 を管理者権限で起動する。
これはCOM登録時にレジストリを変更するため。
2.プロジェクトの追加で「.NET Framework 2.0」 と 「クラスライブラリ」を選択
3. ビルドにてプラットフォームのターゲットを「x86」または「x64」とする。
これは使用するExcelに合わせる。
4. ビルドにてCOM相互運用機能の登録にチェックをつける。
5. アプリケーションのアセンブリ情報で、「アセンブリをCOM参照可能にする」
6. 公開したいインターフェイスとその実態について以下のように記述する
using System.Runtime.InteropServices;
namespace NMeCabCom
{
[ComVisible(true)]
public interface INmcTagger
{
void Create();
NmcNode[] Parse(string text);
}
[ClassInterface(ClassInterfaceType.None)]
public class NmcTagger : INmcTagger
{
private MeCabTagger nmcab;
public NmcTagger()
{
}
public void Create()
{
MeCabParam p = new MeCabParam();
p.DicDir = @"C:\dev\NMeCab\dic\ipadic";
this.nmcab = MeCabTagger.Create(p);
}
public NmcNode[] Parse(string text)
{
List<NmcNode> result = new List<NmcNode>();
if (this.nmcab == null)
{
return result.ToArray();
}
MeCabNode node = this.nmcab.ParseToNode(text);
while (node != null)
{
result.Add(new NmcNode(node));
node = node.Next;
}
return result.ToArray();
}
}
}
まず、公開するインターフェイスの直前に「ComVisible(true)」と記述する。
[ComVisible(true)]
public interface INmcTagger
{
void Create();
NmcNode[] Parse(string text);
}
そして、そのインターフェイスの実装部分はClassInterfaceType.Noneとする。
[ClassInterface(ClassInterfaceType.None)]
public class NmcTagger : INmcTagger
7. ビルドを行うことでCOMの登録まで行われる
インターフェイスの設計時に注意すべきこと。
・List<>などのジェネリック型はCOMとしては公開できない
・ClassInterfaceTypeにAutoDualを記述すると、インターフェイス不要にできるがすべきでない
http://msdn.microsoft.com/ja-jp/library/ms182205.aspx
・Uint、ULONG等のUnsignedの型をインターフェイスに使用してはいけない
COMとしては使用できても、VBAやVBSはUnsignedをサポートしていないので、ULONGなどのインターフェイスは使用できない。
・オブジェクトの配列は返えしてはいけない
以下のようなCOMのインターフェイスがあったとする。
public interface INmcTagger
{
string GetModulePath();
void Create(NmcParam p);
NmcNode[] Parse(string text);
}
このインターフェイスの場合、VBAやC#などの型を明示できるプログラミング言語では適切に処理できる
Dim ret As NmcNode()
ret = t.Parse("This is a pen.")
しかし、VBSの場合、型が明示できないため、Unknownとなり処理できなくなる。
Dim ret ' As NmcNode()
ret = t.Parse("This is a pen.")
WScript.Echo TypeName(ret) ' Unknownとなり、以降処理できない。
こういう場合は、配列を管理するインターフェイスを作成して、それを経由するようにする。
public interface INmcNodeCollection
{
int Count { get; }
NmcNode GetItem(int index);
}
配列ではないオブジェクトを返した場合は、VBSでも処理ができる
set ret = t.Parse("This is a pen.")
For i = 0 To ret.Count- 1
WScript.Echo TypeName(ret.GetItem(i))
WScript.Echo ret.GetItem(i).Surface
Next
利用方法
開発環境以外の登録方法
.NET Frameworkのフォルダに存在するregasmを使用する。
作成したdllに対して /tlb と /codebase を付与してregasmを実行する。
regasmは各バージョンの.NETに存在する。
SET BIN=C:\Windows\Microsoft.NET\Framework\v2.0.50727
REM 登録
%BIN%\regasm C:\dev\NMeCabCom\NMeCabCom\bin\Debug\NMeCabCom.dll /tlb /codebase
この際、以下のメッセージが出力される場合がある。
「RegAsm : warning RA0000 : 署名されていないアセンブリを /codebase を使用して登録すると、同じコンピュータにインストールされるその他のアプリケーションとの競合が生じる可能性があります。/codebase スイッチは署名されたアセンブリのみに使用できます。アセンブリに厳密な名前を付けて、再登録してください。」
これは、警告だけであり、COMの登録はされている。
この警告を消すには、プロジェクトの設定で「署名」→「アセンブリの署名」 厳密な名前のキーファイルを選択する必要がある。
依存するすべてのDLLが同様に厳密な名前を有しなければならないので気をつけること。
COMの削除方法
/tlb と /unregister を付与したregasmコマンドを実行後、ファイルを消すればよい。
regasm /tlb C:\dev\NMeCabCom\NMeCabCom\bin\Debug\NMeCabCom.dll /unregister
ExcelVBAで利用する方法
参照設定してやれば、使用できるようになる
以下のようにインテリセンスが効く。
VBSからの利用方法
以下のようにCreateObjectを利用する。
set t = CreateObject("NMeCabCom.NmcTagger")
実際のサンプル
VBAやVBScriptで形態素解析を行う方法
http://qiita.com/mima_ita/items/bc2aeb060ee12d280d7b