Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
- - - - -

[Delphi] How To Get Windows Explorer (shell) Icons

combobox

  • Please log in to reply
No replies to this topic

#1 Luthfi

Luthfi

    CC Leader

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1320 posts
  • Programming Language:PHP, Delphi/Object Pascal, Pascal, Transact-SQL
  • Learning:C, Java, PHP

Posted 02 January 2011 - 09:52 AM

Delphi programs can take advantage of using Windows Explorer (default shell of Windows OS) icons to reduce size and get consistent look and feel. We get size reduction since now we don't have to embed our own icons inside the programs. We get consistent look and feel since icons in our application match with those displayed in Windows Explorer. Making it easier for new users to get familiar with our programs.

Almost all VCL controls that can use icons contained in an instance of TImageList can use the shell icon. But for this tutorial we'll use a TComboBoxEx as an example. For the example we'll use a TComboBoxEx to list known drives of the host computer. Drives in windows can be shown using different icons. Usually the drive icon indicates the type of the drive (such as fixed drive, CD/DVD drive, and floppy drive). But just like with folders, users can also customize the icon for a specific drive.

Now in this tutorial we'll show how to use TComboBoxEx to list drives with the same icons as shown in Shell (Windows Explorer). TComboBoxEx is selected because it supports showing icons from and TImageList.

Also note that this time we will heavily use Windows API SHGetFileInfo. This Windows API is provided to retrieve information about objects in the file system, such as a file, folder, directory, or drive root. More detailed information about this API can be read in this MSDN page.

The steps are:
  • Get the drive letters. There is a full tutorial on this. Please check it out if you haven't done so.
  • Get the handle of shell image list using the first (or any) drive letter we got.
  • Assign the handle of shell image list to our TComboBoxEx
  • For each drive detected in step 1 get the icon index for icon in the shell image list associated with the drive and then add new item in the TComboBoxEx by passing the drive letter and icon index.

And that's it. Of course to make it immediately available for user you need to put the code somewhere in the initialization stage. It could be in form's OnCreate event or in form's constructor.

Now let's translate the steps into code implementation, into a procedure.

The following procedure will populate an instance of TComboBoxEx (passed as AComboBox parameter) with available drives along with their icons and volume labels. The procedure does not generate the drive list by itself. It uses drive list provided by a TStrings passed to it as ADrives parameter (please read this tutorial about this.

procedure DisplayDrivesEx(AComboBox: TComboBoxEx; ADrives: TStrings);
var
  i, j     : Integer;
  vItem    : TComboExItem;
  vFileInfo: TSHFileInfo;
  vImgList : THandle;
  S, D     : string;
begin
  ADrives.BeginUpdate;
  try
    AComboBox.ItemsEx.BeginUpdate;
    try
      // clear the ComboBoxEx from possible leftover from prior operations
      AComboBox.ItemsEx.Clear;

      // if there is no drive just exit, no further processing required
      if ADrives.Count < 1 then Exit;
      // get system imagelist handle
      vImgList := SHGetFileInfo(PChar(ADrives[0]), 0, vFileInfo, SizeOf(vFileInfo), SHGFI_SYSICONINDEX or SHGFI_SMALLICON);
      // assign the shell image list to the ComboBoxEx
      SendMessage(AComboBox.Handle, CBEM_SETIMAGELIST, 0, vImgList);
      DestroyIcon(vFileInfo.hIcon);

      // for each drive do the following block
      for i := 0 to ADrives.Count - 1 do
      begin
        // get drive information:
        //   SHGFI_SYSICONINDEX flag indicates we want the icon index associated with the given drive
        //   SHGFI_SMALLICON flag indicates we want small icon (16x16)
        //   SHGFI_DISPLAYNAME flag indicates we also want shell display name for the drive (the volume label)
        SHGetFileInfo(PChar(ADrives[i]), 0, vFileInfo, SizeOf(vFileInfo), SHGFI_SYSICONINDEX or SHGFI_SMALLICON or SHGFI_DISPLAYNAME);

        // add new item in the ComboBoxEx
        vItem := AComboBox.ItemsEx.Add;
        vItem.ImageIndex := vFileInfo.iIcon;  // assign the icon index
        S := vFileInfo.szDisplayName;         // Get the drive volume label

        // format the volume label
        j := System.Pos(':)', S);
        if j > 0 then
        begin
          D := System.Copy(S, j-2, 4);
          System.Delete(S, j-2, MaxInt);
          S := '[' + Copy(D, 2, 2) + '] ' + S;
        end;

        vItem.Caption := S;  // set the formatted volume label to the new item of the ComboBoxEx
      end;
      AComboBox.ItemIndex := 0;  // activate the first item of the ComboBoxEx
    finally
      AComboBox.ItemsEx.EndUpdate;
    end;
  finally
    ADrives.EndUpdate;
  end;
end;

In the demo project (full source code attached), to populate a TComboBoxEx I added the following code for a button's OnClick event.

procedure TForm1.Button1Click(Sender: TObject);
begin
  GetDriveLetters(ListBox1.Items);  // get the drive letters
  DisplayDrivesEx(ComboBoxEx1, ListBox1.Items); // populate the ComboBox
end;

Here is screenshot of the demo project when running before we retrieve drives information.
[ATTACH]3610[/ATTACH]

And here is the one after we retrieve the drives information (clicking the second Refresh button).
[ATTACH]3611[/ATTACH]

Full source code attached, feel free to use or improve it. Looking forward for feedback on the writing or the content.

Cheers!

Attached Thumbnails

  • DrivesWithIcons_Before01.png
  • DrivesWithIcons_After01.png

Attached Files


  • 0





Also tagged with one or more of these keywords: combobox

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download