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

GExperts 1.3.12 beta for Delphi 10.3 Rio available

 Delphi, GExperts  Comments Off on GExperts 1.3.12 beta for Delphi 10.3 Rio available
Nov 252018
 

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

NOTE: This is a BETA!

Beware of bugs, e.g. the Goto-Dialog enhancements cause redraw problems if theming is enabled, the Run Parameters dialog enhancements (drag and drop for files and directories) don’t work at all.

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

See also: GExperts 1.3.12 beta 2 for Delphi 10.3 Rio.

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

Found the cause of the AV on exiting the Delphi IDE

 Delphi, GExperts  Comments Off on Found the cause of the AV on exiting the Delphi IDE
Nov 242018
 

There was a bug in the (yet unreleased) GExperts code that caused an access violation every time the Delphi IDE was closed. I have just found it, but boy was that difficult!

I knew the problem existed in the current source code and by trial and error I found a source code revision that did not yet have it: #2415. So I compared those revisions and step by step narrowed it down to the changes in the unit GX_IdeFormChangeManager in revision #2433 which was a fix for a redrawing bug in the Delphi 10.2 Search Path dialog.

So I removed the code I had added, which consisted of two parts:

procedure TFormChangeManagerInternal.ProcessActivatedForm(Form: TCustomForm);
var
  i: Integer;
  NeedsWorkaround: Boolean;
begin
  Assert(Assigned(Form));

  // We are executing the callbacks in last registered first order to allow callbacks to
  // unregister themselves. (And we don't check whether a callback only unregisters itself, so
  // please be cautios!). That means registering a new callback while executing a callback
  // is not allowed.
  FIsInFormChangeCallback := True;
  try
// ------------- workaround part 1 starts here ------------
    // Workaround for redraw issue in Delphi 10.2 when theming is enabled:
    // https://sourceforge.net/p/gexperts/bugs/86/
    // Disable redraws while we change the window
    NeedsWorkaround := HasRedrawProblems(Form);
    if NeedsWorkaround then
      SendMessage(Form.Handle, WM_SETREDRAW, WParam(False), 0);
// ------------- workaround part 1 ends here ------------
    try
      for i := FFormChangeCallbacks.Count - 1 downto 0 do begin
        try
          TFormChangeCallbackItem(FFormChangeCallbacks[i]).FCallback(Self, Form);
        except
          // just so we can have a look at any exceptions that might be raised ...
          raise;
        end;
      end;
    finally
// ------------- workaround part 2 starts here ------------
      if NeedsWorkaround then begin
        // Allow and force a redraw of the whole window
        SendMessage(Form.Handle, WM_SETREDRAW, WParam(True), 0);
        RedrawWindow(Form.Handle, nil, 0, RDW_INVALIDATE or RDW_ALLCHILDREN);
        // see Remarks on
        // https://docs.microsoft.com/en-us/windows/desktop/gdi/wm-setredraw
      end;
// ------------- workaround part 2 ends here ------------
    end;
  finally
    FIsInFormChangeCallback := False;
  end;
end;

I didn’t really think this could make a difference because the HasRedrawProblems function only returns true in Delphi 10.2 but the AV occurred in all versions of the IDE. And guess what? It didn’t make a difference at all! The AV still happened.

So I reverted all the changes to the unit, which included the addition of a few units to the uses clause in the implementation section: Messages, Registry and GX_IdeSearchPathEnhancer

The AV was gone!

Now what? I added Messages and Registry again, everything still was fine. Then I added GX_IdeSearchPathEnhancer and boom, the AV was back.

After I knew what to look for, the cause was simple to spot: Both units GX_IdeSearchPathEnhancer and GX_IdeFormChangeManager have got a finalization section. They both free an instance of a class that gets created some time during the life time of a GExperts session. By adding GX_IdeSearchPathEnhancer to the uses list of GX_IdeFormChangeManager, the execution order of the finalization sections changed.

