Jump to content
Steve Maughan

Right Process for Changing an Application's Icon?

Recommended Posts

The way Delphi handles application icons seems to be terrible.

 

Here's what happened. We have a new icon for our application. I managed to delete the old icon and all *.res file and update it with a new icon. Then suddenly the application is using the wrong icon in the main form. I've repeated the icon update process once again and now I seem to have messed things up. I now have the default icon as the application icon.

 

OK - rant over, now for my questions:

 

  1. Is there an approved step-by-step process for changing a Delphi application's icon?
  2. How do I determine which size icon is used for the main form. Is it the 16x16 or 24x24 version of the main icon?

 

Thanks,

 

Steve

Share this post


Link to post
Posted (edited)

1) I don't know of any "approved process" apart from specifying an icon in the project options and, as you have discovered, that doesn't always work. Here's why:

The default icon to use as the application icon is determined by Windows. Delphi has no control over it.

Windows simply selects "the first icon" as the default application icon. The order of icons are determined by their resource ID/name (AFAIR this is only true for Delphi because Delphi sorts the resources at link time (which is actually a good thing as the alternative would means we had no control over what icon got selected (as we have no control over the order))).

The Delphi project icon is always named (by Delphi) "MAINICON". If you add another icon to the project, and the name of that icon is sorted before MAINICON, then this icon will be ordered before MAINICON and will be selected by Windows as the application icon.

 

For this reason I usually name my application icon "A" and add it as an external resource file to my projects. This way I don't have to worry about what other icons there might be added by 3rd parties (or other developers) and what their names are. The MAINICON I just ignore or load with the same icon as the "A" icon.

mainicon_a.jpg.fd66b3ec1f1cb65998b7d0c463c0332b.jpg

 

2) The icon size used for the forms depends on the size of the windows caption area, which depends on scaling/zoom, font sizes and so on. The icon is selected by Windows from the different sizes available in your application icon (or whatever icon you have associated with the form).

--

See also: forms.pas (search for WM_SETICON and WM_GETICON)

 

Edited by Anders Melander
  • Like 2

Share this post


Link to post

Thanks Anders. 

 

This is really helpful. Can I ask, what is the resource editor you're using in the screenshot?

 

Steve

 

Share this post


Link to post
Just now, Ondrej Kelle said:

Looks like Anders' Resource Editor which you can download from his website: http://melander.dk/download/

Only because I've just uploaded a new version 🙂. It's been gone for at least 5 years. My ISP keeps flagging it as a virus (probably because it's built with Delphi) and taking it offline.

  • Like 1
  • Thanks 3
  • Sad 1

Share this post


Link to post
20 hours ago, Anders Melander said:

size of the windows caption area,

 

That and your Explorer settings, because what you see there depends on finding a matching icon size/color depth.

 

I used to maintain my own res file due to all the issues that brought up but now use Andy's DDevExtensions:

 

 

Untitled.png

Share this post


Link to post
22 hours ago, Steve Maughan said:

Then suddenly the application is using the wrong icon in the main form.

TForm also has an Icon property. Just for the record.

An assigned Icon could lead to the same symptoms.

Share this post


Link to post

Don't forget to clear the Windows icon cache after you have made an icon change, to be sure that you are seeing what your users will see on first installing your application.  Your search engine will find many ways to do this, some of them better than others...

  • Like 1
  • Thanks 1

Share this post


Link to post
Posted (edited)
On 3/9/2019 at 6:44 PM, Anders Melander said:

Only because I've just uploaded a new version 🙂.

A word of warning to those (I'm counting 50 since yesterday) that downloaded this version: If your resources contains bitmaps that were created by older versions of Delphi (or rather applications built with older versions of Delphi) then the resource editor might corrupt them on save.

 

It appears that a bug was introduced in TBitmap between Delphi 2009 and 10.2.  Here's the short version:

The format of a windows bitmap is basically 1) Header, 2) Color table, 3) Pixel data. For bitmaps with PixelFormat>pf8bit the color table is optional.

The Header specifies the number of colors in the color table (the TBitmapInfoHeader.biClrUsed field).

 

Older versions of Delphi sometimes saved bitmaps in pf24bit/pf32bit format with a color table and the corresponding value in the biClrUsed field. This was unnecessary but harmless and perfectly legal according to the bitmap specs.

Here's an example of what such a bitmap might look like:

[File header]

[Bitmap header, biClrUsed=16, biBitCount=32]

 

[Pixel data]

 

These bitmaps can be read by newer versions of Delphi, but when the bitmaps are written again they become corrupt. Delphi keeps the value in the biClrUsed field but fails to write the corresponding color table. The result is that the pixel data ends up at the wrong file offset.
Here's an example of a corrupt bitmap:

[File header]

[Bitmap header, biClrUsed=16, biBitCount=32]

[Pixel data]

 

The reason why this is a problem for the resource editor is that it is built with Delphi 10.2. I have a fix for the problem but I'm not ready to release a new version with the fix.

Here's the fix btw:

// Fix for bug in TBitmap.
// Saving bitmap with PixelFormat>pf8bit with biClrUsed>0 fails to save the color table
// leading to a corrupt bitmap.
type
  TBitmapColorTableBugFixer = class helper for TBitmap
  type
    TBitmapImageCracker = class(TBitmapImage);
  public
    function FixColorTable: boolean;
  end;

function TBitmapColorTableBugFixer.FixColorTable: boolean;
begin
  if (TBitmapImageCracker(FImage).FDIB.dsBmih.biBitCount > 8) and (TBitmapImageCracker(FImage).FDIB.dsBmih.biClrUsed <> 0) then
  begin
    TBitmapImageCracker(FImage).FDIB.dsBmih.biClrUsed := 0;
    Result := True;
  end else
    Result := False;
end;

 The problem appears to be the same one reported here: Setting TBitmap.PixelFormat can lead to later image corruption or EReadError

Edited by Anders Melander
  • Like 4
  • Thanks 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×