Created
July 17, 2022 06:31
-
-
Save Far-Se/20f38bbc9ada7c62f44a71c4a3b8e096 to your computer and use it in GitHub Desktop.
Extract Icons using PowerShell
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Globals { | |
static String iconCachePath = "${Directory.current.path}\\cache"; | |
} | |
class WinUtils { | |
static Future<List<String>> runPowerShell(List<String> commands) async { | |
final io.ProcessResult result = await io.Process.run( | |
'powershell', | |
<String>['-NoProfile', ...commands], | |
); | |
if (result.stderr != '') { | |
return <String>[]; | |
} | |
List<String> output = result.stdout.toString().trim().split('\n').map((String e) => e.trim()).toList(); | |
return output; | |
} | |
static Future<Uint8List> getCachedIcon(String path, {int iconID = 0}) async { | |
final WinIcons winIcon = WinIcons(); | |
if (iconID == 0) { | |
winIcon.add(path); | |
} else { | |
winIcon.add('$path,$iconID'); | |
} | |
await winIcon.fetch(Globals.iconCachePath); | |
if (iconID == 0) { | |
return File("${Globals.iconCachePath}\\${Win32.getExe(path)}.cached").readAsBytesSync(); | |
} else { | |
return File("${Globals.iconCachePath}\\dll_${iconID}_${Win32.getExe(path)}.cached").readAsBytesSync(); | |
} | |
} | |
static String getIconPath(String exe) { | |
return "${Globals.iconCachePath}\\$exe.cached"; | |
} | |
} | |
class WinIcons { | |
//[0] - Path, [1] - iconINDEX, which is +/- int | |
List<List<dynamic>> list = <List<dynamic>>[]; | |
WinIcons(); | |
void add(String item) { | |
int dll = 0; | |
if (item.contains(',')) { | |
final String lastItem = item.substring(item.lastIndexOf('.')); | |
final List<String> xploded = lastItem.split(','); | |
if (xploded.length == 2) { | |
dll = int.parse(xploded[1]); | |
item = item.replaceAll(',$dll', ''); | |
} | |
} | |
list.add(<dynamic>[item, dll]); | |
} | |
void addAll(List<String> item) { | |
for (String element in item) { | |
add(element); | |
} | |
} | |
Future<void> fetch(String directory) async { | |
List<String> commands = <String>[ | |
"Add-Type -AssemblyName System.Drawing;", | |
"\$Format = [System.Drawing.Imaging.ImageFormat]::Png;", | |
]; | |
if (list.where((List<dynamic> e) => e[1] != 0).isNotEmpty) { | |
commands.add( | |
'''add-type -typeDefinition ' using System; using System.Runtime.InteropServices; public class Shell32_Extract { [DllImport( "Shell32.dll", EntryPoint = "ExtractIconExW", CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall) ] public static extern int ExtractIconEx( string lpszFile , int iconIndex , out IntPtr phiconLarge, out IntPtr phiconSmall, int nIcons ); }';'''); | |
} | |
int totalAdded = 0; | |
for (List<dynamic> element in list) { | |
final String path = element[0]; | |
final int iconID = element[1]; | |
final String exePath = Win32.getExe(path); | |
String exeCache = directory; | |
if (iconID != 0) { | |
exeCache += "\\dll_${iconID}_$exePath.cached"; | |
if (File(exeCache).existsSync()) continue; | |
totalAdded++; | |
commands.addAll(<String>[ | |
"[System.IntPtr] \$phiconLarge = 0;", | |
"[System.IntPtr] \$phiconSmall = 0;", | |
"[Shell32_Extract]::ExtractIconEx('$path', $iconID, [ref] \$phiconLarge, [ref] \$phiconSmall, 1);", | |
"\$Icon = [System.Drawing.Icon]::FromHandle(\$phiconSmall).ToBitMap().Save('$exeCache',\$Format);", | |
]); | |
} else { | |
exeCache += "\\$exePath.cached"; | |
if (File(exeCache).existsSync()) continue; | |
totalAdded++; | |
commands.add("\$Icon = [System.Drawing.Icon]::ExtractAssociatedIcon('$path').ToBitMap().Save('$exeCache',\$Format);"); | |
} | |
} | |
if (totalAdded > 0) { | |
print("total new: $totalAdded"); | |
await WinUtils.runPowerShell(commands); | |
} | |
} | |
Future<List<Uint8List>> getHandleIcons(List<int> handles) async { | |
List<String> commands = <String>[ | |
"Add-Type -AssemblyName System.Drawing;", | |
"\$Format = [System.Drawing.Imaging.ImageFormat]::Png;", | |
]; | |
for (int handle in handles) { | |
commands.addAll(<String>[ | |
"\$MemoryStream = New-Object System.IO.MemoryStream;", | |
"[System.Drawing.Icon]::FromHandle($handle).ToBitMap().Save(\$MemoryStream,\$Format);", | |
"\$Bytes = \$MemoryStream.ToArray();", | |
"\$MemoryStream.Flush();", | |
"\$MemoryStream.Dispose();", | |
"[convert]::ToBase64String(\$Bytes);", | |
]); | |
} | |
final List<String> output = await WinUtils.runPowerShell(commands); | |
List<Uint8List> list = output.map(base64Decode).toList(); | |
return list; | |
} | |
Future<Uint8List> getHandleIcon(int handle) async { | |
final List<int> handles = <int>[handle]; | |
final List<Uint8List> output = await getHandleIcons(handles); | |
if (output.isNotEmpty) { | |
return output[0]; | |
} else { | |
return Uint8List.fromList(<int>[0]); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment