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;
}
}
}
---サンプルコード ここまで---