如何用PyWin32从exe文件加载嵌入的图标?

7 投票
4 回答
4440 浏览
提问于 2025-04-11 09:18

我有一个用py2exe生成的exe文件。在setup.py文件中,我指定了一个图标要嵌入到exe里:

windows=[{'script': 'my_script.py','icon_resources': [(0, 'my_icon.ico')], ...

我尝试用以下方式加载这个图标:

hinst = win32api.GetModuleHandle(None)
hicon = win32gui.LoadImage(hinst, 0, win32con.IMAGE_ICON, 0, 0, win32con.LR_DEFAULTSIZE)

但是这导致了一个(非常不具体的)错误:
pywintypes.error: (0, 'LoadImage', '没有可用的错误信息')

如果我尝试把0指定为字符串

hicon = win32gui.LoadImage(hinst, '0', win32con.IMAGE_ICON, 0, 0, win32con.LR_DEFAULTSIZE)

那么我就会得到这个错误:
pywintypes.error: (1813, 'LoadImage', '在图像文件中找不到指定的资源类型。')

那么,加载图标的正确方法或语法是什么呢?
另外请注意,我没有使用任何图形用户界面工具包 - 只是通过PyWin32使用Windows API。

4 个回答

1

如果你在使用wxPython这个工具,你可以用下面这段简单的代码:

wx.Icon(sys.argv[0], wx.BITMAP_TYPE_ICO)

我通常会写一些代码来检查程序是从一个可执行文件(EXE)运行的还是其他方式,然后根据这个情况来做不同的处理:

def get_app_icon():
    if hasattr(sys, "frozen") and getattr(sys, "frozen") == "windows_exe":
        return wx.Icon(sys.argv[0], wx.BITMAP_TYPE_ICO)
    else:
        return wx.Icon("gfx/myapp.ico", wx.BITMAP_TYPE_ICO)
1

好吧,最近我安装了py2exe,我觉得这可能是个bug。在py2exe_util.c这个文件里,他们应该把rt_icon_id的初始值设为1,而不是0。现在这样的话,使用LoadIcon/LoadImage加载第一个图标的第一个格式是做不到的。

如果这还不是一个大家都知道的问题,我会通知开发者的。

在此之前,有个临时解决办法,就是在你的setup.py里把同一个图标写两遍:

'icon_resources': [(1, 'my_icon.ico'), (2, 'my_icon.ico')]

这样你可以加载第二个图标,而Windows会把第一个图标当作外壳图标来用。不过记得要使用非零的ID哦。:)

5

@efotinis:你说得对。

在py2exe修复之前,这里有个临时解决办法,避免重复包含同一个图标:

hicon = win32gui.CreateIconFromResource(win32api.LoadResource(None, win32con.RT_ICON, 1), True)

要注意的是,1 不是你在setup.py中给图标指定的ID(那是图标组的ID),而是py2exe自动分配给每个图标的资源ID。我理解是这样的。

如果你想创建一个指定大小的图标(因为CreateIconFromResource使用的是系统默认的图标大小),你需要使用CreateIconFromResourceEx,但这个在PyWin32中是没有的:

icon_res = win32api.LoadResource(None, win32con.RT_ICON, 1)
hicon = ctypes.windll.user32.CreateIconFromResourceEx(icon_res, len(icon_res), True,
    0x00030000, 16, 16, win32con.LR_DEFAULTCOLOR)

撰写回答