xlsgen 4.9.0.9 : Range fillFilling cells is an extension of paste where a source area gets duplicated to a larger area multiple times both horizontally and vertically, hence the fill. Creating a range fillAs an example, you could have content at row 3 that according to some scenario needs to be duplicated in rows 6 to 8. If the paste/pasteTo function is used, this needs iteration over rows 6 to 8. But using fill, a single statement will do : C/C++ code |
worksheet->Rows[L"3:3"]->Range->FillTo(worksheet, worksheet->Rows[L"6:8"]->Range, xlsgen::pasteoption_valuesandformattingandformulas);
|
Another example is range C3:F4 that gets used in order to fill range B5:Z8 of another worksheet : C/C++ code |
worksheet->NewRange(L"C3:F4")->FillTo(worksheet2, worksheet2->NewRange(L"B5:Z8"), xlsgen::pasteoption_valuesandformattingandformulas);
|
|  |  | Posted on 02-May-2021 18:02 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.9.0.8 : Fix for pivot table report filters Build 4.9.0.8 of xlsgen fixes a problem for generating custom report filters in pivot tables. The bug appeared in XLSX and XLSB files.
|  |  | Posted on 18-April-2021 10:56 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.9.0.7 : Rust programming languageBuild 4.9.0.7 of xlsgen adds support for Rust as a programming language. xlsgen supports Rust as a programming language which allows to build rust applications of any size and complexity. Rust in xlsgenRust is a functional language popularized in a number of environments and places, and it turns out that it can also make low-level calls. The xlsgen install package takes advantage of this and comes with an interface layer (called xlsgen.rs ) which exposes the entire object model to Rust code environments. Both enumerated types and interfaces are available. It is assumed that the basic Rust development or runtime environment is installed on the computer. The xlsgen interface layer does not use any particular feature of a recent Rust version, so most likely any Rust version of the language and environment is compatible with it. In fact, what xlsgen relies on is the Rust winapi crate, which provides a number of Windows types and macros that make it easier to expose and handle. Here is how a simple Rust program looks like in structure : - src | |- main.rs (your code goes here) |- xlsgen.rs (xlsgen interface layer (available from the xlsgen install package)) - Cargo.toml (known dependency declaration (winapi))
Here is how you build it : cd \tmp\rust\simple cargo build
Here is how you run it : cd \tmp\rust\simple cargo run
During the first run, the package manager will download a compatible version of the winapi crate in order to meet the dependency specifications, so the compuer where this runs must be online and ready to download stuff, even though this stuff has nothing to do with xlsgen. xlsgen.rs on the other hand is part of the xlsgen install package, so it can be copied over in your source code folder structure. xlsgen.rs is computer-generated by a tool that was designed to convert a COM IDL object model to a Rust compatible object model. Rust can execute low-level statements, but because of what they are those statements have to be enclosed inside an unsafe section. Here is how you put a number in cell B4 : let _hr = unsafe { (*p_worksheet).put_float(4, 2, 4.5); };
The return value of any call is a HRESULT, i.e. a value of zero means everything went fine, and you can look up winerr.h to find the list of existing HRESULT errors (for instance 0x80070057 = invalid parameter). Before you can load xlsgen in memory, the COM library must be loaded, which means a paired CoInitialize/CoUninitalize call. In Rust, all depending types must be declared, tha's why your typical application will include statements such as : use winapi::{Class, Interface};
Last but not least, Rust macros can help group code patterns together. For instance, if you'd like to create a pointer to an object, initialize to null, you would declare a macro like this : macro_rules! new_pointer { ($param:ident, $type:ty) => {let mut $param: *mut $type = unsafe { std::mem::zeroed() };} }
And then you would use this macro like this : new_pointer!(p_engine, xlsgen::IXlsEngine);
Here is a Rust sample application in full that creates a spreadsheet with two sheets, puts a couple numbers in it and reads back the content of a cell. It's available in the /samples folder of the xlsgen install : use winapi::um::winnt::{LPWSTR}; use winapi::{Class, Interface}; use std::ffi::{OsStr, OsString}; use std::os::windows::ffi::OsStrExt; use std::os::windows::ffi::OsStringExt; use std::slice;
pub mod xlsgen;
// *** MACROS begin here ***
macro_rules! retVal { ($param:ident) => {&mut $param as *mut _ as *mut _} }
macro_rules! new_pointer { ($param:ident, $type:ty) => {let mut $param: *mut $type = unsafe { std::mem::zeroed() };} }
macro_rules! release_pointer { ($param:ident) => { unsafe { (&mut * $param).Release() }; } }
macro_rules! release_bstr_string { ($param:ident) => { unsafe { winapi::um::oleauto::SysFreeString( $param as LPWSTR ) }; } }
// *** MACROS end here ***
// unicode strings (Rust stores strings using UTF8 encoding, not UTF16) so we have to convert back and forth
fn to_wstring(string: &str) -> Vec<u16> { let mut v: Vec<u16> = OsStr::new(string).encode_wide().collect(); v.push(0); // EOL v }
fn from_wstring(string: LPWSTR) -> String { let string_slice = unsafe { let len = winapi::um::oleauto::SysStringLen(string); slice::from_raw_parts(string, len as usize) };
OsString::from_wide(string_slice).into_string().unwrap() }
fn main() {
println!("step1");
let _hr = unsafe { winapi::um::objbase::CoInitialize(std::ptr::null_mut()) };
println!("step2");
new_pointer!(p_engine, xlsgen::IXlsEngine);
let _hr = unsafe { winapi::um::combaseapi::CoCreateInstance( &xlsgen::XlsEngine::uuidof(), std::ptr::null_mut(), winapi::shared::wtypesbase::CLSCTX_INPROC_SERVER, &xlsgen::IXlsEngine::uuidof(), retVal!(p_engine)) };
println!("step3 {}", _hr);
new_pointer!(p_workbook, xlsgen::IXlsWorkbook);
let _hr = unsafe { (*p_engine).new(to_wstring("d:\\tmp\\eer.xlsx").as_ptr(), retVal!(p_workbook)) };
new_pointer!(p_worksheet1, xlsgen::IXlsWorksheet);
let _hr = unsafe { (*p_workbook).addworksheet(to_wstring("sheet 1").as_ptr(), retVal!(p_worksheet1)) };
new_pointer!(p_worksheet2, xlsgen::IXlsWorksheet);
let _hr = unsafe { (*p_workbook).addworksheet(to_wstring("sheet 2").as_ptr(), retVal!(p_worksheet2)) };
println!("step4");
let mut i_wksht_count : i32 = 0;
let _hr = unsafe { (*p_workbook).get_worksheetcount(&mut i_wksht_count) };
println!("step4a {}, wkshtCount = {}", _hr, i_wksht_count);
unsafe { (*p_workbook).put_factorizedstringsmode(true) };
let mut b_factorized : bool = false;
let _hr = unsafe { (*p_workbook).get_factorizedstringsmode(&mut b_factorized) };
println!("step4ab {}, bFactorized = {}", _hr, b_factorized);
// write some content for r in 1..10 { let _hr = unsafe { (*p_worksheet1).put_label(r, 2, to_wstring("hello world").as_ptr()) }; }
// read some content
println!("step4b");
new_pointer!(cell_string, LPWSTR);
println!("step4c");
let _hr = unsafe { (*p_worksheet1).get_label(3, 2, retVal!(cell_string)) };
println!("step5");
println!("cell value is : {}", from_wstring(cell_string as LPWSTR));
println!("step6");
new_pointer!(p_richlabel, xlsgen::IXlsRichLabel);
println!("step6b");
let _hr = unsafe { (*p_worksheet1).newrichlabel(retVal!(p_richlabel)) };
println!("step6c {}", _hr);
let _hr = unsafe { (*p_richlabel).put_htmllabel(to_wstring("<span>hello <b>world</b></span>").as_ptr()) };
println!("step6d");
let _hr = unsafe { (*p_worksheet1).put_richlabel(1, 4, p_richlabel) };
println!("step6e");
let _hr = unsafe { (*p_workbook).close(); };
println!("step7");
release_bstr_string!(cell_string); release_pointer!(p_worksheet1); release_pointer!(p_worksheet2); release_pointer!(p_workbook); release_pointer!(p_engine);
unsafe { winapi::um::combaseapi::CoUninitialize() };
println!("step8");
}
Here is an excerpt from xlsgen.rs : (...)
RIDL!{#[uuid(0xD97500CF,0x37CC,0x48fd,0x87,0x72,0x0E,0xBC,0x8F,0x8A,0x93,0x76)] interface IXlsEngine(IXlsEngineVtbl): IDispatch(IDispatchVtbl) { fn new( // creates a new .xls/.xlsx file with the name (filename or filepath) passed in parameter. excelfilename : LPCWSTR, workbook : *mut *mut IXlsWorkbook, ) -> HRESULT,
(...)
RIDL!{#[uuid(0x12B7B224,0xC026,0x4eb6,0xBA,0x94,0xC4,0x9B,0x91,0x6F,0x77,0x40)] interface IXlsWorkbook(IXlsWorkbookVtbl): IDispatch(IDispatchVtbl) { fn addworksheet( // creates a new worksheet with the name passed in parameter. The following characters are forbidden : / \\ : * [ ], and the name must be less than 32 characters long. name : LPCWSTR, worksheet : *mut *mut IXlsWorksheet, ) -> HRESULT,
(...)
RIDL!{#[uuid(0xB150D9DA,0x1F10,0x4850,0x9A,0xBB,0x76,0xD9,0x95,0x47,0x96,0xEE)] interface IXlsWorksheet(IXlsWorksheetVtbl): IDispatch(IDispatchVtbl) { fn put_label( // puts a label in a cell. row : i32, col : i32, label : LPCWSTR, ) -> HRESULT,
|  |  | Posted on 17-April-2021 18:37 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.9.0.6 : Fix for relative cells (II) Build 4.9.0.6 of xlsgen fixes another problem related to relative cells and inserting/deleting rows and columns. This time the problem could corrupt the Excel file without producing an error message, and was related to rebuilding internal shared formulas.
|  |  | Posted on 07-April-2021 19:27 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.9.0.5 : Fix for relative cells Build 4.9.0.5 of xlsgen fixes a problem related to manipulating rows/columns with formulas using partially relative rows or columns, such as R$170 (R is relative as a column, 170 is an absolute reference due to the presence of the $ prefix). Inserting, deleting rows or columns would corrupt such formulas. There was no problem with cell references either not relative at all (for instance $A$5), or both relative for rows and columns (for instance A5).
|  |  | Posted on 24-March-2021 18:22 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.9.0.4 : Style optimisation xlsgen 4.9.0.4 adds a new property to the xlsgen object model, to be used before loading files. This Style optimisation property allows to disable the style optimisation algorithm done by xlsgen on behalf of the client application, trying to remove useless styles. This algorithm is on by default and has been going on for years, it is nothing new. By setting this property as false, the algorithm is disabled, in order to meet scenarios where style optimization is not expected to occur (i.e. pure template scenarios).
engine.Workbooks.StyleOptimisation = False
engine.Open("mytemplatefile.xlsx", "")
...
|  |  | Posted on 24-February-2021 12:48 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.9.0.3 : Elapsed timeBuild 4.9.0.3 of xlsgen adds direct support for elapsed time, i.e. time used with either hour, minute or second enclosed in square brackets, as in [hh]:mm:ss in order to display out of boundaries numbers. Using elapsed time, you can display with 30:00:00 the fact that you've had an event lasting 30 hours, notably bypassing the implicit limit of 24 hours. All it takes is to pass 30:00:00 as a date and apply a number format of the form [h]:mm:ss. It works like this : worksheet->Cell[2][1]->HtmlDate = L"<div format=\"[h]:mm:ss\">30:00:00</div>"; In Excel this is effectively stored as an elapsed duration of 30 hours, not a display artefact. Which means that formulas that depend on it can do their calculations properly. Square brackets can apply to minutes or seconds as well, to represent an arbitrary duration in minutes or seconds. This feature has been in Excel just about forever, but it was not added to xlsgen until now. |  |  | Posted on 26-January-2021 18:06 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.9.0.2 : Fix pack for memory leaks Build 4.9.0.2 of xlsgen removes half a dozen memory leaks, in all parts of the library. This makes sustained scenarios better work.
|  |  | Posted on 25-January-2021 15:30 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.9.0.1 : Retargeting name scope Build 4.9.0.1 of xlsgen makes it possible to retarget the scope of a defined name. Particularly make it local to a sheet. To that end, the Local property of existing named ranges can be set accordingly as in :
// let's say we have two sheets, Sheet1 and Sheet2
// also let's say range2 = Sheet2!R2C2:R20C5, and of global scope
workbook->WorksheetByName[L"Sheet1"]->DynamicRange[L"range2"]->Local = TRUE; // tell range2 to be local to Sheet2
|  |  | Posted on 11-December-2020 09:02 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.9 ships ! xlsgen 4.9 developer friendly edition ships !
Features, most notably :
- multithreaded calc engine - PDF Unicode and font embedding - SVG charts - HTML markup for rich labels - Rendering treemaps and sunbursts - Advanced OpenOffice - Performance improvements
|  |  | Posted on 26-November-2020 06:27 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.9 preview #7 : Improved LibreOffice/OpenOfficexlsgen 4.9 adds the following support to LibreOffice/OpenOffice files : - read existing pivot tables
- write pivot charts (introduced in libre office 5.4.1)
- read cell data validations
- read auto filter and custom filters
- improved writing of custom filters
|  |  | Posted on 25-November-2020 11:38 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.9 preview #6 : Performance improvementsxlsgen 4.9 includes performance improvements. Those are particularly noticeable in server scenarios where xlsgen runs for long periods of time. - for reading and creating XLS files, memory consumption much lowered by defaulting to 4KB blocks instead of 64KB blocks
- for reading chart formatting details from any Excel file, memory leak removal
|  |  | Posted on 25-November-2020 11:36 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.9 preview #5 : Chart renderingsxlsgen 4.9 improves chart renderings in multiple ways : - Rendering of treemaps and sunbursts. (outputs : PNG, PDF, SVG)
- Avoid chart element overlap wherever possible, for instance make sure the legend never overlaps with the plot area
- Additional chart element formatting that were not supported in past xlsgen versions
xlsgen 4.9 renders treemaps and sunbursts, charts which were introduced in Excel 2016 and were already supported in read and write. Those two charts are particularly suited when the data being charted is hierarchical in nature. For instance if you have multiple level of time groups in a timeline, or multiple level of particular regions in a geographical division. The multiple levels are taken as chart categories. Categories usually are a single row or a single column. With multiple levels of depth, it's more than one row or more than one column. Rendering treemaps in xlsgenAnd here is how you can create this : xlsgen::IXlsChartPtr chartTreemap = worksheet->NewChart(xlsgen::charttype_treemap, 9, //row1 2, //col1 25, //row2 9 //col2 );
chartTreemap->MainTitle->Label = L"treemap"; xlsgen::IXlsChartDynamicDataSourceSeriesPtr s1 = chartTreemap->DynamicDataSource->AddSerie(); s1->SeriesValuesFormula = L"=Sheet1!$D$2:$D$6"; s1->DataLabelsFormula = L"=Sheet1!$A$2:$C$6"; // Categories with 3 levels of depth
chartTreemap->ExtractAsPNG(L"treemap.png");
Rendering sunbursts in xlsgen
xlsgen::IXlsChartPtr chartSunburst = worksheet->NewChart(xlsgen::charttype_sunburst, 27, //row1 2, //col1 43, //row2 9 //col2 );
chartSunburst->MainTitle->Label = L"sunburst"; xlsgen::IXlsChartDynamicDataSourceSeriesPtr s2 = chartSunburst->DynamicDataSource->AddSerie(); s2->SeriesValuesFormula = L"=Sheet1!$D$2:$D$6"; s2->DataLabelsFormula = L"=Sheet1!$B$2:$C$6"; // Categories with 2 levels of depth
chartSunburst->ExtractAsSVG(L"sunburst.svg");
As for when to choose sunbursts over treemaps, sunbursts show the entire depth of categories, as in rings, whereas treemaps show a less detailed depth of categories. |  |  | Posted on 25-November-2020 11:26 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.9 preview #4 : Advanced HTML markupxlsgen 4.9 adds HTML markup to all rich label formattings, not only in cells. Rich label formatting is in many other places, notably text boxes, comments, vector shapes, chart elements (titles, data labels, ...), and the only way so far to put more than one formatting run in rich labels was to create multiple styles and pass them. In other word, there wasn't for the rich label object model, the same mechanism that was added years ago for cells, which is the ability to either pass styles (one style for each formatting run) or use HTML markup. So what xlsgen 4.9 introduces is the ability to use HTML markup as well in general purpose rich labels. Of course, you can also read existing formatting runs and obtain the HTML markup. Last but not least, the automatic source code generator tool exposes the HTML markup in rich labels. So if you open Excel, insert a text box, write this This is blue text in it, save the file, then open the automatic source code generator, you'll get the following source code fragment in the programming language of your choice, here C/C++ : xlsgen::IXlsTextBoxPtr textbox001s0 = wksht001->NewTextBox(4, 3, 9, 7, 38, 208, 128, 896); xlsgen::IXlsRichLabelPtr richLabel001s000c0 = wksht001->NewRichLabel(); richLabel001s000c0->HtmlLabel = L"<font color=#000000 size=11 name=\"Calibri\"><b>This is </b></font><font color=#00B0F0 size=11 name=\"Calibri\"><b>blue </b></font>" \ L"<font color=#000000 size=11 name=\"Calibri\"><b>text</b></font>"; textbox001s0->RichLabel = richLabel001s000c0;
Before this, here is what you had to write : xlsgen::IXlsTextBoxPtr textbox001s0 = wksht001->NewTextBox(4, 3, 9, 7, 38, 208, 128, 896);
xlsgen::IXlsStylePtr styleDefault = wksht001->NewStyle(); styleDefault->Font->Bold = TRUE; styleDefault->Apply();
xlsgen::IXlsStylePtr styleBlue = styleDefault->Duplicate(); styleBlue->Font->Color = 0x0000FF; styleBlue->Apply();
xlsgen::IXlsRichLabelPtr richLabel001s000c0 = wksht001->NewRichLabel(); richLabel001s000c0->Label(L"This is ", styleDefault); richLabel001s000c0->Label(L"blue ", styleBlue); richLabel001s000c0->Label(L"text", styleDefault);
textbox001s0->RichLabel = richLabel001s000c0;
|  |  | Posted on 24-November-2020 11:18 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.9 preview #3 : SVG chartsxlsgen 4.9 introduces charts using the SVG file format. It is now possible to export one or more charts as SVG, or Scalable Vector Graphics. This W3C norm is now very popular on the web thanks to the nature of SVG, i.e. vector-based drawing along with its effectiveness when specifying complex combinations (clipping, gradients, ...). It is also more efficient in size. Here is a sample chart in PNG, PNG chartand then the same in SVG, SVG chartTo get this, just write : currentWorksheet.Charts.Item(2).ExtractAsSVG("c:\\tmp\\export.svg"); Of course, all chart types and their formatting details can be exported as SVG, including the new charts we are introducing in xlsgen 4.9 When SVG charts are part of an HTML page, the beauty of it is that instead of having to worry about retrieving secondary parts (images are binary elements that are loaded after the HTML page itself is loaded), SVG charts can now be part of the HTML page itself, right within the HTML markup, and so it's much simpler to handle if you are serving HTML pages on your server. By default, HTML export in xlsgen uses bitmap charts (PNG files), but all it takes is the following line of code to replace PNG charts with SVG charts during HTML export : workbook.ChartEngine = enumChartEngine.chartengine_svg; |  |  | Posted on 24-November-2020 10:21 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.9 preview #2 : PDF font embeddingxlsgen 4.9 improves PDF output in the following ways : - Unicode fonts : prior to this, only ANSI characters in Excel files would be encoded correctly in PDF files. That would leave much of eastern languages unsupported. With Unicode fonts, PDF files use whatever character from whatever encoding.
- Font embedding : the embedding of the subset of fonts actually used in the Excel file ensures that PDF readers can accurately display characters for viewing and printing purposes. This is activated by default, meaning that such PDF files are bigger in size from those not embedding the fonts. For this reason, font embedding can be disabled by setting the boolean value to the corresponding export option :
C/C++ code | worksheet->Export->Options->FontEmbedding = FALSE;
|
- improved character spacing : even though PDF is character-based, fonts are not. Accurate spacing depends on actual glyph bounding boxes and this is taken care of to improve the reading of words in PDF files.
|  |  | Posted on 23-November-2020 07:59 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.9 preview #1 : multithreaded calculation enginexlsgen 4.9 introduces a multithreaded calculation engine. xlsgen multithreaded calculation engine can be taken advantage of to accelerate calculations or just avoid having many CPU cores staying idle. Here is a snapshot of a calculation scenario using single thread calculations :  Single thread calculations (notice the 24% overall usage and the bottom right chart) |
And here is the same calculation scenario with all of the 6 CPU cores of that i5-9400 taken to handle the calculations :  Mlutithread calculations (notice the 100% overall usage and all charts) |
The amount of worker threads is up to the client application. Of course, if you are running a CPU with n cores, it makes sense to create no more than n worker threads otherwise threads will be waiting one another, not doing work in parallel. If you don't know how many cores the CPU where xlsgen runs has, it can be queried very easily : C/C++ code |
int nbCores = workbook->CalculationOptions->MultithreadCores;
|
And then, creating n worker threads for next calculations is just as simple : C/C++ code |
workbook->CalculationOptions->MultithreadCores = n;
workbook->CalculateFormulas();
|
|  |  | Posted on 22-November-2020 10:01 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.9 developer friendly editionxlsgen 4.9 is coming and the theme for this next major release is developer friendliness. More than half of the features are actually meant to make existing tasks easier to write and use, such as PDF engine improvements, chart rendering improvements, HTML markup improvements, and so on. Over the next few days, we'll be previewing details. And also new features such as the introduction of multithreaded calculations, SVG chart export and so on.  |  |  | Posted on 22-November-2020 09:57 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.5.0.99 : Fix for HTML in cells (III) Build 4.5.0.99 of xlsgen fixes a problem related to content with multiple formatting runs in cells, particularly for the calculation of the height of autofit.
|  |  | Posted on 20-November-2020 13:22 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets xlsgen 4.5.0.98 : Fix for rendering Build 4.5.0.98 of xlsgen has two fixes related to rendering :
- some merged cells incorrectly (by Excel!) storing a different style (particularly background color) across the cells, still have to be rendered using only the style referenced in the top left corner of the merged cells area
- in XLSX files, some HTML encoded characters were not parsed correctly to Unicode
|  |  | Posted on 14-October-2020 09:49 | Category: xlsgen, Excel generator | Tags: generating Excel spreadsheets <-- previous page
|
|