Skip to content

Instantly share code, notes, and snippets.

@Far-Se
Created July 17, 2022 06:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Far-Se/20f38bbc9ada7c62f44a71c4a3b8e096 to your computer and use it in GitHub Desktop.
Save Far-Se/20f38bbc9ada7c62f44a71c4a3b8e096 to your computer and use it in GitHub Desktop.
Extract Icons using PowerShell
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