如何使用powershell查找并计算与exe文件关联的图标数量?

问题描述 投票:0回答:2

我想获取 EXE 或 DLL 文件的嵌入(或关联)图标的数量。 在另一个 question 中,提供了一些代码来提取所有图标文件,但没有信息显示如何实际使用 iconIndex

-1
来给出图标对象的总数。

来自 ExtractIconExW 文档:

UINT ExtractIconExW(
  [in]  LPCWSTR lpszFile,
  [in]  int     nIconIndex,
  [out] HICON   *phiconLarge,
  [out] HICON   *phiconSmall,
        UINT    nIcons
);

nIconIndex
的解释如下:

如果该值为 –1 并且 phiconLargephiconSmall 均为 NULL,则 该函数返回指定文件中的图标总数。如果文件是可执行文件或DLL,则返回值是RT_GROUP_ICON资源的数量。如果文件是.ico文件,则返回值为1。

所以我尝试用以下方法来做到这一点:

function get-icon-count {
    Param ( 
        [parameter(Mandatory = $true)]  [string] $SourceFile = 'C:/Windows/system32/shell32.dll',
        [parameter(Mandatory = $False)] [Int32]  $IconIndex  = 0    # -1: To count icons, 
    )

    $code = @'
    using System;
    using System.Drawing;
    using System.Runtime.InteropServices;
    using System.ComponentModel;
    using System.IO;
    using System.Management.Automation;

    namespace System {
        public class FileIconInfo {
            [DllImport("Shell32.dll", EntryPoint = "ExtractIconExW", CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
            public static extern int ExtractIconExW( string szFileName, int nIconIndex, out IntPtr phiconLarge, out IntPtr phiconSmall, uint nIcons);
        }
    }
'@

#@'
    Add-Type -AssemblyName System.Drawing
    $refAssemblies = @([Drawing.Icon].Assembly.Location)    # C:\Program Files\PowerShell\7\System.Drawing.Common.dll

    try {
        Add-Type -TypeDefinition $code -PassThru -ReferencedAssemblies $refAssemblies #| Import-Module -Assembly { $_.Assembly }
        $img = [System.FileIconInfo]::ExtractIconExW($SourceFile, -1, $null, $null, 1)    
    } Catch {
        Write-Host -f Red "[ERROR] Failed in ExtractIconExW()!"
        Write-Host -f Red "[ERROR] $_"
        $_ | select *
        Return
    }

    Write-Host -f DarkYellow "The number of icon indexes fund are: $([int32]$img)"
    Return $([int32]$img)
}

但是,运行它:

. .\extract-icon.ps1 && get-icon-count 'C:\<path-to>\shell32.dll'

您可以尝试使用任何已知包含大量图标的 EXE 或 DLL。像这些:

'C:\Windows\SystemResources\shell32.dll.mun'
'C:\Windows\SystemResources\imageres.dll.mun'  

但是我得到了例外:

Argument: '3' should be a System.Management.Automation.PSReference. Use [ref].

看起来不太喜欢

$null

如何修复脚本以获取 DLL/EXE 中的图标数量?

c# powershell
2个回答
2
投票

如果您只是想获取图标数量,可能

ExtractIcon
ExtractIconEx
(旨在提取大图标和小图标)更简单。 在当前的实现中,您还缺少对
DestroyIcon
的调用,以按照 备注中的建议处置句柄。
(编辑:在获取图标计数 -
-1
作为参数时不需要这样做)
nIconIndex
- 我的错)。

Add-Type -Namespace Native -Name ShellApi '
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr ExtractIconW(
    [In] IntPtr hInst,
    [In] string lpszExeFileName,
    int nIconIndex);

public static int GetIconCount(string path)
{
    return ExtractIconW(IntPtr.Zero, path, -1).ToInt32();
}'

用法只需将程序集名称或路径传递给可执行文件或

.ico

[Native.ShellApi]::GetIconCount('shell32.dll')               # 329
[Native.ShellApi]::GetIconCount('user32.dll')                # 7
[Native.ShellApi]::GetIconCount((Get-Process -Id $PID).Path) # 1

0
投票

我在here找到了解决方案。 经过一些细微的调整,它现在可以按预期工作:

function get-icon-count {
    Param ( 
        [parameter(Mandatory = $true)]  [string] $SourceFile = 'C:/Windows/system32/shell32.dll'   #"$env:SystemRoot\system32\shell32.dll"
    )
    
    # public static extern int ExtractIconExW( string lpszFile, int nIconIndex, out IntPtr phiconLarge, out IntPtr phiconSmall, int nIcons);
    $code = @'
    using System;
    using System.Runtime.InteropServices;

    namespace System {
        public class FileIconInfo {
            [DllImport("Shell32.dll", EntryPoint = "ExtractIconExW", CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
            public static extern int ExtractIconEx( string lpszFile, int nIconIndex, out IntPtr phiconLarge, out IntPtr phiconSmall, int nIcons);
        }
    }
'@

    [System.IntPtr] $phiconSmall = 0
    [System.IntPtr] $phiconLarge = 0

    Write-Host -f Gray "`n[INFO] Getting the total number of icons in file: $SourceFile"
    If  (-not (Test-path -Path $SourceFile -ErrorAction SilentlyContinue ) ) {
        Write-Host -f Red "[ERROR] Source file does not exist!"
    }

    try {
        Add-Type -TypeDefinition $code 
        $nImages = [System.FileIconInfo]::ExtractIconEx($SourceFile, -1, [ref] $phiconLarge, [ref] $phiconSmall, 0)
    } Catch {
        Write-Host -f Red "[ERROR] Failed to ExtractIconExW() from file!"
        Write-Host -f Red "[ERROR] $_"
        Return
    }

    Write-Host -f DarkYellow "[INFO] The number of icon indexes fund are: $([int32]$nImages)"
}

# . .\extract-icon.ps1 && get-icon-count 'C:\<path-to>\imageres.dll.mun'

# Output:
# [INFO] Getting the total number of icons in file: C:\<path-to>\imageres.dll.mun
# [INFO] The number of icon indexes fund are: 360

太棒了!

© www.soinside.com 2019 - 2024. All rights reserved.