Remote access to the Embarcadero License Center via SSH tunnel

 Delphi  Comments Off on Remote access to the Embarcadero License Center via SSH tunnel
Apr 282018
 

Once you have set up an Embarcadero License Center (ELC) for your company (with network named user or concurrent licenses) you will need network access to it in order to start the Delphi IDE.

Usually the server will only be accessible from within your intranet (I for one would not trust the ELC security to be good enough to let that server directly face the Internet.). So, in order to access it from a remote computer (e.g. your notebook on a customer’s site or your PC in your home office), that computer must have access to your intranet. If the connection is not available, Delphi will revert to offline usage which will work fine until the offline usage period expires which by default is 7 days but can be configured to up to 30 days.

There are multiple options to provide that access, the one I use is SSH tunneling via Putty.

By default the ELC listens on port 5567 for clients to connect to it, that port is specified when importing a license into ELC and cannot be changed later. The license manager reads the server name and port from the .slip file you provided to it, so you need a way to

  1. Resolve the name to the IP address
  2. Tunnel the port to your intranet

Let’s say, the name of your server is elc.yourcompany.local, its internal IP address is 192.168.1.200 and it listens on the default port 5567.

Name resolution can easily be done by adding an entry to the hosts file, but which IP do put there? If you add the IP of the actual server, it will not work, because that IP is in the intranet and your computer is not, so routing will fail. But using ssh you can tunnel local ports to remote ports, so we add our localhost IP (127.0.0.1) to the hosts file:

# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
#      102.54.94.97     rhino.acme.com          # source server
#       38.25.63.10     x.acme.com              # x client host
#
# localhost name resolution is handle within DNS itself.
#       127.0.0.1       localhost
#       ::1             localhost
127.0.0.1 elc.yourcompany.local

This will tell the client to expect the server to be listening on 127.0.0.1:5567. Now we only need to tunnel that local port to the actual ELC server by adding an entry to Putty:

Don’t forget to save that session configuration in order for it to be available later.

Now, simply connect your ssh session, start Delphi and voila, it will connect to the ELC, request a license and you are done.

TThread is not a normal class

 Delphi, GExperts  Comments Off on TThread is not a normal class
Apr 222018
 

In Delphi, threads have traditionally been implemented as classes descending from TThread. While there have been quite a few improvements to multithreading, TThread is still the most compatible way. But TThread is not a normal class.

In a normal class, the constructor and destructor usually look like this:

constructor TSomeClass.Create;
begin
  inherited;
  FSomeList := TStringList.Create;
end;

destructor TSomeClass.Destroy;
begin
  FreeAndNil(FSomeList);
  inherited;
end;

In the constructor, we first call inherited and afterwards add code to initialize additional fields of the object. In the destructor we first free any fields of the object and only then call inherited for the ancestor class to free its resources.

Now, TThread is peculiar because its constructor and destructor are usually executed in the program’s main thread, while its Execute method is executed in a different thread. But, when is that thread started? It’s started when you call the inherited constructor. So any initialization that thread needs must be done before calling inherited!

Edit: Several people have pointed out that my claim is somewhat “outdated”, where “outdated” means that since Delphi 6 the thread is started in the AfterConstruction method rather than in Create. In Delphi 5 it was the last command in TThread.Create (here is a probably not authorized copy of that code, search for “Delphi5Thread” on the page).

What I wrote about the destructor is still true though.

constructor TMyThread.Create;
begin
  FSomeList := TStringList.Create;
  inherited;
end;

Otherwise the field FSomeList might not have been initialized when the thread tries to access it.

Similar, if the thread is still running, you must be sure that all the resources it requires are available until it has stopped. So, the first thing would be to tell the thread to terminate, wait for it to actually do that and only then destroy it.

MyThread := TMyThread.Create;
// do something else while the thread does its thing
// ...
// now tell it to terminate (this is standard way of doing that
// but it might not be the best)
MyThread.Terminate;
// and destroy it
FreeAndNil(MyThread);

But that’s only half of it. The destructor must also take care not to destroy anything the thread still needs:

destructor TMyThread.Destroy;
begin
  // first, wait for the thread to terminate
  // (the inherited destructor calls WaitFor)
  inherited;
  // now the thread has definitely terminated, so we can free the resources
  FreeAndNil(FSomeList);
end;

Beware: These are just the simplest precautions to take when programming with multiple threads. As they say: "Creating threads is easy but multithreading is hard." If you can, use a library that does the ground work for you.

Why do I blog about this? I just fixed a few Access Violations in GExperts that were caused by TThread objects implemented the wrong way. (I have no idea who did that, it’s quite possible that I am myself to blame for that.)

