Click here to Skip to main content
15,892,768 members
Articles / Programming Languages / C#

Full implementation of IShellBrowser

Rate me:
Please Sign up or sign in to vote.
4.86/5 (29 votes)
5 May 2009CPOL4 min read 160K   3.2K   113  
A VS-like open and save file dialog implementation.
using System;
using System.Collections;
using System.Drawing;
using System.Runtime.InteropServices;

namespace FileDialogs
{
    internal enum ShellImageListSize
    {
        Small,
        Large
    }

    internal static class ShellImageList
    {
        #region Member Fields

        private static NativeMethods.IShellFolder m_desktopFolder;
        private static IntPtr m_smallImageListHandle;
        private static IntPtr m_largeImageListHandle;
        private static Hashtable m_imageTable;

        #endregion

        #region Construction

        static ShellImageList()
        {
            IntPtr desktopFolderPtr;
            NativeMethods.Shell32.SHGetDesktopFolder(out desktopFolderPtr);
            m_desktopFolder = (NativeMethods.IShellFolder)Marshal.GetObjectForIUnknown(desktopFolderPtr);

            m_imageTable = new Hashtable();

            uint flag = NativeMethods.SHGFI_USEFILEATTRIBUTES | NativeMethods.SHGFI_SYSICONINDEX | NativeMethods.SHGFI_SMALLICON;
            NativeMethods.SHFILEINFO shfiSmall = new NativeMethods.SHFILEINFO();
            m_smallImageListHandle = NativeMethods.Shell32.SHGetFileInfo(".txt", NativeMethods.FILE_ATTRIBUTE_NORMAL, ref shfiSmall, Marshal.SizeOf(shfiSmall), flag);

            flag = NativeMethods.SHGFI_USEFILEATTRIBUTES | NativeMethods.SHGFI_SYSICONINDEX | NativeMethods.SHGFI_LARGEICON;
            NativeMethods.SHFILEINFO shfiLarge = new NativeMethods.SHFILEINFO();
            m_largeImageListHandle = NativeMethods.Shell32.SHGetFileInfo(".txt", NativeMethods.FILE_ATTRIBUTE_NORMAL, ref shfiLarge, Marshal.SizeOf(shfiLarge), flag);
        }

        #endregion

        #region Methods

        internal static int GetIconIndex(IntPtr pidl, bool selectedIcon, bool openIcon)
        {
            NativeMethods.SHFILEINFO info = new NativeMethods.SHFILEINFO();
            NativeMethods.Shell32.SHGetFileInfo(pidl, 0, ref info, NativeMethods.cbFileInfo, NativeMethods.SHGFI_PIDL | NativeMethods.SHGFI_SYSICONINDEX);
            int index = info.iIcon;

            bool hasOverlay = false; // true if it's an overlay
            int rVal; // The returned Index

            IntPtr[] pidls = new IntPtr[] { pidl };
            NativeMethods.SHGFAO attribs = NativeMethods.SHGFAO.SFGAO_LINK |
                                           NativeMethods.SHGFAO.SFGAO_SHARE |
                                           NativeMethods.SHGFAO.SFGAO_HIDDEN |
                                           NativeMethods.SHGFAO.SFGAO_FILESYSTEM |
                                           NativeMethods.SHGFAO.SFGAO_FOLDER;
            m_desktopFolder.GetAttributesOf(1, pidls, ref attribs);

            uint dwflag = NativeMethods.SHGFI_SYSICONINDEX | NativeMethods.SHGFI_PIDL | NativeMethods.SHGFI_ICON;
            int dwAttr = 0;
            // Build Key into HashTable for this Item
            int key = index * 256;
            if ((attribs & NativeMethods.SHGFAO.SFGAO_LINK) != 0)
            {
                key = key | 1;
                dwflag = dwflag | NativeMethods.SHGFI_LINKOVERLAY;
                hasOverlay = true;
            }
            if ((attribs & NativeMethods.SHGFAO.SFGAO_SHARE) != 0)
            {
                key = key | 2;
                dwflag = dwflag | NativeMethods.SHGFI_ADDOVERLAYS;
                hasOverlay = true;
            }
            if (selectedIcon)
            {
                key = key | 4;
                dwflag = dwflag | NativeMethods.SHGFI_SELECTED;
                hasOverlay = true;
            }
            if (openIcon)
            {
                key = key | 8;
                dwflag = dwflag | NativeMethods.SHGFI_OPENICON;
                hasOverlay = true; // Not really an overlay, but handled the same
            }

            if (m_imageTable.ContainsKey(key))
                rVal = (int)m_imageTable[key];
            else if (!hasOverlay && (attribs & NativeMethods.SHGFAO.SFGAO_HIDDEN) == 0) // For non-overlay icons, we already have
            {
                rVal = (int)Math.Floor((double)key / 256); // the right index -- put in table
                m_imageTable[key] = rVal;
            }
            else // Don't have iconindex for an overlay, get it.
            {
                //item.m_isDisk = (item.m_path.Length == 3 && item.m_path.EndsWith(":\\"));
                if ((attribs & NativeMethods.SHGFAO.SFGAO_FILESYSTEM) != 0 &&
                    (attribs & NativeMethods.SHGFAO.SFGAO_FOLDER) == 0)
                {
                    dwflag = dwflag | NativeMethods.SHGFI_USEFILEATTRIBUTES;
                    dwAttr = dwAttr | NativeMethods.FILE_ATTRIBUTE_NORMAL;
                }

                NativeMethods.SHFILEINFO shfiSmall = new NativeMethods.SHFILEINFO();
                NativeMethods.Shell32.SHGetFileInfo(pidl, dwAttr, ref shfiSmall, Marshal.SizeOf(shfiSmall), dwflag | NativeMethods.SHGFI_SMALLICON);

                NativeMethods.SHFILEINFO shfiLarge = new NativeMethods.SHFILEINFO();
                NativeMethods.Shell32.SHGetFileInfo(pidl, dwAttr, ref shfiLarge, Marshal.SizeOf(shfiLarge), dwflag | NativeMethods.SHGFI_LARGEICON);

                lock (m_imageTable)
                {
                    rVal = NativeMethods.ComCtl32.ImageList_ReplaceIcon(m_smallImageListHandle, -1, shfiSmall.hIcon);
                    NativeMethods.ComCtl32.ImageList_ReplaceIcon(m_largeImageListHandle, -1, shfiLarge.hIcon);
                }

                NativeMethods.User32.DestroyIcon(shfiSmall.hIcon);
                NativeMethods.User32.DestroyIcon(shfiLarge.hIcon);
                m_imageTable[key] = rVal;
            }

            return rVal;
        }

