GExperts is always compiled with the latest update of any of the supported Delphi versions. That unfortunately means that it may not work if the IDE hasn’t been updated to the latest version. E.g. The latest GExperts release will not work with Delphi 10.2, but only with Delphi 10.2.3, the latest update to Delphi 10.2. This is due to changes in the runtime packages that are not always backward compatible.

Until a few years ago, this was no problem because when you bought Delphi you were automatically entitled to receive all updates for this version. E.g. if you bought Delphi 2007 you could download all updates for it and GExperts would simply work for you.

This changed when Embarcadero tried to force all their customers to buy a maintenance subscription. Now, if you don’t have such a subscription, you will no longer receive updates and bug fixes. You automatically get a subscription for 1 year when you buy a new Delphi license so this sounds like a minor issue. But a subscription not only gets you updates but also upgrades to the yearly major releases, e.g. from 10.2 to 10.3.
So, if you do not extend an existing subscription shortly after a new major release you will not get updates and bug fixes for this release. You have only two options then: Stick with the previous major release + all updates and bug fixes, or keep using the latest major release and hope that you don’t need the updates for it. Of course that’s on purpose to keep customers extending their subscriptions.

This also affects GExperts: If you are stuck using a non-updated major release GExperts might not work for you.

I have been asked whether I could make releases for these cases. Unfortunately this would require me to keep all minor Delphi releases around, e.g. 10.2, 10.2.1, 10.2.2 and 10.2.3. These cannot be installed on the same computer so that would mean 4 virtual machines for Delphi 10.2.x alone + several for other major versions. Yes, I could do that. But since GExperts is currently a one man (me) show, it would take quite a lot of my time for very little gain. (But everybody is invited to contribute!)

So, what can be done? If you are one of those people affected by this, simply build your own DLL. It’s not difficult at all. This will create a DLL that is compatible to the Delphi version you are using, so your problem is solved.

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

Microsoft is trying to force everybody to update from the old NT4 domain system to the “new” (as in “was new >10 years ago”) Active Directory system. While that’s probably a good idea for most people there are some like me stuck with a working Samba installation that for some reason needs to continue to use NT4 domains.

Getting a Windows computer to join such a domain has become more difficult with Windows 10. Here is what needs to be done (I write this mostly so I can look it up myself):

1. Make sure your samba server is configured to enforce the NT4 (SMB1) login. samba.conf must contain the following entry:
[global]
// other entries here
server max protocol = NT1

2. Install the SMB1 protocol on the Windows computer. This is done using the “Turn Windows Features on or off” dialog (just type this into the start menu). You need to set the check marks for two entries under “SMB 1.0/CIFS File share Support”:
• SMB 1.0/CIFS Client
• SMB 1.0/CIFS Server

I’m not 100% sure whether the latter is required. I haven’t tried it without.

3. Add the following entries to the registry:
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanManWorkstation\Parameters]
"DomainCompatibilityMode"=dword:00000001
"DNSNameResolutionRequired"=dword:00000000


You can either add them manually or copy the above to the .reg file and import that into the registry.

4. Reboot the computer to activate these changes.

Now it should be possible to join the Windows 10 computer to the Samba Domain.

Source: Required Settings for Samba NT4 Domains on the Samba Wiki.

I got a bug report for GExperts and Delphi 10.4 that’s really curious:

When a secondary editor window is open in the IDE and the FMX form designer is active, trying to insert a component from the clipboard into the form inserts the textual description of that component into the editor windows instead.

I could immediately reproduce this but finding the culprit took quite a bit longer.

Observation 1: It does not happen for the VCL form designer.

Observation 2: It only happens, if you use CTRL+V to insert the component. The form designer’s context menu entry works fine.

Observation 3: Even disabling all experts in GExperts did not solve this problems… Until you restart the IDE, then it’s gone, even if you then enabled the experts again… Until you restart the IDE again which brings it back.

After a lot of trial and error I found that the cause are two of the GExperts editor experts:

• Goto Previous Modification
• Goto Next Modification

Disabling these experts and restarting the IDE solves the problem.

These are rather simple experts that only add entries to the editor window’s context menu for a functionality that already is part of the IDE. I added them to make that functionality more visible, and because I could. Since Delphi 10.3 I had to use a workaround to still be able to add entries to that menu because apparently it is being recreated in the OnPopup event. I think this code somehow activates the menu entries or their associated actions even if the editor window doesn’t have the focus.

So for now until I find a real workaround: If you have this problem, disable these two experts.

(The workaround might be to remove these experts altogether. They aren’t that useful anyway.)

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

