Como você carregar um ícone incorporado a partir de um arquivo EXE com PyWin32?
Pergunta
Eu tenho um arquivo exe gerado com py2exe. No setup.py I especificar um ícone para ser incorporado no exe:
windows=[{'script': 'my_script.py','icon_resources': [(0, 'my_icon.ico')], ...
Eu tentei carregar o ícone usando:
hinst = win32api.GetModuleHandle(None)
hicon = win32gui.LoadImage(hinst, 0, win32con.IMAGE_ICON, 0, 0, win32con.LR_DEFAULTSIZE)
Mas isso produz um erro (muito inespecíficos):
pywintypes.error: (0, 'LoadImage', 'Nenhuma mensagem de erro está disponível')
Se eu tentar especificando 0 como uma string
hicon = win32gui.LoadImage(hinst, '0', win32con.IMAGE_ICON, 0, 0, win32con.LR_DEFAULTSIZE)
então eu recebo o erro:
pywintypes.error: (1813, 'LoadImage', 'O tipo de recurso especificado não pode ser encontrado no arquivo de imagem')
Então, qual é o método / sintaxe correta para carregar o ícone?
Também Por favor note que eu não utilizar qualquer conjunto de ferramentas GUI -. Apenas a API do Windows via PyWin32
Solução
@efotinis: Você está certo.
Aqui está uma solução alternativa até que py2exe fica fixo e você não deseja incluir o mesmo ícone duas vezes:
hicon = win32gui.CreateIconFromResource(win32api.LoadResource(None, win32con.RT_ICON, 1), True)
Esteja ciente de que 1 não é a ID que você deu o ícone no setup.py (que é o ID ícone do grupo), mas o ID do recurso automaticamente atribuído pela py2exe para cada ícone em cada grupo ícone. Pelo menos é assim que eu entendo.
Se você deseja criar um ícone com um tamanho especificado (como CreateIconFromResource usa o tamanho do ícone padrão do sistema), você precisa usar CreateIconFromResourceEx, que não está disponível através 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)
Outras dicas
Se você estiver usando wxPython, você pode usar o seguinte código simples:
wx.Icon(sys.argv[0], wx.BITMAP_TYPE_ICO)
Normalmente, eu tenho o código que verifica se ele está sendo executado a partir de um EXE ou não, e age em conformidade:
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)
Bem, bem ... Eu instalei py2exe e eu acho que é um bug. Em py2exe_util.c eles devem o init rt_icon_id
a 1 em vez de 0. O jeito que está agora, é impossível para carregar o primeiro formato do primeiro ícone usando LoadIcon / LoadImage.
Vou notificar os desenvolvedores sobre isso se não é já um problema conhecido.
Uma solução, entretanto, seria incluir o mesmo ícone duas vezes em sua setup.py:
'icon_resources': [(1, 'my_icon.ico'), (2, 'my_icon.ico')]
Você pode carregar o segundo, enquanto o Windows usará o primeiro como o ícone shell. Lembre-se de usar diferentes de zero IDs embora. :)
Você deve definir o ícone de ID para algo diferente de 0:
'icon_resources': [(42, 'my_icon.ico')]
IDs de recursos do Windows deve estar entre 1 e 32767.