Search notes:

PowerShell: extract icons from a DLL with the WinAPI function ExtractIconEx

Shell32_Extract

Shell32_Extract is a «P/Invoke» class that wraps some Extract…() functions from shell32.dll.
The source code is here.

User32_DestroyIcon

User32_DestroyIcon is a «P/Invoke» class that wraps the single WinAPI call: DestroyIcon(). This function is needed after an Icon is extracted from a DLL.
add-type -typeDefinition '

using System;
using System.Runtime.InteropServices;

public class User32_DestroyIcon {

  [DllImport(
     "User32.dll",
      EntryPoint        = "DestroyIcon"
  )]
   public static extern int DestroyIcon(IntPtr hIcon);

}
';
Github repository about-PowerShell, path: /examples/WinAPI/Shell32/Extract/User32_DestroyIcon.ps1

go.ps1

go.ps1 is a simple PowerShell script that tries to demonstrate how icons might be extracted from a DLL.
#
#  Prevent Error
#    Unable to find type [System.Drawing.Icon]
#  and
#    Unable to find type [System.Drawing.Imaging.ImageFormat].
#
$null = [Reflection.Assembly]::LoadWithPartialName('System.Drawing');
$null = [Reflection.Assembly]::LoadWithPartialName('System.Drawing.Imaging');

$dllPath = "$env:SystemRoot\System32\imageres.dll"

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

$nofImages = [Shell32_Extract]::ExtractIconEx($dllPath, -1, [ref] $phiconLarge, [ref] $phiconSmall, 0)

foreach ($iconIndex in 0 .. ($nofImages-1)) {

   $nofIconsExtracted = [Shell32_Extract]::ExtractIconEx($dllPath, $iconIndex, [ref] $phiconLarge, [ref] $phiconSmall, 1)

   if ($nofIconsExtracted -ne 2) {
      write-error "iconsExtracted = $nofIconsExtracted"
   }

   $iconSmall = [System.Drawing.Icon]::FromHandle($phiconSmall);
   $iconLarge = [System.Drawing.Icon]::FromHandle($phiconLarge);

   $bmpSmall = $iconSmall.ToBitmap()
   $bmpLarge = $iconLarge.ToBitmap()

   $iconIndex_0  = '{0,3:000}' -f $iconIndex

 #
 #  System.Drawing.Image.Save(), without specifying an encoder, stores
 #  the bitmap in png format.
 #
   $bmpLarge.Save("$(get-location)\small-$iconIndex_0.png");
   $bmpLarge.Save("$(get-location)\large-$iconIndex_0.png");

 #
 #  Use System.Drawing.Imaging.ImageFormat to specify a
 #  different format:
 #

   $bmpSmall.Save("$(get-location)\small-$iconIndex_0.bmp", [System.Drawing.Imaging.ImageFormat]::Bmp );
   $bmpLarge.Save("$(get-location)\large-$iconIndex_0.bmp", [System.Drawing.Imaging.ImageFormat]::Bmp );
   
   $bmpSmall.Save("$(get-location)\small-$iconIndex_0.jpg", [System.Drawing.Imaging.ImageFormat]::Jpeg);
   $bmpLarge.Save("$(get-location)\large-$iconIndex_0.jpg", [System.Drawing.Imaging.ImageFormat]::Jpeg);

}
Github repository about-PowerShell, path: /examples/WinAPI/Shell32/Extract/go.ps1

create-html-with-icons-of-dll.ps1

The following script creates a HTML document that contains the icons that are in a DLL or EXE.
When run on imageres.dll, it produces this document.
$dllPath = $args[0]

if ($dllPath -eq $null) {
    write-output "specify a dll";
    return;
}

if (! (test-path $dllPath)) {
    write-output "$dllPath is not a file";
    return;
}

$filenameWithoutSuffix = [IO.Path]::GetFileNameWithoutExtension($dllPath)

. .\Shell32_Extract.ps1
. .\User32_DestroyIcon.ps1


"<html><head>
<title>Icons in $filenameWithoutSuffix.dll</title></head><body>
   <h1>Icons in $filenameWithoutSuffix.dll</h1>
   These icons were extracted with <a href='https://renenyffenegger.ch/notes/Windows/PowerShell/examples/WinAPI/ExtractIconEx'>PowerShell and the WinAPI function <code>ExtractIconEx</code></a><p>
<table><tr>" | out-file "$filenameWithoutSuffix.html";

$null = [Reflection.Assembly]::LoadWithPartialName('System.Drawing');
$null = [Reflection.Assembly]::LoadWithPartialName('System.Drawing.Imaging');

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

$nofImages = [Shell32_Extract]::ExtractIconEx($dllPath, -1, [ref] $phiconLarge, [ref] $phiconSmall, 0);
$nofImages;

foreach ($iconIndex in 0 .. ($nofImages-1)) {

  $nofIconsExtracted = [Shell32]::ExtractIconEx($dllPath, $iconIndex, [ref] $phiconLarge, [ref] $phiconSmall, 1)
  $iconLarge = [System.Drawing.Icon]::FromHandle($phiconLarge);

  $bmpLarge  = $iconLarge.ToBitmap()
  
  $iconIndex_0  = '{0,3:000}' -f $iconIndex
  $imgName = "$filenameWithoutSuffix-$iconIndex_0.png";
  $bmpLarge.Save("$(get-location)\$imgName");
  
  if ($iconIndex -and (! ($iconIndex % 10))) {
    "</tr><tr>" | out-file "$filenameWithoutSuffix.html" -append;
  }
  
  "<td>$iconIndex_0</td><td><img src='$imgName'/></td>" | out-file "$filenameWithoutSuffix.html" -append;
  
  $null = [User32_DestroyIcon]::DestroyIcon($phiconSmall);
  $null = [User32_DestroyIcon]::DestroyIcon($phiconLarge);

}

"</table></body></html>" | out-file "$filenameWithoutSuffix.html" -append;
Github repository about-PowerShell, path: /examples/WinAPI/Shell32/Extract/create-html-with-icons-of-dll.ps1

Index