【问题标题】:Which Icon corresponds to a tentative filename?哪个图标对应于暂定文件名?
【发布时间】:2014-11-12 15:41:42
【问题描述】:

我在数据库中的二进制文件中有一个文件,直到用户双击该项目(带有图标)才加载该文件

ExtractAssociatedIcon 应该可以解决这个问题(我在这里看到过:ExtractAssociatedIcon returns null

但这要求路径上是否存在文档,(我没有),如何关联到暂定文件的扩展名(例如:"something.docx")用户在他的电脑上将哪个扩展关联到我应该显示的图标?

@Edit:我可以从数据库中提取内容 (byte[]),如果这对于获取与图像关联的图标有用的话。 (但是,为了设置图标图像,传输每个文件 byte[] 也可能需要很长时间)。

另外,this example of @MatthewWatson 是我们实际用来获取它的,但每行 object value = rkFileIcon.GetValue(""); 需要大约 8 秒,其中有 8.4k 项要迭代。

@@Edit:也试过了

    public static Icon GetIconOldSchool(string fileName)
    {
        ushort uicon;
        StringBuilder strB = new StringBuilder(fileName);
        IntPtr handle = ExtractAssociatedIcon(IntPtr.Zero, strB, out uicon);
        Icon ico = Icon.FromHandle(handle);

        return ico;
    }

没有成功。

@@@Edit:上面的这个给了我一个文件的图标。(当它得到一个 .docx 时,不是 docx 图标)

    [StructLayout(LayoutKind.Sequential)]
    public 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;
    };
    static SHFILEINFO shinfo = new SHFILEINFO();
    class Win32
    {
        public const uint SHGFI_ICON = 0x100;
        public const uint SHGFI_LARGEICON = 0x0; // 'Large icon
        public const uint SHGFI_SMALLICON = 0x1; // 'Small icon

        [DllImport("shell32.dll")]
        public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);
    }
    public static Icon YetAnotherAttempt(string fName)
    {

        //Use this to get the small Icon
        var hImgSmall = Win32.SHGetFileInfo(fName, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), Win32.SHGFI_ICON | Win32.SHGFI_SMALLICON);

        //Use this to get the large Icon
        //hImgLarge = SHGetFileInfo(fName, 0, 
        //  ref shinfo, (uint)Marshal.SizeOf(shinfo), 
        //  Win32.SHGFI_ICON | Win32.SHGFI_LARGEICON);

        //The icon is returned in the hIcon member of the shinfo struct
        return System.Drawing.Icon.FromHandle(shinfo.hIcon);
    }

@@@@编辑:@AlexK 的结果。解决方案。

FileToImage 转换器是我施展魔法的地方。

     <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <StackPanel Orientation="Horizontal">
                        <Image Source="{Binding Converter={StaticResource FileToImage}}" />
                        <TextBlock Text="{Binding FileName}"
                               Margin="5,0,0,0"
                               VerticalAlignment="Center"/>
                    </StackPanel>

【问题讨论】:

  • SHGetFileInfo()SHGFI_USEFILEATTRIBUTES 不需要传递的文件名存在
  • @MatthewWatson 这是我们已经实现的,不知何故它挂在object value = rkFileIcon.GetValue(""); 行上,它需要永远获取注册表中加载的每个 8400 扩展的值。我正在寻找解决方法。
  • @AlexK。我已经尝试过了,我尝试编辑了我的问题。

标签: c# wpf winapi icons


【解决方案1】:

在你的 Win32 类中添加:

public const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // better as private enum

[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DestroyIcon(IntPtr hIcon);

你的电话变成:

var hImgSmall = Win32.SHGetFileInfo(fName, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), 
                Win32.SHGFI_ICON | Win32.SHGFI_SMALLICON | Win32.SHGFI_USEFILEATTRIBUTES);

要返回图标,您应该复制它,然后销毁 API 返回的图标:

var icon = (Icon)Icon.FromHandle(shinfo.hIcon).Clone();    
Win32.DestroyIcon(shinfo.hIcon);
return icon;

示例(WindowsForm 项目)

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1() {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e) {
            var shinfo = new Win32.SHFILEINFO();
            Win32.SHGetFileInfo("0000000000.DOCX", 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), Win32.SHGFI_ICON | Win32.SHGFI_SMALLICON | Win32.SHGFI_USEFILEATTRIBUTES);
            var icon = (Icon)Icon.FromHandle(shinfo.hIcon).Clone();
            Win32.DestroyIcon(shinfo.hIcon);
            this.BackgroundImage = icon.ToBitmap();
            icon.Dispose();
        }

        private class Win32 {
            internal const uint SHGFI_ICON = 0x100;
            internal const uint SHGFI_SMALLICON = 0x1;
            internal const uint SHGFI_USEFILEATTRIBUTES = 0x000000010;

            [DllImport("user32.dll", SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            internal static extern bool DestroyIcon(IntPtr hIcon);

            [DllImport("shell32.dll")]
            internal static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);

            [StructLayout(LayoutKind.Sequential)]
            internal 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;
            }
        }
    }
}

【讨论】:

  • 我已根据您建议的尝试更新了问题,以防有助于解决问题
  • 此外,@MatthewWatson(关于问题评论)解决方案有效,但需要很长时间才能加载。
  • 添加了一个小例子,应该在表单上绘制图标
  • 我传递的是对象而不是文件名。它创造了奇迹
猜你喜欢
  • 1970-01-01
  • 2010-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-29
  • 2012-10-04
相关资源
最近更新 更多