none
System.__ComObjectの参照時に、低確率で、「System.InvalidCastException: 引数の戻り値の型が無効です」が発生する RRS feed

  • 質問

  • C#でExcelのアドインを作成しています。
    アプリからExcelワークブックおよびワークシートの名前(Workbook.NamesやWorksheet.Names)
    を取得するアドインです。
    ほとんどの場合、成功しますが、まれに、次のような例外で、失敗します。
    ---例外ここから---
    System.InvalidCastException: 引数の戻り値の型が無効です。
       場所 System.Runtime.Remoting.Proxies.RealProxy.ValidateReturnArg(Object arg, Type paramType)
       場所 System.Runtime.Remoting.Proxies.RealProxy.PropagateOutParameters(IMessage msg, Object[] outArgs, Object returnValue)
       場所 System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
       場所 System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
       場所 Microsoft.Office.Interop.Excel._Worksheet.get_Names()
       場所 ExcelAddIn1.Ribbon1.TryGetNameFromSheet(Worksheet sheet, Object index) 場所 XXX
    ---例外ここまで---
    リトライ処理などを入れました(例えば10回)が、5回目で成功する場合もありますが、
    10回全て失敗してしまう場合もあります。
    確実にNames.Itemを取得する方法はありますでしょうか。また、この例外について、他の原因が考えられるのでしょうか。
    ご教授ねがいます。
    簡単ですが、サンプルコードを添付します。
    ※サンプルは、ブックオープン時とリボンタブのボタン押下時に、ブックと各シートの名前を取得して、ログ出力するものです
    ---サンプルコード ここから---
    using System;
    using System.Text;
    using Microsoft.Office.Tools.Ribbon;
    using Excel = Microsoft.Office.Interop.Excel;
    using System.Diagnostics;
    namespace ExcelAddIn1
    {
        public partial class Ribbon1 : OfficeRibbon
        {
            Excel.Workbook _thisWorkbook;
            public Ribbon1()
            {
                InitializeComponent();
            }
            private void Ribbon1_Load(object sender, RibbonUIEventArgs e)
            {
                Globals.ThisAddIn.Application.WorkbookOpen +=
                    new Microsoft.Office.Interop.Excel.AppEvents_WorkbookOpenEventHandler(Application_WookBookOpen);
            }
            private void button1_Click(object sender, RibbonControlEventArgs e)
            {
                OutNames();
            }
            void Application_WookBookOpen(Excel.Workbook workbook)
            {
                _thisWorkbook = workbook;
                OutNames();
            }
            void OutNames()
            {
                // ログ出力
                Debug.WriteLine(string.Format("--Workbook Name:{0}", _thisWorkbook.Name));
                int bookNameCount = _thisWorkbook.Names.Count;
                for (int idxName = 1; idxName <= bookNameCount; idxName++)
                {
                    Excel.Name xlName = TryGetNameFromBook(_thisWorkbook, idxName);
                    Debug.WriteLine(string.Format("----Workbook Names[{0}]:{1}", idxName, xlName.Name));
                }
                // シート毎に
                foreach (Excel.Worksheet sheet in _thisWorkbook.Sheets)
                {
                    // ログ出力
                    Debug.WriteLine(string.Format("--Worksheet Name:{0}", sheet.Name));
                    int sheetNameCount = sheet.Names.Count;
                    for (int idxName = 1; idxName <= sheetNameCount; idxName++)
                    {
                        Excel.Name xlName = TryGetNameFromSheet(sheet, idxName);
                        Debug.WriteLine(string.Format("-----Worksheet Names[{0}]:{1}", idxName, xlName.Name));
                    }
                }
            }
            static public Excel.Name TryGetNameFromBook(Excel.Workbook book, object index)
            {
                Excel.Name retName = null;
                string errReason = string.Empty;
                // 10回リトライ
                for (int i = 0; i < 10; i++)
                {
                    try
                    {
                        retName = book.Names.Item(index, Type.Missing, Type.Missing); //←★ここで例外発生
                        if (retName == null)
                        {
                            errReason = "return Name is NULL";
                            goto GETNAMEERR;
                        }
                        else
                            return retName;
                    }
                    catch (Exception ex)
                    {
                        errReason = ex.Message + ex.StackTrace;
                        goto GETNAMEERR;
                    }
                // 取得エラー
                GETNAMEERR:
                    // ログ
                    Debug.WriteLine(string.Format("Excel Error : failed to TryGetNameFromBook( index [{0}]) {1:D} times [{2}]", index, (i + 1), errReason));
                    // 0.1秒待ってリトライ
                    System.Threading.Thread.Sleep(100);
                }
                // あきらめる
                return null;
            }
            static public Excel.Name TryGetNameFromSheet(Excel.Worksheet sheet, object index)
            {
                Excel.Name retName = null;
                string errReason = string.Empty;
                // 10回リトライ
                for (int i = 0; i < 10; i++)
                {
                    try
                    {
                        retName = sheet.Names.Item(index, Type.Missing, Type.Missing);//←★ここで例外発生
                        if (retName == null)
                        {
                            errReason = "return Name is NULL";
                            goto GETNAMEERR;
                        }
                        else
                            return retName;
                    }
                    catch (Exception ex)
                    {
                        StringBuilder b = new StringBuilder();
                        b.Append(" sheet.GetType:");
                        b.Append(sheet.GetType().ToString());
                        b.Append("\r\n");
                        b.Append(" ToString:");
                        b.Append(ex.ToString());
                        b.Append("\r\n");
                        
                        errReason = b.ToString();
                        //errReason = ex.Message + ex.StackTrace;
                        goto GETNAMEERR;
                    }
                // 取得エラー
                GETNAMEERR:
                    // ログ
                    Debug.WriteLine(string.Format("Excel Error : failed to TryGetNameFromBook( index [{0}]) {1:D} times [{2}]", index, (i + 1), errReason));
                    // 0.1秒待ってリトライ
                    System.Threading.Thread.Sleep(100);
                }
                // あきらめる
                return null;
            }
        }
    }
    ---サンプルコード ここまで---
    2011年7月6日 5:45