トップ 差分 一覧 ソース 検索 ヘルプ PDF RSS ログイン

Visual Studio .NET 2003 C#、Excel2000 COM 操作クラス

[カテゴリ:言語]
[カテゴリ:C#]
[カテゴリ:Excel]

=================================
※このページの情報は古いです。20090210
新しいものは
[C#からExcelを操作するライブラリ Ver2]
=================================

Visual Studio .NET 2003 C#、Excel2000 COM 操作クラス

Excel2000にはPIAが提供されていないので、
今のところC#からExcel2000使うのはこれがベストだと思ってます。
Excel2000ベースなので、Excel2003などで動くのもメリットです。

概要

C#からExcelCOM使うとリークしてしまうのが難点。

[Visual Studio .NET 2003 C#、Excel COM 操作]
のようにVBS経由でExcelCOM使うことで回避もできるが、
C#からVBS、VBSからC# へのパラメータ渡しに
手間がかかる。

ここでは正攻法(?)でExcelCOMに1枚クラスを被せることで
使いにくいExcelCOMの存在をできるだけ隠蔽することを試みます。

COMは「Microsoft Excel 9.0 Object Livraly 1.3」を使用します。

細かな話はソースのコメントにも記述してます。

  • クラスを被せることのメリット
    • COMの開放のことを考えなくてよくなる。
      • わずらわしいリークに悩まされることが激減する。
    • COMの戻り値を適切な型にキャストしたりしなくてよい。
      • キャストミスによるトラブルに悩まされることが激減する。
      • インテリセンス(入力支援)が効くので作業効率アップ。
  • クラスを被せることのデメリット
    • ExcelのCOMオブジェクト、メソッド、プロパティを1つずつラッピングする必要がある。
      • 膨大なので全てをラッピングするのは不可能です。

対応してるExcelオブジェクト、メソッド、プロパティ一覧

対応しているのは次のクラス(Excelオブジェクト)、メソッド、プロパティ
のみです。足りないものは既存のものを参考に追加が必要です。

  • class Application
    • bool Visible
    • bool DisplayAlerts
    • Workbooks Workbooks
    • void Quit()
  • class Workbooks
    • Workbook Open(string filename_,bool read_only_,Excel.XlFileFormat format_,string delimiter_)
    • Workbook Open(string filename_, bool read_only_)
    • Workbook Add()
    • int Count
    • Workbook this[int idx_]
    • Workbook this[string name_]
  • class Workbook
    • Sheets Sheets
  • class Sheets
    • int Count
    • Worksheet this[int idx_]
    • Worksheet this[string name_]
  • class Worksheet
    • string Name
    • void Delete()
    • void CopyAfter(Worksheet aft_)
    • void CopyBefore(Worksheet bef_)
    • Range Cells
    • Range Range
    • Range Rows(int row_)
    • Range Columns(int col_)
  • class Range
    • Range this[int row_, int col_]
    • Range this[Range cell1_, Range cell2_]
    • Range Resize(int row_, int col_)
    • bool Delete()
    • bool Delete(Excel.XlDeleteShiftDirection direction_)
    • object Value
    • Font Font
    • Interior Interior
  • class Font
    • int ColorIndex
    • bool Bold
  • class Interior
    • int ColorIndex
    • Excel.XlPattern Pattern

使用例

private void button1_Click(object sender, System.EventArgs e)
{
    lib.SimpleExcel.Application obj_app = new lib.SimpleExcel.Application();

    // 確実にオブジェクトを開放する為、usingは必須
    using(obj_app)
    {
        obj_app.DisplayAlerts = false;
        obj_app.Visible = true;

        // 新規Workbookを開く
        lib.SimpleExcel.Workbook obj_workbook = obj_app.Workbooks.Add();

        // 不要なSheetを削除
//      MessageBox.Show(obj_workbook.Sheets.Count.ToString());
        while (obj_workbook.Sheets.Count != 1)
        {
            obj_workbook.Sheets[2].Delete();
        }
//      MessageBox.Show(obj_workbook.Sheets.Count.ToString());

        // Sheet名付け
        lib.SimpleExcel.Worksheet obj_sheet = obj_workbook.Sheets[1];
        obj_sheet.Name = "data";

        // 配列データをシートへ複写
        object[,] data = {
                { "データ0-0", "データ0-1" },
                { "データ1-0", "データ1-1" },
        };
        obj_sheet.Cells[1, 1].Value = data; // これでは1セルしかコピーされない。
        obj_sheet.Range[obj_sheet.Cells[3, 1], obj_sheet.Cells[4, 2]].Value = data;         // 明示的に範囲指定
        obj_sheet.Cells[5, 1].Resize(data.GetLength(1), data.GetLength(0)).Value = data;    // 配列データをGetLengthして範囲指定

        // セル値を読む
        object val_obj = obj_sheet.Cells[4, 2].Value;
        if ((val_obj as string) != null) 
        {
            MessageBox.Show((string)val_obj);
        }

        // 取得した型を読む
        lib.SimpleExcel.Object obj1 = new lib.SimpleExcel.Object(null, val_obj);
//      MessageBox.Show(obj1.TypeName);

        // 範囲でセル値を読む
        val_obj = obj_sheet.Range[obj_sheet.Cells[3, 1], obj_sheet.Cells[3, 2]].Value;
        string str = "";
        if ((val_obj as object[,]) != null) 
        {
            object[,] obj2 = (object[,])val_obj;
            for (int row = 1; row <= obj2.GetLength(0); row ++)
            {
                for (int col = 1; col <= obj2.GetLength(1); col ++)
                {
                    if ((obj2[row,col] as string) != null)
                    {
                        str += (string)obj2[row,col] + ",";
                    }
                }
                str += "\n";
            }
        }
//      MessageBox.Show(str);

        // 行削除
        obj_sheet.Rows(1).Delete();
        obj_sheet.Rows(1).Delete();
        obj_sheet.Rows(1).Delete();
        obj_sheet.Rows(1).Delete();

        obj_app.Quit();

//      MessageBox.Show("ComObjectCounter=" + lib.SimpleExcel.Base.ComObjectCounter.ToString());
    }
//  MessageBox.Show("ComObjectCounter=" + lib.SimpleExcel.Base.ComObjectCounter.ToString());
    obj_app = null;
}

SimpleExcelクラス

次の参照指定を行っていることとします。

プロジェクト→参照の追加→COMタブ→
Microsoft Excel 9.0 Object Livraly 1.3
X:\Program Files\Microsoft Office\Office\EXCEL9.OLB
using System;
using System.Collections;
using System.Runtime.InteropServices;

namespace lib.SimpleExcel
{
    /// <summary>
    /// Excel関連のオブジェクトを分類する為の独自クラス
    /// </summary>
    public class Object : Base
    {
        private string _type_name = "";

        public Object(Base parent_, object comobj_) : base(parent_, comobj_)
        {
            if (comobj_ == null)
            {
                this._type_name = "null";
            }
            else if (Marshal.IsComObject(comobj_))
            {
                if ((comobj_ as Excel.Range) != null)
                {
                    this._type_name = "Excel.Range";
                }
                else if ((comobj_ as Excel.Range) != null)
                {
                    this._type_name = "Excel.Range";
                }
            }
            if (this._type_name == "")
            {
                Type t = comobj_.GetType();
                this._type_name = t.FullName;
            }
        }

        public string TypeName
        {
            get { return this._type_name; }
        }
    }

    /// <summary>
    /// Base
    /// </summary>
    public abstract class Base : IDisposable
    {
        private static int _com_object_counter = 0;
        private Base _parent = null;
        private ArrayList _childs = null;
        protected object _comobj = null;

        /// <summary>
        /// 現在使用中の Excel COM の数
        /// 0 でない場合、Excelプロセス が開放されていないことになるので、
        /// 本ライブラリでExcel操作後は、必ず0になっている*はず*
        /// </summary>
        public static int ComObjectCounter
        {
            get { return Base._com_object_counter; }
        }

        /// <summary>
        /// Excelのプロセスを取得
        /// IDとウィンドウタイトルから素性を判断できる。
        /// </summary>
        /// <param name="msg_"></param>
        /// <returns></returns>
        public static System.Diagnostics.Process[] GetExcelProcess(ref string msg_)
        {
            System.Diagnostics.Process[] ps =
                System.Diagnostics.Process.GetProcessesByName("Excel");

            msg_ = "";
            foreach (System.Diagnostics.Process p in ps)
            {
                msg_ += string.Format("Id:{0} Title:{1} \r\n", p.Id, p.MainWindowTitle);
            }
            return ps;
        }

        public Base(Base parent_, object comobj_)
        {
//          if (parent_ == null)
//          {
//              System.Windows.Forms.MessageBox.Show("null");
//          }

            this._parent = parent_;
            if (parent_ != null)
            {
                parent_.AddChild(this);
            }

            this._childs = new ArrayList();

            this._comobj = comobj_;
            if (Marshal.IsComObject(this._comobj))
            {
                Base._com_object_counter ++;
            }
        }

        public object ComObject
        {
            get { return this._comobj; }
        }

        protected void AddChild(Base obj_)
        {
            this._childs.Add(obj_);
        }

        public void Dispose()
        {
            // 子を破棄
            if (this._childs != null)
            {
                for (int idx = 0; idx < this._childs.Count; idx ++)
                {
                    Base obj = (Base)this._childs[idx];
                    obj.Dispose();
                }
                this._childs = null;
            }

            // 自分を破棄
            if (this._comobj != null && Marshal.IsComObject(this._comobj))
            {
                Marshal.ReleaseComObject(this._comobj);
                Base._com_object_counter --;
            }
            this._comobj = null;

            // 親情報を削除
            this._parent = null;

            GC.Collect();   // 一応と思っていたら、これがないとExcelで一般保護違反がでることがあった。
        }
    }

    /// <summary>
    /// Excel.Application
    /// </summary>
    public class Application : Base
    {
        public Application() : base(null, new Excel.Application())
        {
        }

        private Excel.Application _application
        {
            get { return (Excel.Application)this._comobj; }
        }

        public bool Visible
        {
            get { return this._application.Visible; }
            set { this._application.Visible = value; }
        }

        public bool DisplayAlerts
        {
            get { return this._application.DisplayAlerts; }
            set { this._application.DisplayAlerts = value; }
        }

        public Workbooks Workbooks
        {
            get { return new Workbooks(this, this._application.Workbooks); }
        }

        public void Quit()
        {
            this._application.Quit();
        }
    }

    /// <summary>
    /// Excel.Workbooks
    /// </summary>
    public class Workbooks : Base
    {
        public Workbooks(Base parent_, object comobj_) : base(parent_, comobj_)
        {
        }

        private Excel.Workbooks _workbooks
        {
            get { return (Excel.Workbooks)this._comobj; }
        }

        public Workbook Open(
            string filename_,
            bool read_only_,
            Excel.XlFileFormat format_,
            string delimiter_
            )
        {
            return new Workbook(this, this._workbooks.Open(
                filename_,
                Type.Missing,
                read_only_,
                format_,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                delimiter_,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing));
        }

        public Workbook Open(string filename_, bool read_only_)
        {
            return new Workbook(this, this._workbooks.Open(
                filename_,
                Type.Missing,
                read_only_,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing,
                Type.Missing));
        }

        public Workbook Add()
        {
            return new Workbook(this, this._workbooks.Add(Type.Missing));
        }

        public int Count
        {
            get { return this._workbooks.Count; }
        }

        public Workbook this[int idx_]
        {
            get { return new Workbook(this, this._workbooks.get_Item(idx_)); }
        }

        public Workbook this[string name_]
        {
            get { return new Workbook(this, this._workbooks.get_Item(name_)); }
        }
    }

    /// <summary>
    /// Excel.Workbook
    /// </summary>
    public class Workbook : Base
    {
        public Workbook(Base parent_, object comobj_) : base(parent_, comobj_)
        {
        }

        private Excel.Workbook _workbook
        {
            get { return (Excel.Workbook)this._comobj; }
        }

        public Sheets Sheets
        {
            get { return new Sheets(this, this._workbook.Sheets); }
        }
    }

    /// <summary>
    /// Excel.Sheets
    /// </summary>
    public class Sheets : Base
    {
        public Sheets(Base parent_, object comobj_) : base(parent_, comobj_)
        {
        }

        private Excel.Sheets _sheets
        {
            get { return (Excel.Sheets)this._comobj; }
        }

        public int Count
        {
            get { return this._sheets.Count; }
        }

        public Worksheet this[int idx_]
        {
            get { return new Worksheet(this, this._sheets.get_Item(idx_)); }
        }

        public Worksheet this[string name_]
        {
            get { return new Worksheet(this, this._sheets.get_Item(name_)); }
        }
    }

    /// <summary>
    /// Excel.Worksheet
    /// </summary>
    public class Worksheet : Base
    {
        public Worksheet(Base parent_, object comobj_) : base(parent_, comobj_)
        {
        }

        private Excel.Worksheet _worksheet
        {
            get { return (Excel.Worksheet)this._comobj; }
        }

        public string Name
        {
            get { return this._worksheet.Name; }
            set { this._worksheet.Name = value; }
        }

        public void Delete()
        {
            this._worksheet.Delete();
        }

        public void CopyAfter(Worksheet aft_)
        {
            // 指定したワークシートの右側へコピー
            // this._worksheet を aft_ の 右側へコピー
            this._worksheet.Copy(Type.Missing, aft_._comobj);
        }

        public void CopyBefore(Worksheet bef_)
        {
            // 指定したワークシートの左側へコピー
            // this._worksheet を bef_ の 左側へコピー
            this._worksheet.Copy(bef_._comobj, Type.Missing);
        }

        public Range Cells
        {
            get { return new Range(this, this._worksheet.Cells); }
        }

        public Range Range
        {
            get { return new Range(this, this._worksheet.Cells); }
        }

        public Range Rows(int row_)
        {
            return new Range(this, this._worksheet.Rows[row_, Type.Missing]);
        }

        public Range Columns(int col_)
        {
            return new Range(this, this._worksheet.Columns[Type.Missing, col_]);
        }
    }

    /// <summary>
    /// Excel.Range
    /// </summary>
    public class Range : Base
    {
        public Range(Base parent_, object comobj_) : base(parent_, comobj_)
        {
        }

        private Excel.Range _range
        {
            get { return (Excel.Range)this._comobj; }
        }

        public Range this[int row_, int col_]
        {
            get { return new Range(this, this._range.get_Item(row_, col_)); }
        }

        public Range this[Range cell1_, Range cell2_]
        {
            get { return new Range(this, this._range.get_Range(cell1_._comobj, cell2_._comobj)); }
        }

        public Range Resize(int row_, int col_)
        {
            return new Range(this, this._range.get_Resize(row_, col_));
        }

        public bool Delete()
        {
            return (bool)this._range.Delete(Type.Missing);
        }

        public bool Delete(Excel.XlDeleteShiftDirection direction_)
        {
            return (bool)this._range.Delete(direction_);
        }

        public object Value
        {
            get { return this._range.Value; }
            set { this._range.Value = value; }
        }

        public Font Font
        {
            get { return new Font(this, this._range.Font); }
        }

        public Interior Interior
        {
            get { return new Interior(this, this._range.Interior); }
        }
    }

    /// <summary>
    /// Excel.Font
    /// </summary>
    public class Font : Base
    {
        public Font(Base parent_, object comobj_) : base(parent_, comobj_)
        {
        }

        private Excel.Font _font
        {
            get { return (Excel.Font)this._comobj; }
        }

        public int ColorIndex
        {
            get { return (int)this._font.ColorIndex; }
            set { this._font.ColorIndex = value; }
        }

        public bool Bold
        {
            get { return (bool)this._font.Bold; }
            set { this._font.Bold = value; }
        }
    }

    /// <summary>
    /// Excel.Interior
    /// </summary>
    public class Interior : Base
    {
        public Interior(Base parent_, object comobj_) : base(parent_, comobj_)
        {
        }

        private Excel.Interior _interior
        {
            get { return (Excel.Interior)this._comobj; }
        }

        public int ColorIndex
        {
            get { return (int)this._interior.ColorIndex; }
            set { this._interior.ColorIndex = value; }
        }

        public Excel.XlPattern Pattern
        {
            get { return (Excel.XlPattern)this._interior.Pattern; }
            set { this._interior.Pattern = value; }
        }
    }

}

最終更新時間:2008年02月17日 18時18分05秒