Today I had a very strange compiler error in Delphi 10.2, that occurred on one computer but did not occur on another computer:

myUnit.pas(28): error F2613: Unit 'TeEngine' not found.


The project was checked out from svn on both computers, so the source code was identical. So the unit “VCLTee.TeEngine” from TeeChart was in a subdirectory of the project sources and the project’s “Search Path” on both computers. But on one computer the compilation worked fine, on the other I got the error above.

The first thing I checked was that the TeeChart sources were not listed in the “Library Path”. I restrict my “Library Path” to the RTL and VCL units that come with Delphi and remove anything 3rd party libraries tend to add. Third party sources go into svn, are project specific and checked out via svn:external.

Further investigation showed that the prefix “VCLTee” was not listed in the Unit Scope Names setting of the project, that’s why the compiler as only looking for “teEngine” and did not find “VCLTee.TeEngine”. But again: How could the same project compile on the other computer? It should have failed on both!

Half an hour later I found the problem: There is also a “Unit Scope Names” setting in “Tools” -> “Options” -> “Environment Options” -> “Delphi Options” -> “Library”. On the computer where the compilation worked, “VCLTee” was listed there, but only under “32 Bit Windows”.

I missed that because the dialog defaults to the “64 Bit Windows” settings.

After I removed this entry, the compilation failed consistently on both computers. (Yes, I call consistent failures progress.)

And after I had added this entry to the project options and synced the sources, compilation finally worked on both computers.

You might ask why it was necessary to have “VCLTee” under “Unit Scope Names” at all, since the uses list should contain “VCLTee.TeEngine” rather than just “TeEngine”. The reason for this is simple: The unit in question is also used in Delphi 2007 projects where unit scoping was possible but no yet used widely. I had the choice whether I wanted the unit compile in Delphi 2007 projects or Delphi 10.2. Alternatively I could have added ifdefs around the uses clause, but since the IDE keeps on messing with these entries I don’t do that.

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

I just released dzBdsLauncher 1.0.6. The only change is support for detecting .dproj files created by Delphi 10.4.2 (these have a ProjectVersion of 19.2).

Starting with Windows Vista Microsoft has started to take security really serious. That’s a good thing. Unfortunately in typically Microsoft attitude they think they always know best and that the user is an idiot, so it’s best to keep anything dangerous from him.

Fast forward to Windows 10 and the issue at hand:

Windows 10 tries to identify networks and based on that classifies them as private or public. The Windows firewall then changes some settings based on this classification.

Now imagine a computer installed in a special setting that is connected via LAN to some other computers in the same place. Network wise this is an isolated island, there is no connection to any company LAN or the Internet. All computers have fixed IP addresses, so there is no DHCP server involved, and provide network shares to each other.

Unfortunately Windows sees this setup as an unidentified network and classifies it as a public network. This means that many things – in particular network shares – do not work.

And since Microsoft doesn’t trust users to know what they are doing, there is no easy (GUI) way to change this. It used to be possible in Windows 7 but no longer.

So, what can be done? Google turned up lots of different suggestions but the only one that worked for me was this answer on SuperUser.com.

It gives a PowerShell script which I have adjusted to my needs:

Write-Host "current settings:"
Get-NetConnectionProfile |
Where{ $_.InterfaceAlias -eq 'NetworkCardName'} | ForEach {$_
$_|Set-NetConnectionProfile -NetWorkCategory Private } Write-Host "new settings:" Get-NetConnectionProfile | Where{$_.InterfaceAlias -eq 'NetworkCardName'}

Write-Host "Beliebige Taste um fortzufahren..."
$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")  It reads all connection profiles, filters for the one that apply to a network adapter with a given name (which I renamed to make it unique) and changes this profile to be private. It then displays the new settings and waits for the user to press a key. In order to work, this script must be started with administrator privileges. Of course, that would have been too simple: Microsoft also by default prevents the execution of PowerShell scripts. Again, that might be a valid security measure but in this situation it’s merely a pain in the lower back. So in order to allow scripts, we need to change this setting as suggested in yet another answer on SuperUser.com: Start PowerShell as administrator and run the following command: set-executionpolicy remotesigned  This allows the execution of local scripts, which is what we want. It also allows remote scripts if those are signed, which isn’t particularly what I want but apparently you can’t get one without the other. Diesmal funktioniert alles [music video] COVID-19 got us all down a bit and even with the vaccines theoretically available now, the light at the end of the tunnel seems very far away. My own turn for a jab will probably not come before fall 2021, so I can only hope that summer will reduce the infection rates as much as it did last year, but the new mutants that spread around the world definitely aren’t good news. Maybe I can lighten up your mood a bit with a new GExperts release. There are a few bug fixes and an also a few new features in the new version, but nothing really exciting. The “major” new feature is the Explicit Properties Filter expert. This was the one functionality I missed most when Andreas Hausladen did not update his ddevextensions for Delphi 10.4. But did you know that Andreas has now open sourced this plugin? There is also a small speed improvement in the Project Option Sets expert. I hope this time the installers won’t be wrongly detected as malware by virus scanners. Sorry about that. Please note that GExperts for Delphi 10.4 requires Update 1! The new version is available for download on the GExperts download page. If you want to discuss this article, you can do so in the corresponding post in the international Delphi Praxis forum. Note to self: In order to allow changes to the author of an svn commit, the pre-revprop-change hook of the repository must be changed like this: Insert the line if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:author" ]; then exit 0; fi  just below the existing, similar line that allows changing svn:log. Omitting the comments the script will then look like this: #!/bin/sh REPOS="$1"
REV="$2" USER="$3"
PROPNAME="$4" ACTION="$5"

