Drive combo box in C#

Standard

As most of the .Net developers, I am also started my development career with VB6. :) VB6 comes with few file system controls, like DriveListbox, DirectoryListbox, FileListbox etc. But in .Net framework didn’t support these controls. Here is a solution for creating a drive listbox(it is not a listbox, it is dropdown list).

Drive Combo box in C#

Drive Combo box in C#

The drive information can be retrieved using DriveInfo.GetDrives() method. And for getting the corresponding icons for drive letters, I am using the SHGetFileInfo WIN32 API call.

Here is the implementation.

private void Form1_Load(object sender, EventArgs e)
{
    comboBox1.DrawMode = DrawMode.OwnerDrawFixed;
    comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
    comboBox1.DrawItem += new DrawItemEventHandler(comboBox1_DrawItem);

    var drives = DriveInfo.GetDrives()
        .Where(drive => drive.Name != string.Empty).ToArray();
    comboBox1.Items.AddRange(drives);
}

And here is the DrawItem event

private void comboBox1_DrawItem(object sender, DrawItemEventArgs e)
{
    if (e.Index != -1)
    {
        e.DrawBackground();
        var icon = GetIcon(comboBox1.Items[e.Index].ToString());
        e.Graphics.DrawIcon(icon, 3, e.Bounds.Top);
        e.Graphics.DrawString(comboBox1.Items[e.Index].ToString(),
            comboBox1.Font, Brushes.Black, icon.Width + 2, e.Bounds.Top);
        e.DrawFocusRectangle();
    }
}

And here is the GetIcon method and API declaration.

private const uint SHGFI_ICON = 0x100;
private const uint SHGFI_LARGEICON = 0x0;
private const uint SHGFI_SMALLICON = 0x1;

[DllImport("shell32.dll")]
private static extern IntPtr SHGetFileInfo(string pszPath,
                            uint dwFileAttributes,
                            ref SHFILEINFO psfi,
                            uint cbSizeFileInfo,
                            uint uFlags);
[StructLayout(LayoutKind.Sequential)]
private struct SHFILEINFO
{
    public IntPtr hIcon;
    public IntPtr iIcon;
    public uint dwAttributes;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
    public string szDisplayName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
    public string szTypeName;
};

private Icon GetIcon(string fileName)
{
    IntPtr hImgSmall;
    SHFILEINFO shinfo = new SHFILEINFO();
    hImgSmall = SHGetFileInfo(fileName, 0, ref shinfo,
                (uint)Marshal.SizeOf(shinfo),
                    SHGFI_ICON |
                    SHGFI_SMALLICON);
    return Icon.FromHandle(shinfo.hIcon);
}

This implementation is using normal Combobox, you can do same thing by extending Combobox. So that it can be used in any project without any dependency.