I am making a Launcher, I want to get the icon of the exe file to show it in my programs. But I don't know how to do that. I have been searching for several days for a solution.
I tried icoextract : https://github.com/jlu5/icoextract but i don't understand how it works.
This is a bit complex so I can't give you an example of a direction to help you figure this out and leave you to write your own code, so...
This will extract the first icon from an exe, and dll file if it contains one and give you the necessary hIcon for RegisterClassW and WNDCLASSW.
import ctypes
from collections.abc import Callable
from ctypes import wintypes
from typing import Any
# https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw
LOAD_LIBRARY_AS_DATAFILE = 0x00000002
# https://learn.microsoft.com/en-us/windows/win32/menurc/resource-types
RT_ICON = 3
RT_GROUP_ICON = RT_ICON + 11
# https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createiconfromresourceex
LR_DEFAULTCOLOR = 0x00000000
LR_DEFAULTSIZE = 0x00000040
kernel32 = ctypes.WinDLL('kernel32', use_last_error = True)
user32 = ctypes.WinDLL('user32', use_last_error = True)
# https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nc-libloaderapi-enumresnameprocw
# ENUMRESNAMEPROCW Enumresnameprocw;
#
# BOOL Enumresnameprocw(
# [in, optional] HMODULE hModule,
# LPCWSTR lpType,
# LPWSTR lpName,
# [in] LONG_PTR lParam
# )
# {...}
ENUMRESNAMEPROC = ctypes.WINFUNCTYPE(
wintypes.BOOL,
wintypes.HMODULE,
wintypes.LPVOID,
wintypes.LPVOID,
wintypes.LPARAM,
use_last_error = True
)
def enum_res_name_proc(func: Callable[[int, int, int, int], bool]) -> ENUMRESNAMEPROC:
return ENUMRESNAMEPROC(func)
# https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-enumresourcenamesw
# BOOL EnumResourceNamesW(
# [in, optional] HMODULE hModule,
# [in] LPCWSTR lpType,
# [in] ENUMRESNAMEPROCW lpEnumFunc,
# [in] LONG_PTR lParam
# );
EnumResourceNames = kernel32.EnumResourceNamesW
EnumResourceNames.argtypes = [wintypes.HMODULE, wintypes.LPVOID, ENUMRESNAMEPROC, wintypes.LPARAM]
EnumResourceNames.restype = wintypes.BOOL
def enum_resource_names(hModule: int, lpType: str, lpEnumFunc: Any, lParam: int) -> bool:
return EnumResourceNames(hModule, lpType, lpEnumFunc, lParam)
# https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-findresourcew
# HRSRC FindResourceW(
# [in, optional] HMODULE hModule,
# [in] LPCWSTR lpName,
# [in] LPCWSTR lpType
# );
FindResource = kernel32.FindResourceW
FindResource.argtypes = [wintypes.HMODULE, wintypes.LPVOID, wintypes.LPVOID]
FindResource.restype = wintypes.HRSRC
def find_resource(hModule: int, lpName: int | str, lpType: int | str) -> int:
def prep_resource_arg(val):
if isinstance(val, str):
return ctypes.cast(ctypes.c_wchar_p(val), wintypes.LPVOID)
elif isinstance(val, int):
return wintypes.LPVOID(val)
else:
raise TypeError("Resource identifiers must be an int or str")
h_res_info = FindResource(
hModule,
prep_resource_arg(lpName),
prep_resource_arg(lpType)
)
if h_res_info is None or h_res_info == 0:
raise ctypes.WinError(ctypes.get_last_error())
return h_res_info
# https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-freelibrary
# BOOL FreeLibrary(
# [in] HMODULE hLibModule
# );
FreeLibrary = kernel32.FreeLibrary
FreeLibrary.argtypes = [wintypes.HMODULE]
FreeLibrary.restype = wintypes.BOOL
def free_library(hLibModule: int) -> bool:
return FreeLibrary(hLibModule)
# https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw
# HMODULE LoadLibraryExW(
# [in] LPCWSTR lpLibFileName,
# HANDLE hFile,
# [in] DWORD dwFlags
# );
LoadLibraryEx = kernel32.LoadLibraryExW
LoadLibraryEx.argtypes = [wintypes.LPCWSTR, wintypes.HANDLE, wintypes.DWORD]
LoadLibraryEx.restype = wintypes.HMODULE
def load_library(lpLibFileName: str, hFile: int, dwFlags: int) -> int:
h_module = LoadLibraryEx(lpLibFileName, hFile, dwFlags)
if h_module is None: raise ctypes.WinError(ctypes.get_last_error())
return h_module
# https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadresource
# HGLOBAL LoadResource(
# [in, optional] HMODULE hModule,
# [in] HRSRC hResInfo
# );
LoadResource = kernel32.LoadResource
LoadResource.argtypes = [wintypes.HMODULE, wintypes.HRSRC]
LoadResource.restype = wintypes.HGLOBAL
def load_resource(hModule: int, hResInfo: int) -> int:
h_res_data = LoadResource(hModule, hResInfo)
if h_res_data is None: raise ctypes.WinError(ctypes.get_last_error())
return h_res_data
# https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-lockresource
# LPVOID LockResource(
# [in] HGLOBAL hResData
# );
LockResource = kernel32.LockResource
LockResource.argtypes = [wintypes.HGLOBAL]
LockResource.restype = ctypes.c_void_p
def lock_resource(hResData: int) -> int:
p_res_data = LockResource(hResData)
if p_res_data is None: raise ctypes.WinError(ctypes.get_last_error())
return p_res_data
# https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-sizeofresource
# DWORD SizeofResource(
# [in, optional] HMODULE hModule,
# [in] HRSRC hResInfo
# );
SizeofResource = kernel32.SizeofResource
SizeofResource.argtypes = [wintypes.HMODULE, wintypes.HRSRC]
SizeofResource.restype = wintypes.DWORD
def size_of_resource(hModule: int, hResInfo: Any) -> int:
size = SizeofResource(hModule, hResInfo)
if size == 0: raise ctypes.WinError(ctypes.get_last_error())
return size
# https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createiconfromresourceex
# HICON CreateIconFromResourceEx(
# [in] PBYTE presbits,
# [in] DWORD dwResSize,
# [in] BOOL fIcon,
# [in] DWORD dwVer,
# [in] int cxDesired,
# [in] int cyDesired,
# [in] UINT Flags
# );
CreateIconFromResourceEx = user32.CreateIconFromResourceEx
CreateIconFromResourceEx.argtypes = [
wintypes.LPVOID,
wintypes.DWORD,
wintypes.BOOL,
wintypes.DWORD,
ctypes.c_int,
ctypes.c_int,
wintypes.UINT
]
CreateIconFromResourceEx.restype = wintypes.HICON
def create_icon_from_resource(
presbits: bytes,
dwResSize: int,
fIcon: bool,
cxDesired: int,
cyDesired: int,
Flags: int
) -> int | None:
hIcon = CreateIconFromResourceEx(
presbits,
dwResSize,
fIcon,
0x00030000, # dwVersion (always 3.0)
cxDesired,
cyDesired,
Flags
)
if hIcon is None:
raise ctypes.WinError(ctypes.get_last_error())
return hIcon
class IconExtractor:
@classmethod
def extract_from_library(cls, filepath: str, target_size: int = 16) -> int:
h_module = 0
try:
h_module = load_library(filepath, 0, LOAD_LIBRARY_AS_DATAFILE)
target_group_id = None
@enum_res_name_proc
def enumerator_callback(_hModule, _lpszType, lpszName, _lParam):
nonlocal target_group_id
target_group_id = lpszName
return False
enum_resource_names(h_module, RT_GROUP_ICON, enumerator_callback, 0)
if target_group_id is None:
raise ValueError("No icon groups found in the executable.")
dir_data = cls._get_data_from_resource(h_module, RT_GROUP_ICON, target_group_id)
count = int.from_bytes(dir_data[4:6], byteorder = 'little')
best_id = 0
min_diff = float('inf')
for i in range(count):
offset = 6 + (14 * i)
width = dir_data[offset]
width = 256 if width == 0 else width
nID = int.from_bytes(dir_data[offset + 12: offset + 14], byteorder = 'little')
# Calculate how close this icon is to our target (16x16 or 32x32)
diff = abs(target_size - width)
if diff < min_diff:
min_diff = diff
best_id = nID
raw_icon_bytes = cls._get_data_from_resource(h_module, RT_ICON, best_id)
hIcon = cls._create_hicon_from_bytearray(raw_icon_bytes, target_size, target_size)
return hIcon
finally:
if h_module:
free_library(h_module)
@staticmethod
def _create_hicon_from_bytearray(icon_data: bytearray, width: int = 0, height: int = 0) -> int:
raw_bytes = bytes(icon_data)
buffer = ctypes.create_string_buffer(raw_bytes)
flags = LR_DEFAULTCOLOR
if width == 0 and height == 0:
flags = LR_DEFAULTSIZE
hIcon = create_icon_from_resource(
buffer,
len(raw_bytes),
True, # True means we want an Icon, not a Cursor
width,
height,
flags
)
if hIcon == 0 or hIcon is None:
raise ctypes.WinError(ctypes.get_last_error())
return hIcon
@staticmethod
def _get_data_from_resource(h_module, res_type, name) -> bytearray:
h_res_info = find_resource(h_module, name, res_type)
h_res_data = load_resource(h_module, h_res_info)
p_res_data = lock_resource(h_res_data)
size = size_of_resource(h_module, h_res_info)
raw_bytes = ctypes.string_at(p_res_data, size)
return bytearray(raw_bytes)
Usage...
hicon = IconExtractor.extract_from_library(
filepath = r'C:\path\to\executable file.exe'
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With