5

I am trying to create a custom component that shows an icon when the mouse is moved over it. I am loading the icons like this:

UNIT Test;

constructor TTestPath.Create(aOwner: TComponent);
VAR myIcon: TIcon;
begin
 inherited Create(aOwner);

 ImgList:= TImageList.Create(Self);   
 myicon := TIcon.Create;
 TRY
   myicon.LoadFromResourceName(HInstance, 'FOLDER');  <------ this becomes application's icon!
   ImgList.AddIcon(myicon);
 FINALLY
   FreeAndNil(myicon);
 end;

The thing is that as soon as I add Test.pas to the USES cause of my test application, application's icon (red delphi helmet) is replaced by the 'FOLDER' icon.

Update:
The icons in EXE file are in this order: 'FOLDER', Default_Delphi_icon So, TTestPath's icon is added to the exe BEFORE application's icon.

What is wrong here: the fact that TTestPath's icon be present in this way in EXE file or the fact that it is placed before application's (default) icon?


Control's code below:

UNIT test;

INTERFACE

USES
  System.SysUtils, Winapi.Windows, System.Classes, Vcl.StdCtrls, Vcl.Controls, Vcl.Graphics, vcl.imglist, Vcl.ExtCtrls;   {$WARN GARBAGE OFF}   {Silent the: 'W1011 Text after final END' warning }

TYPE
  TValidity= (vaNone, vaValid, vaInvalid);                   { Normal / Green / Red color }
  TInputType= (itFile, itFolder);                            { What kind of path will the user type in this control: folder or file }

  TTestPath = class(TCustomGroupBox)
   private
     edtPath     : TButtonedEdit;
     btnApply    : TButton;
     btnExplore  : TButton;
     FInputType  : TInputType;
     imgList     : TImageList;
     FShowApplyBtn: Boolean;
    protected
   public
     constructor Create(aOwner: TComponent);  override;
   published

     property Align;
     property Anchors;
     property BiDiMode;
     property Caption;
     property Color;
     property Constraints;
     property Ctl3D;
     property DockSite;
     property DoubleBuffered;
     property DragCursor;
     property DragKind;
     property DragMode;
     property Enabled;
     property Font;
     property Padding;
     property ParentBackground default True;
     property ParentBiDiMode;
     property ParentColor;
     property ParentCtl3D;
     property ParentDoubleBuffered;
     property ParentFont;
     property ParentShowHint;
     property PopupMenu;
     property ShowHint;
     property TabOrder;
     property TabStop;
     property Touch;
     property Visible;
     property StyleElements;
     property OnAlignInsertBefore;
     property OnAlignPosition;
     property OnClick;
     property OnContextPopup;
     property OnDblClick;
     property OnDragDrop;
     property OnDockDrop;
     property OnDockOver;
     property OnDragOver;
     property OnEndDock;
     property OnEndDrag;
     property OnEnter;
     property OnExit;
     property OnGesture;
     property OnGetSiteInfo;
     property OnMouseActivate;
     property OnMouseDown;
     property OnMouseEnter;
     property OnMouseLeave;
     property OnMouseMove;
     property OnMouseUp;
     property OnStartDock;
     property OnStartDrag;
     property OnUnDock;
  end;


procedure Register;



IMPLEMENTATION {$R cPathEdit.res}

USES cIO;




constructor TTestPath.Create(aOwner: TComponent);
VAR myIcon: TIcon;
begin
 inherited Create(aOwner);
 Caption := 'Folder';
 Height:= 41;
 FShowApplyBtn:= TRUE;

 ImgList:= TImageList.Create(Self);   { Freed by Self }
 myicon := TIcon.Create;
 TRY
   myicon.LoadFromResourceName(HInstance, 'FOLDER');
   ImgList.AddIcon(myicon);

   myicon.LoadFromResourceName(HInstance, 'FOLDER_OPEN');
   ImgList.AddIcon(myicon);
 FINALLY
   FreeAndNil(myicon);
 end;

 edtPath:= TButtonedEdit.Create(Self);
 WITH edtPath DO
  begin
   Parent                := Self;
   Align                 := alClient;
   Margins.Left          := 1;
   Margins.Top           := 2;
   Margins.Right         := 1;
   Margins.Bottom        := 1;
   AlignWithMargins      := TRUE;
   Images                := imgList;
   TabOrder              := 0 ;
   OnChange              := nil;
   RightButton.Hint      := 'Browse for a folder';
   RightButton.ImageIndex:= 0;
   RightButton.HotImageIndex:= 1;
   RightButton.Visible   := TRUE;
   OnRightButtonClick    := nil;
   OnKeyPress            := nil;
  end;

 btnExplore:= TButton.Create(Self);
 WITH btnExplore DO
  begin
   Parent           := Self;
   Align            := alRight;
   Width            := 22;
   Margins.Left     := 1;
   Margins.Top      := 1;
   Margins.Right    := 1;
   Margins.Bottom   := 1;
   AlignWithMargins := TRUE;
   Caption          := '^';
   TabOrder         := 1;
   Hint             := 'Open this folder in Windows Explorer';
   OnClick          := nil;
 end;

 btnApply:= TButton.Create(Self);
 WITH btnApply DO
  begin
   Parent           := Self;
   Align            := alRight;
   Width            := 38;
   Margins.Left     := 1;
   Margins.Top      := 1;
   Margins.Right    := 1;
   Margins.Bottom   := 1;
   AlignWithMargins := TRUE;
   Hint             := 'Create folder if necessary';
   Caption          := 'Apply';
   TabOrder         := 2;
   OnClick          := nil;
 end;

 FInputType:= itFolder;
