A C++ Language Conversation with Bjarne Stroustrup Hosted by David Intersimone “David I”

This session was presented by David Intersimone as part of Embarcadero’s CodeRage 2018 virtual developers conference. The conversation took place live online on December 4, 2018.

Bjarne Stroustrup (designer and original implementer of C++, Managing Director in the technology division of Morgan Stanley in New York City and a Visiting Professor in Computer Science at Columbia University) participated in a C++ conversation with David Intersimone “David I” (Embarcadero MVP). Bjarne recently attended the ISO C++ committee meeting in San Diego where committee members continued work on the next International Standard (IS), C++20.

This CodeRage conversation covered some of the recent language proposals as well as other important C++ features that will be included in the future. Specific C++ areas David asked about included the future of generic programming (Concepts), how to better organize C++ code (Modules), and how to ensure stability in the language while also allowing the language to evolve.

Books by Bjarne Stroustrup

A Tour of C++ (C++ In-Depth Series) 3rd Edition

Programming: Principles and Practice Using C++ (2nd Edition) 2nd Edition

The C++ Programming Language, 4th Edition 4th Edition

Using Python4Delphi with C++Builder VCL applications

Some C++ developers also use Python for their application development. There are several ways to integrate the two languages together. One way is to create Python extension modules containing C++ functions that implement new object types and functions. Another way is to use the Boost Python C++ library that enables interoperability between the Python and C++ languages. A third way is to use the productivity, resusability, and encapsulation of components to to integrate C++Builder and Python. In this chapter you’ll learn how to use the Python4Delphi open source components in your VCL applications.

Introduction to Python4Delphi (and C++Builder)

Python for Delphi (P4D) is a set of free components (MIT Open Source License), created by Kiriakos Vlahos author of the popular PyScripter Python IDE, that wrap up the Python DLL into Delphi. The components allow you to create or extend your Delphi and C++Builder applications to execute Python scripts, create new Python modules and new Python types. You can also create Python extensions as DLLs and much more.

You’ll find Python4Delphi on GitHub at https://github.com/pyscripter/python4delphi. The GitHub project includes a readme file, installation notes, supported platforms, how Python4Delphi finds your Python distributions, tutorials and demos.

Jim McKeeth recently hosted a webinar with Kiriakos, “Python for Delphi Developers Part 1 – Introduction” (replay is available on YouTube). A Part 2 Python for Delphi Developers will take place on Wednesday, October 14, 2020 at 7am Pacific Time. While this webinar series focuses on Delphi programming, it also provides information about the Python4Delphi components and Python programming that can help C++Builder developers.

While the webinar and Python4Delphi speaks to Delphi developers, C++Builder developers can compile and install the components for use in their Win32 and Win64 C++ VCL applications. To build and install the Python4Delphi components you can use all editions of C++Builder (community, professional, enterprise and architect) and RAD Studio (professional, enterprise and architect) for versions 10.3.3, 10.4 and 10.4.1. If you only have C++Builder, you’ll learn how to use the included Delphi DCC32 and DCC64 command line compilers to build the Delphi component package project and install the components.

Installing Python for Windows (32 and 64 bit)

Before you start using the Python4Delphi components in your C++Builder VCL applications you’ll need to make sure you have Python for Win32 and Win64 installed on your computer.

You can download and install releases of Python from the Python.org web site. For Win32 and Win64 you will find installers at https://www.python.org/downloads/windows/

To find Python distributions installed on your computer, use the “where python.exe” Windows command.

By default, Python for Win32 installs into the C:\Users\david\AppData\Local\Programs\Python\Python39-32\ folder (or wherever you tell the install to put the distribution).

By default, Python for Win64 installs into the C:\Users\david\AppData\Local\Programs\Python\Python39\ folder (or wherever you tell the install to put the distribution).

Installing Python4Delphi and Using the Components

The following are the steps I followed to download and build the Python4Delphi components for use with C++Builder 10.3.3, 10.4 and 10.4.1. While I used RAD Studio (which includes C++Builder and Delphi), you can also use C++Builder along with the Delphi command line compilers to compile and install the components.

Step 1 – Download the latest release of the Python4Delphi

