New features in GExperts

 Delphi, GExperts  Comments Off on New features in GExperts
Dec 152018
 

GExperts has recently gained a few new features:

  • Two new experts to start/stop recording and to replay a keyboard macro. These are minimal experts which allow you to add additional keyboard shortcuts to the existing IDE functionality. The idea and the code were contributed by Dejan M.
  • Goto Previous / Next modification Editor Experts. These again are minimal experts that create menu items for existing functionality of the IDE. They are only available in Delphi XE5 and later. The idea comes from Kryvich who has also written an IDE plugin for that functionality.
  • The Identfier tab I had already introduced into the Uses Clause Manager is now much more useful, because it fills much faster and because of the speed improvement now by default parses all units in the search path, not just the favorites.
  • The Set Tab Order expert now has two buttons to set the tab order by position. It also has buttons to move a control up or down in the sort order like in the Edit Tab Order dialog of the IDE, but these button have keyboard shortcuts.
  • The Remove Matching Lines editor expert in its default configuration removes the useless and annoying { Private declarations } etc. comments that are automatically added by the IDE for a new form. It can be configured to delete lines that match other text.
  • The Favorite Files expert can now optionally add a new menu entry to the Files menu showing the configured files.
  • And of course there is support for Delphi 10.3 Rio, currently as Beta 3 but you can expect a normal release shortly (maybe as early as later today).

If you want to comment on this post, you can do so in the international Delphi Praxis forum.

 Posted by on 2018-12-15 at 15:26

Pointers are dangerous

 Delphi  Comments Off on Pointers are dangerous
Dec 112018
 

Pointers can be really helpful, especially they can improve performance and readability, but they are also dangerous. I spent nearly a day tracking down the reason why the code a former colleague wrote about 5 years ago all of a sudden led to access violations. The code used to work fine, the problem only surfaced when I changed the size of a record. Consider this code:

var
  arr: array of TSomeRec;
  ptr1: ^SomeRec;
  Ptr2: ^SomeRec;
begin
  SetLength(arr, 0);
  // [...]
  SetLength(arr, Length(arr) + 1);
  ptr1 := @arr[High(arr)];
  ptr1.SomeField := SomeValue;
  // [...]
  SetLength(arr, Length(arr) + 1);
  ptr2 := @arr[High(arr)];
  ptr2.SomeField := SomeValue;
  // [...]
  SomeVariable := ptr1.SomeField); // boom

(Of course this is a very simplified example. There is a lot of code where I put the […] comments.)

So why is accessing ptr1 a problem? It was assigned and pointed to the right kind of variable. And it still points to that memory.

It’s not the pointer that was changed, it’s the array. arr is a dynamically allocate array. Each call to SetLength changes the length of the array and, if the previously allocated memory block is too small to fit the new length, a new memory block will be allocated, the contet of the array will be copied to the new memory block and the old memory block will be marked as unused.

And this is where ptr1 becomes invalid. It still points to the old memory block which now is marked as unused and will be used to store other data as soon as necessary.

So: Boom 💣

This is called a “stale pointer” and is the cause of a lot of debugging headaches.

So, why did this work before I changed the record size?

It’s due to the allocation strategy of the memory manager. When it gets a memory request, it checks for free blocks and assigns the block that fits best. Depending on how large the requested memory block is, it takes that memory from one of several pools. Each pool contains blocks of available memory of a fixed size, e.g. pool1 contains blocks of 16 bytes, pool2 contains blocks of 64 bytes etc. (these are just examples the real sizes depend on which memory manager is used and how it has been configured).

When I changed the record size, the record became smaller so the first array entry was allocated from a different pool than before, one that contained smaller blocks. Where previously the memory allocated to the array was large enough to fit more than one record, it now was so small that it fit only one record. Increasing the length of the array therefore required requesting a larger block of memory and copying the array contents. So the pointer became stale.

Discuss this in Delphi Praxis.

 Posted by on 2018-12-11 at 10:49

