Вопрос или проблема
Эта статья утверждает, что MS-Windows извлекает 1ю иконку, встроенную в файл .dll
или .exe
, для отображения в оболочке Windows.
Какая иконка?
Если файл .EXE или .DLL содержит только один ресурс RT_GROUP_ICON, первый шаг тривиален; Windows просто использует этот ресурс. Однако, если в файле существует более одного такого группового ресурса, Windows должен решить, какой из них использовать. Windows NT просто выбирает первый ресурс, указанный в сценарии RC приложения.
Обратите внимание, что это относится к 1й RT_GROUP_ICON
ресурсу, НЕ к наименьшему идентификатору ресурса (или имени)!
Т.е. Не к Resource ID == 0
или Resource ID == 1
или Resource ID == "AAA"
, которые могут даже не существовать. Даже если файл .exe
или .dll
имеет только один RT_GROUP_ICON
ресурс, нахождение его идентификатора представляется нетривиальной задачей.
Я написал следующие функции для того, чтобы воспроизвести поведение оболочки:
BOOL EnumProc(HMODULE hModule, LPCTSTR lpType, LPTSTR lpName, LONG_PTR lParam)
{
*(reinterpret_cast<LPTSTR*>(lParam)) = reinterpret_cast<LPTSTR>(lpName);
return FALSE;
}
HGLOBAL FindFirstIconInDLL(LPCTSTR szFileName, int nSize)
{
HMODULE hMod = LoadLibraryEx(szFileName, NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
LPCWSTR idResource;
EnumResourceNames(hMod, RT_GROUP_ICON, EnumProc, reinterpret_cast<LONG_PTR>(&idResource));
HRSRC hResIbIconDir = FindResource(hMod, idResource, RT_GROUP_ICON);
HGLOBAL hResDatIconDir = LoadResource(hMod, hResIbIconDir);
return hResDatIconDir;
}
Код выше находит и загружает 1й RT_GROUP_ICON
ресурс, но является довольно неэффективным и неуклюжим, потому что:
- Требуется формирование двух отдельных функций.
- Функция
EnumResourceNames()
необходима для получения идентификатора ресурса для 2го параметра функцииFindResource()
. - EnumResourceNames() требует отдельной процедуры обратного вызова
EnumProc()
. FindResource()
снова находит первый ресурс по его идентификатору, несмотря на то, что он уже был найден с помощьюEnumResourceNames()
.
Существует ли более простой или более эффективный метод для нахождения 1й RT_GROUP_ICON
ресурса в файле .dll
или .exe
?
Ответ или решение
Для эффективного поиска первого ресурса типа RT_GROUP_ICON
в библиотеке DLL или исполняемом файле EXE можно значительно упростить и оптимизировать исходный код, избегая избыточного вызова функций и использования вспомогательных процедур. Давайте рассмотрим более элегантное решение.
Оптимизированный код для поиска первого RT_GROUP_ICON
Мы можем использовать функцию FindResourceEx
, которая позволяет нам получать ресурсы по идентификатору и типу в одну операцию. Также мы можем использовать BeginUpdateResource
и EndUpdateResource
, чтобы предотвратить лишние вызовы при получении ресурсов. Вот упрощенная версия кода:
#include <windows.h>
HGLOBAL FindFirstIconInDLL(LPCTSTR szFileName) {
HMODULE hMod = LoadLibraryEx(szFileName, NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
if (!hMod) {
return NULL; // Ошибка загрузки файла
}
// Ищем первый RT_GROUP_ICON ресурс
HRSRC hResGroupIcon = FindResource(hMod, MAKEINTRESOURCE(1), RT_GROUP_ICON);
if (!hResGroupIcon) {
FreeLibrary(hMod);
return NULL; // Ресурс не найден
}
// Загружаем ресурс
HGLOBAL hResData = LoadResource(hMod, hResGroupIcon);
if (!hResData) {
FreeLibrary(hMod);
return NULL; // Ошибка при загрузке ресурса
}
// Возвращаем данные ресурса
return hResData;
}
Объяснение кода
-
Загрузка библиотеки: Используется
LoadLibraryEx
с флагамиLOAD_LIBRARY_AS_DATAFILE
иLOAD_LIBRARY_AS_IMAGE_RESOURCE
, что позволяет загружать ресурсы, не инициализируя программу. -
Поиск
RT_GROUP_ICON
ресурса: Вместо использованияEnumResourceNames
, мы можем обратиться непосредственно к первому ресурсу с идентификатором1
, что соответствует первому ресурсу, поскольку Windows выбирает первый ресурс по порядку в файле. -
Загрузка ресурса: Используя
LoadResource
, мы можем сразу загружать найденный ресурс. -
Освобождение ресурса: Важно освобождать загруженный модуль после работы с ресурсами.
Преимущества данного подхода
- Упрощение: Убрано использование вспомогательных функций и процедур, сокращая общий код и увеличивая его читаемость.
- Производительность: Поскольку теперь мы обращаемся только к двум функциям, а не трем, уменьшается оверхед, свойственный вызову колбеков.
- Надежность: Мы проверяем, были ли возвращены корректные указатели ресурсов и модуля, что позволяет избежать потенциальных ошибок.
Заключение
Теперь, с использованием описанного метода, вы можете эффективно находить и загружать первый ресурс типа RT_GROUP_ICON
в DLL или EXE файле. Обратите внимание на необходимость обработки ошибок и освобождения ресурсов, чтобы избежать утечек памяти.