Specifying the msbuild configuration for a Delphi project on the commandline

 Delphi  Comments Off on Specifying the msbuild configuration for a Delphi project on the commandline
Mar 312018
 

Starting with Delphi 2007 EmBorCodera switched to msbuild for the build system. The newly introduced .dproj file used since then is a valid build script for msbuild but unfortunately the format has changed between Delphi 2007 and 2009. This means that there is a difference if you want to make command line builds and specify the build configuration:

With Delphi 2007, you use:

msbuild /target:rebuild /p:Configuration=Release %dprname%

You might also want to add the -p:DCC_Quiet=true option to reduce the amount of empty lines output:

msbuild /target:rebuild /p:Configuration=Release -p:DCC_Quiet=true %dprname%

With Delphi 2009 and later, you use:

msbuild /target:rebuild /p:config=Release %dprname%

(Source: This answer on StackOverflow.)

Until today I wasn’t aware of this difference so my automated GExperts builds for Delphi 2007 always used the build configuration that was selected in the IDE, which probably means that I have released debug builds rather than release builds for that Delphi version.

GExperts Usage Statistics

 Delphi, GExperts  Comments Off on GExperts Usage Statistics
Mar 302018
 

Have you ever wondered which functions of GExperts you have used the most? Or how often at all? How much time it has saved you?

Now you can find out: I just added Usage Statistics to GExperts which tells you exactly how often you have called each of the experts, in the current session and also in total (data between sessions is saved in the registry). Currently it can be accessed via a button in the Configuration dialog, but I am not sure yet where to put it.

So far, it has told me nothing new: My most used functions are, in descending order:

But this is just after a few minutes of actually using GExperts after I have added the statistics, so there might still be some surprises. I am wondering about the Code Proofreader for example.

I plan to do a new release shortly (oh my, the last one is over a year old!), maybe even during the Easter holidays, but don’t hold your breath. In the meantime, you can simply compile your own GExperts dll.

When an exception is nil in the exception handler

 Delphi  Comments Off on When an exception is nil in the exception handler
Mar 232018
 

A colleague of mine asked me today, how this could be:

Given this exception handler:

try
  // some code that calls methods
except
  on e: Exception do
    LogError(e.Message);
end;

How could e be nil? (and e.Message result in an Access Violation?)

It turned out to be an error in one of the methods that were called:

if SomeCondition then
  raise Exception('some error message');

Can you spot the problem here? For whatever reason the .Create call is missing! So instead of an exception object raise was working on a string typecasted to exception.
Changing it as follows fixed the error:

if SomeCondition then
  raise Exception.Create('some error message');

