Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi form icons are blurry on Windows 7's taskbar (with MainFormOnTaskbar enabled)

We have a Windows desktop application written in Delphi that works fine on Windows 7, except that the icon of the main form looks blurry in Windows' new taskbar. As long as the application has not been started the icon looks fine (i.e. when it's pinned to the taskbar). Once it has been started Windows uses the icon of the main form (instead of the .exe resource icon) and it's blurry (it looks like a 16x16 version of the icon is scaled up).

The icon that we use for the .exe and for the main form are exactly the same and it contains all kinds of resolutions, including 48x48 with alpha blending.

My theory is that Delphi ignores/deletes the extra resolutions of the icon when I import the .ico file for the main form in Delphi. Is there a way to prevent/fix this? What's the best way to ensure that an application written in Delphi uses the correct icon resolution in Windows 7's taskbar?

like image 821
Dennis G. Avatar asked Apr 12 '10 11:04

Dennis G.


2 Answers

The problem lies within lazy programming within the VCL not fitting with the behavioral change of the OS. More or less it is like this;

TCustomForm.CreateWnd, after the window handle is created, calls;

  SendMessage(Handle, WM_SETICON, 1, LPARAM(GetIconHandle)) else

Notice the "1" in place of wParam, that's ICON_BIG. Actually the VCL sets the large icon of the form. But the icon's requested size (TIcon.FRequestedSize) is 16x16 (by default), and so the TIcon of the form returns a handle for the small icon. That's the size for the system small icon and is determined in the constructor CreateNew with calls to GetSystemMetrics.

Since earlier versions of Windows used the small icon on the taskbar this was no problem. Hovewer the Alt+Tab dialog had the problem other way around; if an icon was assigned to a form it showed "blurred" in the Alt+Tab dialog. Anyway, Windows 7, still, by default returns 16x16 for the small icon (SM_CXSMICON/SM_CYSMICON) and 32x32 for the large icon (SM_CXICON/SM_CYICON), but the large taskbar displays the large icon, if there is one that is..

The correct approach would be to assign a large image (if there is one in the icon) for the large icon and assign a small image (if there is one) to the small icon. Granted, since the sizes would not have to have exact matches, this would require a complex algorithm. Instead, a simpler but broken design is implemented.


For a workaround, I don't assign an icon to the forms in the OI and instead use this;

procedure SetFormIcons(FormHandle: HWND; SmallIconName, LargeIconName: string);
var
  hIconS, hIconL: Integer;
begin
  hIconS := LoadIcon(hInstance, PChar(SmallIconName));
  if hIconS > 0 then begin
    hIconS := SendMessage(FormHandle, WM_SETICON, ICON_SMALL, hIconS);
    if hIconS > 0 then
      DestroyIcon(hIconS);
  end;
  hIconL := LoadIcon(hInstance, PChar(LargeIconName));
  if hIconL > 0 then begin
    hIconL := SendMessage(FormHandle, WM_SETICON, ICON_BIG, hIconL);
    if hIconL > 0 then
      DestroyIcon(hIconL);
  end;
end;

and include an "icons.res" with named icons having 16x16 and 32x32 images, in the project. All the forms in their OnCreate call

 SetFormIcons(Handle, 'MYFORM', 'MYFORM');
like image 112
Sertac Akyuz Avatar answered Nov 04 '22 02:11

Sertac Akyuz


It can be a bit of a nightmare getting this right. I have found that the most successful strategy is to place a very simple icon on the main form and application, and then to incorporate the ReplaceVistaIcon program into the build workflow to replace the icon with your multiple-icon file after the build is complete (and before signing the exe). This seems to place the icon correctly so that Windows picks it up in preference to any other icon resource. It's a nuisance to have to do this, but once set up (in our FinalBuilder project) it works for us.

The annoying problem, while you are testing this, is that you may have to delete the Windows icon cache to see the effect of any changes. This involves shutting down Explorer to allow you to delete the cache file from a command session.

like image 24
frogb Avatar answered Nov 04 '22 04:11

frogb