From 8c54f3caa175a26d1dc89149de057a72fb6a38b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E7=85=8C?= Date: Sun, 13 Sep 2020 23:57:35 +0800 Subject: [PATCH] write application icon file --- .../ProjectFileWriterSdkStyle.cs | 8 ++ .../WholeProjectDecompiler.cs | 94 +++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs index 222c5d133..4899e024a 100644 --- a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs +++ b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs @@ -85,6 +85,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler PlaceIntoTag("PropertyGroup", xml, () => WriteAssemblyInfo(xml, module, project, projectType)); PlaceIntoTag("PropertyGroup", xml, () => WriteProjectInfo(xml, project)); + PlaceIntoTag("PropertyGroup", xml, () => WriteMiscellaneousPropertyGroup(xml, files)); PlaceIntoTag("ItemGroup", xml, () => WriteResources(xml, files)); PlaceIntoTag("ItemGroup", xml, () => WriteReferences(xml, module, project, projectType)); @@ -187,6 +188,13 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler } } + static void WriteMiscellaneousPropertyGroup(XmlTextWriter xml, IEnumerable<(string itemType, string fileName)> files) + { + var (itemType, fileName) = files.FirstOrDefault(t => t.itemType == "ApplicationIcon"); + if (fileName != null) + xml.WriteElementString("ApplicationIcon", fileName); + } + static void WriteResources(XmlTextWriter xml, IEnumerable<(string itemType, string fileName)> files) { // remove phase diff --git a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs index 1ad283b97..875c8d494 100644 --- a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs @@ -22,6 +22,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection.Metadata; +using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -142,6 +143,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler directories.Clear(); var files = WriteCodeFilesInProject(moduleDefinition, cancellationToken).ToList(); files.AddRange(WriteResourceFilesInProject(moduleDefinition)); + files.AddRange(WriteMiscellaneousFilesInProject(moduleDefinition)); if (StrongNameKeyFile != null) { File.Copy(StrongNameKeyFile, Path.Combine(targetDirectory, Path.GetFileName(StrongNameKeyFile))); @@ -367,6 +369,98 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler } #endregion + #region WriteMiscellaneousFilesInProject + const int RT_ICON = 3; + const int RT_GROUP_ICON = 14; + + protected virtual IEnumerable<(string itemType, string fileName)> WriteMiscellaneousFilesInProject(PEFile module) + { + var resources = module.Reader.ReadWin32Resources(); + if (resources == null) + yield break; + + byte[] icon = CreateIcon(resources); + File.WriteAllBytes(Path.Combine(TargetDirectory, "app.ico"), icon); + yield return ("ApplicationIcon", "app.ico"); + } + + unsafe static byte[] CreateIcon(Win32ResourceDirectory resources) + { + var iconGroup = resources.Find(new Win32ResourceName(RT_GROUP_ICON))?.Directories.FirstOrDefault()?.Datas.FirstOrDefault()?.Data; + if (iconGroup == null) + return null; + + var iconDir = resources.Find(new Win32ResourceName(RT_ICON)); + if (iconDir == null) + return null; + + using var outStream = new MemoryStream(); + using var writer = new BinaryWriter(outStream); + fixed (byte* pIconGroupData = iconGroup) + { + var pIconGroup = (GRPICONDIR*)pIconGroupData; + writer.Write(pIconGroup->idReserved); + writer.Write(pIconGroup->idType); + writer.Write(pIconGroup->idCount); + + int iconCount = pIconGroup->idCount; + uint offset = (2 * 3) + ((uint)iconCount * 0x10); + for (int i = 0; i < iconCount; i++) + { + var pIconEntry = pIconGroup->idEntries + i; + writer.Write(pIconEntry->bWidth); + writer.Write(pIconEntry->bHeight); + writer.Write(pIconEntry->bColorCount); + writer.Write(pIconEntry->bReserved); + writer.Write(pIconEntry->wPlanes); + writer.Write(pIconEntry->wBitCount); + writer.Write(pIconEntry->dwBytesInRes); + writer.Write(offset); + offset += pIconEntry->dwBytesInRes; + } + + for (int i = 0; i < iconCount; i++) + { + var icon = iconDir.FindDirectory(new Win32ResourceName(pIconGroup->idEntries[i].nID))?.Datas.FirstOrDefault()?.Data; + if (icon == null) + return null; + writer.Write(icon); + } + } + + return outStream.ToArray(); + } + + [StructLayout(LayoutKind.Sequential, Pack = 2)] + unsafe struct GRPICONDIR + { + public ushort idReserved; + public ushort idType; + public ushort idCount; + private fixed byte _idEntries[1]; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "")] + public GRPICONDIRENTRY* idEntries { + get { + fixed (byte* p = _idEntries) + return (GRPICONDIRENTRY*)p; + } + } + }; + + [StructLayout(LayoutKind.Sequential, Pack = 2)] + struct GRPICONDIRENTRY + { + public byte bWidth; + public byte bHeight; + public byte bColorCount; + public byte bReserved; + public ushort wPlanes; + public ushort wBitCount; + public uint dwBytesInRes; + public short nID; + }; + #endregion + /// /// Cleans up a node name for use as a file name. ///