我想获取 EXE 或 DLL 文件的嵌入(或关联)图标的数量。 在另一个 question 中,提供了一些代码来提取所有图标文件,但没有信息显示如何实际使用 iconIndex 和
-1
来给出图标对象的总数。
来自 ExtractIconExW 文档:
UINT ExtractIconExW(
[in] LPCWSTR lpszFile,
[in] int nIconIndex,
[out] HICON *phiconLarge,
[out] HICON *phiconSmall,
UINT nIcons
);
对
nIconIndex
的解释如下:
如果该值为 –1 并且 phiconLarge 和 phiconSmall 均为 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 中的图标数量?
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
我在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
太棒了!