I must say: I never use Excel macros - when an analysis becomes so complicated that macros would be justified I don't use Excel at all. Therefore, I never considered to implement xlsm files for fpspreadsheet.
But this site makes me wonder:
https://www.lifewire.com/xlsm-file-2622538. They say here:
XLSM files are actually identical to Microsoft Excel Open XML Format Spreadsheet (XLSX) files with the only difference being that XLSM files will execute embedded macros that are programmed in the Visual Basic for Applications (VBA) language.
So, I'd only have to allow the xlsxm extension to be accepted by fpspreadsheet and xlsm files could be read - no other change needed... BUT: Macros will never (?) be executed by fpspreadsheet. Therefore, xlsm files will only provide the data part, not the code part which certainly is existent here because otherwise the file would have been written with its default extension. For this reason - because fpspreadsheet will not handle xlsm files as expected - I think it is not a good idea to officially support this file extension.
But fpspreadsheet can be extended to user-defined file formats. The essential part is the file reader and writer code -- but we already have it, it is the standard ooxml unit containing the TsSpreadXLSXReader and TsSpreadXLSXWriter (we don't need the latter one). All what has to be done is to call "RegisterSpreadFormat()" (in unit fpsReaderWriter) with the appropriate parameters. The format id returned by the registration is the format parameter to be used in the ReadFromFile() method of the workbook. The workbook then looks up the format id in an internal list and finds the reader class this way.
Therefore, the following code for reading xlsm works:
program read_xlsm;
uses
SysUtils,
fpstypes, fpspreadsheet, fpsutils, fpsreaderwriter, xlsxooxml;
var
wb: TsWorkbook;
sh: TsWorksheet;
xlsmID: Integer;
cell: PCell;
begin
// Register the xlsm file format
xlsmID := RegisterSpreadFormat(
sfUser, // indicator that a user-defined format is registered
TsSpreadOOXMLReader, // class providing the file reader code
nil, // class providing the file writer code - we don't need it.
'Excel 2007+ Macro-Enabled XML', // Item in file format combobox
'OOXML', // Short abbreviation of the format name
['.xlsm'] // Extension(s) of the format
);
// Open a sample xlsm file
wb := TsWorkbook.Create;
try
wb.ReadFromFile('sample.xlsm', xlsmID);
sh := wb.GetFirstWorksheet;
// Display the cells
for cell in sh.Cells do
WriteLn(Format('%s: %s', [GetCellString(cell^.Row, cell^.Col), sh.ReadAsText(cell)]));
finally
wb.Free;
end;
ReadLn;
end.