Добавить dll в ресурсы

Обновлено: 30.06.2024

Появление в палитре компонентов Borland C++ Builder компонента TCppWebBrowser и компонента TWebBrowser в палитре компонентов Borland Delphi открыло для программистов этих двух сред возможности использования функциональности Internet Explorer'а в прикладных программах. В совокупности со средствами HTML-редакторов, TCppWebBrowser (TWebBrowser) позволяет с легкостью создавать автономные продукты, базируемые на технологии Web-дизайна, отличающиеся не только быстротой и качественностью написания, но и современным интерфейсом. Однако, самым неприятным фактом в использовании данного компонента при написании локального программного продукта, каковым могут быть, например, мультимедийная энциклопедия либо интерактивный учебник, является необходимость наличия отображаемых HTML-страниц, являющихся частью самой программы. Явное их присутствие в открытом виде на дистрибутивах или в уже установленном состоянии на жестких дисках вызывает непреодолимое желание любознательного пользователя заняться их самостоятельным редактированием и некоторое чувство незаконченности процесса создания продукта у самого программиста. Самыми простым и легким способом решения подобной проблемы является помещение служебной информации программы (Web-страниц) в ресурсы DLL.

Широко известен тот факт, что интерфейс Windows насквозь пропитан окнами отображения, аналогичными по функциональности окну, находящемуся в клиентской области Internet Explorer. Тем не менее, в открытом виде это явление практически незаметно глазу обычного пользователя. И уж совсем немногие знают, что некоторые элементы панели управления Windows напрямую выполнены в виде Web-страниц. В частности, элемент панели управления под названием "Установка и удаление программ" исполняется именно в таком виде, начиная с версий Windows ME и Windows 2000. Возникает вполне закономерный вопрос: где же Windows хранит содержимое этих страниц?

Скрупулезное исследование системного каталога даёт ответ на данный вопрос. Web-страницы, используемые интерфейсом Windows, хранятся в виде обычных ресурсов библиотек DLL. К примеру, попытка установления связи в Internet Explorer с недоступным адресом приводит к отображению в окне IE страницы, содержащей соответствующую информацию. Данная страница представлена ресурсом DNSERROR.HTM файла shdoclc.dll, убедиться в чем можно при помощи любого редактора ресурсов (Resource Workshop, Resource Scrutator и т.п.). Таким образом, становится очевидным, что Internet Explorer (а, следовательно, TCppWebBrowser и TWebBrowser аналогично) имеет возможность использования ресурсов, содержащихся в библиотеках DLL.

В прилагаемых к статье архивах содержится весь описанный в ней инструментарий и пример готовой DataBank.dll.

Архив Initial.zip содержит промежуточный объектный файл DataBank.obj будущей библиотеки, файл сценария ресурсов DataBank.rc и компилируемый из него двоичный файл ресурсов DataBank.res. Кроме того, в данный архив включены файлы, непосредственно помещаемые в качестве ресурсов в библиотеку: Header.jpg, Return.jpg, Back.jpg, Index.htm, Mainpage.htm, Page.htm и Top.htm.

Архив Tools.zip содержит весь инструментарий, необходимый для компиляции и линковки библиотеки DLL. В него входят компилятор ресурсов BRCC32.EXE, линкер ILINK32.EXE, необходимые для их корректной работы файлы UUID.LIB, LNKDFM60.DLL, RLINK32.DLL, RW32CORE.DLL, а также пакетный файл BuildAll.bat, содержащий командные строки для работы с компилятором ресурсов и линкером. Данный инструментарий в обязательно должен входить в поставки Borland C++ Builder и Borland Delphi любых версий, но, возможно, с именами, отличными от имен прилагаемых в архивах файлов.

Архив Results.zip содержит конечный результат работы - библиотеку ресурсов DataBank.dll. Кроме этого, в данный архив включен файл URL.txt с примером адреса головной страницы ресурса данной библиотеки для Internet Explorer , с учетом того, что DataBank.dll предположительно расположен в директории C:\IEnDLL.

Архив DllSymChanger.zip содержит созданную мной программу DllSymChanger.exe, облегчающую процесс замены символов, необходимый для функционирования библиотеки DLL.

Содержимое архивов автономно от наличия или отсутствия на компьютере пользователя установленных версий BCB и Delphi, его работа проверена на машине с абсолютно "свежей" Windows 98 SE.

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

