一人情シスのつぶやき

名古屋の中小企業で一人情シスをしている作者が、日々の業務で思うことをつぶやきます。

C#でExcelのバージョンに依存しないCOM経由での操作

C#での社内プログラムでExcelを操作する際、大部分はClosedXMLを利用しているのだが、ActiveXを使用しているなどでうまく動作しない場合にはCOM経由で操作している。

Visual Studioで参照ツリーにExcelのCOM参照を追加するのだが、その時点でPCにインストールされているOfficeのバージョンに対応したCOMを追加する形になる。
ビルド時に参照ツリーにあるCOMを参照するため、参照追加時のPCとビルド時のPCでインストールされているOfficeのバージョンが異なると、ビルド時に警告、またはエラーとなる。

参照追加時には2013、ビルド時に2016だったためにビルド時に警告が出て、そのまま実行すると該当箇所でRuntime Errorでコケる事象が発生した。 社内には、今後2013, 2016が混在する予定のため、どちらかだけしか対応できないとなると困るので、対応方法を調査した。

参照ツリーに追加して開発する形式を事前バインディング、実行時にCOMの名前から該当のCOMを参照する形式を遅延(動的)バインディングというらしい。

  • 事前バインディング
    • Visual StudioでCOMオブジェクトの仕様を把握しているため、補完が効いて開発効率が高い
    • 型情報なども取得済みでコンパイルするため、実行速度は遅延バインディングと比較して速い
    • 使用するOfficeのバージョンを指定する必要がある。
  • 遅延バインディング
    • 使用するOfficeのバージョンを指定する必要がない
    • Visual Studioでの補完は効かず、各オブジェクト、メソッドの情報を調べながら呼び出す必要がある。大変。
    • 実行時に型チェックを行うため、遅い。実行時エラーが出る可能性も。

遅延バインディングは、各メソッドをInvokeMemberで引数を調査しながら呼び出す必要があり、とても大変。以下のサイトにこの大変さをWrapするコードが公開されていた。

Excelの参照を追加せずにExcelを使う[C#]zenmai.wordpress.com とても素晴らしいのでぜひ利用しようと考えたのだが、(当然ながら)COMオブジェクトのすべてが実装されているわけではないので不足個所を追加実装する必要があり、結構大幅な追加が必要と思われた。

で、たどり着いたのがこちらの記事。

teratail.com

なんと、dynamicという宣言に変更するだけで、ビルド時のチェックはやめて実行時に動的に呼び出してくれるとのこと。 (COMオブジェクトの生成部分は固有の書き方への変更が必要)。素晴らしい!!

実際にdyamicに変更したところ、WorkbookオブジェクトへのReleaseComObject呼び出し時にエラーが発生。

hiro-syumi.ldblog.jp こちらの記事を参照させてもらってエラー箇所のみobject型へのキャスト処理を追加したところ、問題なく動作するようになった。

このdynamicの利用だが、最初からこれを前提に行うと上記の通りVisualStudioによるサポートが効かないので開発効率はかなり落ちると思われる。今回のようにCOM参照を追加して事前バインディングで実装したうえで、dynamicに書き換えるという形が効率が良いと感じた。