We did a grep search for “raise Exception(” in our code base and found 4 more cases where this problem existed. 4 bugs less, probably still quite a few to go.

But even worse: Greping for “raise e[a-z]*(” turned up two more cases. One in my own dzlib (unit u_dzVclUtils), another in the jcl (That one has already been fixed, my copy is a bit dated.).

Edit:
In the comments to the corresponding Google+ post, David Hoyle pointed out another common mistake regarding exceptions: Forgetting to actually raise them:

if SomeCondition then
  Exception.Create('some error message');

So, I did a grep for ” e[a-z]*\.Create\(” and found several, one in the (old) SynEdit version used in GExperts, several in Indy 10 and JVCL (old versions again) and one in System.JSON.Types of the current Delphi 10.2.3 RTL (RSP-20192). None in my own code this time. ­čÖé

Fixing the Delphi 10.2.2 February 2018 Patch

 Delphi, GExperts  Comments Off on Fixing the Delphi 10.2.2 February 2018 Patch
Feb 172018
 

UPDATE: The problem was that I was using Delphi 10.2.2 build 1978. Apparently I have missed an update in December 2017 to build 2004. I have downloaded and installed the new version, and now the patch worked fine.

I hereby apologize for being stupid, because it clearly says in the description:

This patch for RAD Studio 10.2.2 (build 2004 — it won’t work on build 1978) resolves some compatibility issues in the RTL and fixes a problem with Android animations. It is designed to be installed only on top of an existing RAD Studio 10.2.2 Tokyo installation.

(emphasis mine)

I was so sure to be running the latest version that I didn’t even check. Sorry about causing so much fuss.

I’ll leave the rest of the blog post unchanged just in case anybody is googling for some of the key words and to remind me to check first and complain later.

After I reported the problem with the Delphi 10.2.2 February 2018 Patch, Embarcadero first removed the download and has now released a new installer. Unfortunately this new patch might have solved some other problems, but it didn’t solve mine. I did a complete uninstall of Delphi 10.2.2 (I even removed all directories and files that the uninstall left behind) and a new installation from my DVD followed by applying the new patch. I could still not compile GExperts and the simple test program I described in the steps for the bug report did not compile either. (Guess what: Embarcadero apparently never actually tried to reproduce my problem, but the ticket was closed anyway.). I don’t know what exactly they think they fixed, but they didn’t fix the problem I reported which is:

RAD Studio 10.2.2 Tokyo February 2018 Patch breaks “Link with rutime packages”

  1. Create a new VCL project
  2. Open project options
  3. Select Packages -> Runtime Packages
  4. Set “Link with runtime packages” to true
  5. Close dialog with OK
  6. Compile the project
  7. -> Error

Today I tried to find out what the problem was and how to fix it. It turned out to be actually quite simple:

They updated the packages rtl.bpl and fmx.bpl together with their corresponding .dcp files. Since the .dcp files contain some versioning information the packages that use these packages (e.g. vcl.bpl which uses rtl.bpl) were no longer compatible with the new packages and the compiler complained about this.

So, the fix for this would be to recompile all the packages depending on rtl.bpl and fmx.bpl, but since I don’t have all the sources required for that, I couldn’t do that (but Embarcadero should).

What I did instead was replacing the .dcp files in libs\win32\debug and libs\win32\release with the .bak files that the Patch created. Afterwards, GExperts compiled again. And since probably the interface of the bpl files didn’t change, I don’t expect any problems. But of course, I can’t guarantee this. So, if you follow my example, you might still run into problems and, No, I won’t fix your computer. ­čśë

My improved version of IMAPCopy

 Delphi  Comments Off on My improved version of IMAPCopy
Feb 142018
 

IMAPcopy is a tool written by Armin Diehl. Its purpose is to copy emails from one IMAP server to another (or from one IMAP account to another) including the folder hierarchy and even the read status. It’s a command line program written in Delphi and fpc.

Since I am currently migrating a mail server I had use for such a tool and this one was the only one that did not require Java or dotNET, so I tried it. Of course, being a software developer, I found it lacking and improved it.

So, what did I improve?

Mostly one part: I did not like the fact that I had to specify the passwords of the IMAP accounts in the configuration file, so I added an option to specify “?” as the password and the tool would then let me input it at run time. I also added colouring to the the output, so it is easier to spot warnings and errors. And last but not least, I fixed a few typos in the messages.

It’s GPL code, so I’m required to give the source code to everybody to whom I give the executable. I could, of course, simply use the improved version and not tell anybody about it, so I could keep the source code “secret”, but on the other hand, why should I?

So, here is the source code. It compiles with Delphi 2007, I have not tested any other versions and I am sure it won’t compile with fpc (yes, that’s no improvement, but I don’t care).

It also needs a a Delphi port of the Borland CRT unit. I used the one released 1998 by Sergey Perevoznik, which is NOT licensed under the GPL. I have no idea where I got it from and I am not sure about the copyright since it looks like it started out as a copy of Borland’s source code. So I am not going to provide it here, sorry. But you might have a look at Embarcadero’s CodeCentral for alternatives.

Extended = Double in Lazarus Win64

 Delphi, Lazarus  Comments Off on Extended = Double in Lazarus Win64
Feb 112018
 

Note to self: In Lazarus Win64 there is no floating point type Extended, it’s mapped to Double. So, overloading something like:

function TryStr2Float(const _s: string; out _flt: Extended; _DecSeparator: Char = '.'): Boolean; overload;
function TryStr2Float(const _s: string; out _flt: Double; _DecSeparator: Char = '.'): Boolean; overload;
function TryStr2Float(const _s: string; out _flt: Single; _DecSeparator: Char = '.'): Boolean; overload;

will not compile.

Workaround: Add an {$IFNDEF Win64} around it:

{$IFNDEF Win64}
function TryStr2Float(const _s: string; out _flt: Extended; _DecSeparator: Char = '.'): Boolean; overload;
{$ENDIF}
function TryStr2Float(const _s: string; out _flt: Double; _DecSeparator: Char = '.'): Boolean; overload;
function TryStr2Float(const _s: string; out _flt: Single; _DecSeparator: Char = '.'): Boolean; overload;

This probably also applies to Delphi when compiling for others than the Win32 target, e.g. Win64, Android, IOS etc.

Warning: RAD Studio 10.2.2 Tokyo February 2018 Patch has issues

 Delphi  Comments Off on Warning: RAD Studio 10.2.2 Tokyo February 2018 Patch has issues
Feb 102018
 

Embarcadero just released a patch for RAD Studio 10.2.2. I downloaded and installed it, and regretted doing that: It breaks linking projects with runtime packages, like GExperts, any other IDE expert and probably also most component packages.

See here for a discussion.

I submitted a bug report as RSP-19914.