【问题标题】:Updating images in resource section of an exe (in c#/C)在 exe 的资源部分更新图像(在 c#/C 中)
【发布时间】:2012-03-10 02:58:26
【问题描述】:

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

  1. 使用某些实用程序为目录中的所有图像 (.jpg) 生成 .resx 文件。图像命名为 image1.jpg、image2.jpg 等。
  2. 从 .resx 文件创建 .resources 文件,使用:resgen myResource.resx
  3. 使用 /res 标志嵌入生成的 .resource 文件为: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

谢谢,

维克拉姆

【问题讨论】:

  • 两种不同的动物。 .resx 文件包含 托管 资源,它们嵌入到程序集清单中。 UpdateResource() 只知道非托管资源。除了使用 ildasm.exe 反编译和使用 ilasm.exe 重新编译之外,没有任何机制可以重建程序集清单。非常不切实际,尤其是与简单地将 jpegs 文件存储在目录中相比。

标签: c# resources .net-2.0


【解决方案1】:

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

【讨论】:

  • 你确定吗?我可以添加新图像,它们会显示在资源部分。我只是不能使用它们,因为我在运行时不知道标识符。如果我以某种方式枚举可用资源列表,我可能也可以使用它们。
【解决方案2】:

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

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

【讨论】:

  • 哎呀..我真傻,没有注意到 /WIn32res 标志。我会试一试。谢谢。
  • 可以将lpData 设为byte[] 而不是IntPtr 会造成任何麻烦吗?在生产代码中这样做是否安全?
  • @Zuck - 是的,你可以,这取决于你输入的内容。
  • 谢谢,您知道是否可以传递lpType 字符串并更新现有位图或图标?我尝试使用lpType 作为"#2", "BITMAP", "RT_BITMAP" 等更新文件中的位图,但它没有更新位图,而是创建了一个名为"#2", "BITMAP", "RT_BITMAP" 的新资源类型,并在其下添加了新资源。我必须重载lpType 以输入IntPtr,然后将其传递给new IntPtr(2) 以进行当前更新。
  • @Zuck - 你应该问一个完整的问题
【解决方案3】:

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

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

您不使用内容是否有原因?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-22
    • 2020-12-18
    • 1970-01-01
    • 1970-01-01
    • 2020-02-12
    • 1970-01-01
    相关资源
    最近更新 更多