If you have control over the Excel sheet and can place the public sub methods in the ThisWorkbook of the Excel as opposed to under Modules you can use this helper method to invoke the methods and have a .Net exception thrown:
static object CallSub(Workbook workbook, string name)
{
var bindingFlags = BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.InvokeMethod | BindingFlags.OptionalParamBinding;
try
{
return workbook.GetType().InvokeMember(
name,
bindingFlags,
null,
workbook,
new object[] { }, // arguments
null,
CultureInfo.InvariantCulture,
null);
}
catch (TargetInvocationException tie)
{
throw tie.InnerException;
}
}
I found the InvokeMember
idea via How can I capture a Microsoft Access VBA debug error from my C# code? because I checked on Interaction.CallByName
. While you can add a reference to Microsoft.VisualBasic to get that helper class, I opted to strip it down to its bare minimum that just works for a simple method.
This is how you would use it:
var app = new Microsoft.Office.Interop.Excel.Application();
var workbook = app.Workbooks.Open(@"test.xlsm");
try
{
CallSub(workbook, "DivByZero");
}
catch(DivideByZeroException dbz)
{
Console.WriteLine(dbz.Message);
}
Or if you like dynamic
you can do:
var app = new Microsoft.Office.Interop.Excel.Application();
var workbook = app.Workbooks.Open(@"test.xlsm");
dynamic wb = workbook; // cast workbook to dynamic
wb.DivByZero(); // the runtime figures it out for you
Remember that this only works for subs that are in ThisWorkbook. See this image to get a visual on the differences:
