The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,862 other subscribers

Archive for the ‘Delphi’ Category

delphi – How to convert a null terminated string to string? – Stack Overflow

Posted by jpluimers on 2020/10/22

An old trick that I tend to forget: [WayBack] delphi – How to convert a null terminated string to string? – Stack Overflow:

You can assign a null-terminated PChar directly to a String:

function GetFileName(DiskName: TFileNameIO): string;
begin
 Result := PChar(@DiskName);
end;

It can work even on string literals and constants, where you can leave out the @, like in:

var
  S: string;
begin
  S := PChar(FastMM4Messages.LogFileExtension;

Probably time to update the unit I mention in ISO 8601 Date, Time and DateTime in Delphi (was: Simple example to show DateTime.Now in ISO 8601 format on ideone.com | Online C# Compiler & Debugging Tool).

–jeroen

Posted in Delphi, Development, Software Development | Leave a Comment »

Automated testing Windows applications using Katalon and WinAppDriver

Posted by jpluimers on 2020/10/21

[WayBack] Top 45 Best Automation Testing Tools Ultimate List • Test Automation Made Easy: Tools, Tips & Training Awesomeness A few notes, partially related to Enable your device for development – UWP app developer | Microsoft Docs.

One research project I had a while ago, was to see how it was possible to use a generic testing tool like Katalon Studio (that can test many platforms), for testing Windows applications.

Katalon uses a Selenium interface that normally is used for web applications through the [WayBack] WebDriver protocol (formerly [WayBack] JsonWireProtocol) that continues to be updated: [WayBack] draft upcoming WebDriver protocol, which is more generic than just web applications:

Read the rest of this entry »

Posted in .NET, Conference Topics, Conferences, Delphi, Development, Event, Software Development, Windows Development, WinForms, WPF | Leave a Comment »

Delphi: get timestamp as ISO8601 string for use in filenames

Posted by jpluimers on 2020/10/21

On Windows, filenames do not like some characters (including : and +), so this is a quick way to get a timestamp into ISO8601 format that is compatible with filenames.

TimeStamp := Now();
StartIso8601String := DateToISO8601(TimeStamp, False).Replace('-', '').Replace(':', '') // https://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators

It Depends on the [WayBackSystem.DateUtils unit which had the [WayBackDateToISO8601 function [Archive.isadded in Delphi XE6.

A poor man’s solution (that skips timezones altogether) is this one:

FormatDateTime('yyyymmdd''T''hhnnss''.''zzz', TimeStamp); // note quoted T and ., as otherwise they will be expanded.

–jeroen

Posted in Delphi, Development, Software Development | Leave a Comment »

Class methods in Record vs Class in Delphi 2010 – Stack Overflow

Posted by jpluimers on 2020/10/20

A still relevant part for [WayBack] Class methods in Record vs Class in Delphi 2010+ – Stack Overflow is the distinction between class methods on both:

  • on classes they can be either regular (no extra keyword), static or virtual.
  • on records they can only be static, as there is no inheritance on records
    • this also holds for any helpers that are not class helpers (and presumably if they are ever created: interface helpers)

While class methods inside classes can be used in the same way, they can in addition have another goal: they can be virtual. Called from a class variable this can lead to different implementations depending on the current content of that variable. This is not possible for records. As a consequence class methods in records are always static.

Thanks Uwe Raabe for this insight!

One odd thing on class methods in classes, is that when they need to be static when they are the read or write backing of a class property.

When a class method is static, any calls from it to virtual (or dynamic) methods will not be handled as such: there is no class VMT for it (as because they are static, they do not have a self parameter).

–jeroen

PS: I realised later that part of the above was already in E2398 Class methods in record types must be static (Delphi) – RAD Studio

Posted in Delphi, Development, Software Development | Leave a Comment »

Delphi and conditional compilation

Posted by jpluimers on 2020/10/15

There are various ways for Delphi code to verify what features are available.

Historically, testing for the existence of VER### defines with $IFDEF or $IFNDEF is the oldest means, and as of Delphi 6, you can also test for the existence and values of identifiers is $IF defined, $IF not defined and, especially for CompilerVersion and RTLVersion .

My versioned PowerShell script List-Delphi-Installed-Packages.ps1 tries to keep an up to date list of versions and features starting with BDS 1 (which was C# Builder) and BDS 2 (which was Delphi 8 with VER160). One day I will make it Pascal based in stead of BDS based.

The JEDI Code Library has kept a versioned JEDI.INC up to date since Delphi 1.0.

Binding those to specific features can be a tough thing when you depend on version numbers, but less hard when you rely on feature names.

Every couple of years, people start proposing units to replace include files, usually with an argument like this:

If you forget to include it into your source code, all your IFDEFS will fail and in the worst case your workaround won’t be active (the best case is that the compiler runs into an error so you will notice the missing include).

The problem is that for such a unit to work:

  1. you have to always use it (debunking the above argument)
  2. you will need to have the very latest version, even if you use old compilers (so you can use code written for any Delphi version)
    • See the quoted below “Do you expect that the old versions will get an update to know the new constants RTLVersion_Atlantis = 99.0; too?” below
  3. you need a central place where that version is available (like JEDI.INC)
  4. it will only work with booleans
    • See the quote below “Which is also backwards compatible because the compiler (at least in XE and up, haven’t checked any older versions) just evaluates a non existing value as False.”
  5. it requires $IF, which is a pain in the ass
    • See the quote below “Using $IF is a major pita because of $IFEND or $ENDIF depending on compiler version and $LEGACYIFEND setting.”

The only good thing is what Rudy Velthuis commented:

checking for a $DEFINE like DELPHI_RIO_UP can go wrong. If you have a typo, it will simply not be recognized as defined and compile the wrong code. Checking for {$IF CompilerVersion >= some_constant} will fail to compile if some_constant is not defined

A few people tried:

JEDI.INC

You might think that JEDI.INC was only introduced in 2003, but it is in fact much older as the JEDI Code Library had its own version control system (initially called FreeVCS) before first switching to SVN and later to GIT.

So these are only part of the history:

VER### got introduced as VER40 in Turbo Pascal 4

The product naming mess now completely has disconnected people from binding it to their Delphi version.

It helps knowing that VER### is the compiler version starting with Turbo Pascal 1, and remembering that Delphi 1 had VER80, and the three digits only started with Delphi 3 which introduced VER100.

Turbo Pascal 1 through 3 did not have any VER## defined, despite some sites

The first ever VER## conditional define was VER40 was introduced in Turbo Pascal 4, as you can see in Full text of “borland :: turbo pascal :: Turbo Pascal Version 4.0 Owners Manual 1987” (or PDF via borland :: turbo pascal :: Turbo Pascal Version 4.0 Owners Manual 1987 : Free Download, Borrow, and Streaming : Internet Archive)

Related:

JEDI History:

–jeroen

Read the rest of this entry »

Posted in Delphi, Development, Software Development, Turbo Pascal | Leave a Comment »

Reminder to self: find open source tool that strips TDS / TD32 debug information from EXE

Posted by jpluimers on 2020/10/14

There is StripTDS from SmartBear, but it is not open source or downloadable without their full product install.

So either find an open source tool that can strip TDS / TD32 symbol information from EXE files, or make one.

Related:

–jeroen

Posted in Delphi, Development, Software Development | Leave a Comment »

Unicode is hard, also for the Delphi compiler and IDE

Posted by jpluimers on 2020/10/13

The Delphi compiler does not see a unicode non-breaking space (0x00A0 as whitespace, and the Delphi IDE does not warn you about it: [WayBack] Delphi revelations #2 – Space characters are not just space characters.

Given that this character was introduced in 1993, I wonder how the compiler tests look like.

These also will not be recognised as whitespace:

Related, as many other tools also do not properly support various whitespace characters:

Via: [WayBack] A Delphi “Aha” experience – Kim Madsen – Google+

–jeroen

Posted in Delphi, Development, Software Development, Unicode | Leave a Comment »

Delphi icons to distinguish various Delphi versions

Posted by jpluimers on 2020/10/08

When installing many Delphi versions, all have similar icons. So I asked this a while ago: [WayBack] I remember someone creating version specific icons for Delphi a while ago (around XE4 era I think), but cannot find them any more. Anyone who can prov… – Jeroen Wiert Pluimers – Google+.

Luckily Achim Kalwa responded quickly with a set of icons he designed and put them up at https://drive.google.com/drive/folders/1VoYeMmsr6FYgoe9EkR-psrV7aPO7Gv-v

Hopefully by now I have had time to edit them for more Delphi versions (he had them for Delphi XE7 until 10.2 Tokyo).

Delphi XE2 and lower icons seem to be at [Archive.is] Delphi versions and icons, mortenbs.com

–jeroen

Posted in Delphi, Development, Software Development | Leave a Comment »

Reverse engineering Delphi and Turbo Pascal unit interfaces (and maybe DCP files too)

Posted by jpluimers on 2020/10/07

Boy, I wish there was both an Embarcadero sanctioned grammar (see Delphi code completion fail with anonymous methods – Stack Overflow) and a DCU parser.

This might work for DCP files as well, since the PKX0 signature at the start of DCP files is in [WayBack] DCU32INT/DCP.pas at master · rfrezino/DCU32INT · GitHub.

Being able to dump DCP files makes it way easier to create documenting a matrix of all DCP files and units, to their interdependencies and containments become clear (including any unit scopes).

Right now that is only documented from the unit to the package on the page of the unit (see for instance [WayBack] System.SysUtils – RAD Studio API Documentation), not the other way around. This is a pain to select which packages you need in your project when building with packages.

The list at [WayBack] Unit List – RAD Studio API Documentation (which actually is an “Alphabetical list of unit scopes, along with miscellaneous units that have no unit scope.” is only partially helpful, especially as for instance the System unit page at [WayBack] System – RAD Studio API Documentation is 90% about the System unit scope, has the System unit itself about a 3rd down and does not mention it lives in the rtl.dcp package.

The list at [WayBack] Deciding Which Runtime Packages to Use – RAD Studio is even worse than the unit list, as it misses many useful packages (like dsnap)

For my link archive:

Johan wanted to create a compiler symbol table from the binary DCU files (unlike DelphiAST which does it from the Pascal source files).

From the pre-Delphi era, I found back some info from my own archive:

In the Turbo Pascal days, you had TW1UNA and TPUUNA by William L. Peavy, which I think led to INTRFC from Duncan Murdoch (or maybe vice versa) which got updated to Turbo/Borland Pascal 7 format by Milan Dadok (see [Wayback/Archive] http://sources.ru/pascal/hacker/intrfc70.htm). Since the basic format of DCU files is very similar to that, my guess is that DCU32INT built on that.

Later I found [Wayback/Archive] The Programmer’s Corner » TPU60C.ZIP » Pascal Source Code also by William L. Peavy and Wayback/Archive] Duncan Murdoch’s Programs .

Edit 20220621:

  • moved the www8.pair.com links to murdoch-sutherland.com
  • added more Wayback and Archive links

–jeroen

Posted in Borland Pascal, Conference Topics, Conferences, Delphi, Development, Event, History, Pascal, Software Development, Turbo Pascal | Leave a Comment »

From Delphi 1: Type Compatibility and Identity

Posted by jpluimers on 2020/09/30

A feature overlooked by many Delphi programmer was already introduced in Delphi 1 which is more or less the same as in the Delphi 2007 documentation at [WayBack] Type Compatibility and Identity.

There is a distinction between these explained in the above link:

type
  TMyInteger1 = Integer;
  TMyInteger2 = type Integer;

Where TMyInteger1 is an alias for Integer, TMyInteger2 introduces a new type which is distinct from Integer and TMyInteger. That way the compiler can set them apart, and even generates separate RTTI (Run-Time TypeInformation) for them.

Probably the most used distinct types are these:

TDateTime = type Double;
...
TDate = type TDateTime;
TTime = type TDateTime;
TFontName = type string

These are unlike TColor which is defined as “just” a subrange of Integer, but because it is a subtype, also gets a distinct type:

TColor = -$7FFFFFFF-1..$7FFFFFFF;

Type identity is important because Delphi 1 introduced these mechanisms:

  • the streaming instances and their properties
  • editing instances and properties in the object inspector
  • two way binding of designer (form/datamodule/frame/…) and the underlying Pascal source

Without them, very basic Delphi features would not work.

In addition, a lot of other RTTI based code now enables features like object relational mapping, binding to JSON/XML and many others.

What I did not know is that the Pascal and Delphi type systems have been heavily influenced by ADA. Luckily Lutz Donnerhacke pointed me to ADA [WayBack] Types and Subtypes.

Example

I made an example Distinct type types in Delphi · GitHub showing the differences on RTTI level in these properties:

property IntegerProperty: Integer read FIntegerField write FIntegerField;
property ColorProperty: TColor read FColorField write FColorField;
property DoubleProperty: Double read FDoubleField write FDoubleField;
property DateTimeProperty: TDateTime read FDateTimeField write FDateTimeField;
property DateProperty: TDate read FDateField write FDateField;
property TimeProperty: TTime read FTimeField write FTimeField;
property StringProperty: string read FStringField write FStringField;
property FontNameProperty: TFontName read FFontNameField write FFontNameField;

The generated table (see also the source below using [Archive.is] TRttiContext added in Delphi 2010) indeed shows distinct types on the RTTI level:

Name Type.Name Type.QualifiedName Type.TypeKind
IntegerProperty Integer System.Integer tkInteger
ColorProperty TColor System.UITypes.TColor tkInteger
DoubleProperty Double System.Double tkFloat
DateTimeProperty TDateTime System.TDateTime tkFloat
DateProperty TDate System.TDate tkFloat
TimeProperty TTime System.TTime tkFloat
StringProperty string System.string tkUString
FontNameProperty TFontName System.UITypes.TFontName tkUString

This post was inspired by an interesting discussion on [WayBack] What’s the technical term for the following construct: type intx = type integer; type inty = integer; What term would you use to describe the differen… – Johan Bontes – Google+

Documentation:

RTTI dump inspired by [WayBack] delphi – How can I distinguish TDateTime properties from Double properties with RTTI? – Stack Overflow.

–jeroen

Read the rest of this entry »

Posted in Conference Topics, Conferences, Delphi, Development, Event, Software Development | 2 Comments »