Все началось давно, в незапамятные времена… Я узнал из какой-то статьи о файлах *.manifest. Тогда я обрадовался, что мои программы смогут выглядеть в
XP как настоящие. Вскоре файл, который надо таскать с собой, мне надоел. Интернет рассказал, что к проекту можно подключать ресурс, действие которого было равнозначно присутствию манифеста. Но так я мог помочь только своим программам. Оставалось вспомнить о существовании программы ResHacker, то есть о теоретической возможности редактировать ресурсы. И опять мне помог Интернет, убогая заметка за пол дня превратилась во вполне симпатичную программу. Итак, приступим.
Писать мы будем в CBuilder’е. File – New – Application. По самым скромным подсчетам нам потребуются один TEdit, четыре кнопки, один TMemo и TOpenDialog. Красиво их размещаем. Первая кнопка у нас будет выбор файла, вторая – добавить манифест, третья проверить наличие манифеста, а четвертая его из файла вычистить. Так же нужно не забыть добавить к проекту нашей программы ресурс с манифестом.
Так выглядит сам манифест:
processorArchitecture="x86"
name="Author.Program_Name"
type="win32"
/>
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="x86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
Чтобы сделать из него ресурс, мы сохраняем его, как «exe.manifest». Затем создаем «exe.rc» и пишем в нем 1 24 “exe.manifest” (здесь 1 – имя ресурса, а 24 – его тип). И превращаем его ресурс – brcc32.exe exe.rc. Brcc32 лежит в папке /bin/ твоего билдера. Теперь у нас есть exe.res, его-то мы и подключаем к нашему проекту. Наконец мы приступаем к самому программированию.
Онклик Button1 прост до безобразия, нам всего лишь нужно, пользуясь стандартным диалогом, получить путь к файлу.
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if(OpenDialog1->Execute())
Edit1->Text=OpenDialog1->FileName;
}
Теперь немного теории. Нам нужно сначала найти ресурс манифеста у себя в файле программы, а потом дописать его в выбранную пользователем программу. Ищет ресурс функция
FindResource. =) Ей скармливается три параметра – хендл модуля, в котором мы ищем ресурс (у нас NULL потому, что ищем в своей программе), имя этого ресурса и его тип. Так как у нас не названия, а номера ресурсов, то перед ними ставим # (вот так “#24”). Затем загружаем выбранный ресурс в память функцией LoadResource. Ее первый параметр тоже хендл модуля (опять NULL), а второй – то, что возвратила предыдущая функция. И, наконец, мы запираем ресурс в памяти (дословный перевод билдеровского хелпа), используя LockResource. Ее единственный параметр это то, что возвратил LoadResource.
Сейчас в наших руках многострадальный ресурс манифеста. Добавим же его к выбранному пользователем
экзешнику. Мы даем понять программе, что собираемся редактировать ресурсы – BeginUpdateResource. Первый параметр - строка, содержащая путь к файлу, а второй параметр false (если мы передадим true, то все родные ресурсы подопытного исчезнут, а останется лишь добавленные нами). Если BeginUpdateResource вернет NULL, то кричим об ошибке. Если же нам повезло, то передаем полученный хендл как первый параметр UpdateResource, затем тип ресурса, его имя, язык, указатель на то, что мы хотим записать и размер этого. Примечательно, что если вместо указателя на ресурс в памяти передать NULL, то указанный ресурс будет удален. Чтобы изменения вступили в силу, вызываем EndUpdateResource. Передаем хендл файла (его нам предоставил BeginUpdateResource) и false (если передадим true – изменения не вступят в силу).
void __fastcall TForm1::Button2Click(TObject *Sender)
{
HRSRC hRes,hResLoad;
HANDLE hUpdateRes;
char *lpResLock;
hRes= FindResource(NULL,"#1","#24");
hResLoad= LoadResource(NULL,hRes);
lpResLock= (char*)LockResource(hResLoad);
hUpdateRes= BeginUpdateResource(Edit1->Text.c_str(),false);
if(!hUpdateRes) {ShowMessage("Что-то не так.");return;}
UpdateResource (hUpdateRes, MAKEINTRESOURCE(24), MAKEINTRESOURCE(1), MAKELANGID
(LANG_NEUTRAL, SUBLANG_NEUTRAL), lpResLock,SizeofResource(NULL, hRes));
EndUpdateResource (hUpdateRes,FALSE);
}
Если ты внимательно прочитал написанное выше, то сделать функцию для удаления ресурса тебе будет не сложно. Один минус – наша программа не будет удалять манифест с другим языком (у нас выбран нейтральный). Оставляю разбирательство с функцией EnumResourceLanguages (она дает доступ к информации о языках ресурса) тебе.
Не охваченным оказалось нажатие кнопки «проверить». Все очень просто (как обычно) – начало примерно такое же, как и при добавлении ресурса. Только вместо NULL в BeginUpdateResource и UpdateResource нужно писать то, что нам вернет LoadLibrary, ее единственный параметр есть путь к файлу, который мы собираемся проверить. Остается только попробовать найти ресурс манифеста. Если это получиться, то манифест подключен, иначе нет. В своей программе я, для занятия свободного места, еще вывожу дату создания файла, его размер и прочее.
Вот собственно и все. Теперь ты сможешь без труда делать программы от Win9x/WinNT приятными взгляду. А может, (кто знает?) напишешь программу, от которой Restorator навсегда уйдет со сцены… Удачи тебе! И да пребудет с тобой дебаггер.
Faithfully yours,
Lord Kelvin.