C#:如何判断EXE是否有图标

本文关键字:EXE 是否 图标 判断 何判断 | 更新日期: 2023-09-27 18:21:12

我正在寻找一种方法来判断EXE文件是否包含应用程序图标。从这里的答案来看,我尝试了这个:

bool hasIcon = Icon.ExtractAssociatedIcon(exe) != null;

但是,即使EXE没有图标,这似乎也能工作。有没有一种方法可以在.NET中检测到这一点?


编辑:我可以接受涉及p/Invoke的解决方案。

C#:如何判断EXE是否有图标

您可以通过SystemIcons类的SystemIcons.Application属性获取IDI_APPLICATION图标

if (Icon.ExtractAssociatedIcon(exe).Equals(SystemIcons.Application)) 
{
    ...
}

有关详细信息,请参阅MSDN。

试试这个。像这样定义你的pinvoke:

[DllImport("user32.dll")]
internal static extern IntPtr LoadImage(IntPtr hInst, IntPtr name, uint type, int cxDesired, int cyDesired, uint fuLoad);
[DllImport("kernel32.dll")]
static extern bool EnumResourceNames(IntPtr hModule, int dwID, EnumResNameProcDelegate lpEnumFunc, IntPtr lParam);
delegate bool EnumResNameProcDelegate(IntPtr hModule, IntPtr lpszType, IntPtr lpszName, IntPtr lParam);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr LoadLibraryEx(string name, IntPtr handle, uint dwFlags);
private const int LOAD_LIBRARY_AS_DATAFILE = 0x00000002;
private const int LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020;
private const int IMAGE_ICON = 1;
private const int RT_GROUP_ICON = 14;

然后你可以写一个这样的函数:

static bool HasIcon(string path)
{
    // This loads the exe into the process address space, which is necessary
    // for LoadImage / LoadIcon to work note, that LOAD_LIBRARY_AS_DATAFILE
    // allows loading a 32-bit image into 64-bit process which is otherwise impossible
    IntPtr moduleHandle = LoadLibraryEx(path, IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
    if (moduleHandle == IntPtr.Zero)
    {
        throw new ApplicationException("Cannot load executable");
    }
    IntPtr index = IntPtr.Zero;
    bool hasIndex = false;
    bool enumerated = EnumResourceNames(moduleHandle, RT_GROUP_ICON, (module, type, name, param) =>
    {
        index = name;
        hasIndex = true;
        // Only load first icon and bail out
        return false;
    }, IntPtr.Zero);
    if (!enumerated || !hasIndex)
    {
        return false;
    }
    // Strictly speaking you do not need this you can return true now
    // This is to demonstrate how to access the icon that was found on
    // the previous step
    IntPtr result = LoadImage(moduleHandle, index, IMAGE_ICON, 0, 0, 0);
    if (result == IntPtr.Zero)
    {
        return false;
    }
    return true;
}

它增加了额外的好处,如果你想,在LoadImage之后,你可以用加载图标

Icon icon = Icon.FromHandle(result);

用它做任何你想做的事。

重要提示:我没有对函数进行任何清理,所以你不能按原样使用它,你会泄露句柄/内存。适当的清理是留给读者的练习。阅读MSDN中使用的每个winapi函数的描述,并根据需要调用相应的清理函数。

这里可以找到使用shell32api的另一种方法,尽管我不知道它是否也遇到了与您相同的问题。

此外,一篇古老但仍然非常相关的文章:https://msdn.microsoft.com/en-us/library/ms997538.aspx