This only concerns Bitmap resources (RT_BITMAP). Updating others type of resources is easier and doesn’t require specific code.
- BMP files
Inserting BMP files is quite easy. You only have to remove the header and you are good to go.
int BMP_HEADER_BYTES = 14;
FileStream stream = new FileStream(file, FileMode.Open,
FileAccess.Read,
FileShare.Read);
BinaryReader reader = new BinaryReader(stream);
byte[] data = reader.ReadBytes((int)reader.BaseStream.Length);
GCHandle gcHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
IntPtr bitmap = Marshal.UnsafeAddrOfPinnedArrayElement(data, BMP_HEADER_BYTES);
uint size = (uint)(data.GetLength(0) - BMP_HEADER_BYTES);
UpdateResource(hDll, 2, resourceId, LANG_ENGLISH_ID, bitmap, size);
gcHandle.Free();
stream.Close();
- PNG files
It’s a bit more difficult with PNG files. You must add a header before inserting the image data. You also need to rotate the image before inserting because of the bitmap is copied and read (alternatively, you can insert a negative height into the header, but I haven’t tested it).
Also note that we do not set the compression to BI_PNG (5) and the size of the image in the BITMAPINFO header.
[StructLayout(LayoutKind.Sequential)]
class BITMAPINFO {
public int biSize;
public int biWidth;
public int biHeight;
public short biPlanes;
public short biBitCount;
public int biCompression;
public int biSizeImage;
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public int biClrUsed;
public int biClrImportant; }
// Load file
Bitmap pngFile = new Bitmap(file);
// Required due to the way bitmap is copied and read
pngFile.RotateFlip(RotateFlipType.RotateNoneFlipY);
BitmapData data = pngFile.LockBits(new Rectangle(0, 0,
pngFile.Width, pngFile.Height),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb);
byte[] dataBuffer = new byte[data.Height * data.Stride];
Marshal.Copy(data.Scan0, dataBuffer, 0, data.Height * data.Stride);
pngFile.UnlockBits(data);
// Setup Header
BITMAPINFO header = new BITMAPINFO();
header.biSize = Marshal.SizeOf(typeof(BITMAPINFO));
header.biWidth = pngFile.Width;
header.biHeight = pngFile.Height;
header.biPlanes = 1;
header.biBitCount = 32;
// Convert the structure to an array
byte[] buffer = new byte[header.biSize];
GCHandle h = GCHandle.Alloc(buffer , GCHandleType.Pinned);
Marshal.StructureToPtr(header, h.AddrOfPinnedObject(), false);
h.Free();
// Write header + data
MemoryStream memory = new MemoryStream();
memory.Write(buffer, 0, buffer.Length);
memory.Write(dataBuffer, 0, dataBuffer.Length);
byte[] imageData = memory.GetBuffer();
GCHandle gcHandle = GCHandle.Alloc(imageData, GCHandleType.Pinned);
IntPtr firstCopyElement = Marshal.UnsafeAddrOfPinnedArrayElement(imageData, 0);
UpdateResource(hDll, 2, resourceId, LANG_ENGLISH_ID,
firstCopyElement, (uint)imageData.GetLength(0));
gcHandle.Free();
memory.Close();