Remembering an Application’s Size and Position on Multiple Screens

 Delphi  Comments Off on Remembering an Application’s Size and Position on Multiple Screens
Dec 102018
 

David Hoyle just blogged about this topic (go ahead, read it first but remember to come back. 😉 )

Welcome back.

I think he is making two mistakes here (for suitable definitions of “mistake”):

  1. Don’t store the form positions in an ini file, use the registry. These positions make sense only on the same computer. They don’t need to be portable and if they get lost, it’s no big deal.
  2. And if these settings are stored in the registry, all of a sudden, it doesn’t matter whether it is a single or multi monitor setup. Just store the absolute position and be done.

You still need to handle the case that the stored position is outside the visible area, e.g. the monitor is no longer available, the monitor position has been changed, or the monitor settings have been changed.

All the above does not apply to other settings of a program, you might still want to store these in INI files to make them portable.

Of course, this is just my opinion, you have the right to disagree. 😉

This post caused has some comments in the English Delphi Praxis forum.

 Posted by on 2018-12-10 at 11:15

Delphi IDE Explorer is broken in Delphi 10.3 Rio

 Delphi  Comments Off on Delphi IDE Explorer is broken in Delphi 10.3 Rio
Dec 092018
 

I just found out what is wrong with my Delphi IDE Explorer in Delphi 10.3 Rio. The symptom is that the Follow Focus option and the Select Active button no longer work in some forms, in particular in the options dialog (Tools -> Options / Run -> Parameters / Project -> Options). The reason is that this dialog now uses the Screen.OnActiveControlChange event itself and does not bother to call the original event. In previous Delphi versions it did not use this event. Delphi IDE Explorer hooks it to track the control that has the focus and provide the functionality mentioned above. It does call the original event though.

Interestingly the IDE restores the previous event when closing the options dialog so Delphi IDE Explorer gets back its functionality for other dialogs. Unfortunately that does not apply to the dialogs called from within the Options dialog.

Nobody at Embarcadero seems to have read my proposal about Safe event hooking for Delphi IDE plugins or maybe they chose to ignore it. (I guess the number of people who have read it can be counted on the fingers of one hand anyway 😉 )

I have to investigate whether there is any safe method to get my plugin work again. Until then, you will have to live without the Follow Focus feature.

 Posted by on 2018-12-09 at 16:00

GExperts 1.3.12 beta 3 for Delphi 10.3 Rio available

 Delphi, GExperts  Comments Off on GExperts 1.3.12 beta 3 for Delphi 10.3 Rio available
Dec 082018
 

I have just uploaded the third beta version of GExperts 1.3.12 for Delphi 10.3 Rio.

NOTE: This is still a BETA!

Also note that this is for Delphi 10.3 Rio only. It won’t work with any other versions.

This beta release contains a (ugly) work around for the redraw bug in the Goto-Dialog enhancement when theming is enabled. Also, a few other bugs have been fixed.

I am not aware of any more bugs that are specific to this version of GExperts or Delphi 10.3 Rio. If you still find some, please report them on SourceForge.

Also note, that I have still not tested the installer as I don’t have a fresh Delphi 10.3 installation for that test.

Download link

 Posted by on 2018-12-08 at 11:25

Using dxgettext on Windows 10

 Delphi  Comments Off on Using dxgettext on Windows 10
Dec 022018
 

The dxGetText installer available from SourceForge has been quite outdated for a while. Via this StackOverflow answer I got this link, where somebody actually went through the trouble to update the tools and create a new installer for them. He also provides the sources he used for the tools. I hope they are based on a recent version of the ones in the SVN repository.

Thanks Dr. Jürgen Rathlev for taking the time!

(Note: I haven’t yet tried them)

 Posted by on 2018-12-02 at 14:33

Conditional compilation for various Delphi versions

 Delphi  Comments Off on Conditional compilation for various Delphi versions
Dec 022018
 

If you are maintaining a library, component or plugin for various Delphi versions you will sooner or later hit a point where it becomes necessary to have different code for some of them.

