When I developed my tool YM Login BG for changing background of YM Login Dialog, I had a chance to work more with resource section of a compiled executable file. To make this tool, there are two steps I must pass.
– I must insert a bitmap image into Bitmap resource section of file.
– I must somehow insert a new control into login dialog. This control is just the background of the dialog.
1. Use ResHacker
To accomplish these two steps, we can use ResHacker http://angusj.com/resourcehacker/ to add bitmap and control. To add bitmap, use ResHacker to open executable file, browse to Bitmap branch, on the menu Action, choose “Add a new Resource”
Adding control to dialog is almost same, browse to Dialog branch, choose which dialog we want to edit, add control and press Compile Script to save all information
So it’s pretty simple when we have ResHacker in hand. But I would like to run this progress completely automatically. That means I just need to choose an image and click to finish the remaining steps. Therefore I should use some APIs which are relevant to resource of an executable file.
2. Programming
General, to add,edit,replace a resource to an assembly we must call 3 APIs functions: BeginUpdateResource, UpdateResource and EndUpdateResource. They must be called in order to get the handle of the target, edit it and save all changes. Their signatures in c# are below
[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 UpdateResource(IntPtr hUpdate, uint lpType, uint lpName, ushort wLanguage, byte[] lpData, uint cbData); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
For example if we want to add a bitmap to resource of an executable file, we should write like this
IntPtr ipTarget = Win32API.BeginUpdateResource(strFileName, false); if (Win32API.UpdateResource(ipTarget, Win32API.RT_BITMAP, 41713, 1033, baRes, (uint)baRes.Length)) { Win32API.EndUpdateResource(ipTarget, false); Console.WriteLine("Update successfully"); }
The strFileName is the path to target file which we want to add,replace or edit resource. baRes is the byte array of bitmap file. Please pay attention that this byte array is not the complete byte array of bitmap image. We must eliminate the first 14 bytes header of bitmap before adding it. Otherwise your bitmap will be not correctly handled. The baRes was constructed as below
byte[] baBMP = File.ReadAllBytes(strBMPPath); byte[] baRes = new byte[baBMP.Length - 14]; Buffer.BlockCopy(baBMP, 14, baRes, 0, baRes.Length);
The argument wLanguage is the LangID of resource. In my example above, I used hard-code but if you want a variable way then you can get the LangID as below
CultureInfo ciInfo = new CultureInfo("en-US"); ushort uLcid = (ushort)ciInfo.LCID;
The main idea is unchanged when we want to read, replace information of a dialog. We just need to call some more APIs to load resource into memory and read it out.
byte[] baData = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x02, 0x54, 0xC8, 0xFF, 0xFE, 0xFF, 0x3B, 0x01, 0x81, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x82, 0x00, 0xFF, 0xFF, 0xF1, 0xA2, 0x00, 0x00, 0x00, 0x00 }; // Load the DLL/EXE without executing its code IntPtr ipModule = Win32API.LoadLibraryEx(strFileName, IntPtr.Zero, Win32API.LOAD_LIBRARY_AS_DATAFILE); if (ipModule != IntPtr.Zero) { // Find the group resource which lists its images IntPtr ipResInfo = Win32API.FindResource(ipModule, 929, Win32API.RT_DIALOG); if (ipResInfo != IntPtr.Zero) { uint nSizeOfResource = Win32API.SizeofResource(ipModule, ipResInfo); IntPtr ipResData = Win32API.LoadResource(ipModule, ipResInfo); if (ipResData != IntPtr.Zero) { byte[] baTemp = new byte[nSizeOfResource + baData.Length]; IntPtr ipMemorySource = Win32API.LockResource(ipResData); Marshal.Copy(ipMemorySource, baTemp, 0, (int)nSizeOfResource); for (int nIndex = (int)nSizeOfResource; nIndex < baTemp.Length; nIndex++) { baTemp[nIndex] = baData[nIndex - nSizeOfResource]; } baTemp[0x10] = (byte)(1 + baTemp[0x10]); IntPtr ipTarget = Win32API.BeginUpdateResource(strFileName, false); if (Win32API.UpdateResource(ipTarget, Win32API.RT_DIALOG, 929, 1033, baTemp, (uint)baTemp.Length)) { Win32API.EndUpdateResource(ipTarget, false); Console.WriteLine("Update successfully"); } else { Console.WriteLine("Update false"); } } else { Console.WriteLine("Could not load login dialog"); } } else { Console.WriteLine("Could not locate login dialog"); } } else { Console.WriteLine("Could not load dll"); }
I think it’s very simple to understand the code. For a sample project you can download at following link. “Add,Replace,Edit resource of an executable file with C#“.
Hi, nice post. I just wonder if you know or if you can point me in the right direction.
I want to change the Icon programmatically to any file type. Like DropBox is doing when it finished sinchronizing, it put a check mark on the file.
Thanks for the help.
@Felipe: I knew this problem, I’ll try myself to make overlay icons with C#. If it’s urgent for you, maybe this link will help
http://www.google.com/#hl=en&source=hp&q=c%23+overlay+icon&aq=f&aqi=&aql=&oq=&fp=93b6e195ecf679eb
Hello its very urgent i am working on my project logon tweaker vista
and i want to know how can we update resources in a .dll or .exe file . The file i want to edit resource is imageres.dll
Hello,
thank you for this tutorial. I’ve got a problem. If I add a resource, which not exists in the .dll all works fine. If I use a lpType / ResourceType which already exists in the .dll nothing happens. BeginUpdateResource works, but at UpdateResource it hangs up. No exception. Nothing. It hangs at this point. Does anybody know, what the problem could be?
Greets from Germany,
Raffael
@Raffi: Principally UpdateResource can add, delete, or replace a resource in a portable executable (PE) file. For more details about this function you can read here http://msdn.microsoft.com/en-us/library/windows/desktop/ms648049%28v=vs.85%29.aspx
In case that you can’t update, you can delete resource and add new one. It makes same effect.