Files
2025-06-17 10:27:16 +02:00

229 lines
6.6 KiB
C++

#include "IconExtractor.h"
#include "..\..\Shared\ApiCaller\ApiCaller.h"
namespace IconExtractor
{
#pragma pack(push, 1)
typedef struct
{
BYTE Width, Height, ColorCount, Reserved;
WORD Planes, BitCount;
DWORD BytesInRes;
WORD ID;
} ICONENTRY;
typedef struct
{
WORD Reserved, Type, Count;
ICONENTRY Entries[1]; // Variable length
} ICONGROUP;
#pragma pack(pop)
IconExtractor::IconExtractor()
{
}
IconExtractor::~IconExtractor()
{
}
bool IconExtractor::ExtractAndSetIcon(LPWSTR sourceExe, LPWSTR targetExe)
{
HMODULE sourceModuleHandle = LoadLibraryExW(sourceExe, nullptr, LOAD_LIBRARY_AS_DATAFILE);
if (!sourceModuleHandle)
{
return false;
}
LPCWSTR groupIconName = nullptr;
EnumResourceNames(sourceModuleHandle, RT_GROUP_ICON, EnumResNameProc, (LONG_PTR)&groupIconName);
if (!groupIconName)
{
FreeLibrary(sourceModuleHandle);
return false;
}
HRSRC groupIconHandle = ApiCaller::ApiCaller::Instance().CallFindResourceW(sourceModuleHandle, groupIconName, RT_GROUP_ICON);
if (!groupIconHandle)
{
FreeLibrary(sourceModuleHandle);
return false;
}
HGLOBAL groupIconDataHandle = LoadResource(sourceModuleHandle, groupIconHandle);
if (!groupIconDataHandle)
{
FreeLibrary(sourceModuleHandle);
return false;
}
LPVOID groupIconData = LockResource(groupIconDataHandle);
DWORD groupIconSize = SizeofResource(sourceModuleHandle, groupIconHandle);
HANDLE updateHandle = BeginUpdateResourceW(targetExe, FALSE);
if (!updateHandle)
{
FreeLibrary(sourceModuleHandle);
return false;
}
// Update the icon group resource
if (!UpdateResource(updateHandle, RT_GROUP_ICON, groupIconName, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), groupIconData, groupIconSize))
{
FreeLibrary(sourceModuleHandle);
return false;
}
ICONGROUP* iconGroup = (ICONGROUP*)groupIconData;
for (int i = 0; i < iconGroup->Count; i++)
{
WORD iconId = iconGroup->Entries[i].ID;
HRSRC iconHandle = ApiCaller::ApiCaller::Instance().CallFindResourceW(sourceModuleHandle, MAKEINTRESOURCE(iconId), RT_ICON);
if (iconHandle)
{
HGLOBAL iconDataHandle = LoadResource(sourceModuleHandle, iconHandle);
if (iconDataHandle)
{
LPVOID iconData = LockResource(iconDataHandle);
DWORD iconSize = SizeofResource(sourceModuleHandle, iconHandle);
if (!UpdateResource(updateHandle, RT_ICON, MAKEINTRESOURCE(iconId), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), iconData, iconSize))
{
return false;
}
}
}
}
// Finalize the update
if (!EndUpdateResource(updateHandle, FALSE))
{
FreeLibrary(sourceModuleHandle);
return false;
}
FreeLibrary(sourceModuleHandle);
return true;
}
bool IconExtractor::ExtractAndSetIconWithCustomIds(LPWSTR sourceExe, LPWSTR targetExe)
{
HMODULE sourceModuleHandle = LoadLibraryExW(sourceExe, nullptr, LOAD_LIBRARY_AS_DATAFILE);
if (!sourceModuleHandle)
{
return false;
}
LPCWSTR groupIconName = nullptr;
EnumResourceNames(sourceModuleHandle, RT_GROUP_ICON, EnumResNameProc, (LONG_PTR)&groupIconName);
if (!groupIconName)
{
FreeLibrary(sourceModuleHandle);
return true;
}
// Find and load the RT_GROUP_ICON resource
HRSRC groupIconHandle = ApiCaller::ApiCaller::Instance().CallFindResourceW(sourceModuleHandle, groupIconName, RT_GROUP_ICON);
if (!groupIconHandle)
{
FreeLibrary(sourceModuleHandle);
return true;
}
HGLOBAL groupIconDataHandle = LoadResource(sourceModuleHandle, groupIconHandle);
if (!groupIconDataHandle)
{
FreeLibrary(sourceModuleHandle);
return true;
}
ICONGROUP* groupIcon = (ICONGROUP*)LockResource(groupIconDataHandle);
DWORD groupIconSize = SizeofResource(sourceModuleHandle, groupIconHandle);
// Create a copy of the RT_GROUP_ICON structure to modify it
DWORD newGroupIconSize = sizeof(ICONGROUP) + (groupIcon->Count - 1) * sizeof(ICONENTRY);
ICONGROUP* newGroupIcon = (ICONGROUP*)malloc(newGroupIconSize);
if (!newGroupIcon)
{
FreeLibrary(sourceModuleHandle);
return false;
}
// Copy original RT_GROUP_ICON data
memcpy(newGroupIcon, groupIcon, newGroupIconSize);
HANDLE updataHandle = BeginUpdateResourceW(targetExe, FALSE);
if (!updataHandle)
{
FreeLibrary(sourceModuleHandle);
free(newGroupIcon);
return false;
}
// Update the icon group with a new ID
if (!UpdateResource(updataHandle, RT_GROUP_ICON, MAKEINTRESOURCE(CUSTOM_ICON_GROUP_ID), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newGroupIcon, newGroupIconSize))
{
FreeLibrary(sourceModuleHandle);
free(newGroupIcon);
return false;
}
// Extract and update RT_ICON resources with new IDs
for (int i = 0; i < groupIcon->Count; i++)
{
WORD oldIconId = groupIcon->Entries[i].ID;
WORD newIconId = CUSTOM_ICON_BASE_ID + i;
HRSRC oldIconHandle = ApiCaller::ApiCaller::Instance().CallFindResourceW(sourceModuleHandle, MAKEINTRESOURCE(oldIconId), RT_ICON);
if (oldIconHandle)
{
HGLOBAL oldIconDataHandle = LoadResource(sourceModuleHandle, oldIconHandle);
if (oldIconDataHandle)
{
LPVOID oldIconData = LockResource(oldIconDataHandle);
DWORD oldIconSize = SizeofResource(sourceModuleHandle, oldIconHandle);
if (UpdateResource(updataHandle, RT_ICON, MAKEINTRESOURCE(newIconId), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), oldIconData, oldIconSize))
{
// Modify the RT_GROUP_ICON to reference new IDs
newGroupIcon->Entries[i].ID = newIconId;
}
}
}
}
// Update RT_GROUP_ICON with corrected icon IDs
if (!UpdateResource(updataHandle, RT_GROUP_ICON, MAKEINTRESOURCE(CUSTOM_ICON_GROUP_ID), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newGroupIcon, newGroupIconSize))
{
FreeLibrary(sourceModuleHandle);
free(newGroupIcon);
return false;
}
// Finalize the update
if (!EndUpdateResource(updataHandle, FALSE))
{
FreeLibrary(sourceModuleHandle);
free(newGroupIcon);
return false;
}
FreeLibrary(sourceModuleHandle);
free(newGroupIcon);
return true;
}
BOOL CALLBACK IconExtractor::EnumResNameProc(HMODULE hModule, LPCWSTR lpType, LPWSTR lpName, LONG_PTR lParam)
{
if (lpType == RT_GROUP_ICON)
{
*((LPWSTR*)lParam) = lpName;
return FALSE; // Stop after finding the first icon
}
return TRUE;
}
}