        public static Image GetSmallImage(SpecialFolder specialFolder)
        {
            uint dwflag = NativeMethods.SHGFI_SYSICONINDEX | NativeMethods.SHGFI_PIDL | NativeMethods.SHGFI_ICON;
            int dwAttr = 0;

            IntPtr pidl;
            NativeMethods.Shell32.SHGetSpecialFolderLocation(IntPtr.Zero, (int)specialFolder, out pidl);

            NativeMethods.SHFILEINFO shfi = new NativeMethods.SHFILEINFO();
            NativeMethods.Shell32.SHGetFileInfo(pidl, dwAttr, ref shfi, Marshal.SizeOf(shfi), dwflag);

            IntPtr iconPtr = NativeMethods.ComCtl32.ImageList_GetIcon(m_smallImageListHandle, shfi.iIcon, NativeMethods.ILD_NORMAL);

            return Icon.FromHandle(iconPtr).ToBitmap();
        }

        public static Image GetImage(SpecialFolder specialFolder)
        {
            uint dwflag = NativeMethods.SHGFI_SYSICONINDEX | NativeMethods.SHGFI_PIDL | NativeMethods.SHGFI_ICON;
            int dwAttr = 0;

            IntPtr pidl;
            NativeMethods.Shell32.SHGetSpecialFolderLocation(IntPtr.Zero, (int)specialFolder, out pidl);

            NativeMethods.SHFILEINFO shfi = new NativeMethods.SHFILEINFO();
            NativeMethods.Shell32.SHGetFileInfo(pidl, dwAttr, ref shfi, Marshal.SizeOf(shfi), dwflag);

            IntPtr iconPtr = NativeMethods.ComCtl32.ImageList_GetIcon(m_largeImageListHandle, shfi.iIcon, NativeMethods.ILD_NORMAL);

            return Icon.FromHandle(iconPtr).ToBitmap();
        }

        public static Image GetSmallImage(IntPtr pidl)
        {
            uint dwflag = NativeMethods.SHGFI_SYSICONINDEX | NativeMethods.SHGFI_PIDL | NativeMethods.SHGFI_ICON;
            int dwAttr = 0;

            NativeMethods.SHFILEINFO shfi = new NativeMethods.SHFILEINFO();
            NativeMethods.Shell32.SHGetFileInfo(pidl, dwAttr, ref shfi, Marshal.SizeOf(shfi), dwflag);

            IntPtr iconPtr = NativeMethods.ComCtl32.ImageList_GetIcon(m_smallImageListHandle, shfi.iIcon, NativeMethods.ILD_NORMAL);

            return Icon.FromHandle(iconPtr).ToBitmap();
        }

        public static Image GetImage(IntPtr pidl)
        {
            uint dwflag = NativeMethods.SHGFI_SYSICONINDEX | NativeMethods.SHGFI_PIDL | NativeMethods.SHGFI_ICON;
            int dwAttr = 0;

            NativeMethods.SHFILEINFO shfi = new NativeMethods.SHFILEINFO();
            NativeMethods.Shell32.SHGetFileInfo(pidl, dwAttr, ref shfi, Marshal.SizeOf(shfi), dwflag);

            IntPtr iconPtr = NativeMethods.ComCtl32.ImageList_GetIcon(m_largeImageListHandle, shfi.iIcon, NativeMethods.ILD_NORMAL);

            return Icon.FromHandle(iconPtr).ToBitmap();
        }

        public static Icon GetIcon(int index, ShellImageListSize size)
        {
            IntPtr iconPtr = IntPtr.Zero;

            switch (size)
            {
                case ShellImageListSize.Small:
                    iconPtr = NativeMethods.ComCtl32.ImageList_GetIcon(m_smallImageListHandle, index, NativeMethods.ILD_NORMAL);
                    break;

                case ShellImageListSize.Large:
                    iconPtr = NativeMethods.ComCtl32.ImageList_GetIcon(m_largeImageListHandle, index, NativeMethods.ILD_NORMAL);
                    break;
            }

            if (iconPtr != IntPtr.Zero)
            {
                Icon icon = Icon.FromHandle(iconPtr);
                Icon retVal = (Icon)icon.Clone();
                NativeMethods.User32.DestroyIcon(iconPtr);
                return retVal;
            }
            else
                return null;
        }

        #endregion

        #region Properties

        public static IntPtr SmallImageList
        {
            get { return m_smallImageListHandle; }
        }

        public static IntPtr LargeImageList
        {
            get { return m_largeImageListHandle; }
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer IDesignIT Kungsbacka
Sweden Sweden
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions