This only concerns Bitmap resources (RT_BITMAP). Updating others type of resources is easier and doesn’t require specific code.
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();
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();