The unit GX_IdeFormChangeManager provides a singleton instance of TFormChangeManagerInternal which gets created on demand in any of the class methods of TIDEFormChangeManager. That instance is freed in the finalization section.

The unit GX_IdeSearchPathEnhancer has an internal instance of TSearchPathEnhancer which also gets freed in its finalization section. TSearchPathEnhancer.Create registers itself for Screen.OnActiveFormChanged events to detect when the IDE’s Sarch Path dialog is being shown. In the Destructor it unregisters itself for that event.

So far, so good, now the problem occurs when the finalization of GX_IdeFormChangeManager runs before the one of GX_IdeSearchPathEnhancer: The singleton instance of TFormChangeManagerInternal gets freed and afterwards the destructor of TSearchPathEnhancer tries to use it to unregister itself from the OnActiveFormChanged event. This created a new TFormChangeManagerInternal instance which hooked the Screen.OnActiveFormChanged event. Since the finalization of GX_IdeFormChangeManager had already run, this new instance never got freed, so as soon as the GExperts DLL was unloaded, the event pointed to uninitialized memory and thus the access violation occurred. This of course will never show anything usable in the debugger as the offending code has already been unloaded.

Now you might ask, why in the world I added the additional unit to the uses clause? That was because of the fix introduced in that revision. It needed to know if the new active form as the Search Path dialog, and following the Don’t repeat yourself (DRY) principle [1] of good software development, I moved the code for detecting that, which was already in a method of TSearchPathEnhancer, to a public class method of that class. So I avoided duplicating the code. but in order to call that class method, I had to add the unit to the uses clause. Which introduced the bug.

Even though it was difficult to trace it, at least it was a reproducible bug, so I could finally track it down. Now I’m going to fix it and then I will start testing GExperts in Delphi 10.3 so I can make a new release.

[1] Yes, it is DRY, because the knowledge of how to detect if a form is the Sarch Path dialog is “business knowledge”, in this case knowledge about what class and name that form has in any of the IDE versions.

 Posted by on 2018-11-24 at 15:44

Creating and calling DLLs in Delphi

 Delphi  Comments Off on Creating and calling DLLs in Delphi
Nov 182018
 

I just got reminded that in 2006 I wrote an article about creating DLLs with Delphi in the Delphi Wiki.

Unfortunately I got that reminder because somebody (again) vandalized it. He probably thinks he is a l33t h4x0r for being able to edit a website. I think he simply is a [enter your favorite swearword here].

But I reverted his changes and read through that article again. It’s still correct nowadays even though it should probably be updated to mention Unicode, WideString and PWideChar.

EDIT:

There is also a nice article by Rudy Velthuis DLL dos and don’ts.

 Posted by on 2018-11-18 at 14:31

Fake TSpeedButton based on TBitBtn updated again

 Delphi  Comments Off on Fake TSpeedButton based on TBitBtn updated again
Nov 102018
 

My fake TSpeedButton based on TBitBtn has been updated again. It now supports any combination of Glyph and single/multi line Text. It also supports setting Margin and Spacing.

Note that it still requires the Glyph to be on the left.

(Yes, I know, I should have selected some examples where the text does actually fit the button. ;-). But this is just the same problem as in the original TBitBtn control, I even fixed some if its bugs.)

(Click on the image to view an animated demo.)

Also, the original BitBtn object is now exposed via a read only property and there is a new pointer type Data property to attach some additional information to the object.

In addition I added a new class TdzSpeedBitBtnGroup which easily emulates the behaviour of a TRadioGroup using TdzSpeedBitBtns.

The source code is part of my dzlib library which is available from OSDN.

 Posted by on 2018-11-10 at 11:27

Making “Stay-on-top-forms” do want you want in Delphi

 Delphi  Comments Off on Making “Stay-on-top-forms” do want you want in Delphi
Nov 052018
 