Some examples are:

  • The constants faTemporary and faSymlink are only declared in Delphi 2009 and later, so you have to declare them yourself for older versions.
  • Some Open Tools API function have bugs in some versions so you have to implement a workaround.
  • Some classes or functions have been added to later versions of the RTL so you need to implement them yourself for older versions, but you don’t want to use these implementations for newer versions

The traditional way of masking code for some Delphi versions is using the VERxxx symbols which the compiler defines, where xxx is the compiler version multiplied by 10.

Note that the compiler versions started with Turbo Pascal, not with Delphi, so VER60 is not Delphi 6 but Turbo Pascal 6, while Delphi 6 is compiler version 14 and therefore defines VER140. By the time of this writing the current Delphi version is 10.3 Rio which contains the compiler version 33.

{$IFDEF VER330} // Delphi 10.3 Rio
// do some version specific stuff here
{$ENDIF}

There are various include files that make this more convenient by adding symbols like DELPHInn and DELPHInn_UP so you don’t have to memorize those VERxxx symbols.

{$IFDEF DelphiX103}
// do some version specific stuff here
{$ENDIF}

But using these include files has got a major drawback: 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).

An alternative is the {$IF } compiler directive which can test for arbitrary Boolean expressions, like

const
  SomeConstantValue = 5;

//later on
{$IF SomeConstantValue >= 5}
// do some stuff here that requires SomeConstValue to be at least 5
{$IFEND}

It was added to the Delphi compiler in Delphi 6, so it covers quite a few Delphi versions. (Edit: Note that Delphi XE2 and older requires {$IF } to be closed by {$IFEND}. Newer versions also accept {$ENDIF}.)

Combined with predefined constants (in the System unit) like

this is a powerful method for conditional compilation.

{$IF CompilerVersion = 330} // Delphi 10.3 Rio
// do some version specific stuff here
{$IFEND}

It can also replace those additional symbols DELPHInn_UP I mentioned above: “>=” replaces {$IFDEF DELPHInn_UP} and “<=" replaces {$IFNDEF DELPHInn_UP}. Also by using ">=” you can “future proof” your code, assuming that code for Delphi 10.3 Rio will also work with all newer versions of Delphi.

{$IF CompilerVersion >= 330} // Delphi 10.3 Rio
// do some version specific stuff here that will
// hopefully also work in the future
{$IFEND}

But unfortunately we are back to memorizing compiler and RTL version constants. Even with tools like the IF Directive Expert in GExperts this is a nuisance because if you forget to add a comment (or if you later change the expression and forget to update the comment), you will still have to know those values to understand the code.

So, what can be done? An idea that occurred to me today (Yes, I am a bit slow on creativity.) would be to define additional constants which can then be used to compare against the CompilerVersion and RtlVersion constants.

unit CompilerAndRtlVersions;

interface

const
  CompilerVersionDelphi6 = 14;
  CompilerVersionDelphi7 = 15;
  // we all want to forget Delphi 8, but it had compiler version 16
  CompilerVersionDelphi2005 = 17;
  CompilerVersionDelphi2006 = 18;
  CompilerVersionDelphi2007 = 18.5;
  // anybody remember Delphi 2007 for dotNET? That one had compiler version 19
  CompilerVersionDelphi2009 = 20;
  // and so on until
  CompilerVersionDelphiRio = 33;

// and of course we would also need the RtlVersions:
const
  RtlVersionDelphi6 = 14;
  RtlVersionDelphi7 = 15;
  // and so on until
  RtlVersionDelphiRio = 33;

implementation
end.

Add the above unit to the uses clause and you can do:


{$IF CompilerVersion >= CompilerVersionDelphiRio}
// do some version specific stuff here
{$IFEND}

These constants should go into a unit rather into an include file so the compiler will complain if you forget to add that unit to the uses clause. In addition a unit will be compiled once and afterwards the compiler will use the DCU file it created, while an include fill will be parsed every single time it is included. This should speed up compilation a (probably tiny) bit.

