Skip to content

Instantly share code, notes, and snippets.

@ynkdir
Last active June 13, 2026 13:39
Show Gist options
  • Select an option

  • Save ynkdir/a543c492f70de26bf5580ce8c9a34bda to your computer and use it in GitHub Desktop.

Select an option

Save ynkdir/a543c492f70de26bf5580ce8c9a34bda to your computer and use it in GitHub Desktop.
enum resource
# /// script
# dependencies = ["win32more"]
# ///
import sys
from ctypes import Structure, cast, memoryview_at, pointer, wstring_at
from win32more import WINFUNCTYPE, Char, IntPtr, UInt16, WinError
from win32more.Windows.Win32.Foundation import (
BOOL,
HMODULE,
PWSTR,
TRUE,
FreeLibrary,
GetLastError,
SetLastError,
)
from win32more.Windows.Win32.Graphics.Gdi import DeleteObject
from win32more.Windows.Win32.Media.KernelStreaming import RT_RCDATA, RT_STRING
from win32more.Windows.Win32.Storage.FileSystem import VS_FIXEDFILEINFO
from win32more.Windows.Win32.System.LibraryLoader import (
ENUMRESNAMEPROCW,
ENUMRESTYPEPROCW,
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE,
LOAD_LIBRARY_AS_IMAGE_RESOURCE,
EnumResourceNamesExW,
EnumResourceTypesExW,
FindResourceExW,
LoadLibraryExW,
)
from win32more.Windows.Win32.System.LibraryLoader import LoadResource as _LoadResource
from win32more.Windows.Win32.System.LibraryLoader import LockResource as _LockResource
from win32more.Windows.Win32.System.LibraryLoader import (
SizeofResource as _SizeofResource,
)
from win32more.Windows.Win32.UI.WindowsAndMessaging import (
IMAGE_BITMAP,
IMAGE_CURSOR,
IMAGE_ICON,
LR_DEFAULTCOLOR,
RT_ACCELERATOR,
RT_ANICURSOR,
RT_ANIICON,
RT_BITMAP,
RT_CURSOR,
RT_DIALOG,
RT_DLGINCLUDE,
RT_FONT,
RT_FONTDIR,
RT_GROUP_CURSOR,
RT_GROUP_ICON,
RT_HTML,
RT_ICON,
RT_MANIFEST,
RT_MENU,
RT_MESSAGETABLE,
RT_PLUGPLAY,
RT_VERSION,
RT_VXD,
DestroyAcceleratorTable,
DestroyCursor,
DestroyIcon,
DestroyMenu,
LoadAcceleratorsW,
LoadImageW,
LoadMenuW,
LoadStringW,
)
# WORKAROUND:
# ENUMRESTYPEPROCW is defined as
# BOOL ENUMRESTYPEPROCW(HMODULE hModule, LPWSTR lpType, LONG_PTR lParam)
# But lpType is actually LPWSTR or int.
# Ctypes convert LPWSTR to str and it causes crash for int resource.
ENUMRESTYPEPROCW_INTPTR = WINFUNCTYPE(BOOL, HMODULE, IntPtr, IntPtr)
ENUMRESNAMEPROCW_INTPTR = WINFUNCTYPE(BOOL, HMODULE, IntPtr, IntPtr, IntPtr)
# https://learn.microsoft.com/en-us/windows/win32/menurc/vs-versioninfo
class VS_VERSIONINFO(Structure):
_fields_ = [
("wLength", UInt16),
("wValueLength", UInt16),
("wType", UInt16),
("szKey", Char * 16),
("Padding1", UInt16),
("Value", VS_FIXEDFILEINFO),
("Padding2", UInt16),
("Children", UInt16),
]
def IS_INTRESOURCE(r):
return r >> 16 == 0
def LoadLibraryResource(filename):
hModule = LoadLibraryExW(filename, None, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE)
if not hModule:
raise WinError()
return hModule
def EnumResourceTypes(hModule, dwFlags=0, LangId=0):
@ENUMRESTYPEPROCW_INTPTR
def enumfunc(hModule, lpType, lParam):
if not IS_INTRESOURCE(lpType):
lpType = wstring_at(lpType)
types.append(lpType)
return TRUE
types = []
lParam = 0
r = EnumResourceTypesExW(hModule, cast(enumfunc, ENUMRESTYPEPROCW), lParam, dwFlags, LangId)
if not r:
raise WinError()
return types
def EnumResourceNames(hModule, lpType, dwFlags=0, LangId=0):
@ENUMRESNAMEPROCW_INTPTR
def enumfunc(hModule, lpType, lpName, lParam):
if not IS_INTRESOURCE(lpName):
lpName = wstring_at(lpName)
names.append(lpName)
return TRUE
names = []
lParam = 0
r = EnumResourceNamesExW(hModule, lpType, cast(enumfunc, ENUMRESNAMEPROCW), lParam, dwFlags, LangId)
if not r:
raise WinError()
return names
def FindResource(hModule, lpType, lpName, wLanguage=0):
hResInfo = FindResourceExW(hModule, lpType, lpName, wLanguage)
if not hResInfo:
raise WinError()
return hResInfo
def SizeofResource(hModule, hResInfo):
size = _SizeofResource(hModule, hResInfo)
if size == 0:
raise WinError()
return size
def LoadResource(hModule, hResInfo):
hResData = _LoadResource(hModule, hResInfo)
if not hResData:
raise WinError()
return hResData
def LockResource(hResData):
pResLock = _LockResource(hResData)
if not pResLock:
raise OSError("LockResource() failed")
return pResLock
def resource_data(hModule, lpType, lpName, wLanguage=0):
hResInfo = FindResource(hModule, lpType, lpName, wLanguage)
size = SizeofResource(hModule, hResInfo)
hResData = LoadResource(hModule, hResInfo)
pResLock = LockResource(hResData)
return memoryview_at(pResLock, size, readonly=True).tobytes()
def LoadAccelerators(hInstance, lpTableName):
hAccel = LoadAcceleratorsW(hInstance, lpTableName)
if not hAccel:
raise WinError()
return hAccel
# RT_STRING resource is memory block which contains 16 strings.
# Each strings are stored as <len:16bit> + <string>.
def LoadStringBlock(hModule, lpName):
block = []
for i in range(16):
uID = ((lpName - 1) << 4) + i
string = LoadString(hModule, uID)
block.append((uID, string))
return block
def LoadString(hInstance, uID):
buf = IntPtr()
SetLastError(0)
r = LoadStringW(hInstance, uID, cast(pointer(buf), PWSTR), 0)
if GetLastError() != 0:
raise WinError()
return wstring_at(buf.value, r)
def LoadBitmap(hInstance, lpBitmapName):
hBitmap = LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR)
if not hBitmap:
raise WinError()
return hBitmap
def LoadCursor(hInstance, lpCursorName):
hCursor = LoadImageW(hInstance, lpCursorName, IMAGE_CURSOR, 0, 0, LR_DEFAULTCOLOR)
if not hCursor:
raise WinError()
return hCursor
def LoadIcon(hInstance, lpIconName):
hIcon = LoadImageW(hInstance, lpIconName, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR)
if not hIcon:
raise WinError()
return hIcon
def LoadMenu(hInstance, lpMenuName):
hMenu = LoadMenuW(hInstance, lpMenuName)
if not hMenu:
raise WinError()
return hMenu
def main():
hModule = LoadLibraryResource(sys.argv[1])
for lpType in EnumResourceTypes(hModule):
for lpName in EnumResourceNames(hModule, lpType):
if lpType == RT_CURSOR: # 1
data = resource_data(hModule, lpType, lpName)
print(f"RT_CURSOR: {lpName=}, {data[:20]}...")
elif lpType == RT_BITMAP: # 2
hBitmap = LoadBitmap(hModule, lpName)
print(f"RT_BITMAP: {lpName=}, {hBitmap=}")
DeleteObject(hBitmap)
elif lpType == RT_ICON: # 3
data = resource_data(hModule, lpType, lpName)
print(f"RT_ICON: {lpName=}, {data[:20]}...")
elif lpType == RT_MENU: # 4
hMenu = LoadMenu(hModule, lpName)
print(f"RT_MENU: {lpName=}, {hMenu=}")
DestroyMenu(hMenu)
elif lpType == RT_DIALOG: # 5
data = resource_data(hModule, lpType, lpName)
print(f"RT_DIALOG: {lpName=}, {data[:20]}...")
elif lpType == RT_STRING: # 6
print(f"RT_STRING: {lpName=}")
for uID, string in LoadStringBlock(hModule, lpName):
print(f" {uID=}, {string=}")
elif lpType == RT_FONTDIR: # 7
data = resource_data(hModule, lpType, lpName)
print(f"RT_FONTDIR: {lpName=}, {data[:20]}...")
elif lpType == RT_FONT: # 8
data = resource_data(hModule, lpType, lpName)
print(f"RT_FONT: {lpName=}, {data[:20]}...")
elif lpType == RT_ACCELERATOR: # 9
hAccel = LoadAccelerators(hModule, lpName)
print(f"RT_ACCELERATOR: {lpName=}, {hAccel=}")
DestroyAcceleratorTable(hAccel)
elif lpType == RT_RCDATA: # 8
data = resource_data(hModule, lpType, lpName)
print(f"RT_RCDATA: {lpName=}, {data[:20]}...")
elif lpType == RT_MESSAGETABLE: # 8
data = resource_data(hModule, lpType, lpName)
print(f"RT_MESSAGETABLE: {lpName=}, {data[:20]}...")
elif lpType == RT_GROUP_CURSOR: # 12
hCursor = LoadCursor(hModule, lpName)
print(f"RT_GROUP_CURSOR: {lpName=}, {hCursor=}")
DestroyCursor(hCursor)
elif lpType == RT_GROUP_ICON: # 14
hIcon = LoadIcon(hModule, lpName)
print(f"RT_GROUP_ICON: {lpName=}, {hIcon=}")
DestroyIcon(hIcon)
elif lpType == RT_VERSION: # 16
data = resource_data(hModule, lpType, lpName)
version_info = VS_VERSIONINFO.from_buffer_copy(data)
print(f"RT_VERSION: {lpName=}, {data[:20]=}...")
print(" VS_VERSIONINFO(")
print(f" wLength = {version_info.wLength}")
print(f" wValueLength = {version_info.wValueLength}")
print(f" wType = {version_info.wType}")
print(f" szKey = {version_info.szKey}")
print(f" Padding1 = {version_info.Padding1}")
print(" Value = VS_FIXEDFILEINFO(")
print(f" dwSignature = {version_info.Value.dwSignature}")
print(f" dwStrucVersion = {version_info.Value.dwStrucVersion}")
print(f" dwFileVersionMS = {version_info.Value.dwFileVersionMS}")
print(f" dwFileVersionLS = {version_info.Value.dwFileVersionLS}")
print(f" dwProductVersionMS = {version_info.Value.dwProductVersionMS}")
print(f" dwProductVersionLS = {version_info.Value.dwProductVersionLS}")
print(f" dwFileFlagsMask = {version_info.Value.dwFileFlagsMask}")
print(f" dwFileFlags = {version_info.Value.dwFileFlags}")
print(f" dwFileOS = {version_info.Value.dwFileOS}")
print(f" dwFileType = {version_info.Value.dwFileType}")
print(f" dwFileSubtype = {version_info.Value.dwFileSubtype}")
print(f" dwFileDateMS = {version_info.Value.dwFileDateMS}")
print(f" dwFileDateLS = {version_info.Value.dwFileDateLS}")
print(" )")
print(f" Padding2 = {version_info.Padding2}")
print(f" Children = {version_info.Children}")
print(" )")
elif lpType == RT_DLGINCLUDE: # 17
data = resource_data(hModule, lpType, lpName)
print(f"RT_DLGINCLUDE: {lpName=}, {data[:20]}...")
elif lpType == RT_PLUGPLAY: # 19
data = resource_data(hModule, lpType, lpName)
print(f"RT_PLUGPLAY: {lpName=}, {data[:20]}...")
elif lpType == RT_VXD: # 20
data = resource_data(hModule, lpType, lpName)
print(f"RT_VXD: {lpName=}, {data[:20]}...")
elif lpType == RT_ANICURSOR: # 21
data = resource_data(hModule, lpType, lpName)
print(f"RT_ANICURSOR: {lpName=}, {data[:20]}...")
elif lpType == RT_ANIICON: # 22
data = resource_data(hModule, lpType, lpName)
print(f"RT_ANIICON: {lpName=}, {data[:20]}...")
elif lpType == RT_HTML: # 23
data = resource_data(hModule, lpType, lpName)
print(f"RT_HTML: {lpName=}, {data[:20]}...")
elif lpType == RT_MANIFEST: # 24
data = resource_data(hModule, lpType, lpName)
print(f"RT_MANIFEST: {lpName=}, {data=}")
else:
assert isinstance(lpType, str)
data = resource_data(hModule, lpType, lpName)
print(f"{lpType}: {lpName=}, {data[:20]}...")
FreeLibrary(hModule)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment