Сохранение и выдёргивание ресурсов в DLL или EXE

{codecitation class=»brush: pascal; gutter: false;» width=»600px»}

В трамвае:

— Девушка! А девушка! А вы наверно программистка?

— Да, но как вы догадались?!!

— У вас очень глупое лицо!

— ДУРАК!!!

— Да, я тоже программист…

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

Далее рассмотрим, как создать файл ресурсов, содержащий корию какого-либо файла. После создания такого файла его можно легко прицепить к Вашему проекту директивой {$R}. Файл ресурсов, который мы будем создавать имеет следующий формат:

заголовок

заголовок для нашего RCDATA ресурса

собственно данные — RCDATA ресурс

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

Заголовок ресурса выглядит следующим образом:

TResHeader = record

DataSize: DWORD; // размер данных

HeaderSize: DWORD; // размер этой записи

ResType: DWORD; // нижнее слово = $FFFF => ordinal

ResId: DWORD; // нижнее слово = $FFFF => ordinal

DataVersion: DWORD; // *

MemoryFlags: WORD;

LanguageId: WORD; // *

Version: DWORD; // *

Characteristics: DWORD; // *

end;

Поля помеченны звёздочкой Мы не будем использовать.

Приведённый код создаёт файл ресурсов и копирует его в данный файл:

procedure CreateResourceFile(

DataFile, ResFile: string; // имена файлов

ResID: Integer // id ресурсов

);

var

FS, RS: TFileStream;

FileHeader, ResHeader: TResHeader;

Padding: array [0..SizeOf(DWORD)-1] of Byte;

begin

{ Open input file and create resource file }

FS := TFileStream.Create( // для чтения данных из файла

DataFile, fmOpenRead);

RS := TFileStream.Create( // для записи файла ресурсов

ResFile, fmCreate);

{ Создаём заголовок файла ресурсов — все нули, за исключением

HeaderSize, ResType и ResID }

FillChar(FileHeader, SizeOf(FileHeader), #0);

FileHeader.HeaderSize := SizeOf(FileHeader);

FileHeader.ResId := $0000FFFF;

FileHeader.ResType := $0000FFFF;

{ Создаём заголовок данных для RC_DATA файла

Внимание: для создания более одного ресурса необходимо

повторить следующий процесс, используя каждый раз различные

ID ресурсов }

FillChar(ResHeader, SizeOf(ResHeader), #0);

ResHeader.HeaderSize := SizeOf(ResHeader);

// id ресурса — FFFF означает «не строка!»

ResHeader.ResId := $0000FFFF or (ResId shl 16);

// тип ресурса — RT_RCDATA (from Windows unit)

ResHeader.ResType := $0000FFFF

or (WORD(RT_RCDATA) shl 16);

// размер данных — есть размер файла

ResHeader.DataSize := FS.Size;

// Устанавливаем необходимые флаги памяти

ResHeader.MemoryFlags := $0030;

{ Записываем заголовки в файл ресурсов }

RS.WriteBuffer(FileHeader, sizeof(FileHeader));

RS.WriteBuffer(ResHeader, sizeof(ResHeader));

{ Копируем файл в ресурс }

RS.CopyFrom(FS, FS.Size);

{ Pad data out to DWORD boundary — any old

rubbish will do!}

if FS.Size mod SizeOf(DWORD) 0 then

RS.WriteBuffer(Padding, SizeOf(DWORD) —

FS.Size mod SizeOf(DWORD));

{ закрываем файлы }

FS.Free;

RS.Free;

end;

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

Извлечение ресурсов из EXE

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

Вся процедура заключается в создании потока ресурса, создании файлового потока и копировании из потока ресурса в поток файла.

procedure ExtractToFile(Instance:THandle; ResID:Integer; ResType, FileName:string);

var

ResStream: TResourceStream;

FileStream: TFileStream;

begin

try

ResStream := TResourceStream.CreateFromID(Instance, ResID, pChar(ResType));

try

//if FileExists(FileName) then

//DeleteFile(pChar(FileName));

FileStream := TFileStream.Create(FileName, fmCreate);

try

FileStream.CopyFrom(ResStream, 0);

finally

FileStream.Free;

end;

finally

ResStream.Free;

end;

except

on E:Exception do

begin

DeleteFile(FileName);

raise;

end;

end;

end;

Всё, что требуется, это получить Instance exe-шника или dll (у Вашего приложения это Application.Instance или Application.Handle, для dll Вам придётся получить его самостоятельно 🙂

ResID

тот же самый ID , который был присвоен ресурсу

ResType: WAVEFILE, BITMAP, CURSOR, CUSTOM

это типы ресурсов, с которыми возможно работать, но у меня получилось успешно проделать процедуру только с CUSTOM

FileName

это имя файла, который мы хотим создать из ресурса

{/codecitation}

Добавить комментарий