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

New in C++Builder/Delphi 10.4.1 IDE: Package LibSuffix Auto Choice

The C++Builder and Delphi Project | Options | Description page allows developers to

  • Choose and Set build target configurations
  • Write a description for the package
  • Set strings for the package library filename’s prefix, suffix and version
  • Define the use of the package (designtime, runtime or both)
  • Specify how the package is built (rebuild as needed or explicit rebuild)

In previous versions (version 10.3 and earlier) of C++Builder and Delphi developers building packages needed to manually set their package’s library suffix setting. The DocWiki “What’s new in version 10.4.1” mentions a new IDE projects option for setting the library suffix:

“Package AUTO libsuffix: packages can now have an automatic version suffix, instead of manually updating and specifying the right version suffix with each new release. (The compiler quietly supported this in 10.4, but full support for the feature in the IDE and package project settings is introduced in 10.4.1.)”

While you can still set a string for the library filename suffix, selecting the new ComboBox choice, “$(Auto)”, allows the compiler to set the suffix to match the package build version used by the compiler. For each target build (debug and release) and OS platform the resulting package filename follows a pattern:

Win32 and Win64: <prefix>Package1<suffix>.<version>.bpl
Android: <prefix>Package1<suffix>.so.<version>
macOS and iOS: <prefix>Package1<suffix>.<version>.dylib

Creating and building a package with Delphi and C++Builder version 10.4.1, choosing the $Auto option for the suffix and setting other Description page settings results in a filename like the test package project images shown below.

C++Builder and Delphi also support package-specific compiler directives to include in a package project’s source code.

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.