В процессе создания исполняемого файла для среды Windows, файлы с исходными текстами приложения компилируются в объектные модули OBJ. Затем редактор связей собирает из объектных модулей промежуточный вариант загрузочного модуля, не содержащий ресурсов. При этом используется файл определения модуля DEF. Текстовый файл сценария ресурсов RC и файлы, непосредственно содержащие требуемые ресурсы, компилируются в двоичный файл RES. На последней стадии формирования загрузочного модуля, его промежуточный вариант собирается с файлом ресурсов для получения окончательного исполняемого файла. Следовательно, для создания DLL ресурсов нам потребуется пройти все эти стадии. Но, чтобы облегчить задачу и всегда пропускать (по нескольким причинам) в будущем первый этап, я самостоятельно создал требуемый объектный файл будущей библиотеки. Сделано это было следующим образом: в BCB6 создаем новый проект DLL, отключаем в мастере создания возможность использования VCL, отключаем в опциях проекта использование пакеджей времени выполнения и использование RTL, и собираем (строим) проект. Из всего, что было создано BCB в каталоге проекта, нас интересует единственный файл. В прилагаемом архиве Initial.zip этот файл носит название DataBank.obj, который, собственно, и являлся бы результатом выполнения первых двух этапов действий, необходимых для создания требуемой DLL. (В случае, если у читателя возникнет желание самостоятельно проверить целесообразность предложенного мной подхода, он может самостоятельно написать текст программы, текст заголовочного файла программы, текст DEF-файла, скопировать в каталог примера H- и LIB-файлы, необходимые для компиляции, и, непосредственно, компилятор кода BCC32.EXE). Название OBJ-файла не имеет никакого значения, так как в дальнейшем из этого файла будет образован конечный файл библиотеки ресурсов с тем именем, которое пользователь может назначить либо при сборке, либо просто переименовать созданный им файл DLL (тем более, что в теле этой библиотеки ее имя нигде не присутствует).

На следующем этапе нам необходимо получить компилированный файл ресурсов, которые будут включены в нашу DLL. Для этого необходимы непосредственно сами ресурсы (HTM-страницы) и файл сценария ресурсов (в нашем случае он носит имя DataBank.rc).

В прилагаемом архиве Initial.zip в виде примера рассмотрено создание DLL с размещенными внутри связанными Web-страницами. Файлы, представляющие эти страницы, носят следующие имена: Index.htm, Mainpage.htm, Page.htm, Top.htm, Header.jpg, Return.jpg, Back.jpg. Далее следуют три необходимых требования, предъявляемых для правильного функционирования IE внутри создаваемой DLL:

Все файлы, участвующие в работе Web-страниц должны находиться в одной директории; Все ссылки в Web-страницах должны быть относительными; Имя ни одного из файлов, используемых в Web-страницах, не должно содержать символов подчеркивания. Имена файлов должны состоять из набора символов A…Z и 0…9. Имена файлов не должны начинаться с цифр. При несоблюдении первого требования, пользователь просто не сможет разместить файлы внутри DLL в соответствии с их начальным положением. Следовательно, в ссылках HTM-документов изначально будут указаны несуществующие объекты.

При несоблюдении второго требования (при использовании абсолютных ссылок), IE будет пытаться отыскать указанные объекты с использованием абсолютного адреса (в данном случае - пути расположения файла), что в корне неверно. Впрочем, использование относительных ссылок само по себе является нормальной практикой Web-программирования.

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

Expecting resource name or resource type name

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

Вторым элементом строки описания ресурса является имя типа ресурса. Если мы будем применять для назначения нашим ресурсам предопределенный произвольный тип RCDATA, компиляция и сборка DLL пройдут, ресурсы будет корректно вызываться из библиотеки любыми прикладными программами как ресурсы, но IE откажется обрабатывать их таким образом, как нам необходимо. Точно то же самое произойдет, если мы присвоим ресурсам страниц любой другой произвольный тип. То есть, у меня существовала определенная надежда, что IE будет рассматривать типы сгруппированных ресурсов как своеобразные поддиректории, что было бы совсем неплохо для систематизации иерархии взаимосвязей между логическими группами страниц, но разработчики IE, видимо, придерживаются иного мнения на этот счет. Таким образом, если мы присвоим типу ресурса имя, например, PAGEAREA или какое-либо другое, включая и RCDATA, после завершающей обработки библиотеки IE все равно откажется воспринимать Web-страницы в виде Web-страниц. Решение в этой тупиковой ситуации подсказывает изучение структуры системой библиотеки shdoclc.dll. Все страницы, расположенные в его ресурсах, принадлежат двум типам, имена которых являются не строковыми, а целочисленными идентификаторами. Для задания целочисленных типов ресурсов, в строке файла сценария ресурсов необходимо целочисленные значения идентификаторов заключить в круглые скобки. В противном случае, компилятор ресурсов воспримет их как строковые идентификаторы.

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

В конечном виде строка, описывающая присоединение страницы index.htm к ресурсам будущей библиотеки, выглядит так:

index_htm (23) index.htm

