正在更新exe(在c#/c中)的资源部分中的图像

本文关键字:图像 资源部 exe 更新 | 更新日期: 2023-09-27 18:25:02

我在资源部分的可执行文件中嵌入了一些图像。我按照以下步骤创建了我的可执行文件:

  1. 使用某种实用程序为目录中的所有图像生成.resx文件(.jpg)。这些图像分别命名为image1.jpg、image2.jpg等
  2. 使用以下命令从.resx文件创建.resources文件:resgen myResource.resx
  3. 使用/res标志将生成的.resources文件嵌入为:csc file.cs /res:myResource.resources

4我正在访问这些图像作为:

ResourceManager resources = new ResourceManager("myResource", Assembly.GetExecutingAssembly());
Image foo = (System.Drawing.Image)(resources.GetObject("image1"));

这一切都如预期的那样顺利。现在我想将嵌入的图像更改为一些新图像。这就是我目前正在做的事情:

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());
        }
    }
}

上面的代码为指定的图像添加了一个新的资源(在IMAGE标题中,有一些随机数,如Resource hacker所示),但我想修改image1的现有资源数据。

我确信我调用UpdateResource时使用了一些无效的参数。

有人能帮我指出这一点吗?

我使用的是.NET版本2

谢谢你,

Vikram

正在更新exe(在c#/c中)的资源部分中的图像

我认为您混淆了.NET资源和Win32资源。使用/res参数向csc.exe添加嵌入的资源是可以使用ResourceManager代码段成功读取的.NET资源。

Win32资源是另一个野兽,它与托管.NET世界总体上不太"兼容",尽管您确实可以使用/win32Res参数将它们添加到.NET exe中,但请注意细微的区别:-)

现在,如果您想修改嵌入式.NET资源,我认为在框架本身中没有类可以做这件事,但是您可以使用Mono.Cecil库。这里有一个例子说明了这一点:C#–如何编辑程序集的资源?

如果你想修改嵌入式Win32资源,你的代码需要一些修复,这里是一个稍微修改过的版本,最重要的区别在于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);
        }
    }

这是不可能的。您无法修改正在运行的已编译文件。

我相信您可以在运行时添加新的映像,但不能更新本质上只保存在内存中的资源。

如果您在运行时添加资源,它是存在的,但我不认为它是编译的,因此我认为您无法访问它。

你不使用内容的原因是什么?