Seeing some strange results in a sense that Excel C Api is performing way slower than Interop COM objects. I'm wondering if (with the small context of code) you have any guesses.
This message is displayed after running code below:
---------------------------
CalcEngine Audit
---------------------------
00:00:00.0313122
00:00:02.2352662
---------------------------
OK
---------------------------
var sw = System.Diagnostics.Stopwatch.StartNew();
var configuration = new ExcelCalcEngineConfigurationFactory( application.ActiveWorkbook ).Configuration;
sw.Stop();
var elapsedInterop = sw.Elapsed;
sw = System.Diagnostics.Stopwatch.StartNew();
configuration = new ExcelDnaCalcEngineConfigurationFactory().Configuration;
sw.Stop();
var elapsedApi = sw.Elapsed;
MessageBox.Show( $"{elapsedInterop}{Environment.NewLine}{elapsedApi}", "CalcEngine Audit", MessageBoxButtons.OK, MessageBoxIcon.Information );
My two classes are derive from generic class, their signatures are:
public class ExcelCalcEngineConfigurationFactory : CalcEngineConfigurationFactory<MSExcel.Workbook, MSExcel.Worksheet, MSExcel.Range>
public class ExcelDnaCalcEngineConfigurationFactory : CalcEngineConfigurationFactory<ExcelWorkbook, ExcelWorksheet, ExcelReference>
The base `CalcEngineConfigurationFactory` simply loops tabs and ranges and grabs values to build a configuration. I can show that code if needed. There are also some extensions you'll see in the ExcelDna* version - I could show, but again they just wrap XlCall.Excel calls.
The two generic classes are as follows. If you have any guesses why the Interop would work 150x faster than C API let me know :)
public class ExcelDnaCalcEngineConfigurationFactory : CalcEngineConfigurationFactory<ExcelWorkbook, ExcelWorksheet, ExcelReference>
{
public ExcelDnaCalcEngineConfigurationFactory() { }
protected override string FileName => (string)XlCall.Excel( XlCall.xlfGetDocument, (int)GetDocumentType.ActiveWorkbook );
protected override string Version => ExcelApi.GetReference( "Version" ).GetText() ?? "Unknown";
protected override ExcelWorksheet[] Worksheets => new ExcelWorkbook( ExcelApi.Selection ).Worksheets.ToArray();
protected override ExcelWorkbook GetWorkbook( ExcelReference range ) => new( range );
protected override ExcelWorkbook GetWorkbook( ExcelWorksheet sheet ) => sheet.Workbook;
protected override ExcelWorksheet GetSheet( ExcelReference range ) => new( range );
protected override string GetName( ExcelWorksheet sheet ) => sheet.Name;
protected override string? RangeTextOrNull( string name ) => name.GetReferenceOrNull()?.GetText();
protected override string? RangeTextOrNull( ExcelWorksheet sheet, string name ) => name.GetReferenceOrNull( sheet.Name )?.GetText();
protected override ExcelReference GetRange( string name ) => name.GetReference();
protected override ExcelReference GetRange( ExcelWorksheet sheet, string name ) => name.GetReference( sheet.Name );
protected override ExcelReference Offset( ExcelReference range, int rowOffset, int columnOffset ) => range.Offset( rowOffset, columnOffset );
protected override ExcelReference EndRight( ExcelReference range ) => range.End( DirectionType.ToRight );
protected override bool RangeExists( string name ) => name.GetReferenceOrNull() != null;
protected override bool RangeExists( ExcelWorksheet sheet, string name ) => name.GetReferenceOrNull( sheet.Name ) != null;
protected override string GetAddress( ExcelReference range ) => range.GetAddress().Split( '!' ).Last();
protected override string GetText( ExcelReference range ) => range.GetText() ?? "";
protected override string GetFormula( ExcelReference range ) => range.GetFormula() ?? "";
}
public class ExcelCalcEngineConfigurationFactory : CalcEngineConfigurationFactory<MSExcel.Workbook, MSExcel.Worksheet, MSExcel.Range>
{
private readonly MSExcel.Workbook workbook;
public ExcelCalcEngineConfigurationFactory( MSExcel.Workbook workbook ) => this.workbook = workbook;
protected override string FileName => workbook.Name;
protected override string Version => workbook.RangeOrNull<string>( "Version" )!;
protected override MSExcel.Worksheet[] Worksheets => workbook.Worksheets.Cast<MSExcel.Worksheet>().ToArray();
protected override MSExcel.Workbook GetWorkbook( MSExcel.Range range ) => GetWorkbook( range.Worksheet );
protected override MSExcel.Workbook GetWorkbook( MSExcel.Worksheet sheet ) => ( sheet.Parent as MSExcel.Workbook )!;
protected override MSExcel.Worksheet GetSheet( MSExcel.Range range ) => range.Worksheet;
protected override string GetName( MSExcel.Worksheet sheet ) => sheet.Name;
protected override string? RangeTextOrNull( string name ) => workbook.RangeOrNull<string>( name );
protected override string? RangeTextOrNull( MSExcel.Worksheet sheet, string name ) => sheet.RangeOrNull<string>( name );
protected override MSExcel.Range GetRange( string name ) => workbook.RangeOrNull( name )!;
protected override MSExcel.Range GetRange( MSExcel.Worksheet sheet, string name ) => sheet.Range[ name ];
protected override MSExcel.Range Offset( MSExcel.Range range, int rowOffset, int columnOffset ) => range.Offset[ rowOffset, columnOffset ];
protected override MSExcel.Range EndRight( MSExcel.Range range ) => range.End[ MSExcel.XlDirection.xlToRight ];
protected override bool RangeExists( string name ) => workbook.RangeOrNull( name ) != null;
protected override bool RangeExists( MSExcel.Worksheet sheet, string name ) => sheet.RangeOrNull( name ) != null;
protected override string GetAddress( MSExcel.Range range ) => range.Address;
protected override string GetText( MSExcel.Range range ) => range.GetText();
protected override string GetFormula( MSExcel.Range range ) => ( (string)range.Formula )!;
}