if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:log" ]; then exit 0; fi
if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:author" ]; then exit 0; fi

echo "Changing revision properties other than svn:log is prohibited" >&2
exit 1


The script is located in the hooks subdirectory of the repository.
(Of course the above is for an svn repository located on a Linux server only.)

This change is required for the context menu entry in TortoiseSVN Log Messages window called “Edit Author” to work.

Even after Microsoft abandoned the stupid idea of the Windows 8 start screen and gave us back the start menu in Windows 10 there is still a lot to desire. Of course you can replace the the start menu with a tool like Open Shell (formerly known as Classic Shell) which improves it quite a lot. Or you use a separate launcher like the Portable Apps Launcher.

I have switched to Open Shell but I also use JumpFolder to create my own, multiple “Start Menus” using the jump list that every icon on the taskbar has had since Windows 7.

Basic usage means that you put the JumpFolder.exe into any directory on your disk, add subdirectories containing shortcuts to the programs you want to start, pin JumpFolder.exe to the Windows taskbar and start it once. After that the jump list of this icon will show you all those shortcuts:

(In case you are curious: These shortcuts start Civilization, the original DOs game from 1991, 7 Kingdoms, a Windows game from 1997) and Todolist by Abstract Spoon. I can definitely recommend the games but the todo list is not my favourite, but hey, it’s free.)

Note that even though the JumpFolder homepage states that it requires Windows 7, it also works for later Windows versions, including Windows 10.

But the number of entries in the jump list is limited (by default to 10 entries which can be increased, but even then, vertical space on a monitor is limited) and it would be nice to have more than one. But there can only be one JumpFolder.exe icon on the taskbar. So, what can be done? Simple: Create a shortcut to JumpFolder.exe itself and pin that shortcut to the taskbar.

OK, here are the steps:

