Delphi, GExpertsComments Off on New Filter Exceptions expert in GExperts
I my last GExperts related blog post I wrote about the new “Close Exception Notification” expert which I just had added to GExperts. It was a hack that hooked the Exception Notification dialog.
This spawned a discussion in the international Delphi Praxis forum and resulted in a rewrite of the expert. It’s now called “Filter Exception” expert and instead of hooking the dialog it directly hooks into the code that shows this dialog. Thus it prevents the dialog from being shown for filtered exceptions.
I got into programming because I am lazy, I’d rather have the computer do the boring work than doing it myself. So it’s no wonder that I always liked Delphi and GExperts because both support my laziness.
Today I added yet another feature to save me a key stroke or mouse click: The “Close Exception Notification” expert.
You probably have encountered those libraries that always raise the same exception class on errors, or even worse, raise the generic Exception class instead of bothering to declare their own. And if I should guess, you have probably been guilty of doing that yourself (as I definitely have).
Why is that a problem, you ask?
Because you can’t easily ignore these exceptions during debugging. You always get this “Debugger Exception Notification” dialog, have to read it and decide whether you want to break and look at the code or ignore the exception:
There is this nice option to “Ignore this exception type”, but unfortunately ignoring the exception class “Exception” is rarely an option.
The same problem occurs with other rather generic exceptions like EFOpenError which you can’t really simply ignore but need to check for the file name.
So, what we need is a more finely grained filter based on the message.
Enter the new “Close Exception Notification” expert. It adds a “GExperts” button (I need a better caption) to the dialog above which lets you add filters for Exceptions based on class name and message. And since it was more convenient for me (more laziness), the message filter is a regular expression.
This button will call a configuration dialog which allows you to configure how to handle the current exception.
This dialog is mostly pre-filled if opened through the button on the “Debugger Exception Notification” dialog.
You first enter (there will be some kind of recently used list in the future) the exception class name and then a regular expression for the message. In the simplest case this can be the whole message (but beware of characters which have a special meaning in regular expressions, like ‘.’, ‘*’, ‘?’ or ‘\’). There is an additional input field which you can use to test whether the regex matches the message. When you are satisfied with your newly created rule, select the action to take automatically and press OK. The dialog will close and the action will be executed for the first time, e.g. the Ignore button will automatically be pressed.
The “Close Exception Notification” expert does not have a menu entry. But there is a configuration dialog which gives you a list of currently configured filters.
Unfortunately since this expert cannot directly modify the IDE code and I am not aware of any Open Tools API access to the exception notification, it has to hack the dialog. This results in the dialog being displayed for a short time before the expert “presses” the button for you. This is certainly not ideal but still better than not having it.
There is no GExperts release with this new functionality yet, so in order to get it, you will have to compile your own DLL.
DelphiComments Off on Fixing wrong position and size of the Delphi 10.4 IDE window
Apparently the bug that causes the Delphi IDE to not store its position correctly when placed in full screen on a secondary monitor to the left of the primary monitor (which is my setup at home and at work) still hasn’t been fixed in Delphi 10.4. Luckily the work around of editing the desktop settings still works.
I revisited my dzBdsLauncher tool again – no idea why, it just occurred to me 😉 – and added quite a few improvements:
It now supports .dof (Delphi 6 and 7) and .bdsproj (Delphi 2005 and 2006) files.
In addition to the previous checks it now also looks at the disabled packages list to determine which Delphi version to start. That’s the only option for Delphi 2005 and 2006 because these files are nearly identical.
It can now also handle .dpr files by looking for corresponding .dproj, .bdsproj and .dof files (in that order) and taking these to determine the correct Delphi version.
As a side effect I found a problem with the Delphi 10.1 version of the GExperts .dproj file. It had a wrong ProjectVersion entry.
Delphi, dzLibComments Off on When computers try to be clever
Don’t you just hate it when computers try to be clever but get it wrong? OK, it’s not really the computer itself but the programmer who tried to be clever. The problem usually is that he overlooked a corner case that you then hit where his sophisticated strategy fails and leaves you with something – lets say less desirable.
Today I wasted several hours trying to find out what was wrong with my hack to create a TSpeedButton which can take the input focus (which standard TSpeedButtons can’t), by using a TBitBtn instead. I blogged about this before.
There was a certain button width which caused the button to display only a square part of the caption. At closer inspection it turned out to not be a fixed width but kind of a width to height ratio that caused the problem. Here are several buttons with different widths and heights that show this behaviour:
Buttons with a width to height ratio of (w-1) : (h-1) = 4 : 1 looked like the screenshot above, e.g. 97×25, 101×26, 105×27, 93×24 or 89×23. Other sizes were fine.
The code I use in this hack is very simple: I generate two bitmaps, one for the Up state of the button, the other for the Down state and assign them to the TBitBtn’s Glyph property.
if FBtn.Tag <> 0 then
FBtn.Glyph := FDownBmp
FBtn.Glyph := FUpBmp;
That bitmap is always one pixel smaller than the button itself, so the problem occurred with bitmaps of 96×24, 100×25, 104×26, 92×23 and 88×22 pixels respectively.
So I tried to reproduce that behaviour with a simple TBitBtn with default settings by assigning a bitmap with 96×24 pixels. It looked like this …
… even at design time. Closer inspection showed that the NumGlyps property also had a different value than expected: 4. Setting it to 1 made the button display the whole bitmap again:
So there seemed to be some code behind assigning a bitmap to the glyph that tried to guess how many images there actually are stored in the bitmap. If the width to height ratio is 4, it assumes that there are 4 images in the bitmap.
With that knowledge I looked into the documentation of TBitBtn.Glyph and guess what: It’s documented behaviour, kind of:
You can provide up to four images within a single bitmap. All images must be the same size and next to each other in a row. Bit buttons display one of these images depending on their state.
If you have multiple images in a bitmap, you must specify the number of images that are in the bitmap with the NumGlyphs property
I actually knew that but since I rarely use TBitBtn controls I hadn’t thought of it. It doesn’t say that the code tries to be clever and guess how many images there are though.
Tests showed that the code calculates the width to height ratio and for ratios of 2, 3 or 4 assumes that to be the number of images and sets NumGlyphs accordingly. And of course it’s easy to find once you know what you’re looking for:
procedure TButtonGlyph.SetGlyph(Value: TBitmap);
if (Value <> nil) and (Value.Height > 0) then
FTransparentColor := Value.TransparentColor;
if Value.Width mod Value.Height = 0 then
Glyphs := Value.Width div Value.Height;
if Glyphs > 4 then Glyphs := 1;
(from unit Vcl.Buttons)
Why did it take me several hours to find some simple problem like this, you ask? (I asked myself that question too.) Of course this didn’t happen in a simple test program like the one in the screen shot. It happened in a dialog in GExperts. GExperts is a plugin for the Delphi IDE and as such must be built with runtime packages. And if you do that, you can’t compile with debug dcus and simply step into the RTL/VCL code in the debugger, all you can see is some assembler code. So I first tried to find the problem in my code. Did I maybe overlook a corner case? Then I tried to reproduce the problem with a test program but couldn’t, because the width to height ratio of my test buttons wasn’t the one which caused the problem. I puzzled quite a while over this, looked into the DFM files to find anything suspicious, but there was nothing. Only after I copied the buttons from the GExperts form to the form of the test program I could reproduce it.
Once I knew the cause, the fix was easy: After assigning the Glyph change NumGlyphs back to 1.
if FBtn.Tag <> 0 then
FBtn.Glyph := FDownBmp
FBtn.Glyph := FUpBmp;
FBtn.NumGlyphs := 1;