Консольный редактор ресурсов: редактирование ресурсов в EXE DLL файлах. Ресурсные dll – все в одном месте

Кроме хранения ресурсов внутри.EXE файла, разработчик Delphi может также создать динамическую библиотеку, содержащую только ресурсы. Давайте посмотрим, как это сделать.

Ресурсы могут быть стандартные и определенные пользователем. Данные в стандартном ресурсе описывают иконку, курсор, меню, диалоговое окно, точечный рисунок, расширенный метафайл, шрифт, таблицу горячих клавиш, строки и версию. Определенный пользователем ресурс может содержать любые данные, требуемые приложением (другой.EXE, GIF, MP3 и т.д.).

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

Создание DLL с ресурсами

Чтобы сделать DLL только с ресурсами, нужно создать и скомпилировать проект пустой DLL , которая содержит ссылки на файл ресурсов .RES , который содержит Ваши ресурсы.

Затем выполнить следующие шаги:

  1. Создайте RC файл, описывающий ресурсы, которые Вы хотите поместить в DLL . Как в примере: (adpdllresources - имя RC файла ASCII ) - один ICON и один GIF добавлен в RC файл:
  2. adpdllresources.rc aboutlogo RCDATA aboutlogo.gif factory ICON FACTORY.ICO
  3. Скомпилируйте RC файл в RES файл при помощи компилятора ресурсов BRCC32
  4. Создайте проект пустой DLL . Сохраните его как adpResources.dpr - после компиляции DLL будет иметь имя adpResources.dll . Полный код проекта DLL будет иметь всего четыре строки в одном файле.
  5. library adpResources; {$R adpdllresources.RES} begin end.
  6. Откомпилируйте Ваш DLL (убедитесь, что adpdllresources.res находится в том же каталоге, что и проект DLL

Как только DLL с ресурсами будет создан, Вы можете использовать его внутри Ваших приложений Delphi. Обратите внимание, что эти ресурсы внутри DLL может использовать любое приложение (не обязательно Delphi).

Как использовать ресурсы из DLL

Чтобы использовать ресурсы из динамической библиотеки, просто загрузите DLL и ресурсы, которые Вы хотите использовать.

Следуйте этим шагам:

  1. Создайте новый проект Delphi. По умолчанию, Delphi добавляет одну форму к проекту. Сохраните проект
  2. Скопируйте DLL с ресурсами (adpResources.dll в папку, где Ваше новое приложение было сохранено
  3. Загрузите ресурс, как показано ниже...

Пример, как загрузить иконку factory и нарисовать ее на холсте Form1 , когда Button1: TButton была нажата).

Procedure TForm1.Button1Click(Sender: TObject); const resICON = "factory"; var h: THandle; Icon: HIcon; begin h:= LoadLibrary("adpResources.DLL"); try if h 0 then begin Icon:= LoadIcon(h, resICON); DrawIcon(Canvas.Handle, 10, 10, Icon); end else begin ShowMessage("Load Resource DLL FAILED!"); end; finally FreeLibrary(h); end; end;

Если Вы добавите поддержку GIF , Вы можете использовать изображение GIF , хранимое в ресурсном DLL , а также его рисовать:

Procedure TForm1.Button2Click(Sender: TObject); const resGIF = "aboutlogo"; var h: THandle; gif: TGifImage; r:TRect; begin h:= LoadLibrary("adpResources.DLL"); try if h 0 then begin gif:= TGIFImage.Create; try gif.LoadFromResourceName(h,resGIF); gif.Paint(Canvas, Form1.ClientRect, ); finally gif.Free; end; end else begin ShowMessage("Load Resource DLL FAILED!"); end; finally FreeLibrary(h); end; end;

Создание DLL, содержащей одни лишь ресурсы

Файл ресурсов надо скомпилировать - "rc MyResDll.rc" - и преобразовать линкером в DLL, обязательно указав флаг "/NOENTRY", т. к. эта динамическая библиотека содержит исключительно одни ресурсы и ни строки кода: "link MyRedDll.res /DLL /NOENTRY".

В Visual Studio это сделать еще проще - достаточно кликнуть по папке "Resourses" окна "File View" и добавить новый файл ресурса, который затем можно будет модифицировать визуальным редактором по своему усмотрению.

Для загрузки ресурса из DLL - в принципе, можно воспользоваться уже знакомой нам функцией LoadLibray, и передавать возращенный ею дескриптор LoadString или другой функции, работающей с ресурсами. Однако загрузку динамической библиотеки можно значительно ускорить, если "объяснить" системе, что эта DLL не содержит ничего, кроме ресурсов, и нам достаточно лишь спроецировать ее на адресное пространство процесса, а обо всем остальном мы сумеем позаботиться и самостоятельно.

Вот тут-то и пригодится функция LoadLibraryEx: ее первый аргумент, как и у коллеги LoadLibrary, задает имя динамической библиотеки для загрузки, второй - зарезервирован и должен быть равен нулю, а третий, будучи равным LOAD_LIBRARY_AS_DATAFILE, заставляет функцию делать именно то, что нам нужно - загружать DLL как базу данных (если динамическая библиотека содержит помимо ресурсов еще и код, то загрузка с этим ключом проходит все равно успешно, но функции загруженной DLL не будут доступны - только ресурсы):

#include

#include

h=LoadLibraryEx("MyResDll.dll",0,

LOAD_LIBRARY_AS_DATAFILE);

LoadString(h,1,&buf,99);

printf("%s\n",&buf);

Демонстрация оптимизированной загрузки DLL, не содержащей ничего кроме ресурсов

Эта программа компилируются точно так же, как и предыдущие примеры явной компоновки - и после запуска победно выводит на экране "Hello, Word!", подтверждая, что ресурс "строка" из динамической библиотеки был успешно загружен! Аналогичным способом можно загружать ресурсы из исполняемых файлов; с этой точки зрения они ничем не отличаются от динамических библиотек.

ООП и DLL

#include "stdafx.h"

DWORD ul_reason_for_call,

LPVOID lpReserved

//Наш код.

//Добавляем функцию Add.

if(a>b) res = a; else res = b;

Мастер нам сделал заготовку для нашей dll. Будем развивать ее. Для этого добавим 1 функцию и один класс с методом. Вот код:

#include "stdafx.h"

BOOL APIENTRY DllMain(HANDLE hModule,

DWORD ul_reason_for_call,

LPVOID lpReserved

//Наш код.

//Добавляем функцию Add.

Declspec(dllexport) int Add(int a, int b)

//Добавляем класс MyClass с методом MyMax.

Declspec(dllexport) int MyMax(int a, int b){

if(a>b) res = a; else res = b;

Обратите внимание, что добавляемы функции и методы, которые мы хотим вызывать извне, вы пишем с модификатором __declspec(dllexport). Таким образом мы помечаем так называемые экспортируемые функции.

Компилируем программу. В папке debug проекта должен появится файл firstdll.dll.

Теперь пишем тестовую программу.

#include

//Подключаем необходимый заголовочный файл.

#include "..\firstdll.cpp"

cout<

cout<

Запускаем программу. Как и следовало ожидать, она выведет 22 и 11.

Функция DllMain

Большинство библиотек DLL - просто коллекции практически независимых друг от друга функций, экспортируемых в приложения и используемых в них. Кроме функций, предназначенных для экспортирования, в каждой библиотеке DLL есть функция DllMain. Эта функция предназначена для инициализации и очистки DLL. Она пришла на смену функциям LibMain и WEP, применявшимся в предыдущих версиях Windows. Структура простейшей функции DllMain может выглядеть, например, так:

BOOL WINAPI DllMain (HANDLE hInst,DWORD dwReason, LPVOID IpReserved) {

BOOL bAllWentWell=TRUE;

switch (dwReason) {

case DLL_PROCESS_ATTACH: // Инициализация процесса.

case DLL_THREAD_ATTACH: // Инициализация потока.

case DLL_THREAD_DETACH: // Очистка структур потока.

case DLL_PROCESS_DETACH: // Очистка структур процесса.

if(bAllWentWell) return TRUE;

else return FALSE;

Функция DllMain вызывается в нескольких случаях. Причина ее вызова определяется параметром dwReason, который может принимать одно из следующих значений.

При первой загрузке библиотеки DLL процессом вызывается функция DllMain с dwReason, равным DLL_PROCESS_ATTACH. Каждый раз при создании процессом нового потока DllMain вызывается с dwReason, равным DLL_THREAD_ATTACH (кроме первого потока, потому что в этом случае dwReason равен DLL_PROCESS_ATTACH).

По окончании работы процесса с DLL функция DllMain вызывается с параметром dwReason, равным DLL_PROCESS_DETACH. При уничтожении потока (кроме первого) dwReason будет равен DLL_THREAD_DETACH.

Все операции по инициализации и очистке для процессов и потоков, в которых нуждается DLL, необходимо выполнять на основании значения dwReason, как было показано в предыдущем примере. Инициализация процессов обычно ограничивается выделением ресурсов, совместно используемых потоками, в частности загрузкой разделяемых файлов и инициализацией библиотек. Инициализация потоков применяется для настройки режимов, свойственных только данному потоку, например для инициализации локальной памяти.

В состав DLL могут входить ресурсы, не принадлежащие вызывающему эту библиотеку приложению. Если функции DLL работают с ресурсами DLL, было бы, очевидно, полезно сохранить где-нибудь в укромном месте дескриптор hInst и использовать его при загрузке ресурсов из DLL. Указатель IpReserved зарезервирован для внутреннего использования Windows. Следовательно, приложение не должно претендовать на него. Можно лишь проверить его значение. Если библиотека DLL была загружена динамически, оно будет равно NULL. При статической загрузке этот указатель будет ненулевым.

В случае успешного завершения функция DllMain должна возвращать TRUE. В случае возникновения ошибки возвращается FALSE, и дальнейшие действия прекращаются.

Замечание. Если не написать собственной функции DllMain(), компилятор подключит стандартную версию, которая просто возвращает TRUE.

Пример проблемы:

HANDLE hThread; DWORD dwThreadId;

switch (fdwReason)

case DLL_PROCESS_ATTACH:

// DLL проецируется на адресное пространство процесса

// создаем поток для выполнения какой-то работы

hThread = CreateThread(NULL, 0, SomeFunction, NULL, 0, &dwThreadId);

// задерживаем наш поток до завершения нового потока

WaitForSingleObject(hThread, INFINITE);

// доступ к новому потоку больше не нужен

CloseHandle(hThread);

case DLL_THREAD_ATTACH:

// создается еще один поток

case DLL_THREAD_DETACH:

// поток завершается корректно

case DLL_PROCESS_DETACH:

// DLL выгружается из адресного пространства процесса

Функции точки входа должно выполнять только простые задачи инициализации. Они не должны вызвать функцию LoadLibrary или LoadLibraryEx (или функцию, которая вызывает эти функции), потому что это может создать циклы взаимозависимости в порядке загрузки DLL. Это может стать результатом того, что DLL начнет использоваться прежде, чем система выполнит код ее инициализации. Точно так же функция точки входа не должна вызвать функцию FreeLibrary (или функцию, которая ее вызывает), потому что это может привести к тому, что DLL начнет использоваться после того, как система выполнила код завершения ее работы.

Пример от Microsoft. Пошаговое руководство. Создание и использование библиотеки DLL (C++) Visual Studio 2013

В этом пошаговом руководстве описывается создание библиотеки динамической компоновки (DLL) для использования с C++ приложением. Использование библиотеки - хороший способ повторного использования кода. Вместо повторной реализации одних и тех же процедур в каждой программе, вы создаете их один раз и затем ссылаетесь на них из других приложений. Поместив код в библиотеке DLL, вы сэкономите место в каждом приложении, которое ссылается на этод код, а так же сможете обновлять DLL без перекомпиляции всех приложений. Дополнительные сведения о библиотеках DLL см. в разделе DLL в Visual C++.

Cоздание файла dll

Очень часто в своей работе, Вы будете сталкиваться с такой ситуацией.

Перед вами стоит задача, нужно написать программу "Супер Блокнот" которая должна сохранить все функции стандартного блокнота, но при этом иметь ряд каких-то дополнительных функций, благодаря которым, при выборе программы для работы с текстом, пользователь будет отдавать предпочтение именно вашей программе. Для этого было решено добавить несколько новых функций, одна из них, будет отвечать за подсчет и вывод количества слов в тексте.

Через пару недель программа была написана, затем она попала в Интернет, пользователи оценили новый продукт и стали им пользоваться. Цель достигнута.

Проходит время и перед вами ставят новую задачу, написать программу "Супер парсер ". Одной из функции данной программы, будет подсчет слов в тексте. Вы понимаете, что снова придется разрабатывать метод, который будет вести подсчёт слов. Но, при этом вспоминаете, что совсем не давно уже разрабатывали программу, в которой применялась данная функция. Чтобы не изобретать велосипед, Вы открываете исходник программы "Супер блокнот "; и копируете весь метод в исходник новой программы "Супер парсер ". Отлично, теперь Вам не придется тратить время на написание этого метода заново, и Вы можете посветить больше времени остальным элементам программы. Задача решена.

Но, что если метод по подсчету слов, писали не Вы, а допустим, какой-нибудь коллега по работе и по каким-то причинам, Вы не можете получить доступ к исходному коду программы "Супер блокнот ". То есть первый вариант, копирование метода из исходника, не прокатит и данный метод придется писать самому ммм, печалька.

Но, тут вам звонит ваш коллега по работе и говорит: Ты знаешь, я тут вспомнил, когда я разрабатывал данный метод, я подумал, что возможно мне придется его использовать ещё где-то, и по этому я решил вынести его в отдельную сборку, в виде файла динамической библиотеки (dll).Ты просто скопируй этот файл dll в свой проект, и подключи его, как внешнюю сборку, после чего ты получишь доступ к моему методу и сможешь им пользоваться.

Отлично! Вы проделываете все описанные действия, в программе “Супер парсер ” появляется нужный метод, задача решена и вам вновь не пришлось повторно писать код руками.

На этом присказка закончена и теперь переходим к более подробному изучению.

Что такое DLL

DLL (dynamic-link library) - это динамически подключаемая библиотека, или сокращено динамическая библиотека.

Как уже писал ранее, динамические библиотеки, позволяют повторно использовать ранее написанный код, а так же они обеспечивают лучшую переносимость кода. Достаточно, скинуть файл на флешку, или скачать dll файл из Интернета, после чего добавить его в текущий проект и тут же получить набор разных дополнительных функций для вашего приложения. Так же стоит знать, что в одном dll файле может храниться любое количество типов, членов и пространств имён.

Создание файла dll

Для начала выберем тип нового создаваемого приложения, а точнее проекта.

Выбираем Class Library , то есть создаем файл динамической библиотеки (dll)

Так же Вы можете указать, под какую версию Фреймворка будет создаваться данный проект.

После того, как Visual Studio создаст каркас проекта, Вы увидите следующее:

Так будет выглядеть окно Solution Explorer

А так будет выглядеть рабочая область, где Вы обычно пишите код программы

И так дано пространство имён: Car и класс: Class1. Class1 не удачное название, давайте немного изменим наш код, заменив Class1 на BMW, и добавим метод, который будет выводить имя нашего класса.

И так код написан, и теперь необходимо выполнить компиляцию, чтобы получить сборку.
Если сейчас попытаться нажать F5 или Ctrl+F5, то вы увидите данное окно


Данная ошибка, говорит лишь о том, что был создан файл динамической библиотеки (dll ), а не исполняемый файл (exe), который не может быть запущен.

Для того, чтобы скомпилировать проект, нажмите клавишу F6, после чего в директории bin\Debug появиться файл Car.dll.

Чтобы проверить был ли создан файл библиотеки, воспользуйтесь кнопкой Show All Files на вкладке Solution Explorer

Сборка, в виде файла динамической библиотеки успешно создана.

Теперь перейдем в папку bin\Debug, для того, чтобы быстро переместиться в текущую директорию проекта, в том же Solution Explorer воспользуйтесь пунктом Open Folder in Windows Explorer

Скопируйте полученный файл сборки (в нашем случае - это файл Car.dll) в какую-нибудь временную папку. На самом деле, это делать необязательно, Вы можете оставить данный файл в этой папке, но для удобства, создадим новую папку, и поместим туда созданный файл библиотеки.

После чего закроем текущий проект и создадим новый. Но, на этот раз выберем тип проекта — консольное приложение.

Создаем новый проект.

Новый проект создан. Теперь подключим в текущий проект, нашу библиотеку (Car.dll)

Подключение dll

Для этого на папке References , в окне Solution Explorer нужно нажать правую кнопку мыши и выбрать пункт Add Reference, откроется вот такое окно:

  1. Выберите вкладку Browse
  2. Укажите папку, в которой лежит файл созданной библиотеки (в нашем примере - Car.dll)
  3. Выделите файл нужной библиотеки и нажмите кнопку ОК ;
Если всё выполнено, верно, Вы увидите следующую картинку

На ней видно, что в наш текущий проект была успешна, добавлена ссылка на нашу сборку Car.dll, в которой храниться наш код на языке IL. Надеюсь, Вы помните, что после компиляции весь написанный вами код преобразуется в промежуточный код на языке IL (CIL, MSIL - это одно и тоже). А так же видно, что в папку bin\Debug была помещёна копия нашей библиотеки.

Если вдруг Вы забыли, какое пространство имен, типы, или члены содержит ваша созданная библиотека. Вы всегда можете воспользоваться таким инструментом Visual Studio, как Object Browser . Для этого перейдите на вкладку Solution Explorer, откройте папку References, и просто щёлкните правой кнопкой мыши по добавленной ранее библиотеке, в нашем случае напоминаю - это файл (Car.dll) и выберите пункт View in Object Browser , появиться вот такое окно.

В окне Object Browser можно посмотреть содержимое нашей сборки.

Сборка подключена и теперь Вы можете работать с её содержимым. Далее выполним необязательный пункт.

Добавим, с помощью ключевого слова using пространство имен Car из созданной нами библиотеки Car.dll, после чего создадим объект класса BMW и выполним метод Вывести_Имя_Класса().

Результат:

Всё работает.

И так ещё раз по порядку:

  1. Создаем файл динамической библиотеки (dll)
  2. Подключаем созданную библиотеку в наш проект, путем добавления в папку References ссылки на наш файл dll.
  3. (Необязательный пункт) Подключаем пространство имен из подключенной сборки, с помощью ключевого слова using, либо используем полное наименование, то есть Пространство имён.Тип (Car.BMW).
  4. Profit
Эти четыре действия помогут Вам создать библиотеку dll и подключить её к своему проекту.

И в конце не много информации о типах сборок:

Сборки бывают следующих основных видов: общие и частные.

Частная сборка (private assembly)

Это файлы библиотек, как наш ранее созданный файл Car.dll, которые содержаться на протяжении всего времени в каталоге текущего приложения или любом из его подкаталогов.

Вернёмся к началу статьи.

После того, как было создано приложение “Супер парсер”, мы получили сборку в виде файла (exe). Затем мы решили протестировать нашу программу и отдаём её нашему другу, при этом Вы так же упоминаете, что если он хочет иметь дополнительные функции в программе, то ему нужно просто рядом с его exe файлом поместить файл библиотеки Car.dll. После чего он получит возможность подсчёта слов в тексте. То есть библиотека будет храниться в той же директории, что и исполняемый файл.

Общие сборки (shared assembly)

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

К примеру, у нас есть две программы. Которые будет использовать наш файл Car.dll, чтобы не копировать данный файл в каждую папку, мы можем поместить его в специальное место, которое называется Global Assembly Cache — (GAC) или глобальный кэш сборок. Теперь сборка будет храниться в одном специальном месте, и ваши программа всегда будут знать, где можно найти данную библиотеку кода. Если бы мы воспользовались приватным способом, то нам бы пришлось поместить нашу библиотеку, в каждую папку того приложения, с которым она должна взаимодействовать.

Resource Tuner Console (RTC) разработан для решения проблемы, с которой часто сталкиваются разработчики программного обеспечения. Продукт выполняет задачу редактирования ресурсов 32- и 64-битных исполняемых файлов в автоматическом режиме, по заранее написанному сценарию, из командной строки .

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

Редактирование Portable Executable (PE) файлов

  • Работает с 32- и 64-битными PE файлами - такими, как.EXE, .DLL, компилированные файлы ресурсов (.RES), драйвера устройств (.SYS, .ACM), элементы ActiveX (.OCX), библиотеки Borland (.DPL и.BPL), апплеты контрольной панели (.CPL), скринсейверы (.SCR) и другие.
  • Вычисление и коррекция контрольной суммы файла.
  • Изменение адреса Image Base .
  • Автоматический распаковщик UPX .
  • Возможно подключение пользовательских плагинов для обработки файлов при открытии.

Кроме функций редактирования ресурсов, Resource Tuner Console так же содержит ряд методов для изменения структуры PE файлов: обновление контрольной суммы, ребазирование DLL, обновление штампа времени и даты, создание или удаление пустой секции ресурсов.

При помощи Resource Tuner Console вы можете:

  • Добавлять или изменять File Version и Product Version Information
  • Добавлять или заменять Icons и Cursors
  • Добавлять или заменять графические ресурсы (BMP, GIF, JPEG, PNG, AVI)
  • Добавлять, заменять или удалять строковые ресурсы в исполняемых файлах
  • Добавлять или заменять манифест приложения
  • Добавлять секцию ресурсов в файлы, скомпилированные без ресурсов
  • Обрабатывать много файлов одновременно

Редактирование ресурсов по сценарию

Resource Tuner Console получает управление из файла скрипта. Использование сценария в скрипте - это единственный способ, позволяющий с достаточной гибкостью описать всё многообразие возможных операций с ресурсами различных типов и в большом наборе файлов. Сценарий также позволяет повторно использовать одни и те же операции много раз подряд без ошибок и легко адаптируется к изменению условий.

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

  • Resource Tuner Console поддерживает любой установленный активный скриптовый язык, который работает с Windows Scripting Host
  • Resource Tuner Console поддерживает Unicode

Скачайте бесплатную ознакомительную версию!


Resource Tuner Console работает на всех версиях Windows
от Windows 2000 и XP до 7, 8 и 10.

Минимальные системные требования:
Процессор Intel Pentium® или AMD K5 166 MHz
16 MB RAM

Resource Tuner Console не устанавливает никаких дополнительных DLLs или ActiveX в системные папки Windows. Единственные папки, куда инсталлятор помещает файлы - это папка программы и специальная папка Windows для Application Data.

В состав Resource Tuner Console входят примеры, объясняющие основную функциональность программы и демонстрирующие самые популярные возможности. Ознакомьтесь с библиотекой скриптов , чтобы получить представление о том, как Resource Tuner Console может вам помочь.