Экспорт ресурсов из приложения
Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain
Всем привет! Я хочу программно брать ресурсы из модуля какого-нибудь приложения или DLL и сохранять их на диске в виде отдельных файлов. Но проблема в том, что иконки, курсоры и битмапы в ресурсах хранятся не так, как в файлах на диске, их формат несколько отличается. С битмапом я разобрался. Сначала загружаю его с помощью функции LoadBitmap(), а потом сохраняю с помощью функции SaveBitmapToFile(), которую на этом форуме любезно представил WinMain. А вот как быть с другими ресурсами? Описания их файловых форматов я в MSDN не нашёл. Как получить список ресурсных строк, которые можно загрузить с помощью LoadString()?
Вообще-то подобные программы существуют уже давно и в большом количестве. Я когда-то сам делал такую программу, но у меня она извлекает не только картинки, а ещё и другие ресурсы: библиотеки типов для СОМ-объектов, строковые таблицы, бинарники диалогов, скрипты меню, HTML-файлы...
Можешь сам ей воспользоваться.
Можешь сам ей воспользоваться.
- Вложения
-
- GrabRes.zip
- (60.2 КБ) 62 скачивания
WinMain, классная программа! Благодарю.
Дело в том, что каждый строковый ресурс (тип RT_STRING) представляет собой массив из 16 строк, даже если в нём присутствует всего одна строка.Как получить список ресурсных строк, которые можно загрузить с помощью LoadString()?
Таким образом, чтобы получить список идентификаторов строк для функции LoadString(), нужно сначала идентификатор строкового ресурса преобразовать в идентификатор первой строки в данном массиве. Для этого применяется простая формула:
UINT nStrFirst = (nResID-1)*16;
Где nResID - это идентификатор строкового ресурса (RT_STRING), получаемый с помощью функции EnumResourceNames()
Далее с помощью цикла опрашиваешь каждую из 16 строк в этом массиве...
Код: Выделить всё
TCHAR szText[256];
for (UINT n = 0; n < 16; n++)
{
int nLen = ::LoadString(hModule, nStrFirst+n, szText, sizeof(szText)/sizeof(TCHAR));
if (nLen > 0)
{
// Такая строка существует...
}
}
Далее с помощью функции LoadString() пробуешь идентификаторы от 1600 до 1615. Если строка с таким идентификатором существует, то функция вернёт ненулевое значение.
WinMain,спасибо за информацию. Попробовал, действительно работает.
А как быть с иконками и курсорами?
А как быть с иконками и курсорами?
На эту тему можно вообще целую статью опубликовать. Скажу лишь так: у меня нет готовой функции, которая сохраняла бы HICON или HCURSOR в некий файл. Я тоже беру бинарный ресурс иконки или курсора из модуля приложения или DLL, тупо меняю ему заголовок (хорошо хоть сами данные не нужно перекодировать) и сохраняю в файл.
Например, для курсоров определён специальный тип ресурса RT_CURSOR. Список имеющихся в модуле курсоров можешь получить с помощью функции EnumResourceNames(). Каждый из ресурсов можешь сохранить в отдельный файл с помощью такой вот функции, которую я сам написал...
Структура заголовка представлена в бинарном виде, поскольку официальной документации по этой структуре в MSDN я тоже не нашёл. Но в том, что эта функция реально работает, можешь даже не сомневаться.
Например, для курсоров определён специальный тип ресурса RT_CURSOR. Список имеющихся в модуле курсоров можешь получить с помощью функции EnumResourceNames(). Каждый из ресурсов можешь сохранить в отдельный файл с помощью такой вот функции, которую я сам написал...
Код: Выделить всё
#include <atlfile.h>
BOOL _SaveCursorToFile(HMODULE hModule, LPCTSTR lpResName, LPCTSTR lpFile)
{
BYTE baHeader[] =
{ 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x20, 0x20,
0x00, 0x00, 0x0F, 0x00, 0x10, 0x00, 0xE8, 0x02,
0x00, 0x00, 0x16, 0x00, 0x00, 0x00
};
HRSRC hResInfo = ::FindResource(hModule, lpResName, RT_CURSOR);
if (hResInfo == NULL)
return FALSE;
//
HGLOBAL hResData = ::LoadResource(hModule, hResInfo);
if (hResData == NULL)
return FALSE;
//
CAtlFile f;
f.Create(lpFile, GENERIC_WRITE, FILE_SHARE_WRITE, CREATE_ALWAYS);
if (f.m_h != NULL)
{
DWORD dwSize = ::SizeofResource(hModule, hResInfo);
LPWORD lpWord = (LPWORD)baHeader;
lpWord[7] = LOWORD(dwSize)-4;
f.Write(baHeader, sizeof(baHeader));
f.Write((LPBYTE)::LockResource(hResData)+4, dwSize-4);
} else
{
return FALSE;
}
::FreeResource(hResData);
//
return TRUE;
}
Действительно работает. Сохраняю ресурс курсора в файл с расширением .cur и его изображение появляется в "Проводнике".
Спасибо, WinMain.
Спасибо, WinMain.
Скачать утилиту GrabRes.exe можно так же отсюда:
http://www.devels.ru/files/GrabRes.ziphttp://vitr.pochtamt.ru/Resource_extractor.html
http://www.devels.ru/files/GrabRes.ziphttp://vitr.pochtamt.ru/Resource_extractor.html
Подскажите, пожалуйста, как мне получить информацию о версии модуля, т.е. взять данные из ресурсной секции VERSIONINFO?
Можешь моей функцией воспользоваться.
Используется она так:
Код: Выделить всё
[size=84]BOOL GetStringFileInfo(LPTSTR szFile, LPCTSTR szInfoKey, CString& strOut)[/size]
[size=84]{[/size]
[size=84][color=#0000ff][size=84][color=#0000ff] if[/color][/size][/color][/size][size=84] ((::PathFileExists(szFile) == FALSE) || (szInfoKey == NULL) || (*szInfoKey == [/size][size=84][color=#800000][size=84][color=#800000]'\0'[/color][/size][/color][/size][size=84]))[/size]
[size=84] {[/size]
[size=84][color=#0000ff][size=84][color=#0000ff] return[/color][/size][/color][/size][size=84] FALSE;[/size]
[size=84] }[/size]
[size=84][color=#008000][size=84][color=#008000]//[/color][/size]
[/color][/size][size=84] DWORD dwHandle(0);[/size]
[size=84] DWORD dwSize = ::GetFileVersionInfoSize(szFile, &dwHandle);[/size]
[size=84][color=#0000ff][size=84][color=#0000ff] if[/color][/size][/color][/size][size=84] (dwSize > 0)[/size]
[size=84] {[/size]
[size=84] std::auto_ptr<BYTE> info([/size][size=84][color=#0000ff][size=84][color=#0000ff]new[/color][/size][/color][/size][size=84] BYTE[dwSize]);[/size]
[size=84] ::GetFileVersionInfo(szFile, 0, dwSize, info.get());[/size]
[size=84][color=#008000][size=84][color=#008000]//[/color][/size]
[/color][/size][size=84] UINT nLen;[/size]
[size=84] LPVOID lpBuff;[/size]
[size=84][color=#0000ff][size=84][color=#0000ff] struct[/color][/size][/color][/size][size=84] LANGANDCODEPAGE {[/size]
[size=84] WORD wLanguage;[/size]
[size=84] WORD wCodePage;[/size]
[size=84] } *lpTranslate;[/size]
[size=84] ::VerQueryValue(info.get(), _T([/size][size=84][color=#800000][size=84][color=#800000]"\\VarFileInfo\\Translation"[/color][/size][/color][/size][size=84]), &lpBuff, &nLen);[/size]
[size=84] lpTranslate = (LANGANDCODEPAGE*)lpBuff;[/size]
[size=84] CString block;[/size]
[size=84] block.Format(_T([/size][size=84][color=#800000][size=84][color=#800000]"\\StringFileInfo\\%04x%04x\\%s"[/color][/size][/color][/size][size=84]), [/size]
[size=84] lpTranslate->wLanguage, lpTranslate->wCodePage, szInfoKey);[/size]
[size=84] ::VerQueryValue(info.get(), (LPTSTR)block.GetString(), &lpBuff, &nLen);[/size]
[size=84][color=#008000][size=84][color=#008000]//[/color][/size]
[/color][/size][size=84] strOut = (nLen > 0)? (TCHAR*)lpBuff : _T([/size][size=84][color=#800000][size=84][color=#800000]""[/color][/size][/color][/size][size=84]);[/size]
[size=84] } [/size][size=84][color=#0000ff][size=84][color=#0000ff]else[/color][/size]
[/color][/size][size=84] {[/size]
[size=84][color=#0000ff][size=84][color=#0000ff] return[/color][/size][/color][/size][size=84] FALSE;[/size]
[size=84] }[/size]
[size=84][color=#008000]
[/color][/size][size=84][color=#0000ff][size=84][color=#0000ff] return[/color][/size][/color][/size][size=84] TRUE;[/size]
[size=84]}[/size]
Используется она так:
Код: Выделить всё
CString info;
GetStringFileInfo(_T("User32.dll"), _T("FileDescription"), info);