Обновление изображений в разделе ресурсов exe (в c # / C) - PullRequest
8 голосов
/ 19 февраля 2012

У меня есть несколько изображений, встроенных в мой исполняемый файл в разделе ресурсов. Я выполнил следующие шаги, чтобы создать свой исполняемый файл:

  1. Создан файл .resx для всех изображений (.jpg) в каталоге с использованием некоторой утилиты. Изображения называются image1.jpg, image2.jpg и т. Д.
  2. создан файл .resources из файла .resx, используя: resgen myResource.resx
  3. Встроенный сгенерированный файл .resource с использованием флага / res в виде: 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

Спасибо,

Викрам

Ответы [ 3 ]

8 голосов
/ 25 февраля 2012

Я думаю, вы путаете ресурсы .NET и ресурсы Win32.Ресурсы, которые вы добавляете для встраивания с аргументом /res в csc.exe, - это ресурсы .NET, которые вы можете успешно прочитать, используя ваш ResourceManager код фрагмента.

Ресурсы Win32 - еще один зверь, который не очень "совместим""в управляемом мире .NET в целом, хотя вы действительно можете добавить их в .NET exe с помощью аргумента /win32Res - обратите внимание на небольшую разницу: -)

Теперь, если вы хотите изменить встроенный.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);
        }
    }
1 голос
/ 19 февраля 2012

Это невозможно. Вы не можете изменить скомпилированный файл, который вы используете.

0 голосов
/ 28 февраля 2012

Я полагаю, что вы можете добавлять новые изображения во время выполнения, но не можете обновить ресурс, который по сути просто хранится в памяти.

Если вы добавляете ресурс во время выполнения, он существует, но я недумаю, что он скомпилирован, и поэтому я не думаю, что он доступен для вас.

Есть ли причина, по которой вы не используете контент вместо этого?

...