end;

procedure Register;
begin
  RegisterComponents('xxx', [TTestPath]);
end;

end.

Test app:

unit Unit1;
interface
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, Forms, 
  test;   <-------- this 

type
  TForm1 = class(TForm)
  private
  public
  end;

var
  Form1: TForm1;

IMPLEMENTATION
{$R *.dfm}

end.
Gabriel
  • 20,797
  • 27
  • 159
  • 293
  • 3
    Delphi uses the main icon from a `MAINICON` resource name which is the first icon. Icon names are sorted by the alphabet. if You name your other icon as e.g. `X_FOLDER` it should work. – kobik Oct 09 '16 at 11:11
  • Odd that all icons in exe MUST be start with 'N' (or higher character) :) But I will try that. Thanks. – Gabriel Oct 09 '16 at 11:15
  • But should 'FOLDER' be present as an accessible icon in EXE? – Gabriel Oct 09 '16 at 11:15
  • @kobik - It worked. Thanks. I will accept your answer if you post it. Is this a bug, or is it documented? – Gabriel Oct 09 '16 at 11:27
  • 1
    Its not a bug. the OS uses the first icon. – kobik Oct 09 '16 at 11:32
  • @kobik-Thaks. Embarcadero should have made sure that application's icon is the first icon then.... :) – Gabriel Oct 09 '16 at 11:34
  • The defect is that Delphi doesn't follow the rules of the underlying platform and ensure that `'MAINICON'` is written first. – David Heffernan Oct 09 '16 at 11:34

1 Answers1

7

Due to a rather messed up decision from Embarcadero, icon resources are sorted alphabetically when linked. The Windows rule is that the icon used by the shell for an executable is the first icon. Delphi VCL code assumes that the application icon is named 'MAINICON'.

Put these requirements together and you can deduce the all your icons must have names that appear after 'MAINICON' in alphabetical order.

It's rather frustrating but easy enough to work around. Adopt a suitable naming convention for your icons and everything will behave as you intend.

Quite why Embarcadero don't change their code to make sure that the icon named 'MAINICON' is emitted first is beyond me. Or arrange that the application icon is defined to be the first one, and thus follow the rules of the platform. But there's nothing much that we can do.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • I guess a nother option is to not use Delphi's main icon at all. and link to my own resource file. – kobik Oct 09 '16 at 11:38
  • @kobik I think Delphi linker takes all the icons you supply and then sorts by their names. I don't use the Delphi main icon myself and supply all my icons in one res file. But Delphi orders them in the executable IIRC. – David Heffernan Oct 09 '16 at 11:41
  • @kobik - This is not a difficult problem to manage. Solutions are available (rename your icons, don't use delphi's main icon). The problem is the knowledge about this issue. Once you have the knowledge...... :) :) – Gabriel Oct 09 '16 at 11:41
  • @kobik @ david - "not use Delphi's main icon at all". This is a good idea. My Delphi XE7 IDE sometimes messes up the DPR/DPROJ files (problems reported here on stackoverflow) and I have to delete the dproj or re-add the ico file to the project. – Gabriel Oct 09 '16 at 11:45
  • I see an absolutely impressive number of bugs fixed in Berlin. Maybe this will fix this too (use aMAINICON as name). Berlins FINALLY seems to be an edition worth spending money on it. – Gabriel Oct 09 '16 at 11:46
  • The VCL loads an icon named `'MAINICON'` so there's not much you can do about that – David Heffernan Oct 09 '16 at 11:46
  • I doubt they will ever change this. They might have fixed a load of bugs but they introduce bugs at a fearsome rate. And they won't fix anything that matters to me relating to performance and floating point. – David Heffernan Oct 09 '16 at 11:48
  • But you MUST admit that this (massive bug fixes) never happen until now. For the first time I am very optimistic about Delphi (even though the trial of Berlin failed to work in my computer :) ). Many in the next releases they will fix floating point too. Let hope that the ratio 'bugs fixed/new bugs introduced' will reverse. – Gabriel Oct 09 '16 at 11:50
  • 1
    Every new release has hundreds of bug fixes. What I want from the product is more fundamental and I don't think they have the talent to deliver it. They've sacked all their talent. – David Heffernan Oct 09 '16 at 11:51
  • It happens when you have a small community :( You cannot pick up good programmers. You have to use what you have. They should pick you as product manager at Embarcadero. I would vote for you :) I thought that marco cantu will change things (well... he did some changes, we have bug fixes... lots of them). – Gabriel Oct 09 '16 at 11:53
  • 1
    They had decent programmers. They got rid of them! They moved Allen Bauer on. Crazy. – David Heffernan Oct 09 '16 at 12:04