.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時代から実行時バインディング使ってましたからね。)
参考:
MSサポート:Visual C# .NET で Office オートメーション サーバーをバインドする方法
とほほな日々 備忘録: Excel 遅延バインディング(LateBinding)
C#から遅延バインディングでEXCELのシート保護をする - とりあえずですけれども - 1981s
リフレクションを利用したレイトバインディングでExcelファイルを開く - Bug Catharsis
(続)リフレクションを利用したレイトバインディングでExcelファイルを開く - Bug Catharsis