После того, как создан файл сценария ресурсов, необходимо провести его компиляцию. Для этого воспользуемся компилятором ресурсов командной строки BRCC32.EXE, входящим в состав BCB6. Взглянув на название файла компилятора, видим, что результатом его работы станет 32-разрядный двоичный файл ресурсов (по крайней мере, если не использовать дополнительных опций командной строки). Теоретически, можно воспользоваться различными 16-разрядными компиляторами (RC.EXE, BRCC.EXE и т.п.) и мы достигнем намеченного результата, но, так как далее нами будет использоваться 32-разрядный линкер, рекомендую пользоваться именно 32-разрядным компилятором ресурсов. Запуск компилятора ресурсов производится из командной строки, которая включает в себя непосредственно имя файла компилятора ресурсов и имя файла сценария ресурсов:

brcc32 DataBank.rc

Следующим шагом в создании DLL является сборка библиотеки из объектного файла DataBank.obj и двоичного файла ресурсов DataBank.res. Для этой цели воспользуемся линкером ILINK32.EXE, вызывающий в свою очередь библиотеки RLINK32.DLL и LNKDFM60.DLL и использующий файл UUID.LIB. Командная строка вызова линкера с параметрами выглядит следующим образом:

ilink32 DataBank.obj, DataBank.dll, , , , DataBank.res

Будьте внимательны и не ошибитесь с количеством запятых при наборе командной строки. Мы видим, что в командной строке указано имя объектного файла, имя двоичного файла ресурсов и конечное имя библиотеки. Если в качестве создаваемого модуля указать не DataBank.dll, а, например, MMedia.dll, то именно MMedia.dll и будет создан. В процессе сборки выводится строка с названием линкера и строка с указанием принадлежности авторских прав на него. Кроме того, при компиляции именно с этим комплектом служебных файлов, будет выводиться следующее предупреждение:

Warning: Image linked as an executable, but with a .DLL or .BPL extension

Это связано с отсутствием DEF-файла, но, тем не менее, на корректность содержимого библиотеки не влияет. В процессе сборки линкером будут созданы файлы с именем результирующего модуля и расширениями TDS, MAP, ILC, ILD, ILF, ILS которые можно безболезненно удалить.

Библиотека с ресурсами Web-элементов создана.

Предположим, что DataBank.dll имеет следующий путь:

C:\IEnDLL\DataBank.dll

Если мы запустим IE и в строке URL введем

res://C:\IEnDLL\DataBank.dll/INDEX_HTM

Internet Explorer найдет ресурс INDEX_HTM расположенный в DataBank.dll, но не сможет правильно определить ожидаемых от него действий, поскольку имя идентификатора ресурса воспринимается IE как имя файла без расширения.

На этом этапе работа по созданию DLL принимает "шаманский" оборот. Мы сталкиваемся с ситуацией, когда Internet Explorer отказывается корректно воспринимать ресурс без "расширения", а компилятор ресурсов отказывается включать в идентификатор ресурса символ точки. Теперь необходимо вооружиться каким-либо Bin-редактором и "руками" аккуратно заменить символы подчеркивания в заголовке библиотеки точками, не изменяя размера файла. Для этого подходит любой Bin-редактор (UltraEdit, WinHex и т.п.), но я лично воспользовался FAR "по F4". Искать строку "INDEX_HTM" в файле бесполезно, так как еще на этапе компиляции двоичного файла ресурсов из-за его 32-разрядной природы между каждой парой символов идентификатора были помещены символы со значением 0x00. Заменив в заголовке библиотеки соответствующие символы подчеркивания точками и сохранив файл, получаем именно такую DLL, ради которой и были предприняты все вышеперечисленные действия. Для облегчения этого процесса в прилагаемый архив DllSymChanger.zip помещена написанная мной программа DllSymChanger.exe, открывающая файл RC и производящая замены символов подчеркивания точками в одноименном файле DLL, находящемся в той же директории.

Теперь осталось запустить IE и в строке URL ввести

res://C:\IEnDLL\DataBank.dll/INDEX.HTM

Основная задача выполнена полностью.

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

Таким образом, при создании DLL можно использовать любые Web-объекты, интерпретируемые IE (звук, видео, VRML и т.д.).

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

В библиотеке DLL, содержащей только ресурсы, нет ничего, кроме ресурсов, таких как значки, растровые изображения, строки и диалоговые окна. Библиотеки DLL, содержащие только ресурсы, удобно использовать, когда необходимо предоставить нескольким программам общий доступ к одному и тому же набору ресурсов. С их помощью можно также легко предоставлять приложение с ресурсами, локализованными для нескольких языков. Дополнительные сведения см. в разделе Локализованные ресурсы в приложениях MFC: вспомогательные библиотеки DLL.

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

Чтобы создать библиотеку DLL, содержащую только ресурсы, создайте новый проект Windows DLL (не MFC) и добавьте в него свои ресурсы.

Выберите Проект Win32 в диалоговом окне Создание проекта. Введите имена проекта и решения, а затем нажмите кнопку ОК.