I am not aware if such a unit already exists, but I would probably write it and make it available if not (it’s not excactly rocket science after all).
EDIT: I’m not the first one who came up with this idea.

Edit: Here you go, my brand new u_dzCompilerAndRtlVersions unit.

I already blogged about using and ab-using ifdef in 2013, if you are interested in this topic.

 Posted by on 2018-12-02 at 13:28

GExperts 1.3.12 beta 2 for Delphi 10.3 Rio available

 Delphi, GExperts  Comments Off on GExperts 1.3.12 beta 2 for Delphi 10.3 Rio available
Dec 012018
 

I have just uploaded the second beta version of GExperts 1.3.12 for Delphi 10.3 Rio.

NOTE: This is still a BETA!

Also note that this is for Delphi 10.3 Rio only. It won’t work with any other versions.

Beware of bugs, e.g. the Goto-Dialog enhancements still cause redraw problems if theming is enabled. But many bugs from the first beta have been fixed.

Please report any bugs on SourceForge.

Also note, that I have not yet tested the installer as I don’t have a fresh Delphi 10.3 installation for that test.

Download link

 Posted by on 2018-12-01 at 16:36

When the stand alone GExperts Experts Manager fails

 Delphi, GExperts  Comments Off on When the stand alone GExperts Experts Manager fails
Dec 012018
 

There have been multiple bug reports regarding the stand alone Experts Manager that comes with GExperts. They all have in common that they fail with the error

Expertmanager: ExpertManager.exe – System Error
The program can’t start because vclactnband250.bpl is missing from your computer. Try reinstalling the program to fix this problem.

Or similar messages giving a different package or a different version of the package.

So, what is the cause?

In short, you have most likely used the wrong GExperts installer. You must always use the one for the Delphi version you have installed. E.g. the current beta version for Delphi 10.3 Rio does not work for any of the older versions.

Technically this is what happens:

The Expert Manager executable loads the GExperts DLL to do the actual work (as do most of the other stand alone programs that come with GExperts, e.g. GExperts Grep or the stand alone Code Formatter).

It looks for that DLL in the directory where the executable is located. If there is only one DLL, it loads it, if there is more than one, the user gets a list to pick the one to load.

The GExperts DLLs are all built with runtime packages because that’s a requirement for IDE plugins to work. These runtime packages are installed with Delphi and reside in the bin subdirectory of the installation. Packages are just glorified DLLs so Windows tries to locate them using the same search path as for all other DLLs. If the Delphi version matching the GExperts DLL is not installed (e.g. You installed GExperts for Delphi 10.3 but your Delphi version is 10.2), you will get the error shown above.

Other possible causes are:

  • The search path does not contain the bin directory of the required Delphi version (no idea how that can happen, but it does happen).
  • The search path has become too long so it gets truncated before the required directory (see here for a possible remedy)
 Posted by on 2018-12-01 at 13:22

Linking to the current Delphi documentation

 Delphi  Comments Off on Linking to the current Delphi documentation
Nov 302018
 

The quality of the online documentation for Delphi at docwiki.embarcadero.com has improved significantly since the time when Borland fired all their help authors, so it is actually worth looking at when you want to know anything.

I see links to topics in that documentation in blog posts and in online forums (e.g. DelphiPraxis [German] [English]), but they always link to a specific version of that documentation (e.g. the one for Delphi 10.1 Berlin). I am sure most posters would like to link to the latest version rather than a specific version but don’t know how to do that or that it is even possible.

The good news is: It is possible. Simply remove the name of the Delphi version from the url and you get a link that always takes you to that page in the lastest version. E.g.:

http://docwiki.embarcadero.com/RADStudio/Berlin/en/Main_Page

remove the “Berlin” part and you get:

http://docwiki.embarcadero.com/RADStudio/en/Main_Page

Which is always (or at least has always been) the lastest version of that page (at the time of this writing it is Delphi 10.3 Rio). This of course also works for specific topcs, like WriteLn [Berlin] [latest]

 Posted by on 2018-11-30 at 12:55