3流プログラマのメモ書き

元開発職→社内SE→派遣で営業支援→開発戻り浦島太郎状態の三流プログラマのIT技術メモ書き。 このメモが忘れっぽい自分とググってきた技術者の役に立ってくれれば幸いです。

.Net(C#)アプリからExcelのVBAを呼び出したい(遅延バインディング)

.NetアプリからExcelのVBAを呼び出したい(事前バインディング) で参照設定からCOMのOffice操作DLLを呼び出す方法を書きました。(あらかじめ呼び出すオブジェクトのタイプライブラリを参照してコンパイル時に型チェックをするこの方法を事前バインディングと言います。)

しかしこの方法では参照設定したバージョンのExcelが入っているPCでしか実行できません。

対策としては、実行時にバインドする遅延バインディングを用います。

事前バインディングのコードと比較しながら遅延バインディングのコードを下記に書いてみます。

(コメント部分のコードが事前バインディングになります。)

using System.Runtime.InteropServices;

using System.Reflection;

 

public ExeMacro()

{

 

//Excelマクロファイルパス

string strMacroPath = @"D:\test.xls";

 

// Excel操作用COMオブジェクトを生成する

//ApplicationClass oExcel = new ApplicationClass();

object oExcel = CreateObject("Excel.Application");

 

//ワークブックコレクションオブジェクトを生成する。

//Workbooks oBooks = oExcel.Workbooks;

object oBooks = oExcel.GetType().InvokeMember("Workbooks", BindingFlags.GetProperty, null, oExcel, null);

 

//Excelファイルのオープン

//Workbook oBook = oBooks.Open(strMacroPath);

object oBook = oBooks.GetType().InvokeMember(

"Open", BindingFlags.InvokeMethod, null,

oBooks, new object[] {

strMacroPath

, Type.Missing

, Type.Missing

, Type.Missing

, Type.Missing

, Type.Missing

, Type.Missing

, Type.Missing

, Type.Missing

, Type.Missing

, Type.Missing

, Type.Missing

, Type.Missing

});

 

// Excelファイルの表示

//oExcel.Visible = true;

oExcel.GetType().InvokeMember("Visible", BindingFlags.SetProperty, null, oExcel, new object[] { true });

 

//マクロ実行(Testというサブプロシージャを実行する)

//oExcel.Run("Test");

oExcel.GetType().InvokeMember("Run", BindingFlags.InvokeMethod, null, oExcel, new object[] { "Test" });

 

//閉じる

//oBook.Close(false);

oExcel.GetType().InvokeMember("Quit", System.Reflection.BindingFlags.InvokeMethod, null, oExcel, null);

//COM解放

System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oBook);

System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oBooks);

System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oExcel);

oBook = null;

oBooks = null;

oExcel = null;

}

 

///

/// COMオブジェクトへの参照を作成および取得します

///

/// 作成するオブジェクトのプログラムID

///

/// オブジェクトが作成されるネットワークサーバー名

///

/// 作成されたCOMオブジェクト

public static object CreateObject(string progId, string serverName)

{

Type t;

if (serverName == null || serverName.Length == 0)

t = Type.GetTypeFromProgID(progId);

else

t = Type.GetTypeFromProgID(progId, serverName, true);

return Activator.CreateInstance(t);

}

 

///

/// COMオブジェクトへの参照を作成および取得します

///

/// 作成するオブジェクトのプログラムID

/// 作成されたCOMオブジェクト

public static object CreateObject(string progId)

{

return CreateObject(progId, null);

}

使い終わったら、Quitメソッドで、Excelファイルを閉じて、Marshal.FinalReleaseComObjectメソッドを使って、COMオブジェクトを必ず解放するようにしましょう。

上記のコードで事前と遅延バインディングの比較をしてもらうとわかるんですが、基本的に oExcel.GetType().InvokeMember メソッドでExcel内のメソッド実行したりプロパティを変更できるようです。(たしかに型が分からないわけですがら、リフレクションを使ってメソッド名やプロパティを指定しないといけませんね。)

VB.Netだとより簡単に遅延バインディング(実行時バインディング)ができるんですが、C#は結構面倒ですね。(VBはVB6時代から実行時バインディング使ってましたからね。)

参考:

(VB.Net)COMオブジェクトを解放する

MSサポート:Visual C# .NET で Office オートメーション サーバーをバインドする方法

とほほな日々 備忘録: Excel 遅延バインディング(LateBinding)

C#から遅延バインディングでEXCELのシート保護をする - とりあえずですけれども - 1981s

リフレクションを利用したレイトバインディングでExcelファイルを開く - Bug Catharsis

(続)リフレクションを利用したレイトバインディングでExcelファイルを開く - Bug Catharsis

Excelの解放: DOBON.NETプログラミング掲示板過去ログ

圧砕の雑記的な何か: 遅延バインディング