How can I directly display an icon with a known dll ID?

2

Anyone knows how to directly display an icon in its "Registry" format? E.g. "%SystemRoot%\system32\shell32.dll,112", i.e. C:\Windows\System32\shell32.dll,112, is typically the ID of an icon as it is found in the Registry Data for the "IconPath" value. The path is real, the "112" icon code just a random number.

Point is that it is cumbersome to find the correct icon when the dll consists of hundreds of icons, even when using a tool like Icon Extractor, which will display icon info when the cursor hovers over the icons. All these tools only seem to function the other way round: one must load the dll, next hope to locate the icon with the corresponding code.

WinMike

Posted 2018-07-22T13:22:04.497

Reputation: 53

Answers

2

The icons for file types are resources (i.e. any type of image, media etc.) embedded in known DLLs. That icon number (or icon group index) aren't random. DLL files have a section to store those resources. Each icons are stored with unique numbers. One type of icon can consist of varying icon sizes, dimensions and bit depth. That icon ID comes form the icon group number so that when user changes zoom level, it changes only icon size not the icon itself.

This can be easily understand with an example. For this case, I use Resource Hacker. Here are the screenshot of icons of Shortcut files (.LNK extensions) in Resource Hacker (icons may vary):

Resource_Hacker_Shell32

And here is the registry settings:

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\.lnk\ShellNew]
"Handler"="{ceefea1b-3e29-4ef1-b34c-fec79c4f70af}"
"IconPath"="%SystemRoot%\system32\shell32.dll,-16769"
"ItemName"="@shell32.dll,-30397"
"MenuText"="@shell32.dll,-30318"
"NullFile"=""

See the number "16769", match it with the screenshot. But how to open it in Resource Hacker? Answer: Download and run that software --> Copy shell32.dll (or any dll/exe file) in your desktop/working folder --> drag that file in Resource Hacker window --> Double click on the "Icon Group" --> Scroll to that number. See there are many icons in one icon group with respect to their dimensions 16x16, 20x20 etc. Those are for different zoom level in File Explorer.

Biswapriyo

Posted 2018-07-22T13:22:04.497

Reputation: 6 640

0

It is cumbersome to find the correct icon when the dll consists of hundreds of icons

You can use the following Powershell script .\DisplayIcon.ps1:

<#
.SYNOPSIS
    Exports an ico and bmp file from a given source to a given destination
.Description
    You need to set the Source and Destination locations. First version of a script, I found other examples 
    but all I wanted to do as grab and ico file from an exe but found getting a bmp useful. Others might find useful
.EXAMPLE
    This will run but will nag you for input
    .\Icon_Exporter.ps1
.EXAMPLE
    this will default to shell32.dll automatically for -SourceEXEFilePath
    .\Icon_Exporter.ps1 -TargetIconFilePath 'C:\temp\Myicon.ico' -IconIndexNo 238
.EXAMPLE
    This will give you a green tree icon (press F5 for windows to refresh Windows explorer)
    .\Icon_Exporter.ps1 -SourceEXEFilePath 'C:/Windows/system32/shell32.dll' -TargetIconFilePath 'C:\temp\Myicon.ico' -IconIndexNo 41

.Notes
    Based on http://stackoverflow.com/questions/8435/how-do-you-get-the-icons-out-of-shell32-dll Version 1.1 2012.03.8
    New version: Version 1.2 2015.11.20 (Added missing custom assembly and some error checking for novices)
#>
Param ( 
    [parameter(Mandatory = $true)]
    [string] $SourceEXEFilePath = 'C:/Windows/system32/shell32.dll',
    [parameter(Mandatory = $true)]
    [string] $TargetIconFilePath,
    [parameter(Mandatory = $False)]
    [Int32]$IconIndexNo = 0
)

$code = @"
using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace System
{
    public class IconExtractor
    {

     public static Icon Extract(string file, int number, bool largeIcon)
     {
      IntPtr large;
      IntPtr small;
      ExtractIconEx(file, number, out large, out small, 1);
      try
      {
       return Icon.FromHandle(largeIcon ? large : small);
      }
      catch
      {
       return null;
      }

     }
     [DllImport("Shell32.dll", EntryPoint = "ExtractIconExW", CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
     private static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons);

    }
}
"@

If  (-not (Test-path -Path $SourceEXEFilePath -ErrorAction SilentlyContinue ) ) {
    Throw "Source file [$SourceEXEFilePath] does not exist!"
}

[String]$TargetIconFilefolder = [System.IO.Path]::GetDirectoryName($TargetIconFilePath) 
If  (-not (Test-path -Path $TargetIconFilefolder -ErrorAction SilentlyContinue ) ) {
    Throw "Target folder [$TargetIconFilefolder] does not exist!"
}

Try {
    If ($SourceEXEFilePath.ToLower().Contains(".dll")) {
        Add-Type -TypeDefinition $code -ReferencedAssemblies System.Drawing
        $Icon = [System.IconExtractor]::Extract($SourceEXEFilePath, $IconIndexNo, $true)    
    } Else {
        [void][Reflection.Assembly]::LoadWithPartialName("System.Drawing")
        [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
        $image = [System.Drawing.Icon]::ExtractAssociatedIcon("$($SourceEXEFilePath)").ToBitmap()
        $bitmap = new-object System.Drawing.Bitmap $image
        $bitmap.SetResolution(72,72)
        $icon = [System.Drawing.Icon]::FromHandle($bitmap.GetHicon())
    }
} Catch {
    Throw "Error extracting ICO file"
}

Try {
    $stream = [System.IO.File]::OpenWrite("$($TargetIconFilePath)")
    $icon.save($stream)
    $stream.close()
} Catch {
    Throw "Error saving ICO file [$TargetIconFilePath]"
}
Write-Host "Icon file can be found at [$TargetIconFilePath]"

# Loosely based on http://www.vistax64.com/powershell/202216-display-image-powershell.html

[void][reflection.assembly]::LoadWithPartialName("System.Windows.Forms")

$img = [System.Drawing.Image]::Fromfile($TargetIconFilePath);

# This tip from http://stackoverflow.com/questions/3358372/windows-forms-look-different-in-powershell-and-powershell-ise-why/3359274#3359274
[System.Windows.Forms.Application]::EnableVisualStyles();
$form = new-object Windows.Forms.Form
$form.Text = "Image Viewer"
$form.Width = $img.Size.Width;
$form.Height =  $img.Size.Height;
$pictureBox = new-object Windows.Forms.PictureBox
$pictureBox.Width =  $img.Size.Width;
$pictureBox.Height =  $img.Size.Height;

$pictureBox.Image = $img;
$form.controls.add($pictureBox)
$form.Add_Shown( { $form.Activate() } )
$form.ShowDialog()
#$form.Show();

Example output:

> .\DisplayIcon.ps1 -SourceEXEFilePath 'C:\Windows\system32\shell32.dll' -TargetIconFilePath 'f:\test\Myicon.ico' -IconIndexNo 41
Icon file can be found at [f:\test\Myicon.ico]

enter image description here

Notes:

  • This script was built using the sources listed below.
  • Thanks to Ben N in Root Access for his help debugging the code.

Sources:

DavidPostill

Posted 2018-07-22T13:22:04.497

Reputation: 118 938

@WinMike Answer completely rewritten with a command line Powershell solution. Enjoy! – DavidPostill – 2018-07-22T19:26:33.770

@Biswapriyo You could have done that yourself. You have enough rep. Link has been added. – DavidPostill – 2018-07-22T19:44:24.990