Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Updating images in resource section of an exe (in c#/C)

I have few images embedded in my executable in resource section. I followed these steps to create my executable:

  1. Generated .resx file for all the images (.jpg) in a directory using some utility. The images are named image1.jpg, image2.jpg and so on.
  2. created .resources file from .resx file using: resgen myResource.resx
  3. Embedded the generated .resource file using /res flag as: csc file.cs /res:myResource.resources

4 I am accessing these images as:

ResourceManager resources = new ResourceManager("myResource", Assembly.GetExecutingAssembly());

Image foo = (System.Drawing.Image)(resources.GetObject("image1"));

This all is working fine as expected. Now I want to change embedded images to some new images. This is what I am currently doing:

class foo
{
    [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr BeginUpdateResource(string pFileName, bool bDeleteExistingResources);

    [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool UpdateResource(IntPtr hUpdate, string lpType, string lpName, string wLanguage, Byte[] lpData, uint cbData);

    [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);


    public static void Main(string[] args)
    {
        IntPtr handle = BeginUpdateResource(args[0], false);

        if (handle.ToInt32() == 0)
            throw new Exception("File Not Found: " + fileName + " last err: " + Marshal.GetLastWin32Error());

        byte[] imgData = File.ReadAllBytes("SetupImage1.jpg");
        int fileSize = imgData.Length;

        Console.WriteLine("Updaing resources");
        if (UpdateResource(handle, "Image", "image1", "image1", imgData, (uint)fileSize))
        {
            EndUpdateResource(handle, false);
            Console.WriteLine("Update successfully");
        }
        else
        {
            Console.WriteLine("Failed to update resource. err: {0}", Marshal.GetLastWin32Error());
        }
    }
}

The above code is adding a new resource for the specified image (inside IMAGE title with some random number, as seen in Resource hacker), but I want to modify the existing resource data for image1.

I am sure that I am calling UpdateResource with some invalid arguments.

Could any one help pointing that out?

I am using .NET version 2

Thank you,

Vikram

like image 215
Vikram.exe Avatar asked Feb 19 '12 13:02

Vikram.exe


1 Answers

I think you are making a confusion between .NET resources, and Win32 resources. The resources you add embedding with the /res argument to csc.exe are .NET resources that you can successfully read using you ResourceManager snippet code.

Win32 resources are another beast, that is not much "compatible" with the managed .NET world in general, athough you can indeed add them to a .NET exe using the /win32Res argument - note the subtle difference :-)

Now, if you want to modify embedded .NET resources, I don't think there are classes to do it in the framework itself, however you can use the Mono.Cecil library instead. There is an example that demonstrates this here: C# – How to edit resource of an assembly?

And if you want to modify embedded Win32 resources, you code needs some fixes, here is a slightly modified version of it, the most important difference lies in the declaration of UpdateResource:

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr BeginUpdateResource(string pFileName, bool bDeleteExistingResources);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool UpdateResource(IntPtr hUpdate, string lpType, string lpName, short wLanguage, byte[] lpData, int cbData);

    [DllImport("kernel32.dll")]
    static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);

    public static void Main(string[] args)
    {
        IntPtr handle = BeginUpdateResource(args[0], false);
        if (handle == IntPtr.Zero)
            throw new Win32Exception(Marshal.GetLastWin32Error()); // this will automatically throw an error with the appropriate human readable message

        try
        {
            byte[] imgData = File.ReadAllBytes("SetupImage1.jpg");

            if (!UpdateResource(handle, "Image", "image1", (short)CultureInfo.CurrentUICulture.LCID, imgData, imgData.Length))
                throw new Win32Exception(Marshal.GetLastWin32Error());
        }
        finally
        {
            EndUpdateResource(handle, false);
        }
    }
like image 110
Simon Mourier Avatar answered Nov 04 '22 11:11

Simon Mourier