There is an article by Peter Laman on the topic Making “Stay-on-top-forms” do want you want on the Embarcadero blog. It’s from 2004 and of course the link to the component he talks about no longer works, because it points to cc.borland.com which no longer exists.

Here is a working link.

(I don’t know whether the component still works or is even reqired. I just encountered a problem with a stay on top form and found this article.)

Edit: It’s not a component but a class TStayOnTopForm derived from TForm. You are supposed to derive your form from this class and it does everything else for you. Unfortunately it doesn’t seem to work in my test program, but it does work in the demo that comes with it.

 Posted by on 2018-11-05 at 10:42

Creating Component Templates in Delphi

 Delphi  Comments Off on Creating Component Templates in Delphi
Nov 032018
 

One nice feature of the Delphi IDE that I keep forgetting are Component Templates. That means you drop and customize one or multiple components on a form and then give them a new name so you can easily create them again on a different form in a different program.

Let’s start with a simple template for an OK button:

  1. Drop a button on a form.
  2. Give it a meaningful name, e.g. “btnOK
  3. Set its “Caption” property to “OK”.
  4. Set its “Default” property to True.
  5. Make sure that the button is sill selected.
  6. Select Component -> Create Component Template from the menu.
  7. Give it a name, e.g. “OKButton”.

That’s it. A new entry has been added to the Tool Palette. Now, whenever you want to add an OK button, you simply press Ctrl+Alt+P to bring up the Tool Plaette, then enter “OK” and maybe some more keys to filter the list and select the new entry. A copy of the created template will be added to your form. No need to change its properties again.

Now, a form usually has not just an OK but also a Cancel button, why not create a template “OkCancelButtons” for that?


(Click on the picture for an animated tutorial for the below.)

  1. Drop a button on a form.
  2. Give it a meaningful name, e.g. “btnOK
  3. Set its “Caption” property to “OK”.
  4. Set its “Default” property to True.
  5. Drop another button on the form.
  6. Move it to your liking in relation to the OK button.
  7. Set its “Caption” property to “Cancel”.
  8. Give it a meaningful name, e.g. “btnCancel”
  9. Set its “Cancel” property to True.
  10. Select both buttons with Shift+Left Mouse Button.
  11. Select Component -> Create Component Template from the menu.
  12. Give it a name, e.g. “OKCancelButton”.

Again, a new entry has been added to the Tool Palette which you can use whenever you need these two buttons on any form in any program. They will have the correct captions, the Default and Cancel properties will be set and they will be in the right place in relation to each other.

To get rid of a component template you don’t need any more, use the “Delete <component name>” entry context menu on the entry in the Tool Palette.

Component templates are stored in the file
%AppData%\Roaming\Embarcadero\BDS\{version}\bds.dct for current versions, and in delphi.dct in the executable directory for Delphi 6 and 7. I don’t know whether even older versions supported them, but if yes I’d expect them to store them in the same way as Delphi 6 and 7.

(Thanks to Ondrej Kelle for that link.)

 Posted by on 2018-11-03 at 14:47

Two buttons to make a difference in the Set Tab Order expert

 Delphi, GExperts  Comments Off on Two buttons to make a difference in the Set Tab Order expert
Nov 012018
 

The Set Tab Order expert in GExperts allows you to change the tab order of controls by dragging them in a tree view. I have always wondered why the standard Tab Order dialog of the IDE has got buttons to move the current control up or down while the one in GExperts does not.

OK, now it has them too:

These buttons even have keyboard shortcuts: Ctrl+Up moves the current item up, Ctrl+Down moves it down.

I’m thinking about further improvements for that expert, but nothing concrete yet. I kind of like the approach that the CnPack IDE wizards take, but on the other hand too much automation can be bad too. What if I want to have a button on the lower left to be the last control in the tab order? Like an “About” button, which in my opinion should not be between the last input field and the OK button because I rarely click it?

 Posted by on 2018-11-01 at 11:25