Adding an icon to the Delphi IDE splash screen

In a previous blog post I described how to add an entry to the Delpih IDE About dialog. This time it’s about the splash screen.

Since Delphi 2005 the IDE provides the SplashScreenServices interface that is available even before the other interfaces that make up the ToolsAPI. It allows adding an icon to the splash screen quite easily:

uses
  ToolsAPI;

// [...]

procedure AddPluginToSplashScreen(_Icon: HBITMAP; const _Title: string; const _Version: string);
{$IFDEF GX_VER170_up}
// Only Delphi 2005 and up support the splash screen services
begin
  if Assigned(SplashScreenServices) then
    SplashScreenServices.AddPluginBitmap(_Title,
      _Icon, False, _Version);
end;
{$ELSE GX_VER170_up}
begin
end;

So, I could now stop writing this article if it weren’t for the case that GExperts supports Delphi 6 and 7 as well and I am stubborn enough to want that functionality for these as well. The SplashScreenServices didn’t exist back then, but it is still possible to do the same even though not as easily as the above.

It’s still no rocket science. Basically, it’s the following steps:

  • Find the splash screen form.
  • Decide where to place the icon and text.
  • Add the necessary controls.

For getting the splash screen, we use the global Screen object which is available to all IDE plugins. It’s just a matter of enumerating all existing forms for which the class provides the Forms and FormCount properties:

for i := 0 to Screen.FormCount - 1 do begin
  frm := Screen.Forms[i];
  if (frm.Name = 'SplashScreen') and frm.ClassNameIs('TForm') then begin
    // we've got it
  end;

(Of course it took me some digging to find out what the form is called and what class it is, but it isn’t rocket science either. (Why do I come back to rocket science all the time?))

Now, where do we place the additional information?

Delphi6-SplashScreen

Delphi7-SplashScreen

There is space for about 4 lines with 32×32 bitmaps and two lines of text to the right of the 6 or 7 respectively. Some experimenting gave me the pixel position: X=140, Y=150.

So, all we need to do is add three controls, one TImage and two labels, to the form, fill in the necessary properties and be done.

  imgLogo := TImage.Create(frm);
  imgLogo.Name := PluginLogoStr + IntToStr(PluginIdx);
  imgLogo.Parent := frm;
  imgLogo.AutoSize := True;
  imgLogo.Picture.Bitmap.Handle := _Icon;
  imgLogo.Left := XPOS;
  imgLogo.Top := YPOS + 32 * PluginIdx;

  lblTitle := TLabel.Create(frm);
  lblTitle.Name := 'PluginTitle' + IntToStr(PluginIdx);
  lblTitle.Parent := frm;
  lblTitle.Caption := _Title;
  lblTitle.Top := imgLogo.Top;
  lblTitle.Left := imgLogo.Left + 32 + 8;
  lblTitle.Transparent := True;
  lblTitle.Font.Color := clWhite;
  lblTitle.Font.Style := [fsbold];

  lblVersion := TLabel.Create(frm);
  lblVersion.Name := 'PluginVersion' + IntToStr(PluginIdx);
  lblVersion.Parent := frm;
  lblVersion.Caption := _Version;
  lblVersion.Top := imgLogo.Top + lblTitle.Height;
  lblVersion.Left := imgLogo.Left + 32 + 20;
  lblVersion.Transparent := True;
  lblVersion.Font.Color := clWhite;

All controls use the form as the owner, so they will be freed automatically. I chose to use unique names for the controls, it would have been easier to just set the name to empty but we’ll come to that in a second. Assigning a HBitmap to a TImage is done by assigning it to the Picture.Bitmap.Handle property. I set the font color to white because black didn’t look too nice. Also I made the title bold. Oh, and of course I made the labels transparent, so they don’t look too ugly.

Now, why use unique names for the controls? Because I was thinking about reuse. I need it for GExperts now, but why not make it usable for other plugins as well? Like my Delphi IDE explorer Expert for which there is also a Delphi 6 and 7 version now.

As said above, there is space for 4 such entries. We will assume that we never need more than that for now. 😉

By using unique control names it is easy to find out how many of the slots are already taken and add another one:

  PluginIdx := 0;
  while frm.FindComponent(PluginLogoStr + IntToStr(PluginIdx)) <> nil do
    Inc(PluginIdx);

Putting it all together gives us a reusable procedure which we can add to any plugin without even thinking about Delphi versions:

procedure AddPluginToSplashScreen(_Icon: HBITMAP; const _Title: string; const _Version: string);
{$IFDEF GX_VER170_up}
// Only Delphi 2005 and up support the splash screen services
begin
  if Assigned(SplashScreenServices) then
    SplashScreenServices.AddPluginBitmap(_Title,
      _Icon, False, _Version);
end;
{$ELSE GX_VER170_up}
const
  XPOS = 140;
  YPOS = 150;
  PluginLogoStr = 'PluginLogo';
var
  imgLogo: TImage;
  lblTitle: TLabel;
  lblVersion: TLabel;
  i: integer;
  PluginIdx: integer;
  frm: TCustomForm;
begin
  for i := 0 to Screen.FormCount - 1 do begin
    frm := Screen.Forms[i];
    if (frm.Name = 'SplashScreen') and frm.ClassNameIs('TForm') then begin
      PluginIdx := 0;
      while frm.FindComponent(PluginLogoStr + IntToStr(PluginIdx)) <> nil do
        Inc(PluginIdx);

      imgLogo := TImage.Create(frm);
      imgLogo.Name := PluginLogoStr + IntToStr(PluginIdx);
      imgLogo.Parent := frm;
      imgLogo.AutoSize := True;
      imgLogo.Picture.Bitmap.Handle := _Icon;
      imgLogo.Left := XPOS;
      imgLogo.Top := YPOS + 32 * PluginIdx;

      lblTitle := TLabel.Create(frm);
      lblTitle.Name := 'PluginTitle' + IntToStr(PluginIdx);
      lblTitle.Parent := frm;
      lblTitle.Caption := _Title;
      lblTitle.Top := imgLogo.Top;
      lblTitle.Left := imgLogo.Left + 32 + 8;
      lblTitle.Transparent := True;
      lblTitle.Font.Color := clWhite;
      lblTitle.Font.Style := [fsbold];

      lblVersion := TLabel.Create(frm);
      lblVersion.Name := 'PluginVersion' + IntToStr(PluginIdx);
      lblVersion.Parent := frm;
      lblVersion.Caption := _Version;
      lblVersion.Top := imgLogo.Top + lblTitle.Height;
      lblVersion.Left := imgLogo.Left + 32 + 20;
      lblVersion.Transparent := True;
      lblVersion.Font.Color := clWhite;
    end;
  end;
end;
{$ENDIF GX_VER170_up}

And the result looks like this:
Delphi7-SplashScreen-with-plugins