Skip to content

Instantly share code, notes, and snippets.

@fliedonion
Last active September 19, 2017 23:51
Show Gist options
  • Save fliedonion/382f2691592af48cb8535463667a75e2 to your computer and use it in GitHub Desktop.
Save fliedonion/382f2691592af48cb8535463667a75e2 to your computer and use it in GitHub Desktop.
Load Icon Data From File. Sideline of my other program using UpdateResource.
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
// https://stackoverflow.com/a/36795367
// http://schima.hatenablog.com/entry/20090512/1242139542
// https://blogs.msdn.microsoft.com/oldnewthing/20120720-00/?p=7083
namespace IconLoadToStruct {
class IconLoader {
List<IconStore> LoadIcons(string iconFilename) {
var icons = new List<IconStore>();
var stream = File.OpenRead(iconFilename);
using (var br = new BinaryReader(stream)) {
var header = LoadToValueClass<IconFileHeader>(br);
if (header.Type != 1) {
throw new Exception($"Invalid type. expected 1 but {header.Type}");
}
for (var i = 0; i < header.NumOfImages; i++) {
var dest = LoadToValueClass<IconBasicInfo>(br);
Console.WriteLine("bps = {0}, w:{1} h:{2}, offset:{3}", dest.BitsPerPixel, dest.Width == 0 ? 256 : dest.Width, dest.Height == 0 ? 256 : dest.Height, dest.Offset);
icons.Add(new IconStore {
Info = dest,
});
}
foreach (var icon in icons) {
if (br.BaseStream.Position < icon.Info.Offset) {
// skip to offset pos
br.ReadBytes((int)(icon.Info.Offset - br.BaseStream.Position));
}
icon.ImageData = br.ReadBytes((int)icon.Info.DataSize);
}
}
return icons;
}
T LoadToValueClass<T>(BinaryReader br) where T : new() {
var dest = new T();
var size = Marshal.SizeOf(dest);
IntPtr pBytes = Marshal.AllocHGlobal(size);
Marshal.Copy(br.ReadBytes(size), 0, pBytes, size);
Marshal.PtrToStructure<T>(pBytes, dest);
Marshal.FreeHGlobal(pBytes);
return dest;
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class IconFileHeader {
public ushort Reserved0;
public ushort Type; // .ico 0, .cur 2
public ushort NumOfImages;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class IconBasicInfo {
public byte Width;
public byte Height;
public byte Colors;
public byte Reserved0;
public ushort ColorPlanes;
public ushort BitsPerPixel;
public uint DataSize;
public uint Offset;
}
public class IconStore {
public IconBasicInfo Info;
public byte[] ImageData;
}
public static class IconStoreListExt {
public static byte[] ToGroupData(this List<IconStore> list, int startNId = 1) {
using (var ms = new MemoryStream())
using (var writer = new BinaryWriter(ms)) {
var i = 0;
writer.Write((ushort)0); // reserved
writer.Write((ushort)1); // icon
writer.Write((ushort)list.Count); // number of icons
foreach (var icon in list) {
writer.Write(icon.Info.Width);
writer.Write(icon.Info.Height);
writer.Write(icon.Info.Colors);
writer.Write((byte)0); // reserved, must be 0
writer.Write(icon.Info.ColorPlanes);
writer.Write(icon.Info.BitsPerPixel);
writer.Write(icon.Info.DataSize);
writer.Write((ushort)(startNId + i)); // nId
i++;
}
return ms.ToArray();
}
//typedef struct GRPICONDIR {
// WORD idReserved;
// WORD idType;
// WORD idCount;
// GRPICONDIRENTRY idEntries[];
//} GRPICONDIR;
//typedef struct GRPICONDIRENTRY {
// BYTE bWidth;
// BYTE bHeight;
// BYTE bColorCount;
// BYTE bReserved;
// WORD wPlanes;
// WORD wBitCount;
// DWORD dwBytesInRes;
// WORD nId;
//} GRPICONDIRENTRY;
}
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace IconResource {
public class Native {
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int UpdateResource(IntPtr hUpdate, uint lpType, ushort lpName, ushort wLanguage, byte[] lpData, uint cbData);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr BeginUpdateResource(string pFileName, [MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
public const uint RT_ICON = 3;
public const uint RT_GROUP_ICON = 14;
public const uint LOAD_LIBRARY_AS_DATAFILE = 0x00000002;
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool FreeLibrary(IntPtr hModule);
[DllImport("kernel32.dll")]
static extern bool EnumResourceNames(IntPtr hModule, string lpszType, EnumResNameProcDelegate lpEnumFunc, IntPtr lParam);
[DllImport("kernel32.dll")]
static extern bool EnumResourceNames(IntPtr hModule, int dwID, EnumResNameProcDelegate lpEnumFunc, IntPtr lParam);
delegate bool EnumResNameProcDelegate(IntPtr hModule, IntPtr lpszType, IntPtr lpszName, IntPtr lParam);
enum ResType {
CURSOR = 1,
BITMAP = 2,
ICON = 3,
MENU = 4,
DIALOG = 5,
STRING = 6,
FONTDIR = 7,
FONT = 8,
ACCELERATOR = 9,
RCDATA = 10,
MESSAGETABLE = 11,
GROUP_CURSOR = 12,
GROUP_ICON = 14,
VERSION = 16,
DLGINCLUDE = 17,
PLUGPLAY = 19,
VXD = 20,
ANICURSOR = 21,
ANIICON = 22,
HTML = 23,
MANIFEST = 24
}
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
// https://stackoverflow.com/a/36795367
// http://schima.hatenablog.com/entry/20090512/1242139542
// https://blogs.msdn.microsoft.com/oldnewthing/20120720-00/?p=7083
namespace IconLoadToStruct {
class Program {
static void Main(string[] args) {
var icons = new Program().Load("app.ico");
Console.ReadKey();
}
List<IconStore> Load(string iconFilename) {
var icons = new List<IconStore>();
var stream = File.OpenRead(iconFilename);
using (var br = new BinaryReader(stream)) {
var header = LoadToValueClass<IconFileHeader>(br);
if(header.Type != 1) {
throw new Exception($"Invalid type. expected 1 but {header.Type}");
}
for (var i = 0; i < header.NumOfImages; i++) {
var dest = LoadToValueClass<IconBasicInfo>(br);
Console.WriteLine("bps = {0}, w:{1} h:{2}, offset:{3}", dest.BitsPerPixel, dest.Width == 0 ? 256 : dest.Width, dest.Height == 0 ? 256 : dest.Height, dest.Offset);
icons.Add(new IconStore {
Info = dest,
});
}
foreach (var icon in icons) {
if (br.BaseStream.Position < icon.Info.Offset) {
// skip to offset pos
br.ReadBytes((int)(icon.Info.Offset - br.BaseStream.Position));
}
icon.ImageData = br.ReadBytes((int)icon.Info.DataSize);
}
}
return icons;
}
T LoadToValueClass<T>(BinaryReader br) where T : new(){
var dest = new T();
var size = Marshal.SizeOf(dest);
IntPtr pBytes = Marshal.AllocHGlobal(size);
Marshal.Copy(br.ReadBytes(size), 0, pBytes, size);
Marshal.PtrToStructure<T>(pBytes, dest);
Marshal.FreeHGlobal(pBytes);
return dest;
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class IconFileHeader {
public ushort Reserved0;
public ushort Type; // .ico 0, .cur 2
public ushort NumOfImages;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class IconBasicInfo {
public byte Width;
public byte Height;
public byte Colors;
public byte Reserved0;
public ushort ColorPlanes;
public ushort BitsPerPixel;
public uint DataSize;
public uint Offset;
}
public class IconStore {
public IconBasicInfo Info;
public byte[] ImageData;
}
public static class IconStoreListExt {
public static byte[] ToGroupData(this List<IconStore> list, int startNId = 1) {
using (var ms = new MemoryStream())
using (var writer = new BinaryWriter(ms)) {
var i = 0;
writer.Write((ushort)0); // reserved
writer.Write((ushort)1); // icon
writer.Write((ushort)list.Count); // number of icons
foreach (var icon in list) {
writer.Write(icon.Info.Width);
writer.Write(icon.Info.Height);
writer.Write(icon.Info.Colors);
writer.Write((byte)0); // reserved, must be 0
writer.Write(icon.Info.ColorPlanes);
writer.Write(icon.Info.BitsPerPixel);
writer.Write(icon.Info.DataSize);
writer.Write((ushort)(startNId + i)); // nId
i++;
}
return ms.ToArray();
}
//typedef struct GRPICONDIR {
// WORD idReserved;
// WORD idType;
// WORD idCount;
// GRPICONDIRENTRY idEntries[];
//} GRPICONDIR;
//typedef struct GRPICONDIRENTRY {
// BYTE bWidth;
// BYTE bHeight;
// BYTE bColorCount;
// BYTE bReserved;
// WORD wPlanes;
// WORD wBitCount;
// DWORD dwBytesInRes;
// WORD nId;
//} GRPICONDIRENTRY;
}
}
}
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IconResource {
class Program {
static void Main(string[] args) {
IntPtr hModule = Native.LoadLibraryEx("app.exe", IntPtr.Zero, Native.LOAD_LIBRARY_AS_DATAFILE);
if(hModule != IntPtr.Zero) {
try {
Native.
} finally {
Native.FreeLibrary(hModule);
}
}
}
public enum ICResult {
Success,
FailBegin,
FailUpdate,
FailEnd
}
//public ICResult ChangeIcon(string exeFilePath, string iconFilePath) {
// using (FileStream fs = new FileStream(iconFilePath, FileMode.Open, FileAccess.Read)) {
// var reader = new IconReader(fs);
// var iconChanger = new IconChanger();
// return iconChanger.ChangeIcon(exeFilePath, reader.Icons);
// }
//}
//public ICResult ChangeIcon(string exeFilePath, Icons icons) {
// // Load executable
// IntPtr handleExe = Native.BeginUpdateResource(exeFilePath, false);
// if (handleExe == null) return ICResult.FailBegin;
// ushort startindex = 1;
// ushort index = startindex;
// ICResult result = ICResult.Success;
// var ret = 1;
// foreach (var icon in icons) {
// // Replace the icon
// // todo :Improve the return value handling of UpdateResource
// ret = Native.UpdateResource(handleExe, Native.RT_ICON, index, 0, icon.Data, icon.Size);
// index++;
// }
// var groupdata = icons.ToGroupData();
// // todo :Improve the return value handling of UpdateResource
// ret = Native.UpdateResource(handleExe, Native.RT_GROUP_ICON, startindex, 0, groupdata, (uint)groupdata.Length);
// if (ret == 1) {
// if (EndUpdateResource(handleExe, false))
// result = ICResult.Success;
// else
// result = ICResult.FailEnd;
// } else
// result = ICResult.FailUpdate;
// return result;
//}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment