Adding an entry to the Delphi IDE’s about dialog

 Delphi  Comments Off on Adding an entry to the Delphi IDE’s about dialog
Nov 222015

Starting with Delphi 2005 the IDE provides an API for plugins to add an entry to its about dialog. It’s pretty simple to use and many plugins and components use it nowadays. But there is one thing that in my opinion most of them get wrong. My first attempt looked like this:

if Supports(BorlandIDEServices, IOTAAboutBoxServices, AboutBoxServices) then begin
  bmSplashScreen := LoadBitmap(HInstance, 'SplashScreenBitMap');
  Result := AboutBoxServices.AddPluginInfo(
    'GExperts is a [...]',
    'open source');

and resulted in this:


The string "Product Licence Status:" annoyed me because it just didn’t make any sense. But since this is pretty much what most other plugin entries look like, I thought it just must be the way for it to look. But then I found this entry added by the Delphi Praxis Help-Booster:


No Prefix? WTF? How did he do it? I asked for input on Google+ but got no help, apart from Uwe Schuster’s rather cryptical answer

Read again and again the parameter list of AddPluginInfo and once you understood it, it will appear as expected.

which I just didn’t understand (even though he was right but …).

The solution hit me quite a few minutes later: Just supply an empty string to the LicenceStatus parameter and put the version information into the SKUName parameter.

