2014年4月24日木曜日

[C#]Excelのマクロ起動

C# で Excel のマクロを実行する処理を書いてみました。

.NET アプリケーションから Office ドキュメントを操作するには、Microsoft Office XX.0 Object Library(COM)経由になります。XXと書いたところがバージョン情報なんですが、バージョン間互換を考えるのが面倒なので(2003、2007で全然違ったりする)、バージョンに依存しない形で実装してみます。

    /// <summary>
    /// マクロ実行
    /// </summary>
    /// <param name="fileName">エクセルファイルパス</param>
    /// <param name="macroName">実行マクロ名</param>
    /// <returns>マクロからの復帰値</returns>
    public static string ExecuteMacro(string fileName, string macroName)
    {
        var result = "";
        var error = "";
        dynamic excel = null;
        dynamic workbooks = null;
        dynamic book = null;
        dynamic sheets = null;

        Type type = Type.GetTypeFromProgID("Excel.Application");
        excel = Activator.CreateInstance(type);
        if (excel != null)
        {
            try
            {
                // 非表示
                excel.DisplayAlerts = false;

                // ワークブック保持
                workbooks = excel.Workbooks;

                // ブックを生成
                book = excel.Workbooks.Open(fileName);

                // シートを保持
                sheets = book.Sheets;

                // マクロ実行
                result = (string)excel.Run(macroName);
            }
            catch (Exception e)
            {
                error = e.Message;
            }


            // 後処理
            dispose(sheets);
            if (book != null)
            {
                book.Close(Type.Missing, Type.Missing, Type.Missing);
                //dispose(book);
            }
            dispose(workbooks);
            if (excel != null)
            {
                excel.Quit();
                dispose(excel);
            }

            if(!string.IsNullOrEmpty(error))
            {
                throw new Exception(error);
            }
        }
        else
        {
            throw new Exception("Excelアプリケーションがインストールされていません。");
        }
        return result;
    }

        /// <summary>
        /// COMオブジェクト破棄
        /// </summary>
        /// <param name="comObject"></param>
        private static void dispose(dynamic comObject)
        {
            try
            {
                if (comObject != null)
                {
                    Marshal.ReleaseComObject(comObject);
                    comObject = null;
                }
            }
            catch
            {
            }
        }



マクロ側から文字列を返すようにしています。マクロのモジュールオブジェクト名とマクロ名が一致しているとエラーになってしまうので注意が必要です。

後処理の book の破棄をコメントアウトしているところですが、Windows8.1+Office2013だと book に触ろうとしただけで例外が起きてしまうので、コメントアウトしています。折角バージョンに依存しないように作ったのにこういうのがあると意味ないですねー。

0 件のコメント:

コメントを投稿