Создайте новый скрипт ресурсов, содержащий ресурсы для этой библиотеки DLL (такие как строка или меню). Сохраните файл .rc .

В меню Проект выберите Добавить существующий элемент, а затем вставьте в проект новый файл .rc .

Укажите параметр компоновщика /NOENTRY. Параметр /NOENTRY запрещает компоновщику привязывать ссылку на _main к библиотеке DLL, поэтому его необходимо указывать при создании библиотеки DLL, содержащей только ресурсы.

Построение библиотеки DLL.

В диалоговом окне Создание проекта выберите Мастер классических приложений Windows и нажмите кнопку Далее. На странице Настройка нового проекта введите имена проекта и решения, а затем нажмите кнопку Создать.

Создайте новый скрипт ресурсов, содержащий ресурсы для этой библиотеки DLL (такие как строка или меню). Сохраните файл .rc .

В меню Проект выберите Добавить существующий элемент, а затем вставьте в проект новый файл .rc .

Укажите параметр компоновщика /NOENTRY. Параметр /NOENTRY запрещает компоновщику привязывать ссылку на _main к библиотеке DLL, поэтому его необходимо указывать при создании библиотеки DLL, содержащей только ресурсы.

Построение библиотеки DLL.

Использование библиотеки DLL, содержащей только ресурсы

Приложение, которое использует библиотеку DLL, содержащую только ресурсы, должно вызывать LoadLibraryEx или связанную функцию, чтобы явно привязать эту библиотеку DLL. Для доступа к ресурсам следует вызывать универсальные функции FindResource и LoadResource , которые работают с ресурсами любого типа. Для доступа к конкретному ресурсу можно также использовать вызов одной из следующих функций:

Создание и использование только ресурсов в DLL

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

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

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

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

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

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

  1. Создайте RC файл, описывающий ресурсы, которые Вы хотите поместить в DLL. Как в примере: (adpdllresources - имя RC файла ASCII) - один ICON и один GIF добавлен в RC файл:
  2. Скомпилируйте RCфайл в RES файл при помощи компилятора ресурсов BRCC32
  3. Создайте проект пустой DLL. Сохраните его как adpResources.dpr - после компиляции DLL будет иметь имя adpResources.dll. Полный код проекта DLL будет иметь всего четыре строки в одном файле.
  4. Откомпилируйте Ваш DLL (убедитесь, что adpdllresources.res находится в том же каталоге, что и проект DLL

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

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

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

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

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

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

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

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

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

Я первоначально планировалось сделать это путем написания кода, чтобы поместить стороннюю DLL в место, указанное System.Reflection.Assembly.GetExecutingAssembly().Location.ToString() минус последний /nameOfMyAssembly.dll . Я могу успешно сохранить третью сторону .DLL в этом месте (где заканчивается

C:Documents и настройкиmyUserNameлокальные настройкиприложение Данныесборкаdl3KXPPAX6Y.ZCYA1MZ1499.\E0115d44 91bb86eb_fe18c901 в 1TR

), но когда я добираюсь до части моего кода, требующей этой DLL, он не может найти оно.

кто-нибудь имеет представление о том, что мне нужно делать по-другому?

в конце концов я сделал это почти точно так, как предложил raboof (и похоже на то, что предложил dgvid), за исключением некоторых незначительных изменений и некоторых упущений. Я выбрал этот метод, потому что он был ближе всего к тому, что я искал в первую очередь и не требовал использования каких-либо сторонних исполняемых файлов и т. д. Он отлично работает!

вот как выглядел мой код:

EDIT: я решил переместить эту функцию в другую сборку, чтобы я мог повторно использовать ее несколько файлов (я просто передаю в сборке.GetExecutingAssembly()).

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

embeddedResourcePrefix-это строковый путь к встроенному ресурсу, обычно это имя сборки, за которым следует любая структура папок, содержащая ресурс (например, "MyComapny.MyProduct.Моя сборка.Ресурсы", если библиотека dll находится в папке Resources в проекте). Он также предполагает, что библиотека имеет .файл DLL.расширение ресурсов.

mbarnett / ILMerge. aspx

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

Установить Путь="C:\Program Файлы\Microsoft\ILMerge"

ilmerge /out:$(ProjectDir)\Deploy\LevelEditor.exe $(ProjectDir)\bin\Release\release.exe $(ProjectDir)\bin\Release\InteractLib.dll $(ProjectDir)\bin\Release\SpriteLib.файл DLL $(ProjectDir)\bin\Release\LevelLibrary.dll

вы можете достичь этого удивительно легко с помощью Netz, а .чистый исполняемые файлы компрессора и Пакер.

вместо записи сборки на диск вы можете попробовать сделать сборку.Загрузите (byte[] rawAssembly), где вы создаете rawAssembly из внедренного ресурса.

Читайте также: