使用任务获取目录图标

Gos*_*ten 5 .net c# winapi datagridview task

我的任务是使用任务获取目录图标并将其显示在DataGridView中(我正在执行搜索文件夹).为此,我使用SHGetImageList WinAPI函数.我有一个帮助类如下:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace WindowsFormsApplication6 {
    public class Helper {
        private const uint ILD_TRANSPARENT = 0x00000001;
        private const uint SHGFI_SYSICONINDEX = 0x000004000;
        private const uint SHGFI_ICON = 0x000000100;
        public static readonly int MaxEntitiesCount = 80;
        public static void GetDirectories(string path, List<Image> col, IconSizeType sizeType, Size itemSize) {
            DirectoryInfo dirInfo = new DirectoryInfo(path);
            DirectoryInfo[] dirs = dirInfo.GetDirectories("*", SearchOption.TopDirectoryOnly);
            for (int i = 0; i < dirs.Length && i < MaxEntitiesCount; i++) {
                DirectoryInfo subDirInfo = dirs[i];
                if (!CheckAccess(subDirInfo) || !MatchFilter(subDirInfo.Attributes)) {
                    continue;
                }
                col.Add(GetFileImage(subDirInfo.FullName, sizeType, itemSize));
            }
        }

        public static bool CheckAccess(DirectoryInfo info) {
            bool isOk = false;
            try {
                var secInfo = info.GetAccessControl();
                isOk = true;
            }
            catch {
            }
            return isOk;
        }

        public static bool MatchFilter(FileAttributes attributes) {
            return (attributes & (FileAttributes.Hidden | FileAttributes.System)) == 0;
        }

        public static Image GetFileImage(string path, IconSizeType sizeType, Size itemSize) {
            return IconToBitmap(GetFileIcon(path, sizeType, itemSize), sizeType, itemSize);
        }

        public static Image IconToBitmap(Icon ico, IconSizeType sizeType, Size itemSize) {
            if (ico == null) {
                return new Bitmap(itemSize.Width, itemSize.Height);
            }
            return ico.ToBitmap();
        }

        public static Icon GetFileIcon(string path, IconSizeType sizeType, Size itemSize) {
            SHFILEINFO shinfo = new SHFILEINFO();
            IntPtr retVal = SHGetFileInfo(path, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), (int)(SHGFI_SYSICONINDEX | SHGFI_ICON));
            int iconIndex = shinfo.iIcon;
            IImageList iImageList = (IImageList)GetSystemImageListHandle(sizeType);
            IntPtr hIcon = IntPtr.Zero;
            if (iImageList != null) {
                iImageList.GetIcon(iconIndex, (int)ILD_TRANSPARENT, ref hIcon);
            }
            Icon icon = null;
            if (hIcon != IntPtr.Zero) {
                icon = Icon.FromHandle(hIcon).Clone() as Icon;
                DestroyIcon(shinfo.hIcon);
            }
            return icon;
        }

        private static IImageList GetSystemImageListHandle(IconSizeType sizeType) {
            IImageList iImageList = null;
            Guid imageListGuid = new Guid("46EB5926-582E-4017-9FDF-E8998DAA0950");
            int ret = SHGetImageList((int)sizeType, ref imageListGuid, ref iImageList);
            return iImageList;
        }

        [DllImport("shell32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
        [DllImport("shell32.dll", EntryPoint = "#727")]
        private static extern int SHGetImageList(int iImageList, ref Guid riid, ref IImageList ppv);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool DestroyIcon(IntPtr hIcon);
        public enum IconSizeType {
            Medium = 0x0,
            Small = 0x1,
            Large = 0x2,
            ExtraLarge = 0x4
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        private struct SHFILEINFO {
            public IntPtr hIcon;
            public int iIcon;
            public uint dwAttributes;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string szDisplayName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
            public string szTypeName;
        }

        [ComImport,
        Guid("46EB5926-582E-4017-9FDF-E8998DAA0950"),
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        private interface IImageList {
            [PreserveSig]
            int Add(IntPtr hbmImage, IntPtr hbmMask, ref int pi);
            [PreserveSig]
            int ReplaceIcon(int i, IntPtr hicon, ref int pi);
            [PreserveSig]
            int SetOverlayImage(int iImage, int iOverlay);
            [PreserveSig]
            int Replace(int i, IntPtr hbmImage, IntPtr hbmMask);
            [PreserveSig]
            int AddMasked(IntPtr hbmImage, int crMask, ref int pi);
            [PreserveSig]
            int Draw(ref IMAGELISTDRAWPARAMS pimldp);
            [PreserveSig]
            int Remove(int i);
            [PreserveSig]
            int GetIcon(int i, int flags, ref IntPtr picon);
            [PreserveSig]
            int GetImageInfo(int i, ref IMAGEINFO pImageInfo);
            [PreserveSig]
            int Copy(int iDst, IImageList punkSrc, int iSrc, int uFlags);
            [PreserveSig]
            int Merge(int i1, IImageList punk2, int i2, int dx, int dy, ref Guid riid, ref IntPtr ppv);
            [PreserveSig]
            int Clone(ref Guid riid, ref IntPtr ppv);
            [PreserveSig]
            int GetImageRect(int i, ref RECT prc);
            [PreserveSig]
            int GetIconSize(ref int cx, ref int cy);
            [PreserveSig]
            int SetIconSize(int cx, int cy);
            [PreserveSig]
            int GetImageCount(ref int pi);
            [PreserveSig]
            int SetImageCount(int uNewCount);
            [PreserveSig]
            int SetBkColor(int clrBk, ref int pclr);
            [PreserveSig]
            int GetBkColor(ref int pclr);
            [PreserveSig]
            int BeginDrag(int iTrack, int dxHotspot, int dyHotspot);
            [PreserveSig]
            int EndDrag();
            [PreserveSig]
            int DragEnter(IntPtr hwndLock, int x, int y);
            [PreserveSig]
            int DragLeave(IntPtr hwndLock);
            [PreserveSig]
            int DragMove(int x, int y);
            [PreserveSig]
            int SetDragCursorImage(ref IImageList punk, int iDrag, int dxHotspot, int dyHotspot);
            [PreserveSig]
            int DragShowNolock(int fShow);
            [PreserveSig]
            int GetDragImage(ref POINT ppt, ref POINT pptHotspot, ref Guid riid, ref IntPtr ppv);
            [PreserveSig]
            int GetItemFlags(int i, ref int dwFlags);
            [PreserveSig]
            int GetOverlayImage(int iOverlay, ref int piIndex);
        }
        ;

        [StructLayout(LayoutKind.Sequential)]
        private struct IMAGELISTDRAWPARAMS {
            public int cbSize;
            public IntPtr himl;
            public int i;
            public IntPtr hdcDst;
            public int x;
            public int y;
            public int cx;
            public int cy;
            public int xBitmap;
            public int yBitmap;
            public int rgbBk;
            public int rgbFg;
            public int fStyle;
            public int dwRop;
            public int fState;
            public int Frame;
            public int crEffect;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct IMAGEINFO {
            public IntPtr hbmImage;
            public IntPtr hbmMask;
            public int Unused1;
            public int Unused2;
            public RECT rcImage;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT {
            public int Left, Top, Right, Bottom;
            public RECT(int l, int t, int r, int b) {
                Left = l;
                Top = t;
                Right = r;
                Bottom = b;
            }

            public RECT(Rectangle r) {
                Left = r.Left;
                Top = r.Top;
                Right = r.Right;
                Bottom = r.Bottom;
            }

            public Rectangle ToRectangle() {
                return Rectangle.FromLTRB(Left, Top, Right, Bottom);
            }

            public void Inflate(int width, int height) {
                Left -= width;
                Top -= height;
                Right += width;
                Bottom += height;
            }

            public override string ToString() {
                return string.Format("x:{0},y:{1},width:{2},height:{3}", Left, Top, Right - Left, Bottom - Top);
            }
        }

        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
        public struct POINT {
            public int X, Y;
            public POINT(int x, int y) {
                this.X = x;
                this.Y = y;
            }

            public POINT(Point pt) {
                this.X = pt.X;
                this.Y = pt.Y;
            }

            public Point ToPoint() {
                return new Point(X, Y);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在表单上,​​我有两个DataGridViews和两个按钮.单击第一个按钮,我在UI线程中加载图标:

private void button1_Click(object sender, EventArgs e) {
    List<Image> list = new List<Image>();
    Helper.GetDirectories(fPath, list, Helper.IconSizeType.Small, new Size(16, 16));
    dataGridView1.DataSource = list;
}
Run Code Online (Sandbox Code Playgroud)

在第二个按钮上单击,我这样做:

private void button2_Click(object sender, EventArgs e) {
    Func<object, List<Image>> a = null;
    a = (p) => {
        string path = (string)p;
        List<Image> list = new List<Image>();
        Helper.GetDirectories(path, list, Helper.IconSizeType.Small, new Size(16, 16));
        return list;
    };
    Task.Factory.StartNew(a, fPath).ContinueWith(t => { dataGridView2.DataSource = t.Result;},
TaskScheduler.FromCurrentSynchronizationContext());
}
Run Code Online (Sandbox Code Playgroud)

所以,我也这样做,但是在一项任务中.

当我单击第一个按钮然后单击第二个按钮时,我得到以下System.InvalidCastException:

无法将"System .__ ComObject"类型的COM对象强制转换为接口类型"IImageList".此操作失败,因为由于以下错误,对IID为"{46EB5926-582E-4017-9FDF-E8998DAA0950}"的接口的COM组件的QueryInterface调用失败:不支持此类接口(HRESULT异常:0x80004002(E_NOINTERFACE)) .

例外是在

int ret = SHGetImageList((int)sizeType, ref imageListGuid, ref iImageList);
Run Code Online (Sandbox Code Playgroud)

GetSystemImageListHandle方法的一行.

我无法弄清楚我做错了什么.任何帮助表示赞赏.

Iva*_*oev 3

只需插入

Marshal.FinalReleaseComObject(iImageList);
Run Code Online (Sandbox Code Playgroud)

iImageList.GetIcon(iconIndex, (int)ILD_TRANSPARENT, ref hIcon);
Run Code Online (Sandbox Code Playgroud)

线。

另外,您可能感兴趣的是,当您传递 SHGFI_SYSICONINDEX 时,SHGetFileInfo 实际上返回 IImageList。所以,这样的事情会起作用:

    [DllImport("shell32.dll", EntryPoint = "SHGetFileInfo", CharSet = CharSet.Auto)]
    private static extern IImageList SHGetFileInfoAsImageList(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
Run Code Online (Sandbox Code Playgroud)

整个图像提取可以很简单:

    public static Image GetFileImage(string path, IconSizeType sizeType, Size itemSize)
    {
        var shfi = new SHFILEINFO();
        var imageList = SHGetFileInfoAsImageList(path, 0, ref shfi, (uint)Marshal.SizeOf(shfi), (int)SHGFI_SYSICONINDEX);
        if (imageList != null)
        {
            var hIcon = IntPtr.Zero;
            imageList.GetIcon(shfi.iIcon, (int)ILD_TRANSPARENT, ref hIcon);
            Marshal.FinalReleaseComObject(imageList);
            if (hIcon != IntPtr.Zero)
            {
                var image = Bitmap.FromHicon(hIcon);
                DestroyIcon(hIcon);
                return image;
            }
        }
        return new Bitmap(itemSize.Width, itemSize.Height);
    }
Run Code Online (Sandbox Code Playgroud)