1. Create a new directory.
2. Put the JumpFolder.exe file into it
3. Create a shortcut to that executable in the same folder and give it a unique name, e.g. “MyJumpFolder1”
4. Optionally, assign an icon to this shortcut.
5. Pin this shortcut to the taskbar
6. Create subdirectories for categories (e.g. “games” and “tools” and put shortcuts into these subdirectories.
7. Start the shortcut on the taskbar. It will now parse the subdirectories and create a jump list from them.
8. Voila: You have a unique “start menu”. Now rinse and repeat for each additional “start menu” you want.

Of course the shortcuts can be for anything, e.g. open a folder or start a program passing it parameters. This way you can create a “start menu” for your music, by putting several shortcuts to your music player into the subdirectories passing it e.g. the directory containing the music files it should play. Eg. for VLC it would look like this:

c:\path\to\VLC.exe "c:\path\to\Peter Fox"

(The parameter is the directory containing mp3s with music from Peter Fox’ album Stadtaffe“.)

My current music “start menu” looks like this:

The same principle can also be used to create entries with jump lists in the start menu, but personally I find that a lot less useful.

I stumbled upon JumpFolder a few years ago when I was considering writing such a program myself. I’ve even got the source code from back then. But it didn’t keep my interest after I discovered that such a program already exists.

The following code looks innocuous but slows down a program significantly:

type
TJCHListSortCompare = function(Item1, Item2: Integer): Integer of object;
TCheckListBoxWithHints = class(TCheckListBox)
private
procedure QuickSort(L, R: Integer; SCompare: TJCHListSortCompare);

// [...]
procedure TCheckListBoxWithHints.QuickSort(L, R: Integer; SCompare: TJCHListSortCompare);
var
I, J, P: Integer;
tmpObj: TObject;
tmpStr: string;
tmpChecked: Boolean;
begin
repeat
I := L;
J := R;
P := (L + R) shr 1;
repeat
while SCompare(I, P) < 0 do Inc(I);
while SCompare(J, P) > 0 do Dec(J);
if I <= J then
begin
// exchange I and J
tmpStr           := Items[I];
tmpObj           := Items.Objects[I];
tmpChecked       := Self.Checked[I];

Items[I]         := Items[J];
Items.Objects[I] := Items.Objects[J];
Self.Checked[I]  := Self.Checked[J];

Items[J]         := tmpStr;
Items.Objects[J] := tmpObj;
Self.Checked[J]  := tmpChecked;
if P = I then
P := J
else if P = J then
P := I;

Inc(I);
Dec(J);
end;
until I > J;
if L < J then QuickSort(L, J, SCompare);
L := I;
until I >= R;
end;


Yes it’s Quicksort and it sorts strings in a TCheckListBox’s Items property, swapping not only the strings but also the objects and the Checked values.

Now, run this with, lets say 100 entries. That shouldn’t be any problem for Quicksort, should it? But it takes about 2 seconds on my computer which is muuuuuuch longer than I expected. The same code running on a simple TStringList takes less than 1/10 of a second. Why is that?

It’s because accessing the strings and changing them each results in a Windows message to be sent, handled and checked.

TCheckListBox inherits its Items property from TCustomListBox which declares it as:

    property Items: TStrings read FItems write SetItems;


Still looks innocuous? Now, let’s see how it is actually instantiated:

  FItems := TListBoxStrings.Create;
TListBoxStrings(FItems).ListBox := Self;


So, what is TListBoxStrings? It’s a class that descends from TStrings and provides access to the strings stored in a TCustomListBox using Windows messages. E.g.:

function TListBoxStrings.Get(Index: Integer): string;
var
Len: Integer;
begin
// [...]
begin
Len := SendMessage(ListBox.Handle, LB_GETTEXTLEN, Index, 0);
if Len = LB_ERR then Error(SListIndexError, Index);
SetLength(Result, Len);
if Len <> 0 then
begin
Len := SendMessage(ListBox.Handle, LB_GETTEXT, Index, Longint(PChar(Result)));
SetLength(Result, Len);
end;
end;
end;


To get a string, it sends two messages to the Listbox’s handle and interprets its results.

Or:

procedure TListBoxStrings.Put(Index: Integer; const S: string);
var
I: Integer;
TempData: Longint;
begin
I := ListBox.ItemIndex;
TempData := ListBox.InternalGetItemData(Index);
ListBox.InternalSetItemData(Index, 0);
Delete(Index);
InsertObject(Index, S, nil);
ListBox.InternalSetItemData(Index, TempData);
ListBox.ItemIndex := I;
end;


In order to set a string to a new value, it first deletes it and then inserts it again.

Want to guess what Delete() does? It sends a message to the listbox’s handle. And what does InsertObject do? It sends a message to the listbox’s handle.

While all this is an ingenious way to provide simple access to the strings normally only available using the mentioned messages, it’s far from efficient when you do a lot of comparisons and some swapping, which is exactly what a sorting algorithm does.

So, what can be done?

First, don’t work on the Items property directly but take a copy of it. Also, don’t swap the Checked property values (which also use messages) directly but take a copy of these too (in particular since some of the Compare functions passed to the sorting code also test the Checked property). Then sort the copy and assign it back to the listbox’s Items and Checked properties:

var
cnt: Integer;
tmpList: TStringList;
ChkArr: TBoolArray;
i: Integer;
//[...]
tmpList := TStringList.Create;
try
SetLength(ChkArr, cnt);
for i := 0 to cnt - 1 do
ChkArr[i] := Checked[i];
QuickSort(tmpList, ChkArr, 0, cnt - 1, Compare);
Items.BeginUpdate;
try
Items := tmpList;
for i := 0 to cnt - 1 do
Checked[i] := ChkArr[i];
finally
Items.EndUpdate;
end;
finally
tmpList.Free;
end;


This code is from the GExperts Project Option Sets expert. This is one of the experts I had never used before and was shocked that, when I opened the dialog, it took several seconds before anything was shown. The reason turned out that the sorting described above was executed not only once but even twice in the FormShow event. After the changes I outlined above and reducing it to sort only once, it was down to less than half a second. That still felt like eternity, but was a significant improvement.

After I added some more tweaks, e.g. use a lookup list into an array of several hundred entries rather than linear search to find a particular string, the dialog now opens nearly instantly (on my computer).

If you want to discuss this article, you can do so in the corresponding post in the international Delphi Praxis forum.