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

时间:2012-02-19 13:54:33

标签: c# resources .net-2.0

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

  1. 使用某个实用程序为目录中的所有图像(.jpg)生成.resx文件。图像命名为image1.jpg,image2.jpg等。
  2. 使用:resgen myResource.resx
  3. 从.resx文件创建.resources文件
  4. 使用/ res标记嵌入生成的.resource文件:csc file.cs /res:myResource.resources
  5. 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中所示),但我想修改{{{}的现有资源数据1}}。

    我确信我使用一些无效的参数调用image1

    任何人都能指出这一点吗?

    我正在使用.NET版本2

    谢谢,

    维克拉姆

3 个答案:

答案 0 :(得分:8)

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

Win32资源是另一种野兽,与托管的.NET世界一般并不太“兼容”,尽管你确实可以使用/win32Res参数将它们添加到.NET exe中 - 请注意细微差别: - )

现在,如果您想修改嵌入式.NET资源,我认为在框架本身中没有类可以执行它,但您可以使用Mono.Cecil库。这里有一个示例:C# – How to edit resource of an assembly?

如果你想修改嵌入式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);
        }
    }

答案 1 :(得分:1)

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

答案 2 :(得分:0)

我相信您可以在运行时添加新图像,但无法更新基本上只在内存中保存的资源。

如果你在运行时添加一个资源,它就存在,但我不认为它是编译的,因此我不认为你可以访问它。

您是否有理由不使用内容?