Экспорт ресурсов из приложения

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Всем привет! Я хочу программно брать ресурсы из модуля какого-нибудь приложения или DLL и сохранять их на диске в виде отдельных файлов. Но проблема в том, что иконки, курсоры и битмапы в ресурсах хранятся не так, как в файлах на диске, их формат несколько отличается. С битмапом я разобрался. Сначала загружаю его с помощью функции LoadBitmap(), а потом сохраняю с помощью функции SaveBitmapToFile(), которую на этом форуме любезно представил WinMain. А вот как быть с другими ресурсами? Описания их файловых форматов я в MSDN не нашёл. Как получить список ресурсных строк, которые можно загрузить с помощью LoadString()?
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Вообще-то подобные программы существуют уже давно и в большом количестве. Я когда-то сам делал такую программу, но у меня она извлекает не только картинки, а ещё и другие ресурсы: библиотеки типов для СОМ-объектов, строковые таблицы, бинарники диалогов, скрипты меню, HTML-файлы...
Можешь сам ей воспользоваться.
Вложения
GrabRes.zip
(60.2 КБ) 62 скачивания
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

WinMain, классная программа! Благодарю.
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Как получить список ресурсных строк, которые можно загрузить с помощью LoadString()?
Дело в том, что каждый строковый ресурс (тип RT_STRING) представляет собой массив из 16 строк, даже если в нём присутствует всего одна строка.
Таким образом, чтобы получить список идентификаторов строк для функции 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)
   {
     // Такая строка существует...
   }
}
К примеру: если ты получил идентификатор строкового ресурса равный 101, то идентификатор первой строки в этом массиве будет равен (101-1)*16 = 1600;
Далее с помощью функции LoadString() пробуешь идентификаторы от 1600 до 1615. Если строка с таким идентификатором существует, то функция вернёт ненулевое значение.
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

WinMain,спасибо за информацию. Попробовал, действительно работает.
А как быть с иконками и курсорами?
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

На эту тему можно вообще целую статью опубликовать. Скажу лишь так: у меня нет готовой функции, которая сохраняла бы HICON или HCURSOR в некий файл. Я тоже беру бинарный ресурс иконки или курсора из модуля приложения или DLL, тупо меняю ему заголовок (хорошо хоть сами данные не нужно перекодировать) и сохраняю в файл.
Например, для курсоров определён специальный тип ресурса 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;
}
Структура заголовка представлена в бинарном виде, поскольку официальной документации по этой структуре в MSDN я тоже не нашёл. Но в том, что эта функция реально работает, можешь даже не сомневаться.
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Действительно работает. Сохраняю ресурс курсора в файл с расширением .cur и его изображение появляется в "Проводнике".
Спасибо, WinMain.
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Скачать утилиту GrabRes.exe можно так же отсюда:
http://www.devels.ru/files/GrabRes.ziphttp://vitr.pochtamt.ru/Resource_extractor.html
Аватара пользователя
Decoder
Сообщения: 308
Зарегистрирован: 19 фев 2008, 23:11
Откуда: Moscow

Подскажите, пожалуйста, как мне получить информацию о версии модуля, т.е. взять данные из ресурсной секции VERSIONINFO?
Аватара пользователя
WinMain
Сообщения: 929
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

Можешь моей функцией воспользоваться.

Код: Выделить всё

[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);
Ответить