Milkのメモ帳

日々の思いつきを忘れないようにのメモ用です。

Milkのメモ帳

【Excelの起動から】 C#でExcelを操作する【保存まで】


こんにちは。Milkです。
ちょっと仕事で、C#経由でExcelを操作しなければならなかったので、メモを残します。

Excelのプログラムでの操作って意外と面倒くさいんですよね・・・

内部でマクロ(VBA)を組むとしても、いろいろ考えなくちゃいけない。

今回の突貫ツールを作成する上で、制約として課されたのが「内部にマクロを入れ込まないこと」

つまり、「外部から何かしらのプログラムでExcelを操作せよ。」ということです。

相性としては、同じMicrosoftの言語である「C#」を選択。

まぁ、昔から使用されるケースは多かったわけですが、「Excelの構造」が理解できないと実装が難しいというのが本音ですね。

過去に何回か実装を行って、最近やっと意味が分かってきたので、メモしときます。

Excelの構造

理解が難しいのは、そもそも「Excelの構造」の部分です。

これが理解できれば、なぜプログラムコードでその部分が必要なのかはすんなり分かってきます。

Excelはツリー構造になっていると表現したらよいでしょうか?

Excelの内部に含まれるもの

以下に図にして表してみました。

何となくイメージは掴めたでしょうか?

まず、Excelをアプリケーションとしてキック(起動)します。

次に、このExcelアプリケーションを通して、必要なExcelのブックファイルを開きます。

単純に1つだけのブックならば、Excel.Workbook型の変数で扱えばいいのですが、複数のブックを同時に扱いたいとなれば、Excel.Workbooks型の変数を用意し、これはブックをリストとして持つことが出来るので、開いたブックをこれに入れていきます。(Addしていく)

さて、1つのブックは複数のシートを持っています。

ですから、Excel.Workbook.Sheets型のリストの状態として管理されています。

あるシートを取り出して操作したいのならば、必要なインデックスを指定して、Excel.Worksheetに格納します。(ただし、参照渡し、つまりポインタです。)

Excelを起動し編集して保存するまで

では基本的な、C#からのExcelの操作方法を見ていきましょう。

dll参照を設定する

必要になるのは、Microsoft Office を操作出来るdllを参照させることから始めます。

参照設定で、「excel」と検索しましょう。

利用している Microsoft Office によってバージョンが異なります。

基本的に同じバージョンのExcel向けに使用出来るツールになることは覚悟して下さい。

「Microsoft Office ○○ Object Library」を追加すると、参照の一覧には、「Microsoft.Office.Core」と「Microsoft.Office.Interop.Excel」のdllが参照されるようになります。

これを、Usingによって利用できるようにするのですが、一般的に以下のようにしてUsingで別名の割当を行います。

using Excel = Microsoft.Office.Interop.Excel;

これによって「Excel.Workbook」 など、短縮して型を利用できるようになります。

ブックをオープンする

それでは、実際にExcelアプリケーションをキックして、ブックをオープンしましょう。

// アプリケーションのオブジェクト
private Excel.Application mExcel;

// ブックのオブジェクト
private Excel.Workbook mWorkbook;

// アプリケーションのインスタンス生成
this.mExcel = new Excel.Application();

// Excelのウィンドウを非表示
this.mExcel.Visible = false;

// ブックのオープン
this.mWorkbook = (Excel.Workbook)(mExcel.Workbooks.Open(
    "Excelファイルのパス",
    Type.Missing,
    Type.Missing,
    Type.Missing,
    Type.Missing,
    Type.Missing,
    Type.Missing,
    Type.Missing,
    Type.Missing,
    Type.Missing,
    Type.Missing,
    Type.Missing,
    Type.Missing,
    Type.Missing,
    Type.Missing));

これで、「mWorkbook」の変数に、開いたブックの情報が格納されるはずです。

「Type.Missing」としているのは、引数で色々とオプションを指定できる部分なんですが、「特に指定しないよ」という意味です。

シートの編集と保存

それでは、次に実際のシートの編集を行いましょう。

// シートを取得する
Excel.WorkSheet SheetSample = (Excel.Worksheet)this.mWorkbook.Sheets[0];

// 値を「A1」に代入
SheetSample.Range["A1"].Value = "文字列を入力";

// 保存
this.mWorkbook.Save();

// ブックをクローズする
this.mWorkbook.Close();

シートをリストの中から抽出します。

今回は、Range関数を使ってExcelのセルの場所を指定しました。

そして、保存を行い、ブックのクローズを行います。

これでブック(Excelファイル)の内容は保存されることになります。

このままの状態で終わると、Excelが起動したままになりますので、これを最後に終了させます。

最終処理

if (null != this.mExcel)
{
    // 警告無視設定
    this.mExcel.DisplayAlerts = false;
    
    // アプリケーションの終了
    this.mExcel.Quit();

    // アプリケーションのオブジェクトの解放
    System.Runtime.InteropServices.Marshal.ReleaseComObject(this.mWorkbook);
    System.Runtime.InteropServices.Marshal.ReleaseComObject(this.mExcel);
}

これで、Excelアプリケーションが終了になります。

最後に、「Marshal」というのを使っていますが、メモリにゴミとしてExcel系のインスタンスが残ってしまう場合があります。

よって、これを強制的に削除しています。
(結構、古くから存在する仕組みなのでメモリ系の部分もしっかり掃除が必要なのです。しかし、ちょっとこの部分は知識不足なので、たぶん・・・ですけどww)

最後に

さて、C#によるExcelの操作の一通りを書いてみました。

特に最後の「最終処理」は、try-catchのfinallyに書くなどして、確実に終わらせる必要があると思います。

そうでないと、バグが発生してツールを起動し直すと、Excelが起動したままどんどん数が増えていってしまいます。

また、どのExcelアプリケーションに対しての操作なのか分からず、思わぬ動作をしバグが再発生する可能性もあります。
(これについては検証してないので、なんとも言い難い・・・しかし、アプリケーションIDで判断などしてないので、この可能性は大だと思う。)

これを応用すれば、Excelファイルの複数の操作は簡単だと思います。

さて、今回はこの辺で。

adios!!