if Supports(BorlandIDEServices, IOTAAboutBoxServices, AboutBoxServices) then begin
  bmSplashScreen := LoadBitmap(HInstance, 'SplashScreenBitMap');
  Result := AboutBoxServices.AddPluginInfo(
    'GExperts is a [...]',
    '', // leave this empty!

And it works:

I should really be used to feeling stupid by now.

Experimental GExperts Version 1.38 2015-10-21 released

 Delphi, GExperts  Comments Off on Experimental GExperts Version 1.38 2015-10-21 released
Nov 212015

Again, there is nothing new about the formatter code. But there is a new option to improve the IDE search path dialogs:

Improved search path config dialog

What it does is replace the list box in the search path dialog with a memo, so editing that path is much easier (in my opinion) than before. Unfortunately I have yet to figure out how to sensibly implement the "Replace", "Delete" and "Delete Invalid" button functionality, so they are disabled for the time being.

Click on the picture for an animated GIF that shows you the change.

In addition, since I was at it, I added short cut keys to the Up/Down buttons: Ctrl+Up / Ctrl+Down. These work even if you don’t replace the listbox (And let me tell you: It wasn’t easy to get this to work but that’s a topic for a different blog post).

There is another change in my experimental GExperts versions, that some of you might not like: There is only one version, the "Regular Expert". I dropped the "Editor Expert" version because it became too tedious to maintain those two versions in parallel. Also, since in the (hopefully near) future the code formatter will be part of the official GExperts, I had to decide which version to keep. If you don’t like this, you are welcome to grab the sources modify them and and compile your own version.

Head over to the Experimental GExperts page to download it.

dzMdbViewer 1.0.1 released

 Delphi  Comments Off on dzMdbViewer 1.0.1 released
Nov 202015

dzMdbViewer is a small tool I wrote, when I was stuck without a MS Access installation but needed to have a look into a .MDB file (and later .ACCDB file, if the Access Database Engine 2012 is installed).

It can open these files and display a list of queries and tables stored in them as well as the data they contain.

Table Data

Also, for tables, it can show the field definitions.

Table Definition

Today I fixed a few bugs and released version 1.0.1. You can get it from SourceForge. The source code is available too, it’s in the Mercurial repository.

Classname with !dx suffix?

 Delphi  Comments Off on Classname with !dx suffix?
Nov 192015

Today I had an interesting bug to fix:

I used a form’s Classname (Yes, I have a reason not to use the Name.) to persist its size in the registry and wondered why it didn’t work. Looking at the registry entries I found, that there was an entry with the class name suffixed by a ‘!dx’.

So I placed an appropriate breakpoint in the constructor and destructor respectively of the form and found that everything was fine in the constructor but in the destructor there was this suffix.

On further investigation it turned out that the culprit was dxgettext. In one of the contributions that were submitted by users but which in this case I committed myself, the class name was suffixed with !dx as a debug help. It’s not necessary for the functionality.

The fix of course was to disable this code. There is now a new conditional define dx_ChangeProxyClassName in the current gnugettext.pas code, that controls whether the suffix is added or not. The default is to not add it.

Bulk-moving units in Delphi

 Delphi  Comments Off on Bulk-moving units in Delphi
Nov 082015

If you change the structure of a Delphi project, you will often face the challenge of moving many units from one directory to another, e.g. you change the name of a subdirectory from src to source:

  \src  <=== change to "source"

In ancient Delphi versions, you would just open the .dpr file in a text editor, use search and replace to change the path and the Delphi IDE would happily work with that new .dpr file.

Starting from Delphi 2007 the IDE stores the path to the units included in the project in two files: The .dpr file and the .dproj file. If they don't match, you can get all sorts of weird errors even though it seems to work at first.

That leaves you the following options:

  • You could open your project in the Delphi IDE remove all units from it and add them again at the new location. No problem if there are only a hand full of units, but with a typical large project this could easily take half an hour and is rather boring (and therefore error prone).
  • You could change the paths not just in the .dpr file but also in the .dproj file using search and replace. But beware, the text you replace might be used in some other places too which you might not want to change. XML files are not really meant to be modified by humans.
  • You could change the paths in the .dpr file and simply delete all
    <DCCReference Include="path goes here">
      <Form>form name goes here</Form>

    entries from the .dproj file. This is much easier done than a search and replace. Afterwards you open it in the IDE, make a small change to the .dpr file (e.g. add and delete a white space) and save it. The IDE will happily recreate all these entries for you.

dzTimer 1.1.0 released

 none  Comments Off on dzTimer 1.1.0 released
Nov 012015

dzTimer is not really something to write home about. It’s a simple countdown timer I wrote to familiarize myself with Lazarus for Windows. It has the following features:

  • Configure and store a list of commonly used timers
  • Display the remaining time as the caption when minimized
  • Minimize to icon tray (new)


Of course it is easy to use, but that’s not a feature but a basic requirement in my book.

The project is on SourceForge.

Safe event hooking and unhooking (for Delphi IDE plugins)

 Delphi, GExperts  Comments Off on Safe event hooking and unhooking (for Delphi IDE plugins)
Oct 122015

In the comments to my Google+ post announcing my blog post on Hacking the Delphi 10 Project Options dialog Ondrej Kelle said:

If two or more plugins hijack the same global event handler then they must restore the previous (from their point of view) handler in reverse order, however this is not guaranteed and therefore this technique is likely to cause trouble.


API should be written, safe for plugins to use instead of the event handlers

to which Heinz Toskano added

This scenario remembers me when I wrote interrupt handlers for DOS. The civilized way was to hook and return the original handler, except when you replace the interrupt, in that case you was obliged to expose the original interface, just to not broke something else. Something similar must be done with IDE plugins, otherwise it will become bad coding.

I did a quick Google search but found no existing standard so I decided to simply describe one and publish it in the hope that others will find it useful and adhere to it.

I have moved the code and description to it’s own static page. I will improve it as I go along and blog about these improvements.

I post a link to this article on Google+. If you want to leave any comments, use this post.

How to disable update checking in TortoiseSVN?

 TortoiseSVN, Windows  Comments Off on How to disable update checking in TortoiseSVN?
Oct 122015

The latest 1.9.x versions of TortoiseSVN no longer support Windows XP (1.8.12 was the last one that did). Since some of the computers I work with are stuck with XP there isn’t much sense in having it check for updates automatically.

Older versions of TortoiseSVN used to have a check box on the settings “General” page, but that apparently was removed later. Now, it is on the “Advanced” page and called “VersionCheck”. Setting it to “false” disables the check.

TortoiseSVN Settings Advanced VersionCheck

Hacking the Delphi 10 Project Options dialog

 Delphi, GExperts  Comments Off on Hacking the Delphi 10 Project Options dialog
Oct 112015

Today I wanted to do something I did before: Add a drop file handler to an edit control in a dialog of the Delphi IDE. The dialog in question is the the Project Options dialog.

I thought it would be pretty simple to do that:

  1. Get the dialog instance from Screen.Forms list.
  2. Get the edit control using the form’s FindComponent method
  3. Attach a drop file handler to it.

Pretty standard for somebody who has written IDE plugins for Delphi before and is somewhat acquainted with its internals. Little did I know how difficult it would become.

First, the Project Options dialog is created dynamically (many other dialogs are created at program start). So, how do I access it?

It turns out that the global Screen object has got a useful event for this: Screen.OnActiveFormChange which is called every time the active form in the IDE changes. So my plugin could just assign an event handler to it and wait for the Project Options form to become the active one. This works, but there are two pitfalls:

  1. The IDE internally uses this event.
  2. How do I know which form is the one I am looking for?

To solve the first I have to hook it and call the original event handler.

To solve the second, I had to enhance my Delphi IDE Explorer to dynamically update its display. It also hooks Screen.OnActiveFormChange for this. This gave me the name and class of the Project Options dialog:

DelphiProjectOptionsDialog: TDelphiProjectOptionsDialog

So, now I had the dialog instance and needed the edit control for the debugging host application. Again, using the IDE explorer, I found its name and class name:

SourcePathInput: THistoryPropComboBox

So, it’s just a matter of calling FindComponent, check the class type to make sure it is the correct control and be done with it, right?

Not so, the Dialog also contains some frames that own their controls rather than the form. So I had to traverse the control hierarchy in order to find the control. It looks like this:

DelphiProjectOptionsDialog: TDelphiProjectOptionsDialog
  [3] Panel2: TPanel
    [1] PropertySheetControl1: TPropertySheetControl
      [0] : TDebuggerLocalPage
        [2] Panel1: TPanel
          [0] HostAppGroupBox: TGroupBox
            [0] HostAppInput: THistoryPropComboBox
          [2] CDWGroupBox: TGroupBox
            [0] CWDInput: THistoryPropComboBox
          [3] SourcePathGroupBox: TGroupBox
            [0] SourcePathInput: THistoryPropComboBox

      [2] : TDebuggerSymbolTablePage
        [1] gbSymbolTables: TGroupBox
          [1] ddDebugSymbolSearchPath: THistoryPropComboBox
          [4] cbLoadAllSymbols: TCheckBox
          [3] Panel1: TPanel
            [0] ListViewPanel: TPanel
              [0] SymbolTablesListView: THintListView

The numbers in front of the controls are its index in the parent’s Controls array.

The last challenge was the control’s class: THistoryPropComboBox. Whatever it is, it is not a TCombobBox but at least it derives from TCustomComboBox, so I could typecast it to that. But how do I access the Text property to fill it with the name of the file dropped on it? It is a protected field in TCustomComboBox. I took a gamble and assumed that it just publishes this field like TComboBox does and hard type casted it to TComboBox. It worked.

So, after several hours of hacking I can now drop an executable from the Windows Explorer on the Host application input field and its filename will automagically appear there.

As you can seen from the table above, there are some other interesting input fields for drop file support. They will come next, but for today, one is enough.