Grab the python4delphi-master.zip file (https://github.com/pyscripter/python4delphi) and unzip it to your hard drive (I put it in my C:\Users\david\Documents\Embarcadero\Studio\Projects/ folder).

Step 2 – In the IDE open the Python_D package project file (RAD Studio editions)

In the C++Builder 10.4.1 RAD Studio IDE, open the Python_D.dproj package project file (you’ll find it in the “python4delphi-master\Packages\Delphi\Delphi 10.4+” folder).

Step 3 – Add an $IFDEF around the requires DesignIDE unit

Look at the Python_D.dpk source file, if you don’t see an $IFDEF around the DesignIDE unit, add it to avoid a compiler error when using the Win64 C++ compiler – DesignIDE is only required for Win32 since the IDE is a 32-bit Windows app.

Notice (in the source code above) that the LibSuffix Delphi compiler directive is set to “AUTO”. This can be done in source code or in the Project | Options | Description page (in the image below) to match the package file suffix with other compiled package files. The suffix is applied before the file extension. In drop down list, you can select the $(Auto) option for the suffix to represent the compiler version suffix for binary package files.

There is a separate Python_D.dpk package source file for versions 10.3 and earlier in the “python4delphi-master\Packages\Delphi\Delphi 10.3-” folder. In this package source file there are $IFDEFs to set the LIBSUFFIX for several recent Delphi compiler releases.

If you are going to use this earlier Python_D.dpk project you may need to comment out (or remove) the “{$R *.res}” statement at the front of the package source file (it may have already been removed in the latest commit of Python4Delphi).

Step 4a – Build and Install the Python4Delphi components with RAD Studio

There are two ways to build and install the components depending on whether you have RAD Studio or one of the C++Builder editions. If you only have C++Builder skip to “Step 4b” to learn how to use the Delphi command line compilers for Win32 and Win64.

Set the Python4Delphi Project Options for the Delphi Compiler | C/C++ Output file generation for Win32 and Win64 platform (all configurations – debug and release). Build and Install the Python4Delphi components for Win32 and Win64 targets.

Building and installing the components will make sure you have the generated C++ header files, package import library files and package static library files for your C++ VCL Win32 and Win64 projects.

From the help file: the “Generate all C++Builder files (including package libs)” option generates the package and all Delphi pieces, along with all necessary header files (.hpp), package import library file (.bpi), and package static library file (.lib and .a) for C++ projects. This is the default in desktop platforms.

Set the Delphi Compiler Search Path to include the Python4Delphi source directory so that the compiler will find any required include files and other files.

Step 4b – Use the Delphi command line compilers to Build and Installing the components

You can use batch files (or other script files) that run the Delphi command line compilers for Win32 (DCC32.exe) and Win64 (DCC64.exe). These Delphi compilers (included in the bin folder) will build the Python4Delphi package file and create the C++ header files, compiled package file, static library and other files required for use in your C++ applications.

CompilePython4DelphiPackage4Win32.bat

@ECHO OFF
ECHO Compiling Python4Delphi Component Package for Win32
dcc32 Python_D.dpk ^
-I"C:\Users\david\Documents\Embarcadero\Studio\Projects\Python4Delphi\python4delphi-master\Source" ^
-LE"C:\Users\Public\Documents\Embarcadero\Studio\20.0\Bpl" ^
-LN"C:\Users\Public\Documents\Embarcadero\Studio\20.0\Dcp" ^
-NH"C:\Users\Public\Documents\Embarcadero\Studio\20.0\hpp\Win32" ^
-NB"C:\Users\Public\Documents\Embarcadero\Studio\20.0\Dcp" ^
-E"C:\Users\Public\Documents\Embarcadero\Studio\20.0\Dcp" ^
-JL ^
--lib-suffix:260 ^
-NSsystem;vcl;winapi;system.win ^
-u"c:\program files (x86)\embarcadero\studio\20.0\lib\win32\release"

move /y "C:\Users\david\Documents\Embarcadero\Studio\Projects\Python4Delphi\python4delphi-master\Packages\Delphi\Delphi 10.3-\Python_D.lib" "C:\Users\Public\Documents\Embarcadero\Studio\20.0\Dcp\Python_D.lib"

ECHO Completed Python4Delphi Component Package Win32
pause

CompilePython4DelphiPackage4Win64.bat

@ECHO OFF
ECHO Compiling Python4Delphi Component Package for Win64
dcc64 Python_D.dpk ^
-I"C:\Users\david\Documents\Embarcadero\Studio\Projects\Python4Delphi\python4delphi-master\Source" ^
-LE"C:\Users\Public\Documents\Embarcadero\Studio\20.0\Bpl\Win64" ^
-LN"C:\Users\Public\Documents\Embarcadero\Studio\20.0\Dcp\Win64" ^
-NH"C:\Users\Public\Documents\Embarcadero\Studio\20.0\hpp\Win64" ^
-NB"C:\Users\Public\Documents\Embarcadero\Studio\20.0\Dcp\Win64" ^
-E"C:\Users\Public\Documents\Embarcadero\Studio\20.0\Dcp\Win64" ^
-JL ^
--lib-suffix:260 ^
-NSsystem;vcl;winapi;system.win ^
-u"c:\program files (x86)\embarcadero\studio\20.0\lib\win64\release"

move /y "C:\Users\david\Documents\Embarcadero\Studio\Projects\Python4Delphi\python4delphi-master\Packages\Delphi\Delphi 10.3-\Python_D.a" "C:\Users\Public\Documents\Embarcadero\Studio\20.0\Dcp\Win64\Python_D.a"

ECHO Completed Python4Delphi Component Package Win64
pause

Install he Python4Delphi Package

In the C++Builder IDE, use the Components | Install Packages menu item and click the “Add…” button.

Navigate to the C:\Users\Public\Documents\Embarcadero\Studio\21.0\Bpl folder (the number will depend on which version of C++Builder you have) and select the Design time package (BPL) file and click the Open button. This will add the package and components to the IDE. You’ll now see “Components for Python” in the list of Design time packages. Highlight the entry and click the Components button to display the list of components in the package.

Step 4c – Verify that the generated Python4Delphi files for C++ use are generated

After you compile the Python4Delphi package project for Win32 and Win64 target platforms the following files will be generated:

C:\Users\Public\Documents\Embarcadero\Studio\21.0\hpp\Win32
Python_D.hpp
PythonEngine.hpp
PythonGUIInputOutput.hpp
MethodCallBack.hpp
WrapDelphi.hpp
C:\Users\Public\Documents\Embarcadero\Studio\21.0\hpp\Win64
Python_D.hpp
PythonEngine.hpp
PythonGUIInputOutput.hpp
MethodCallBack.hpp
WrapDelphi.hpp
C:\Users\Public\Documents\Embarcadero\Studio\21.0\Dcp
Python_D.bpi
Python_D.dcp
Python_D.lib
C:\Users\Public\Documents\Embarcadero\Studio\21.0\Dcp\Win64
Python_D.a
Python_D.bpi
Python_D.dcp
C:\Users\Public\Documents\Embarcadero\Studio\21.0\Bpl
Python_D270.bpl
C:\Users\Public\Documents\Embarcadero\Studio\21.0\Bpl\Win64
Python_D270.bpl
Python_D270.rsm

In the IDE you’ll now see the components in the Component Palette window.

Building Your First C++Builder Python4Delphi VCL Application

Using RAD Studio, I opened the Python4Delphi Demo1 Delphi project and tested it to make sure that I had the components and Python working. C:\Users\david\Documents\Embarcadero\Studio\Projects\Python4Delphi\python4delphi-master\Demos\Demo01

Use File | New | C++Builder VCL application to create a starting C++Builder project (note: the source code for the project is in a zip file listed in the References section). I copied all of the components from the Delphi version of the Demo01 form file.

Demo01Unit.dfm file

object Form2: TForm2
  Left = 0
  Top = 0
  Caption = 'Demo 01 Python (C++, VCL)'
  ClientHeight = 344
  ClientWidth = 534
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Splitter1: TSplitter
    Left = 0
    Top = 153
    Width = 534
    Height = 3
    Cursor = crVSplit
    Align = alTop
    Color = clBtnFace
    ParentColor = False
    ExplicitWidth = 536
  end
  object Memo1: TMemo
    Left = 0
    Top = 156
    Width = 534
    Height = 144
    Align = alClient
    Font.Charset = DEFAULT_CHARSET
    Font.Color = clWindowText
    Font.Height = -13
    Font.Name = 'Consolas'
    Font.Pitch = fpVariable
    Font.Style = []
    Lines.Strings = (
      'print(2+2)')
    ParentFont = False
    ScrollBars = ssBoth
    TabOrder = 0
  end
  object Panel1: TPanel
    Left = 0
    Top = 300
    Width = 534
    Height = 44
    Align = alBottom
    BevelOuter = bvNone
    TabOrder = 1
    object Button1: TButton
      Left = 0
      Top = 6
      Width = 115
      Height = 25
      Caption = 'Execute script'
      TabOrder = 0
      OnClick = Button1Click
    end
    object Button2: TButton
      Left = 167
      Top = 6
      Width = 91
      Height = 25
      Caption = 'Load script...'
      TabOrder = 1
      OnClick = Button2Click
    end
    object Button3: TButton
      Left = 264
      Top = 8
      Width = 89
      Height = 25
      Caption = 'Save script...'
      TabOrder = 2
      OnClick = Button3Click
    end
  end
  object Memo2: TMemo
    Left = 0
    Top = 0
    Width = 534
    Height = 153
    Align = alTop
    Font.Charset = DEFAULT_CHARSET
    Font.Color = clWindowText
    Font.Height = -13
    Font.Name = 'Consolas'
    Font.Pitch = fpVariable
    Font.Style = []
    ParentFont = False
    ScrollBars = ssBoth
    TabOrder = 2
  end
  object PythonEngine1: TPythonEngine
    IO = PythonGUIInputOutput1
    Left = 32
    Top = 32
  end
  object OpenDialog1: TOpenDialog
    DefaultExt = '*.py'
    Filter = 'Python files|*.py|Text files|*.txt|All files|*.*'
    Title = 'Open'
    Left = 240
    Top = 32
  end
  object SaveDialog1: TSaveDialog
    DefaultExt = '*.py'
    Filter = 'Python files|*.py|Text files|*.txt|All files|*.*'
    Title = 'Save As'
    Left = 328
    Top = 32
  end
  object PythonGUIInputOutput1: TPythonGUIInputOutput
    UnicodeIO = True
    RawOutput = False
    Output = Memo2
    Left = 128
    Top = 32
  end
end

Demo01Unit.h file

//---------------------------------------------------------------------------

#ifndef Demo01UnitH
#define Demo01UnitH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include "PythonEngine.hpp"
#include <Vcl.Dialogs.hpp>
#include <Vcl.ExtCtrls.hpp>
#include "PythonGUIInputOutput.hpp"
//---------------------------------------------------------------------------
class TForm2 : public TForm
{
__published:	// IDE-managed Components
	TSplitter *Splitter1;
	TMemo *Memo1;
	TPanel *Panel1;
	TButton *Button1;
	TButton *Button2;
	TButton *Button3;
	TMemo *Memo2;
	TPythonEngine *PythonEngine1;
	TOpenDialog *OpenDialog1;
	TSaveDialog *SaveDialog1;
	TPythonGUIInputOutput *PythonGUIInputOutput1;
	void __fastcall Button1Click(TObject *Sender);
	void __fastcall Button2Click(TObject *Sender);
	void __fastcall Button3Click(TObject *Sender);
private:	// User declarations
public:		// User declarations
	__fastcall TForm2(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm2 *Form2;
//---------------------------------------------------------------------------
#endif

Next, add OnClick event handlers for the 3 buttons.

Demo01Unit.cpp file

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Demo01Unit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "PythonEngine"
#pragma link "PythonGUIInputOutput"
#pragma resource "*.dfm"
TForm2 *Form2;
//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Button1Click(TObject *Sender)
{
	PythonEngine1->ExecStrings( Memo1->Lines );
}
//---------------------------------------------------------------------------

void __fastcall TForm2::Button2Click(TObject *Sender)
{
	if (OpenDialog1->Execute()) {
		Memo1->Lines->LoadFromFile( OpenDialog1->FileName );
	}
}
//---------------------------------------------------------------------------

void __fastcall TForm2::Button3Click(TObject *Sender)
{
	if (SaveDialog1->Execute()) {
		Memo1->Lines->SaveToFile( SaveDialog1->FileName );
	}
}
//---------------------------------------------------------------------------

Save the project to a folder.

Compile and Run the C++ VCL Demo program and try some Python code

In the TMemo at the bottom of the form, type in some Python code. In my example I print the sum of two numbers, print the value of Pi from the Python math library and print the Python version # from the Python platform library. You can also use the Load and Save script buttons to bring up dialog boxes to load and save Python script files. Click the Execute script button to see the results show up in the upper TMemo.

References

Python4Delphi and PyScripter

Python4Delphi on GitHub by Kiriakos Vlahos – https://github.com/pyscripter/python4delphi

Webinar Replay – Python for Delphi Developers – Part 1 – Introduction – https://blogs.embarcadero.com/webinar-replay-python-for-delphi-developers-part-1-introduction/

PyScripter on GitHub by Kiriakos Vlahos – https://github.com/pyscripter/pyscripter

Python for Windows

Python Releases for Windows (python.org) – https://www.python.org/downloads/windows/

Embarcadero DocWiki

Creating Packages and DLLs – http://docwiki.embarcadero.com/RADStudio/en/Creating_Packages_and_DLLs

Project | Options | Output – C/C++ – http://docwiki.embarcadero.com/RADStudio/en/Output_-_C/C%2B%2B

Project | Options | Description – http://docwiki.embarcadero.com/RADStudio/en/Descripti

Package Files Created by Compiling – http://docwiki.embarcadero.com/RADStudio/en/Package_Files_Created_by_Compiling

DCC32.EXE, the Delphi Command Line Compiler – http://docwiki.embarcadero.com/RADStudio/en/DCC32.EXE,_the_Delphi_Command_Line_Compiler

DCC64.EXE, the Delphi 64-bit Command Line Compiler – http://docwiki.embarcadero.com/RADStudio/en/DCC64.EXE,_the_Delphi_64-bit_Command_Line_Compiler

Delphi 32-bit compiler (DCC32.exe) cmd line help (from C++Builder Community Edition 10.3.3)

Embarcadero Delphi for Win32 compiler version 33.0
Copyright (c) 1983,2018 Embarcadero Technologies, Inc.

Syntax: dcc32 [options] filename [options]

  -A<unit>=<alias> = Set unit alias
  -B = Build all units             
  -CC = Console target             
  -CG = GUI target                 
  -D<syms> = Define conditionals   
  -E<path> = EXE/DLL output directory
  -F<offset> = Find error          
  -GD = Detailed map file          
  -GP = Map file with publics      
  -GS = Map file with segments     
  -H = Output hint messages        
  -I<paths> = Include directories  
  -J = Generate .obj file          
  -JPHNE = Generate C++ .obj file, .hpp file, in namespace, export all
  -JL = Generate package .lib, .bpi, and all .hpp files for C++
  -K<addr> = Set image base addr   
  -LE<path> = package .bpl output directory
  -LN<path> = package .dcp output directory
  -LU<package> = Use package       
  -M = Make modified units         
  -NU<path> = unit .dcu output directory
  -NH<path> = unit .hpp output directory
  -NO<path> = unit .obj output directory
  -NB<path> = unit .bpi output directory
  -NX<path> = unit .xml output directory
  -NS<namespaces> = Namespace search path
  -O<paths> = Object directories   
  -P = look for 8.3 file names also
  -Q = Quiet compile               
  -R<paths> = Resource directories 
  -TX<ext> = Output name extension 
  -U<paths> = Unit directories     
  -V = Debug information in EXE    
  -VR = Generate remote debug (RSM)
  -VT = Debug information in TDS   
  -VN = TDS symbols in namespace   
  -W[+|-|^][warn_id] = Output warning messages
  -Z = Output 'never build' DCPs   
  -$<dir> = Compiler directive     
  --help = Show this help screen   
  --version = Show name and version
  --codepage:<cp> = specify source file encoding
  --default-namespace:<namespace> = set namespace
  --depends = output unit dependency information
  --doc = output XML documentation 
  --drc = output resource string .drc file
  --no-config = do not load default dcc32.cfg file
  --description:<string> = set executable description
  --inline:{on|off|auto} = function inlining control
  --legacy-ifend = allow legacy $IFEND directive
  --zero-based-strings[+|-] = strings are indexed starting at 0
  --peflags:<flags> = set extra PE Header flags field
  --peoptflags:<flags> = set extra PE Header optional flags field
  --peosversion:<major>.<minor> = set OS Version fields in PE Header (default: 5.0)
  --pesubsysversion:<major>.<minor> = set Subsystem Version fields in PE Header (default: 5.0)
  --peuserversion:<major>.<minor> = set User Version fields in PE Header (default: 0.0)
  --lib-version:<version> = Output package name version
  --lib-suffix:<suffix> = Output package name suffix
Compiler switches: -$<letter><state> (defaults are shown below)
  A8  Aligned record fields         
  B-  Full boolean Evaluation       
  C+  Evaluate assertions at runtime
  D+  Debug information             
  G+  Use imported data references  
  H+  Use long strings by default   
  I+  I/O checking                  
  J-  Writeable structured consts   
  L+  Local debug symbols           
  M-  Runtime type info             
  O+  Optimization                  
  P+  Open string params            
  Q-  Integer overflow checking     
  R-  Range checking                
  T-  Typed @ operator              
  U-  Pentium(tm)-safe divide       
  V+  Strict var-strings            
  W-  Generate stack frames         
  X+  Extended syntax               
  Y+  Symbol reference info         
  Z1  Minimum size of enum types    
Stack size: -$M<minStackSize[,maxStackSize]> (default 16384,1048576)

Delphi 64-bit compiler (DCC64.exe) cmd line help (C++Builder Community Edition 10.3.3)

Embarcadero Delphi for Win64 compiler version 33.0
Copyright (c) 1983,2018 Embarcadero Technologies, Inc.

Syntax: dcc64 [options] filename [options]

  -A<unit>=<alias> = Set unit alias
  -B = Build all units             
  -CC = Console target             
  -CG = GUI target                 
  -D<syms> = Define conditionals   
  -E<path> = EXE/DLL output directory
  -F<offset> = Find error          
  -GD = Detailed map file          
  -GP = Map file with publics      
  -GS = Map file with segments     
  -H = Output hint messages        
  -I<paths> = Include directories  
  -J = Generate .obj file          
  -JPHNE = Generate C++ .obj file, .hpp file, in namespace, export all
  -JL = Generate package .lib, .bpi, and all .hpp files for C++
  -K<addr> = Set image base addr   
  -LE<path> = package .bpl output directory
  -LN<path> = package .dcp output directory
  -LU<package> = Use package       
  -M = Make modified units         
  -NU<path> = unit .dcu output directory
  -NH<path> = unit .hpp output directory
  -NO<path> = unit .obj output directory
  -NB<path> = unit .bpi output directory
  -NX<path> = unit .xml output directory
  -NS<namespaces> = Namespace search path
  -O<paths> = Object directories   
  -P = look for 8.3 file names also
  -Q = Quiet compile               
  -R<paths> = Resource directories 
  -TX<ext> = Output name extension 
  -U<paths> = Unit directories     
  -V = Debug information in EXE    
  -VR = Generate remote debug (RSM)
  -VT = Debug information in TDS   
  -VN = TDS symbols in namespace   
  -W[+|-|^][warn_id] = Output warning messages
  -Z = Output 'never build' DCPs   
  -$<dir> = Compiler directive     
  --help = Show this help screen   
  --version = Show name and version
  --codepage:<cp> = specify source file encoding
  --default-namespace:<namespace> = set namespace
  --depends = output unit dependency information
  --doc = output XML documentation 
  --drc = output resource string .drc file
  --no-config = do not load default dcc64.cfg file
  --description:<string> = set executable description
  --inline:{on|off|auto} = function inlining control
  --legacy-ifend = allow legacy $IFEND directive
  --zero-based-strings[+|-] = strings are indexed starting at 0
  --peflags:<flags> = set extra PE Header flags field
  --peoptflags:<flags> = set extra PE Header optional flags field
  --peosversion:<major>.<minor> = set OS Version fields in PE Header (default: 5.0)
  --pesubsysversion:<major>.<minor> = set Subsystem Version fields in PE Header (default: 5.0)
  --peuserversion:<major>.<minor> = set User Version fields in PE Header (default: 0.0)
  --lib-version:<version> = Output package name version
  --lib-suffix:<suffix> = Output package name suffix
Compiler switches: -$<letter><state> (defaults are shown below)
  A8  Aligned record fields         
  B-  Full boolean Evaluation       
  C+  Evaluate assertions at runtime
  D+  Debug information             
  G+  Use imported data references  
  H+  Use long strings by default   
  I+  I/O checking                  
  J-  Writeable structured consts   
  L+  Local debug symbols           
  M-  Runtime type info             
  O+  Optimization                  
  P+  Open string params            
  Q-  Integer overflow checking     
  R-  Range checking                
  T-  Typed @ operator              
  V+  Strict var-strings            
  W-  Generate stack frames         
  X+  Extended syntax               
  Y+  Symbol reference info         
  Z1  Minimum size of enum types    
Stack size: -$M<minStackSize[,maxStackSize]> (default 16384,1048576)

C++ Demo project and Delphi command line package build batch files (zip file)

A zip file is available for download at http://davidi.com/code/Python4DelphiDemo01.zip

Windows Printing with C++Builder using VCL and FMX

Do you need to add printer support to your C++ applications using the Visual Component Library (VCL) or FireMonkey (FMX) GUI ? In this blog post I’ll show you how to build Windows applications that support printing image bitmaps using the VCL and FMX frameworks. One of my favorite C++Builder RTL features is that both frameworks provide similar printer components and ways of programming with only a few subtle differences.

Build VCL and FMX Application Projects

Use the “File | New | Windows VCL Application – C++Builder” menu item and create a starting C++ VCL application. Save the product to a folder.

File | New | Windows VCL Application – C++Builder

Next, in the Project Window, right mouse click on the ProjectGroup node and select the “Add New Project…” menu item.

Add New Project to the Project Group

In the popup dialog choose to create a Multi-Device Application.

Add New Multi-Device Application

Click the OK button and on the next screen choose to create a “Blank Application”.

Multi-Device Project templates list – choose Blank Application

Use the File | Save All menu item (or type Shift+Ctrl+S) to save both starting projects and the project group to a folder.

Project Group with VCL and FMX Starting Projects

Each of the VCL and FMX projects have a main form (.dfm and .fmx extensions respectively). While most of the IDE will look the same, if you select each form’s unit you will see different looks for each of their form designers.

VCL Form Designer
FMX Form Designer

There are many videos, articles and help files that describe the details of each designer (check out links in the reference section below). For now, let’s dig into the VCL and FMX printer examples I’ve created.

A Simple UI for each Printer Test Project

On each of the VCL and FMX main forms you’ll see the following components.

VCL form’s components in the Structure Window
FMX form’s components in the Structure Window

Each project’s main menu contains a File and Destination menu. The Destination menu item allows the user to choose to override the printing destination (Printer or File).

The File menu provides an OpenPictureDialog (VCL) or OpenDialog (FMX), PrintPicture dialog for choosing the printer and other printing options, PrinterSetup dialog to set additional printer setup options, Panel (aligned to the top of the form)with a label and ComboBox which will list the available printer device names, and an Image component (aligned to the client area) to contain the picture bitmap.

The VCL and FMX forms look like the following.

VCL app form with components
FMX app form with components

Right mouse click on the form and choose “View as Text” from the popup menu. Now you can see all of the form and component properties and sub-properties that have been set from their default values. You can also make changes in this text form mode but be careful to not make any errors.

To switch back to the form mode click the right mouse button (or hit Alt-F12) and choose “View as Form” from the popup menu.

VCLPrintUnit.dfm (View as Text)

object MainVCLForm: TMainVCLForm
  Left = 0
  Top = 0
  Caption = 'Printer Test (C++, VCL)'
  ClientHeight = 473
  ClientWidth = 667
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  Menu = MainMenu1
  OldCreateOrder = False
  OnShow = FormShow
  PixelsPerInch = 96
  TextHeight = 13
  object Image1: TImage
    Left = 0
    Top = 41
    Width = 667
    Height = 432
    Align = alClient
    Proportional = True
    ExplicitLeft = 104
    ExplicitTop = 102
    ExplicitWidth = 424
    ExplicitHeight = 317
  end
  object Panel1: TPanel
    Left = 0
    Top = 0
    Width = 667
    Height = 41
    Align = alTop
    TabOrder = 0
    object Label1: TLabel
      Left = 10
      Top = 12
      Width = 41
      Height = 13
      Caption = 'Printers:'
    end
    object PrintersComboBox: TComboBox
      Left = 57
      Top = 9
      Width = 250
      Height = 21
      TabOrder = 0
      Text = 'PrintersComboBox'
    end
  end
  object PrintDialog1: TPrintDialog
    Options = [poPrintToFile]
    Left = 176
    Top = 56
  end
  object PrinterSetupDialog1: TPrinterSetupDialog
    Left = 304
    Top = 64
  end
  object OpenPictureDialog1: TOpenPictureDialog
    DefaultExt = 'bmp'
    InitialDir = 'c:\temp'
    Left = 56
    Top = 56
  end
  object MainMenu1: TMainMenu
    Left = 424
    Top = 64
    object File1: TMenuItem
      Caption = 'File'
      object File2: TMenuItem
        Caption = 'Open Picture'
        OnClick = File2Click
      end
      object PrintPicture1: TMenuItem
        Caption = 'Print Picture'
        Enabled = False
        OnClick = PrintPicture1Click
      end
      object PrinterSetup1: TMenuItem
        Caption = 'Printer Setup'
        Enabled = False
        OnClick = PrinterSetup1Click
      end
      object PrintPicture2: TMenuItem
        Caption = 'Exit'
        OnClick = PrintPicture2Click
      end
    end
    object Destination1: TMenuItem
      Caption = 'Destination'
      object PrintToPrinterDestinationMenuItem: TMenuItem
        Caption = 'Print to Printer'
        Checked = True
        OnClick = PrintToPrinterDestinationMenuItemClick
      end
      object PrintToFileDestinationMenuItem: TMenuItem
        Caption = 'Print to File'
        OnClick = PrintToFileDestinationMenuItemClick
      end
    end
  end
end

FMXPrintUnit.fmx (View as Text)

object MainFMXForm: TMainFMXForm
  Left = 0
  Top = 0
  Caption = 'Printer Test (C++, FMX)'
  ClientHeight = 380
  ClientWidth = 640
  Position = Designed
  WindowState = wsMaximized
  FormFactor.Width = 320
  FormFactor.Height = 480
  FormFactor.Devices = [Desktop]
  OnShow = FormShow
  DesignerMasterStyle = 0
  object Image1: TImage
    MultiResBitmap = <
      item
      end>
    Align = Client
    Size.Width = 640.000000000000000000
    Size.Height = 339.000000000000000000
    Size.PlatformDefault = False
  end
  object PrintDialog1: TPrintDialog
    Options = [poPrintToFile]
    Left = 68
    Top = 40
  end
  object PrinterSetupDialog1: TPrinterSetupDialog
    Left = 190
    Top = 42
  end
  object OpenDialog1: TOpenDialog
    DefaultExt = 'bmp'
    Filter = '*.bmp'
    InitialDir = 'c:\temp'
    Left = 312
    Top = 44
  end
  object MainMenu1: TMainMenu
    Left = 418
    Top = 46
    object FileMenu: TMenuItem
      Text = 'File'
      object OpenBitmapMenuItem: TMenuItem
        Locked = True
        Text = 'Open Bitmap'
        OnClick = OpenBitmapMenuItemClick
      end
      object PrintMenuItem: TMenuItem
        Enabled = False
        Locked = True
        Text = 'Print'
        OnClick = PrintMenuItemClick
      end
      object PrinterSetupMenuItem: TMenuItem
        Enabled = False
        Locked = True
        Text = 'Printer Setup'
        OnClick = PrinterSetupMenuItemClick
      end
      object ExitMenuItem: TMenuItem
        Locked = True
        Text = 'Exit'
        OnClick = ExitMenuItemClick
      end
    end
    object DestinationMenu: TMenuItem
      Text = 'Destination'
      object PrintToPrinterDestinationMenuItem: TMenuItem
        Locked = True
        IsChecked = True
        Text = 'Print to Printer'
        OnClick = PrintToPrinterDestinationMenuItemClick
      end
      object PrintToFileDestinationMenuItem: TMenuItem
        Locked = True
        Text = 'Print to File'
        OnClick = PrintToFileDestinationMenuItemClick
      end
    end
  end
  object Panel1: TPanel
    Align = Top
    Size.Width = 640.000000000000000000
    Size.Height = 41.000000000000000000
    Size.PlatformDefault = False
    object PrintersComboBox: TComboBox
      Position.X = 72.000000000000000000
      Position.Y = 8.000000000000000000
      Size.Width = 233.000000000000000000
      Size.Height = 22.000000000000000000
      Size.PlatformDefault = False
    end
    object Label1: TLabel
      Position.X = 8.000000000000000000
      Position.Y = 9.000000000000000000
      Size.Width = 57.000000000000000000
      Size.Height = 17.000000000000000000
      Size.PlatformDefault = False
      Text = 'Printers:'
    end
  end
end

Additional comments about component properties and event handlers are included in the source code for the projects.

The Source Code

Below you will find the header files for the VCL and FMX form units. The header files will show the component declarations, event handlers and any public/private declarations.

VCLPrintUnit.h

//---------------------------------------------------------------------------

#ifndef VCLPrintUnitH
#define VCLPrintUnitH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.Dialogs.hpp>
#include <Vcl.ExtCtrls.hpp>
#include <Vcl.ExtDlgs.hpp>
#include <Vcl.Menus.hpp>
#include <Vcl.WinXCtrls.hpp>
//---------------------------------------------------------------------------
class TMainVCLForm : public TForm
{
__published:	// IDE-managed Components
	TPrintDialog *PrintDialog1;
	TPrinterSetupDialog *PrinterSetupDialog1;
	TImage *Image1;
	TOpenPictureDialog *OpenPictureDialog1;
	TMainMenu *MainMenu1;
	TMenuItem *File1;
	TMenuItem *File2;
	TMenuItem *PrintPicture1;
	TMenuItem *PrintPicture2;
	TMenuItem *Destination1;
	TMenuItem *PrintToPrinterDestinationMenuItem;
	TMenuItem *PrintToFileDestinationMenuItem;
	TMenuItem *PrinterSetup1;
	TPanel *Panel1;
	TLabel *Label1;
	TComboBox *PrintersComboBox;
	void __fastcall File2Click(TObject *Sender);
	void __fastcall FormShow(TObject *Sender);
	void __fastcall PrintToPrinterDestinationMenuItemClick(TObject *Sender);
	void __fastcall PrintToFileDestinationMenuItemClick(TObject *Sender);
	void __fastcall PrintPicture1Click(TObject *Sender);
	void __fastcall PrinterSetup1Click(TObject *Sender);
	void __fastcall PrintPicture2Click(TObject *Sender);
private:	// User declarations
    bool PictureLoaded;  // boolean for whether a picture is loaded or not
public:		// User declarations
	__fastcall TMainVCLForm(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TMainVCLForm *MainVCLForm;
//---------------------------------------------------------------------------
#endif

FMXPrintUnit.h

//---------------------------------------------------------------------------

#ifndef FMXPrintUnitH
#define FMXPrintUnitH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <FMX.Controls.hpp>
#include <FMX.Forms.hpp>
#include <FMX.Controls.Presentation.hpp>
#include <FMX.StdCtrls.hpp>
#include <FMX.Types.hpp>
#include <FMX.Objects.hpp>
#include <FMX.Dialogs.hpp>
#include <FMX.Printer.hpp>
#include <FMX.Menus.hpp>
#include <FMX.ListBox.hpp>
//---------------------------------------------------------------------------
class TMainFMXForm : public TForm
{
__published:	// IDE-managed Components
	TImage *Image1;
	TPrintDialog *PrintDialog1;
	TPrinterSetupDialog *PrinterSetupDialog1;
	TOpenDialog *OpenDialog1;
	TMainMenu *MainMenu1;
	TMenuItem *FileMenu;
	TMenuItem *OpenBitmapMenuItem;
	TMenuItem *PrintMenuItem;
	TMenuItem *PrinterSetupMenuItem;
	TMenuItem *ExitMenuItem;
	TPanel *Panel1;
	TComboBox *PrintersComboBox;
	TLabel *Label1;
	TMenuItem *DestinationMenu;
	TMenuItem *PrintToPrinterDestinationMenuItem;
	TMenuItem *PrintToFileDestinationMenuItem;
	void __fastcall PrintMenuItemClick(TObject *Sender);
	void __fastcall OpenBitmapMenuItemClick(TObject *Sender);
	void __fastcall ExitMenuItemClick(TObject *Sender);
	void __fastcall PrinterSetupMenuItemClick(TObject *Sender);
	void __fastcall FormShow(TObject *Sender);
	void __fastcall PrintToPrinterDestinationMenuItemClick(TObject *Sender);
	void __fastcall PrintToFileDestinationMenuItemClick(TObject *Sender);
private:	// User declarations
	BOOL PictureLoaded;  // boolean for whether a picture is loaded or not
public:		// User declarations
	__fastcall TMainFMXForm(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TMainFMXForm *MainFMXForm;
//---------------------------------------------------------------------------
#endif

Below you will find the source code for the VCL and FMX form units.

VCLPrinterUnit.cpp

//---------------------------------------------------------------------------

#include <vcl.h>
#include <Vcl.Imaging.GIFImg.hpp>
#include <Vcl.Imaging.jpeg.hpp>
#include <Vcl.Imaging.pngimage.hpp>
#include <Vcl.Printers.hpp>

#pragma hdrstop

#include "VCLPrintUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TMainVCLForm *MainVCLForm;
//---------------------------------------------------------------------------
__fastcall TMainVCLForm::TMainVCLForm(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TMainVCLForm::File2Click(TObject *Sender)
{
	if (OpenPictureDialog1->Execute()) {
		Image1->Picture->LoadFromFile(OpenPictureDialog1->FileName);
		PictureLoaded = true;
		PrintPicture1->Enabled = true;
        PrinterSetup1->Enabled = true;
	}
}
//---------------------------------------------------------------------------
void __fastcall TMainVCLForm::FormShow(TObject *Sender)
{

	PictureLoaded = false;
	PrintToPrinterDestinationMenuItem->Checked = true;
	PrintToFileDestinationMenuItem->Checked = false;

	// get printers list and put in combobox
	PrintersComboBox->Items = Printer()->Printers;

	// make the currently selected printer the Item in the ComboBox
	PrintersComboBox->ItemIndex = 0;
	for (int i = 0; i < Printer()->Printers->Count-1; i++) {
		if (Printer()->Printers->Strings[Printer()->PrinterIndex] == PrintersComboBox->Items->Strings[i]) {
			PrintersComboBox->ItemIndex = i;
		}
	}

}
//---------------------------------------------------------------------------
void __fastcall TMainVCLForm::PrintToPrinterDestinationMenuItemClick(TObject *Sender)
{
	// set menu item checked for print to printer
	PrintToPrinterDestinationMenuItem->Checked = true;
	PrintToFileDestinationMenuItem->Checked = false;
	// set PrintDialog PrintToFile checkbox off
	// Note: to allow user to override the menu item - make sure
	//   PrintDialog Options poPrintToFile is set to true
	//   so that the PrintToFile checkbox appears in the dialog
	PrintDialog1->PrintToFile = false;
}
//---------------------------------------------------------------------------
void __fastcall TMainVCLForm::PrintToFileDestinationMenuItemClick(TObject *Sender)
{
	// set menu item checked for print to file
	PrintToPrinterDestinationMenuItem->Checked = false;
	PrintToFileDestinationMenuItem->Checked = true;
	// set PrintDialog PrintToFile checkbox on
	// Note: to allow user to override the menu item - make sure
	//   PrintDialog Options poPrintToFile is set to true
	//   so that the PrintToFile checkbox appears in the dialog
	PrintDialog1->PrintToFile = true;
}
//---------------------------------------------------------------------------
void __fastcall TMainVCLForm::PrintPicture1Click(TObject *Sender)
{

	// check if a picture is loaded
	if (PictureLoaded) {
		if (PrintDialog1->Execute()) {

			// Call BeginDoc - to get the dimensions for selected printer
			Printer()->BeginDoc();

			try {
				// use StretchDraw to do full size bitmap printing
				// notes:
				//   printer settings can be made using the
				//     PrintDialog and PrinterSetupDialog
				//   you can also control page layout in code:
				//     Property is Orientation:
				//       poPortrait
				//       poLandscape
				Printer()->Canvas->StretchDraw(
					Rect(0, 0, Printer()->PageWidth,Printer()->PageHeight),
					Image1->Picture->Graphic);
			}
			__finally {
				// end the document and the printing will begin
				Printer()->EndDoc();
			}
		}
	}

}
//---------------------------------------------------------------------------
void __fastcall TMainVCLForm::PrinterSetup1Click(TObject *Sender)
{
	// Printer Setup
    PrinterSetupDialog1->Execute();
}
//---------------------------------------------------------------------------
void __fastcall TMainVCLForm::PrintPicture2Click(TObject *Sender)
{
    Application->Terminate();
}
//---------------------------------------------------------------------------

FMXPrinterUnit.cpp

//---------------------------------------------------------------------------

#include <fmx.h>
#include "FMX.Printer.hpp"
#include "System.SysUtils.hpp"
#pragma hdrstop

#include "FMXPrintUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
TMainFMXForm *MainFMXForm;
//---------------------------------------------------------------------------
__fastcall TMainFMXForm::TMainFMXForm(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TMainFMXForm::PrintMenuItemClick(TObject *Sender)
{
	TRectF SrcRect, DestRect;

	if (PrintDialog1->Execute()) {
		// Set the default DPI for the printer. The SelectDPI routine defaults
		//	 to the closest available resolution as reported by the driver.
		// Printer->ActivePrinter->SelectDPI(1200, 1200);

		// Printer->ActivePrinter->ActiveDPIIndex = 1; // you can also the DPI index

		// Set canvas filling style
		// Printer->Canvas->Fill->Color = claBlack;
		// Printer->Canvas->Fill->Kind = TBrushKind(1);

		// Start printing
		Printer::Printer()->BeginDoc();

		// Set the Source and Destination TRects

		SrcRect = TRectF(0, 0, Image1->Bitmap->Width, Image1->Bitmap->Height);
		DestRect = TRectF(0, 0, Printer::Printer()->PageWidth, Printer::Printer()->PageHeight);

		// Print the picture, on all the surface of the page and all opaque.
		Printer::Printer()->Canvas->DrawBitmap(Image1->Bitmap, SrcRect, DestRect, 1);

		// Finish the printing job
		Printer::Printer()->EndDoc();
	}

}
//---------------------------------------------------------------------------

void __fastcall TMainFMXForm::OpenBitmapMenuItemClick(TObject *Sender)
{
	// open a bitmap for printing
	if (OpenDialog1->Execute()) {
		Image1->Bitmap->LoadFromFile(OpenDialog1->FileName);
		PrintMenuItem->Enabled = true;
		PrinterSetupMenuItem->Enabled = true;
        PictureLoaded = true;
	}
}
//---------------------------------------------------------------------------

void __fastcall TMainFMXForm::ExitMenuItemClick(TObject *Sender)
{
	// exit the application
    Application->Terminate();
}
//---------------------------------------------------------------------------

void __fastcall TMainFMXForm::PrinterSetupMenuItemClick(TObject *Sender)
{
	// use the Printer Setup dialog box
	PrinterSetupDialog1->Execute();
}
//---------------------------------------------------------------------------

void __fastcall TMainFMXForm::FormShow(TObject *Sender)
{
	// on form show event handler

	PictureLoaded = false;
	PrintToPrinterDestinationMenuItem->IsChecked = true;
	PrintToFileDestinationMenuItem->IsChecked = false;

	// populate the ComboBox with the printer device names
	PrintersComboBox->ItemIndex = 0;
	for (int i = 0; i < Printer::Printer()->Count-1; i++) {
		PrintersComboBox->Items->Add(Printer::Printer()->Printers[i]->Title);
		// set the ComboBox ItemIndex to the active printer
		if (Printer::Printer()->Printers[i]->Title == Printer::Printer()->ActivePrinter->Title) {
			PrintersComboBox->ItemIndex = i;
		}
	}
}
//---------------------------------------------------------------------------

void __fastcall TMainFMXForm::PrintToPrinterDestinationMenuItemClick(TObject *Sender)
{
	// set menu item checked for print to printer
	PrintToPrinterDestinationMenuItem->IsChecked = true;
	PrintToFileDestinationMenuItem->IsChecked = false;
	// set PrintDialog PrintToFile checkbox off
	// Note: to allow user to override the menu item - make sure
	//   PrintDialog Options poPrintToFile is set to true
	//   so that the PrintToFile checkbox appears in the dialog
	PrintDialog1->PrintToFile = false;
}
//---------------------------------------------------------------------------

void __fastcall TMainFMXForm::PrintToFileDestinationMenuItemClick(TObject *Sender)
{
	// set menu item checked for print to file
	PrintToPrinterDestinationMenuItem->IsChecked = false;
	PrintToFileDestinationMenuItem->IsChecked = true;
	// set PrintDialog PrintToFile checkbox on
	// Note: to allow user to override the menu item - make sure
	//   PrintDialog Options poPrintToFile is set to true
	//   so that the PrintToFile checkbox appears in the dialog
	PrintDialog1->PrintToFile = true;
}
//---------------------------------------------------------------------------

The VCL and FMX applications in Action

VCL app in action
FMX app in action

References

VCL Printing

Printing in VCL Applications
Vcl.Printers

FMX Printing

Printing from a FireMonkey Application
FMX.Printer

YouTube Videos

Creating your First VCL Application for Windows with C++Builder
Creating Your First C++ Windows App
Why C++Builder?

Source Code

Source Code for VCL and FMX printing projects (zip file)

About C++Builder

C++Builder Product Page – Native Apps that Perform. Build Windows C++ Apps 10x Faster with Less Code

C++Builder Product Editions – C++Builder is available in four editions – Professional, Enterprise, Architect and Community (free). C++Builder is also available as part of the RAD Studio development suite.

Bjarne Stroustrup’s CppCon 2020 Plenary is Available on YouTube

Bjarne Stroupstrup’s CppCon 2020 plenary sesson, “The Beauty and Power of Primitive C++“, is now available on the CppCon YouTube channel.

From his CppCon 2020 talk description: This is an exploration of a design space close to the hardware and of the use of C++ in that space, rather than a standards proposal or the presentation of a mature tool chain. And, no, by “primitive”, I don’t mean “old-fashioned, C-like” code; some of the general techniques are old, but some of the code requires C++17 and much could be done better given features we are unlikely to get even in C++23.

Links to other replays of Bjarne’s talks at past CppCon (the C++ conference) events

A Few More Bjarne Videos (there are many others)

My Online Conversations with Bjarne Stroustrup

I’ve also had two opportunities to talk live online with Bjarne about the C++ language during past Embarcadero CodeRage online conferences:

You will find ISO C++ articles, news, books, podcasts, training courses, events, videos, product news, standardization activities, etc. on the Standard C++ Foundation site.


Using the Eigen C++ Template Library with C++Builder and VCL

It’s been almost 50 years since I took a Linear Algebra and Matrices course as one of my Computer Science electives at Cal Poly San Luis Obispo, CA. The textbook for the course was “Mathematics Of Matrices: First Book Of Matrix Theory And Linear Algebra” by Philip J Davis. While I have used arrays and vectors in many programming projects, I have to be honest and say that I have not used a lot of matrix math in my code.

Now that the Eigen C++ Template Library is available for download inside the C++Builder IDE using the GetIt Package Manager, I decided to re-introduce myself to matrix math, manipulations and linear algebra (not bad for a 69 year old software engineer). This blog post will show C++ developers how to download, install and use the Eigen C++ library using C++Builder and VCL.

Installing Eigen via the GetIt Package Manager

Inside the C++Builder IDE, use the Tools | GetIt Project Manager menu item to bring up the list of available add-on components, libraries and demos. Type “Eigen” in the search box to see what is available.

Click the Install button to download, install, build and run tests the Eigen C++ library with your release of C++Builder (I used C++Builder version 10.4.1). As part of the Eigen installation you will see two additional windows.

Dependency notice about minimal changes made to allow Eigen to work with C++Builder
Eigen Installation Window showing progress of the download, installation and tests

Once the download and installation is completed, you can start using Eigen in your applications. To learn more about the Eigen C++ Template Library I’ve included some reference links at the end of this post. To dust off my matrix and linear algebra cobwebs and learn a little bit about Eigen, I created three sample C++Builder VCL applications using Eigen.

Simple Eigen Test C++ VCL Application

This first example Button onClick event handler displays the Eigen version number, creates a 3×3 matrix, populates it with random floating point numbers (between -1 and 1) and uses the addition, subtraction and multiplication operators.

The VCL Form containing a button and memo
Application Output using addition, subtraction and multiplication

The Source Code

MainUnit.h

//---------------------------------------------------------------------------

#ifndef MainUnitH
#define MainUnitH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE-managed Components
	TButton *Button1;
	TMemo *MatrixOutputMemo;
	TMemo *DemoCodeMemo;
	TLabel *Label1;
	TLabel *Label2;
	TLabel *EigenVersionLabel;
	void __fastcall Button1Click(TObject *Sender);
private:	// User declarations
public:		// User declarations
	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

MainUnit.cpp

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <Eigen/Dense>
using Eigen::MatrixXd;
using Eigen::IOFormat;

#include "MainUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

// create string stream from Eigen Matrix
  static std::string ConvertToString(const Eigen::MatrixXd& mat){
	std::stringstream ss;
	IOFormat CleanFmt(Eigen::FullPrecision, 0, ", ", "\n", "[", "]");
	ss << mat.format(CleanFmt);
	return ss.str();
}

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	// first sample app adapted from Eigen documentation and put in VCL app

	// display Eigen version number
	EigenVersionLabel->Caption = "Eigen version: "
		+ IntToStr(EIGEN_WORLD_VERSION)
		+ "."
		+ IntToStr(EIGEN_MAJOR_VERSION)
		+ "."
		+ IntToStr(EIGEN_MINOR_VERSION);

	// define a 3x3 matrix of doubles
	MatrixXd m(3,3);
	// Fill matrix with random numbers between -1 and +1
	m.setRandom(3,3);
	// Change three matrix items using + - and *
	m(0,2) = m(0,0) + m(0,1);
	m(1,2) = m(1,0) - m(1,1);
	m(2,2) = m(2,0) * m(2,1);

	// output matrix using strings
	MatrixOutputMemo->Lines->Clear();
	MatrixOutputMemo->Lines->Text = ConvertToString(m).c_str();
}
//---------------------------------------------------------------------------

Matrix Operations C++ VCL Application

The second Eigen C++ VCL application exercises several Eigen operations including adding and subtracting two matricies, multiplying and dividing a matrix by a scalar, multiplying two matricies, transposing a matrix, invert a matrix and sum all elements of a matrix. There are many additional features to explore in Eigen for vector and matrix operations.

In the UI for the application you’ll see a RadioGroup for selecting one of the operations, three StringGrids to display matrix contents, an EditBox for inputing a scalar (I used Pi), and a Label for the summing result.

The Matrix Operations example VCL form
Example Output after subtracting the x and y matrices giving z

The Source Code

MainUnit.h

//---------------------------------------------------------------------------

#ifndef MainUnitH
#define MainUnitH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.Grids.hpp>
#include <Vcl.ExtCtrls.hpp>
#include <Vcl.Samples.Spin.hpp>

//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE-managed Components
	TStringGrid *StringGridX;
	TStringGrid *StringGridY;
	TStringGrid *StringGridZ;
	TLabel *Label1;
	TLabel *Label2;
	TLabel *Label3;
	TRadioGroup *RadioGroup1;
	TButton *Button1;
	TLabel *Label4;
	TEdit *ScalarEdit;
	TLabel *ResultLabel;
	void __fastcall FormShow(TObject *Sender);
	void __fastcall Button1Click(TObject *Sender);
private:	// User declarations
    void __fastcall displayMatricies();
public:		// User declarations
	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

MainUnit.cpp

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <Eigen/Dense>
using Eigen::MatrixXd;

#include <System.SysUtils.hpp>
#include "MainUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

MatrixXd x(3,3);
MatrixXd y(3,3);
MatrixXd z(3,3);

void TForm1::displayMatricies() {
	// display contents of x, y and z matricies
	int numberRows = x.rows();
	int numberColumns = y.cols();
	for (int r=0 ; r < numberRows ; r++) {
		for (int c = 0; c < numberColumns; c++) {
			StringGridX->Cells[r][c] = FloatToStrF(x(r,c),ffFixed,5,3);
			StringGridY->Cells[r][c] = FloatToStrF(y(r,c),ffFixed,5,3);
			StringGridZ->Cells[r][c] = FloatToStrF(z(r,c),ffFixed,5,3);
		}
	}
}

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
	// populate x and y matricies and their string grids with random numbers
	x.setRandom(5,5);
	y.setRandom(5,5);
	z.setZero(5,5);

	// clear selections in the string grids
	TGridRect gr;

	gr.Left = StringGridX->ColCount;
	gr.Top = StringGridX->RowCount;
	StringGridX->Canvas->Brush->Color = clWindow;
	StringGridX->Canvas->FillRect(Rect(StringGridX->Left,StringGridX->Width,StringGridX->Top,StringGridX->Height));

	gr.Left = StringGridY->ColCount;
	gr.Top = StringGridY->RowCount;
	StringGridY->Canvas->Brush->Color = clWindow;
	StringGridY->Canvas->FillRect(Rect(StringGridY->Left,StringGridY->Width,StringGridY->Top,StringGridY->Height));

	gr.Left = StringGridZ->ColCount;
	gr.Top = StringGridZ->RowCount;
	StringGridZ->Canvas->Brush->Color = clWindow;
	StringGridZ->Canvas->FillRect(Rect(StringGridZ->Left,StringGridZ->Width,StringGridZ->Top,StringGridZ->Height));

	// display current values of matricies
	displayMatricies();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
	// do the operation that is currently selected in the Radio Button Group
	// 0 = addition, 1= subtraction, 2 = multiplication,
	// 3 = division, 4 = dot product
	switch(RadioGroup1->ItemIndex) {
		case 0: // addition
			z = x + y;
			break;
		case 1: // subtraction
			z = x - y;
			break;
		case 2: // multiply x by scalar and save result in z
			z = x * StrToFloat(ScalarEdit->Text);
			break;
		case 3: // divide x by scalar and save result in z
			z = x / StrToFloat(ScalarEdit->Text);
			break;
		case 4:  // multiply x * y and save result in z
			z.noalias() = x * y;
			break;
		case 5: // transpose x and save result in z
			z = x.transpose();
			break;
		case 6: // invert x and save result in z
			z = x.inverse();
			break;
		case 7: // sum all elements of x and save in result
			ResultLabel->Caption = "Result: "+FloatToStr(x.sum());
			break;
	}

	// display current values of matricies
	displayMatricies();
}
//---------------------------------------------------------------------------

Shopping Linear Algebra C++ VCL Application

I wanted to use a “real world” linear algebra example to showcase a few additional features of the Eigen C++ template library. There are many matrix and linear algebra courses and examples out on the Internet. After a quick search I decided to use “Real-world Applications of Linear Algebra Tools” by E. Ulrychova, postgradual student at the University of Economics, Department of Mathematics, Prague, Czech Republic.

The scenario has three people who want to each shop for baked goods at only one of two stores. Each person has a quantity of rolls, buns, cakes and breads that they want to purchase. Each store has a list of prices that they charge for each of the baked goods. This linear algebra example calculates a spending analysis for each person at each store to show where each person should shop.

The user interface includes a button to run code that calculates the lowest shopping cost for each person, a StringGrid for the baked goods demand matrix for each person, a StringGrid for the store pricing for each baked good, and a StringGrid for the results of the optimal spending analysis for each person.

The VCL Form for the UI
The demand matrix of baked goods for each person, the prices for each baked good by shop and the resulting optimal shop spending for each person

The Source Code

ShoppingUnit.h

//---------------------------------------------------------------------------

#ifndef ShoppingUnitH
#define ShoppingUnitH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.Grids.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE-managed Components
	TButton *Button1;
	TStringGrid *DemandMatrixStringGrid;
	TLabel *Label1;
	TStringGrid *PriceMatrixStringGrid;
	TLabel *Label2;
	TStringGrid *ResultStringGrid;
	TLabel *Label3;
	void __fastcall Button1Click(TObject *Sender);
private:	// User declarations
public:		// User declarations
	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

ShoppingUnit.cpp

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <Eigen/Dense>
using Eigen::MatrixXd;
using Eigen::VectorXd;
using Eigen::IOFormat;


#include "ShoppingUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{

	// Calculate results of spending analysis by person by store
	//    R = PQ
	// from:
	// Real-world Applications of Linear Algebra Tools
	// by E. Ulrychova, postgradual student
	// University of Economics, Department of Mathematics, Prague, Czech Republic
	// https://www.mff.cuni.cz/veda/konference/wds/proc/pdf06/WDS06_106_m8_Ulrychova.pdf


	int r,c;  // row and column indexes used throughout this event handler

	// matricies used for spending analysis
	MatrixXd DemandMatrix(4,3);   // Q
	MatrixXd PriceMatrix(2,4);    // P
	MatrixXd ResultMatrix(2,3);   // R

	// vectors used for dot product analysis of spending by person by shop
	VectorXd DemandVector(4);
	VectorXd PriceVector(4);


	// Demanded quantity of foodstuffs per person (3 people, 4 foodstuffs)
	DemandMatrix <<  // Q
		6,3,3,  // foodstuff quantities for rolls for each of the 3 people
		5,6,4,  // foodstuff quantities for buns for each of the 3 people
		3,2,3,  // foodstuff quantities for cakes for each of the 3 people
		1,2,1;  // foodstuff quantities for breads for each of the 3 people

	// Prices for each foodstuff in each shop (4 foodstuffs, 2 shops)
	PriceMatrix <<  //P
		1.50,2.00,5.00,16.00,  // prices for foodstuffs at Shop 1
		1.00,2.50,4.50,17.00;  // prices for foodstuffs at Shop 2


	// Calculate results of spending analysis by person by store
	//    R = PQ

	int ResultMatrixNumberRows = ResultMatrix.rows();
	int ResultMatrixNumberColumns = ResultMatrix.cols();

	for (r=0 ; r < ResultMatrixNumberRows ; r++) {
		for (c = 0; c < ResultMatrixNumberColumns; c++) {
			// create price and demand vectors
			DemandVector = DemandMatrix.col(c);
			PriceVector = PriceMatrix.row(r);
			// use dot product of demand and price to get a result
			ResultMatrix(r,c) = DemandVector.dot(PriceVector);
		}
	}

	// set heading and column strings for Demand Matrix rows and columns
	DemandMatrixStringGrid->Cells[1][0] = "roll";
	DemandMatrixStringGrid->Cells[2][0] = "bun";
	DemandMatrixStringGrid->Cells[3][0] = "cake";
	DemandMatrixStringGrid->Cells[4][0] = "bread";
	DemandMatrixStringGrid->Cells[0][1] = "p1";
	DemandMatrixStringGrid->Cells[0][2] = "p2";
	DemandMatrixStringGrid->Cells[0][3] = "p3";

	// set heading and column strings for Price Matrix rows and columns
	PriceMatrixStringGrid->Cells[1][0] = "s1";
	PriceMatrixStringGrid->Cells[2][0] = "s1";
	PriceMatrixStringGrid->Cells[0][1] = "roll";
	PriceMatrixStringGrid->Cells[0][2] = "bun";
	PriceMatrixStringGrid->Cells[0][3] = "cake";
	PriceMatrixStringGrid->Cells[0][4] = "bread";

	// set heading and column strings for Result Matrix String Grid rows and columns
	ResultStringGrid->Cells[1][0] = "s1";
	ResultStringGrid->Cells[2][0] = "s1";
	ResultStringGrid->Cells[0][1] = "p1";
	ResultStringGrid->Cells[0][2] = "p2";
	ResultStringGrid->Cells[0][3] = "p3";

	int DemandMatrixNumberRows = DemandMatrix.rows();
	int DemandMatrixNumberColumns = DemandMatrix.cols();

	// populate string grid with the Demand Data
	for (r=1 ; r <= DemandMatrixNumberRows ; r++) {
		for (c = 1; c <= DemandMatrixNumberColumns; c++) {
			DemandMatrixStringGrid->Cells[r][c] = FloatToStrF(DemandMatrix(r-1,c-1),ffFixed,5,3);
		}
	}

	int PriceMatrixNumberRows = PriceMatrix.rows();
	int PriceMatrixNumberColumns = PriceMatrix.cols();

	// populate string grid with the Price Data
	for (r=1 ; r <= PriceMatrixNumberRows ; r++) {
		for (c = 1; c <= PriceMatrixNumberColumns; c++) {
			PriceMatrixStringGrid->Cells[r][c] = FloatToStrF(PriceMatrix(r-1,c-1),ffFixed,5,3);
		}
	}


	// With the supplied data this program shows it is optimal
	//  for person p1 to buy in the shop s2,
	//  for person p2 to buy in shop s1
	//  and person p3 will pay the same price in shop s1 and s2

	int ResultNumberRows = ResultMatrix.rows();
	int ResultNumberColumns = ResultMatrix.cols();

	// populate string grid with the results
	for (r=1 ; r <= ResultNumberRows ; r++) {
		for (c = 1; c <= ResultNumberColumns; c++) {
			ResultStringGrid->Cells[r][c] = FloatToStrF(ResultMatrix(r-1,c-1),ffFixed,5,3);
		}
	}

}
//---------------------------------------------------------------------------

References

C++Builder DocWiki information

GetIt Package Manager

C++ Libraries in GetIt

Eigen C++ Template Library information

Eigen C++ Template Library main page

Eigen Library Documentation (version 3.3.7 as of this posting)

Eigen Quick Reference Guide

Eigen latest development version documentation (ver 3.3.90 as of this posting)

Eigen Advanced Initialization

Eigen IOFormat Class Reference

Eigen and Linear Algebra Tutorials and Information

Real-world Applications of Linear Algebra Tools by E. Ulrychova, postgradual student University of Economics, Department of Mathematics, Prague, Czech Republic (PDF)

Eigen Tutorial – CS2240 Interactive Computer Graphics (PDF) by Daniel Ritchie, Assistant Professor of Computer Science at Brown University

Eigen Library for Matrix Algebra in C++ by The Quantcademy

C++Builder Product Information

C++Builder Product Page – Native Apps that Perform. Build Windows C++ Apps 10x Faster with Less Code

C++Builder Product Editions – C++Builder is available in four editions – Professional, Enterprise, Architect and Community (free). C++Builder is also available as part of the RAD Studio development suite.

My C++Builder Eigen VCL Example Applications

Source Code zip file for all 3 examples

Recent ISO C++ News and Articles

There’s lots of ISO C++ news and content happening including the unanimous voting approval of ISO C++20, CppCon2020 (starts Monday September 13, 2020) with Bjarne Stroustrup’s opening keynote “The Power and Beauty of Primitive C++”, TIOBE’s Index for September 2020 headline “Programming Language C++ is doing very well”, C++ programming tips and tricks articles and more.

Links to recent ISO C++ news and articles

CppCon 2020 Opening Keynote – The Beauty and Power of “Primitive” C++ – this keynote is an exploration of a design space close to the hardware and of the use of C++ in that space, rather than a standards proposal or the presentation of a mature tool chain. And, no, by “primitive”, I don’t mean “old-fashioned, C-like” code; some of the general techniques are old, but some of the code requires C++17 and much could be done better given features we are unlikely to get even in C++23. Monday, September 14, 2020 8:45 to 10:00 MDT(Mountain Daylight Time).

TIOBE Index for September 2020 – Headline: “Programming Language C++ is doing very well” – Compared to last year, C++ is now the fastest growing language of the pack (+1.48%). I think that the new C++20 standard might be one of the main causes for this. Especially because of the new modules feature that is going to replace the dreadful include mechanism. C++ beats other languages with a positive trend such as R (+1.33%) and C# (+1.18%).

C++20 approved, C++23 meetings and schedule update by Herb Sutter – On Friday September 4, C++20’s DIS (Draft International Standard) ballot ended, and it passed unanimously. This means that C++20 has now received final technical approval and is done with ISO balloting, and we expect it to be formally published toward the end of 2020 after we finish a final round of ISO editorial work.

Concept archetypes by Andrzej Krzemieński – Concepts in the form added in C++20 used to be called lite. This is because they do not provide one quite important functionality: having the compiler check if the author of a constrained template is only using operations and types allowed by the constraining concept. In other words, we can say that our template only requires operations A and B to be valid, but we can still use some other operations inside and this is fine with the compiler. In this post we will show how this is problematic, even for programmers aware of the issue, and how to address it with concept archetypes.

6 Efficient Things You Can Do to Refactor a C++ Project by Bartlomiej Filipe (Bartek) – Bartek took his old pet project from 2006, experimented, refactored it and made it more “modern C++”. This article contains lessons learned and six practical steps that you can apply in your projects.

volatile and Other Small Improvements in C++20 by Rainer Grimm – This article completes Rainer’s tour through the C++20 core language features with a few small improvements. One interesting of these minor improvements is that most of volatile has been deprecated.

The implication of const or reference member variables in C++ by Lesley Lai – In the conventional wisdom of the C++ community, non-static const or reference data variables are considered problematic. There are solid reasons on why you should avoid const or reference member variables in C++. Nevertheless, like many things in C++, “avoid” does not mean “never use.” And they can occasionally still find some uses.

Using Vim for C++ Development by Adem Budak – Adem shares how he uses Vim as C++ development environment, adding things like code completion, linting, formatting and snippet support. If you come from the IDE land and have been set your options with the checkbox on a GUI, you might need a mental shift to use text based configuration tools, like Vim.

LLVM 10 bolsters Wasm, C/C++, and TensorFlow by Serdar Yegulalp – LLVM 10, an upgrade of the open source compiler framework behind a number of language runtimes and toolchains, is available today after a number of delays. The biggest addition to LLVM 10 is support for MLIR, a sublanguage that compiles to LLVM’s internal language and is used by projects like TensorFlow to efficiently represent how data and instructions are handled. Accelerating TensorFlow with LLVM directly is clumsy; MLIR provides more useful programming metaphors for such projects.

Two VCL Example Applications that Use C++Builder and the C++ Boost Libraries by David I – Boost is a set of open source C++ libraries that build on the ISO C++ programming language. In some cases, the Boost library functionality has become part of recent ISO C++ standards. RAD Studio allows you to install a subset of Boost that has been fully tested and preconfigured specifically for C++Builder. Use the GetIt Package Manager to install the Boost libraries for the Win32 classic C++ compiler, Win32 Clang-enhanced C++ compiler and Win64 Clang-enhanced compiler.

C++Builder’s Clang-enhanced ISO C++ compilers, Dinkumware Standard C++ Library and Boost Libraries in version 10.4.1 Sydney

C++ developers often ask about ISO C++ language support in releases of Embarcadero C++Builder. This post includes links and information about the C++ compilers, Dinkumware Standard C++ libraries and Boost libraries that are included in C++Builder 10.4 Sydney Release 1.

The latest release of C++Builder is 10.4 Sydney Release 1 (v10.4.1). Version 10.4.1 includes C++ tool chain and RTL improvements in the Win64 debugger, linker, exception handling and general quality. The DocWiki contains a list of feature enhancements and developer reported issues fixed in the IDE, VCL, FMX, and RTL. RAD Studio 10.4.1 also includes all fixes from 10.4 Patch 1, Patch 2, and Patch 3.

C++Builder Clang-Enhanced Compilers

C++Builder 10.4 Sydney Clang-enhanced compiler Clang and LLVN version information is as follows:

CompilerPlatformClang VersionLLVM Version
BCC32C32-bit Windows5.05.0
BCC32X32-bit Windows5.05.0
BCC6464-bit Windows5.05.0
BCCIOSARM32-bit iOS3.33.3
BCCIOSARM6464-bit iOS3.33.5
BCCAARMAndroid3.33.3

You can find Clang/LLVM ISO C++ Status information at  https://clang.llvm.org/cxx_status.html

  • Clang 3.3 and later implement all of the ISO C++ 2011 standard.
  • Clang 3.4 and later implement all of the ISO C++ 2014 standard.
  • Clang 5 and later implement all the features of the ISO C++ 2017 standard.

If you need your C++ application to test for Clang version use at compile time use the following code:

#if defined(__clang__)
  #if (__clang_major__ == 5 && __clang_minor__ == 0)
    #include <clang5.0\xmmintrin.h>
  #elif (__clang_major__ == 3 && __clang_minor__ == 3)
    #include <clang3.3\xmmintrin.h>
  #else
    #error "Unable to determine correct clang header version"
  #endif
#else
    #error "Only supported for clang compilers"
#endif

David Millington, Product Manager for C++Builder keeps the Embarcadero C++Builder information updated on the C++ Reference compiler support page. On this page you can look at the different ISO C++ language releases to see what many compilers support in their compiler releases.

Dinkumware Standard Library

The Dinkumware Standard C++ Library is the implementation of the C++ Standard Library that C++Builder uses for applications on the 32-bit Windows, 64-bit Windows and macOS target platforms.

The libraries include containers such as vectors, lists, sets, maps, and bitsets. Dinkumware also includes algorithms for common operations, such as sorting a container or searching inside a container.

Dinkumware version 8.03a is available specifically for C++ application development on target platforms that support the Clang enhanced compilers. Dinkumware version 5.01 is provided to support the classic C++ compiler.

Target PlatformCompilerC++ StandardDinkumware Version
32-bit WindowsBCC32C++98/035.01
BCC32CC++178.03a
BCC32XC++178.03a
64-bit WindowsBCC64C++178.03a
Note: C++Builder does not currently support the use of the Dinkumware Standard C++ Library on mobile platforms. On mobile platforms, the SDK’s standard library platform is used.

Boost Libraries

C++Builder supports different versions of the Boost libraries depending on the C++ compiler that you use to compile your application.

PlatformCompilerBoost Version
32-bit WindowsBCC321.39.0
BCC32C1.70.0
64-bit WindowsBCC641.70.0

To install the Boost libraries you need, use the IDE’s Tools | GetIt Package Manager menu and select one or more of the Boost packages.

See Also

C++ Reference

C++Builder Developer’s Guide

Dinkumware Standard C++ Library

Boost Libraries

Supported Target Platforms

C++Builder Product Page – Native Apps that Perform. Build Windows C++ Apps 10x Faster with Less Code

C++Builder Product Editions – C++Builder is available in four editions – Professional, Enterprise, Architect and Community (free). C++Builder is also available as part of the RAD Studio development suite.

Desktop First UX Summit – Sept 16th & 17th, 2020

The FREE Desktop First UX Summit is your chance to learn from the best UI and UX industry experts and practitioners and take your desktop applications to the next level.

Move beyond the Mobile-First design of just stretching a small UI to fill a desktop screen. Learn how to take the most advantage of the most powerful platform and make your users more productive.
Sponsored by Embarcadero’s RAD Studio 10.4 Sydney.

Here are the first two of many talks being given at the Desktop First UX Summit:

Register Now

View the Schedule

Two VCL Example Applications that Use C++Builder and the C++ Boost Libraries

Boost is a set of open source C++ libraries that build on the ISO C++ programming language. In some cases, the Boost library functionality has become part of recent ISO C++ standards. RAD Studio allows you to install a subset of Boost that has been fully tested and preconfigured specifically for C++Builder. Use the GetIt Package Manager to install the Boost libraries for the Win32 classic C++ compiler, Win32 Clang-enhanced C++ compiler and Win64 Clang-enhanced compiler.

Boost libraries available in C++Builder’s GetItPackage Manager

boost::filesystem and std:filesystem VCL example

The ISO C++ std::filesystem evolved from the Boost filesystem library. The Filesystem library started in Boost, then became an ISO C++ Technical Specification and was finally merged into the ISO C++17 standard. The first example shows how to create a C++Builder VCL application using the Boost filesystem and the ISO C++ filesystem.

The VCL form contains two TButton, one TEdit and two TMemo components. The TEdit is used to set a path to files and directories on your hard drive. One button OnClick event handler will use the boost::filesystem functions to display the contents of the path. The other button OnCLick event handler will use the std::filesystem functions to display the contents of the same path. Why use both libraries? You may have an application and compiler than does not support the latest C++17 filesystem library standard. There are additional boost library versions available to support a wider range of platform filesystem operations.

VCL form for Boost and Std filesystem libraries application

C++Builder VCL application after using the boost and std filesystem library buttons

Filesystem VCL app mainunit.h:

//---------------------------------------------------------------------------

#ifndef MainUnitH
#define MainUnitH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE-managed Components
	TButton *BoostButton;
	TEdit *Edit1;
	TMemo *Memo1;
	TButton *Cpp17Button;
	TMemo *Memo2;
	void __fastcall BoostButtonClick(TObject *Sender);
	void __fastcall Cpp17ButtonClick(TObject *Sender);
private:	// User declarations
public:		// User declarations
	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

Filesystem VCL App MainUnit.cpp:

//---------------------------------------------------------------------------

#include <vcl.h>

/*
	https://en.cppreference.com/w/cpp/filesystem
	The filesystem library was originally developed as boost.filesystem,
	was published as the technical specification ISO/IEC TS 18822:2015,
	and finally merged to ISO C++ as of C++17.

	https://www.boost.org/doc/libs/1_70_0/libs/filesystem/doc/index.htm
*/

#include <boost/filesystem.hpp>
namespace Boostfs = boost::filesystem;

#include <filesystem>
namespace Cpp17fs = std::filesystem;

#pragma hdrstop

#include "MainUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::BoostButtonClick(TObject *Sender)
{

	// Boost Filesystem verion

	Memo1->Lines->Clear();
	// use the Boost FileSystem to get directories and files using path in editbox
	Boostfs::path directoryPath = Edit1->Text.c_str();
	for (const auto& entry : Boostfs::directory_iterator(directoryPath)) {
		Boostfs::path p = entry.path();
		// test if the path is a file
		if (is_regular_file(p)) {
			int fsize = file_size(p);
			std::string s = p.string() + " : size = ";
			Memo1->Lines->Add(s.c_str() + IntToStr(fsize));
		}
		// test if the path is a directory
		else if (is_directory(p)) {      // is p a directory?
			std::string s = p.string() + " : directory";
			Memo1->Lines->Add(s.c_str());
		}
		// otherwise it is something else :)
		else {
			std::string s = p.string() + " not a file or directory";
			Memo1->Lines->Add(p.c_str());
		}
	}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Cpp17ButtonClick(TObject *Sender)
{
	// C++17 FileSystem version

	Memo2->Lines->Clear();
	// use C++17 std FileSystem library to get directories given a path in the editbox
	Cpp17fs::path directoryPath = Edit1->Text.c_str();
	for (const auto& entry : Cpp17fs::directory_iterator(directoryPath)) {
		Cpp17fs::path p = entry.path();
		if (Cpp17fs::is_directory(p)) {
			std::string s = p.string() + " : directory";
			Memo2->Lines->Add(s.c_str());
		}
		else if (Cpp17fs::is_regular_file(p)) {
			int fsize = Cpp17fs::file_size(p);
			std::string s = p.string() + " : size = ";
			Memo2->Lines->Add(s.c_str() + IntToStr(fsize));
		}
		else {
			std::string s = p.string() + " not a file or directory";
			Memo2->Lines->Add(p.c_str());
		}
	}
}
//---------------------------------------------------------------------------

boost::circular_buffer VCL example

The boost circular buffer (also known as a ring or cyclic buffer) library allows for the storing of data. The boost is designed to support fixed capacity storage. When the buffer is full, additional elements will overwrite existing elements at the front and back of the buffer (depending on the operations used).

The VCL form contains three TButton, one TSpinEdit and one TMemo components. One TButton OnClick event handler shows the contents of the circular buffer (originally populated by the Form’s OnShow event handler. The other two TButton OnClick event handlers use the boost circular buffer push_front and push_back public member functions.

Boost circular buffer C++Builder VCL form
C++Builder VCL form with Circular Buffer populated by OnShow event handler
Application showing contents of Circular Buffer after Add to front button is clicked
Application showing contents of Circular Buffer after Add to back button is clicked
Circular Buffer VCL app mainunit.h:

//---------------------------------------------------------------------------

#ifndef MainUnitH
#define MainUnitH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.Samples.Spin.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE-managed Components
	TButton *AddToCircularQueueFrontButton;
	TSpinEdit *SpinEdit1;
	TMemo *Memo1;
	TButton *ShowCircularBufferButton;
	TButton *AddToCircularQueueBackButton;
	void __fastcall FormShow(TObject *Sender);
	void __fastcall ShowCircularBufferButtonClick(TObject *Sender);
	void __fastcall AddToCircularQueueFrontButtonClick(TObject *Sender);
	void __fastcall AddToCircularQueueBackButtonClick(TObject *Sender);
private:	// User declarations
public:		// User declarations
	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

Circular Buffer VCL app mainunit.cpp:

//---------------------------------------------------------------------------

#include <vcl.h>
#include <boost/circular_buffer.hpp>
#pragma hdrstop

#include "MainUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

// Create a circular buffer with a capacity for 3 integers.
boost::circular_buffer<int> cb(3);

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
	// initialize circular buffer with 3 integers
	cb.push_back(1);
	cb.push_back(2);
	cb.push_back(3);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ShowCircularBufferButtonClick(TObject *Sender)
{
	int circularbuffersize = cb.size();
	Memo1->Lines->Clear();
	Memo1->Lines->Add("Circular Buffer Size = "+IntToStr(circularbuffersize));
	Memo1->Lines->Add("Items:");
	// display items in the circular buffer
	for (int i : cb)
		Memo1->Lines->Add("  "+IntToStr(i));
}
//---------------------------------------------------------------------------

void __fastcall TForm1::AddToCircularQueueFrontButtonClick(TObject *Sender)
{
	cb.push_front(SpinEdit1->Value);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::AddToCircularQueueBackButtonClick(TObject *Sender)
{
	cb.push_back(SpinEdit1->Value);
}
//---------------------------------------------------------------------------

References

Boost C++Builder DocWiki

Boost C++ Libraries home page

Boost version 1.70

Converting from Boost to std::filesystem by Scott Furry as a guest post on Bartlomiej Filipek (Bartek) blog.

boost::filesystem library documentation

C++ std::filesystem documentation

boost::circular_buffer documentation

boost and std filesystem VCL app source code project (zip file)

boost circular buffer VCL app source code project (zip file)

C++Builder Product Information

C++Builder Product Page – Native Apps that Perform. Build Windows C++ Apps 10x Faster with Less Code
C++Builder Product Editions – C++Builder is available in four editions – Professional, Enterprise, Architect and Community (free). C++Builder is also available as part of the RAD Studio development suite.

Building a C++Builder RSS Feeds VCL Application with XMLDocument, NetHTTPClient, NetHTTPRequest and WebBrowser Components

I have many favorite prebuilt components that are included with C++Builder 10.4 Sydney. In this blog post I’ll show you how to create an RSS Feeds VCL (you can also use the same approach for a FireMonkey FMX) application using the XMLDocument, NetHTTPClient, NetHTTPRequest and WebBrowser components.

Start by creating a C++Builder VCL application. Set the form’s WindowState property to wsMaximized. Add a Panel, Button, ListBox (used to hold the list of RSS feed URLs to process) and a few labels and align them to the top of the form. Add Memo (to display the Feed XML), ListBox (to contain the title and URL for each article found in the feeds) and WebBrowser (to display the web page when you click on an item in the articles list box) components to the rest of the form.

Main Form
The RSS Feed application’s main form.

To populate the Panel’s listbox, I use a text file, “FeedsList.txt”, which contains a number of RSS feed URLs. The panel listbox is populated in the Form’s OnShow event handler.

Clicking on the button will process all of the RSS feed URLs and add each article and URL item found into the list box of articles found.

The XMLDocument component has a DOMVendor property to select the DOM implementation to use for parsing and manipulating the XML document.

DOMVendor choices

Clicking on an item in the articles list box uses the OnClick event handler to call the WebBrowser Navigate method  for the selected article URL. In C++Builder 10.4 Sydney there is a new property added to the WebBrowser component that lets you choose which browser engine will be used on Windows. I’ve chosen the EdgeIfAvailable engine.

SelectedEngine

Here is the contents of the FeedsList.txt file:

https://isocpp.org/blog/rss
https://herbsutter.com/feed/
http://feeds.hanselman.com/scotthanselman
http://feeds.dzone.com/home
https://news.ycombinator.com/rss
http://www.odbms.org/feed/
https://www.techmeme.com/feed.xml
https://techcrunch.com/feed/
http://feeds.feedburner.com/oreilly/radar/atom
http://feeds.feedburner.com/appdevelopermagazine
https://www.infoworld.com/index.rss
https://newsroom.ibm.com/announcements?pagetemplate=rss
https://www.computerworld.com/index.rss
https://techxplore.com/rss-feed/
https://sdtimes.com/feed/
https://www.geeksforgeeks.org/feed/
https://feeds.feedburner.com/venturebeat/SZYF
http://feeds.feedburner.com/ProgrammableWeb

Here is a bitmap of the running application:

Finally here is the source code for the application:

//---------------------------------------------------------------------------

#include <vcl.h>
#include <fstream>
#pragma hdrstop

#include "MainFeedUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;
//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm2::ArticlesFoundListBoxClick(TObject *Sender)
{
	// for the ListBox item clicked - get the URL and Browse to the article
	LabelStatus->Caption = ArticlesFoundListBox->Items->Names[ArticlesFoundListBox->ItemIndex];
	ArticleWebBrowser->Navigate(ArticlesFoundListBox->Items->Values[ArticlesFoundListBox->Items->Names[ArticlesFoundListBox->ItemIndex]]);
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Button1Click(TObject *Sender)
{
	// Find and save Title and URL for items found
	std::ofstream fs (AnsiString(FormatDateTime("yyyy-mm-dd-hhnnss",Now())+"_RSSFound.txt").c_str());
	fs << AnsiString("RSS Feed for: "+ NetHTTPRequest1->URL).c_str() << std::endl;
	fs << AnsiString(FormatDateTime("dddd mmmm dd, yyyy @ hh:nn:ss",Now())).c_str() << std::endl;
	fs << std::endl;

	// Clear the Articles Found List Box to prepare for the title and URL of articles
	ArticlesFoundListBox->Clear();
	FeedsItemsCountLabel->Caption = "Items Found = 0";

	// get all articles and URLs in all feeds
	for (int i = 0; i < FeedsListBox->Count; i++) {
		// Get the RSS feed URL string from the ListBox
		NetHTTPRequest1->URL = FeedsListBox->Items->Strings[i];

		UrlLabel->Caption = "Feed URL: "+NetHTTPRequest1->URL;
        UrlLabel->Update();

		// Use NetHTTPRequest Execute method to get the RSS Feed XML
		UnicodeString FeedString = NetHTTPRequest1->Execute()->ContentAsString();

		// copy the XML string to the Memo
		MemoFeedXML->Lines->Clear();
		MemoFeedXML->Lines->Text = FeedString;
		MemoFeedXML->Update();

		// load the RSS Feed XML into the XMLDocument
		XMLDocument1->LoadFromXML(FeedString);
		XMLDocument1->Active = True;

		LabelStatus->Caption = "Processing RSS for "+NetHTTPRequest1->URL;
		LabelStatus->Update();

		// find the RSS feed channel node
		_di_IXMLNode ChannelNode = XMLDocument1->DocumentElement->ChildNodes->FindNode ("channel");
		// test to make sure the ChannelNote is found
		if (ChannelNode != NULL) {
			for (int I=0;I<ChannelNode->ChildNodes->Count;I++) {
				// iterate through child nodes
				_di_IXMLNode ItemNode = ChannelNode->ChildNodes->Get(I);
				// if child node is an item then get the title, pubDate and URL
				if (ItemNode->NodeName == "item") {
					LabelStatus->Caption = "Processing Node " + IntToStr(I);
					LabelStatus->Update();
					UnicodeString title = ItemNode->ChildValues ["title"];
					UnicodeString pubDate = ItemNode->ChildValues ["pubDate"];
					// author := ItemNode.ChildValues ['author'];    // could be nil
					UnicodeString url = ItemNode->ChildValues ["link"];

					// populate the articles found ListBox with the pair of title and URL
					ArticlesFoundListBox->Items->AddPair(title,url);
					ArticlesFoundListBox->Update();
					FeedsItemsCountLabel->Caption = "Items Found = "+IntToStr(ArticlesFoundListBox->Count);
					FeedsItemsCountLabel->Update();

					// write the Title, pubDate and URL to the text file
					fs << AnsiString(title).c_str() << std::endl;
					fs << AnsiString(pubDate).c_str() << std::endl;
					fs << AnsiString(url).c_str() << std::endl;
					fs << std::endl;
				}
			}
		}

	}

	fs << std::endl;
	fs << AnsiString("Items Found = "+IntToStr(ArticlesFoundListBox->Count)).c_str() << std::endl;
	fs << "end of file" << std::endl;
	fs.close();   // close the text file
	LabelStatus->Caption = "RSS Processing Done!";
    UrlLabel->Caption = "";
}
//---------------------------------------------------------------------------
void __fastcall TForm2::FormShow(TObject *Sender)
{
	// load RSS Feeds ListBox with the "FeedsList.txt" text file
    // I put the text file in the same folder as the app .EXE file
	FeedsListBox->Items->Clear();
	FeedsListBox->Items->LoadFromFile("FeedsList.txt");
	LabelStatus->Caption = "RSS Feed Urls Loaded = "+IntToStr(FeedsListBox->Count);
	LabelStatus->Update();

}
//---------------------------------------------------------------------------

References

Using TXMLDocument

Using the Document Object Model

Using an HTTP Client

System.Net.HttpClientComponent.TNetHTTPClient

System.Net.HttpClientComponent.TNetHTTPRequest

Using TEdgeBrowser Component and Changes to the TWebBrowser Component

RSS 2.0 Specification

Download Source Code ZipFile for RSSFeedListsUsingTextFileVCLCpp

C++Builder Product Information

C++Builder Product Page – Native Apps that Perform. Build Windows C++ Apps 10x Faster with Less Code
C++Builder Product Editions – C++Builder is available in four editions – Professional, Enterprise, Architect and Community (free). C++Builder is also available as part of the RAD Studio development suite.

Roberto V. Zicari interviews Bjarne Stroustrup, the inventor of C++ programming language

Roberto V. Zicari interviewed Bjarne Stroustrup, the inventor of C++ programming language, back in 2007. Roberto again interviews Bjarne 13 years later.

In the interview, Bjarne talks about notable computer scientists that influenced his career and work. Bjarne also talks about why he designed the C++ language and why he started with the C language. Bjarne also talks about three guiding principles for the design of the C++ language: “Make the language simpler! Add these two essential features now!! Don’t break (any of) my code!!!”

Read the interview on the Roberto’s ODBMS.ORG site.

My Conversations with Bjarne Stroustrup

I’ve also had two opportunities to talk live online with Bjarne about the C++ language during past Embarcadero CodeRage online conferences:

A Conversation with the C++ language designer, Bjarne Stroustrup
Monday, December 10, 2012
C++ Language Conversation with Bjarne Stroustrup and David Intersimone
Tuesday, December 4, 2018

About ODBMS.ORG

ODBMS.ORG is designed to meet the fast-growing need for resources focusing on AI, Big Data, Data Science, Analytical Data Platforms, Scalable Cloud platforms, NewSQL databases, NoSQL datastores, In-Memory Databases, and new approaches to concurrency control.

About Roberto Zicari

Roberto is Full Professor of Database and Information Systems at Frankfurt University. He was for over 15 years the representative of the OMG in Europe. Previously, Roberto served as associate professor at Politecnico di Milano, Italy; Visiting scientist at IBM Almaden Research Center, USA, the University of California at Berkeley, USA; Visiting professor at EPFL in Lausanne, Switzerland, the National University of Mexico City, Mexico and the Copenhagen Business School, Danemark.

About Bjarne Stroustrup

Bjarne is a Technical Fellow and a Managing Director in the technology division of Morgan Stanley in New York City and a Visiting Professor in Computer Science at Columbia University. Bjarne designed and implemented the C++ programming language. To make C++ a stable and up-to-date base for real-world software development, Bjarne says “I have stuck with its ISO standards effort for almost 30 years (so far).”

Bjarne Stroustrup’s homepage