Получение иконки окна WinAPI

Discussion in 'WASM.WIN32' started by mazik7512, May 2, 2023.

  1. mazik7512

    mazik7512 New Member

    Blog Posts:
    0
    Joined:
    Oct 22, 2022
    Messages:
    9
    В общем занесла меня нелегкая программировать на питоне, да не просто на питоне, а на WinApi на питоне (конкретно модуль win32gui, win32api).

    В чем собственно суть проблемы, мне понадобилось получить иконки открытых окон (дескрипторы окон уже получены), но все варианты которые я нагуглил не особо-то работают. Например, получение иконки через WM_GETICON возвращает число > 65535 и далее вылезает ошибка что id ресурса должно быть в диапазоне до 216 - 1. Пробовал через EnumResourceNames, но то ли функция косячная, то ли я дурак, но при любом дескрипторе он выдает ошибку(Код 1812) об отсутствии секции ресурсов.

    Собственно, сам вопрос, может знает кто как достать иконку из открытого окна.
     
  2. alex_dz

    alex_dz Active Member

    Blog Posts:
    0
    Joined:
    Jul 26, 2006
    Messages:
    531
    жопати уже спрашивали?
     
  3. mazik7512

    mazik7512 New Member

    Blog Posts:
    0
    Joined:
    Oct 22, 2022
    Messages:
    9
    кого простите?
     
  4. Mikl___

    Mikl___ Супермодератор Staff Member

    Blog Posts:
    14
    Joined:
    Jun 25, 2008
    Messages:
    3,914
  5. mazik7512

    mazik7512 New Member

    Blog Posts:
    0
    Joined:
    Oct 22, 2022
    Messages:
    9
    Спасибо за ссылки, но как я написал в заголовке, подобное я уже пробовал, и оно работает не корректно. То что описано по ссылкам возвращает число больше 216 и оно не проходит ни в LoadResource, ни в LoadIcon.
     
  6. Mikl___

    Mikl___ Супермодератор Staff Member

    Blog Posts:
    14
    Joined:
    Jun 25, 2008
    Messages:
    3,914
    mazik7512,
    можно было и фрагмент программы приложить → шансы на успех возрастают на порядок...
     
  7. alex_dz

    alex_dz Active Member

    Blog Posts:
    0
    Joined:
    Jul 26, 2006
    Messages:
    531
    Ну как его (оно) еще звать то?
    ЧатЖоПаТи
     
  8. mazik7512

    mazik7512 New Member

    Blog Posts:
    0
    Joined:
    Oct 22, 2022
    Messages:
    9
    Вы не подумайте, мне не жалко куска кода, просто тут стандартные WinAPI функции в обёртки пайтона.
    Code (Python):
    1.         handle = win32gui.FindWindow(None, "Steam")
    2.         #test = win32gui.SendMessage(handle, win32con.WM_GETICON, win32con.ICON_SMALL)
    3.         test = win32gui.DefWindowProc(handle, win32con.WM_GETICON, win32con.ICON_SMALL, 0)
    4.         print("defwindowproc=", test)
    5.         test_class_long = win32gui.GetClassLong(handle, win32con.GCL_HICON)
    6.         print("class_log=", test_class_long)
    7.         res = win32api.LoadResource(handle, win32con.RT_ICON, test)
    8.         #res = win32gui.CreateIconFromResource(bytes(test), True)
    9.         #print(res)
    10.         #icon = win32gui.LoadImage(handle, u"icon", win32con.IMAGE_ICON, 0, 0, win32con.LR_DEFAULTSIZE)
    11.         #icon = win32gui.LoadIcon(handle, test_class_long)
    12.         #print(icon)
    13.  
    Вот например, несколько моих попыток получить иконку возвращающие в результате
    Code (Text):
    1. defwindowproc= 66997
    2. class_log= 131659
    , числа больше 216 и при дальнейшей попытке засунуть их в Load... функцию выдает ошибку:
    Code (Text):
    1. "Resource id/name must be unicode or int in the range 0-65536"
    Но даже если попытаться в LoadImage передать юникодовскую строку, для любого окна возникает ошибка
    Code (Text):
    1. (1812, 'FindResourceEx', 'Указанный файл образа не содержит секции ресурсов.')
    Сомневаюсь, что он поможет, он же умеет только типовой код генерировать, так что вряд ли его ответы будут чем-то отличаться от первой страницы поисковика.
     
  9. f13nd

    f13nd Well-Known Member

    Blog Posts:
    0
    Joined:
    Jun 22, 2009
    Messages:
    2,020
    Этот хендл актуален только в пределах самого процесса, создавшего его. Изучай DuplicateHandle, но как бы и с ней результат не гарантирован.
     
  10. ormoulu

    ormoulu Well-Known Member

    Blog Posts:
    0
    Joined:
    Jan 24, 2011
    Messages:
    1,206
    Если мне конечно память не изменяет, хендл должен быть не окна а модуля с ресурсом, кроме того меня терзают сомнения относительно того как это будет работать из внешнего процесса. Кмк DuplicateHandle тут не спасет, надо грузить модуль, это если брать иконку из ресурса. Но м.б. есть способ дернуть загруженный в ядро битмап, надо разбираться.
    HICON опять же не равняется ResourceId.
    Работает в 11 для Steam:
    Code (C):
    1. #include <windows.h>
    2. #include <stdio.h>
    3.  
    4. void main ()
    5. {
    6.     SetConsoleTitle ("Find Icon");
    7.  
    8.     //HWND hwnd = FindWindow ("SciCalc", "Calculator");
    9.     //HWND hwnd = FindWindow ("CalcFrame", "Calculator");
    10.     //HWND hwnd = FindWindowW (L"Windows.UI.Core.CoreWindow", L"Calculator");
    11.     HWND hwnd = FindWindowW (NULL, L"Steam");
    12.     printf ("FindWindow 0x%X\n", hwnd);
    13.  
    14.     LRESULT lr = SendMessage (hwnd, WM_GETICON, ICON_BIG, 0);
    15.     printf ("WM_GETICON 0x%X\n", lr);
    16.     DWORD dw = GetClassLong (hwnd, GCL_HICON);
    17.     printf ("GetClassLong 0x%X\n", dw);
    18.     HICON hcopy = CopyIcon ((HICON)dw);
    19.  
    20.     Sleep(1000);
    21.     HWND hcon = FindWindowW (L"ConsoleWindowClass", L"Find Icon");
    22.     //printf ("FindWindow 0x%X\n", hcon);
    23.     HDC hdc=GetWindowDC(hcon);
    24.     //printf ("GetWindowDC 0x%X\n", hdc);
    25.     DrawIcon (hdc, 100, 100, hcopy);
    26.     //DrawIcon (hdc, 100, 100, (HICON)dw);
    27.  
    28.     getchar();
    29. }
    ***

    С калькулятором в 10/11 выходит поинтереснее: окно отрисовывается через хитрый набор C# апи, как сетится иконка и откуда берется я не понимаю. С точки зрения оконного шпиона окно имеет IDI_APPLICATION.
     
  11. Thetrik

    Thetrik UA6527P

    Blog Posts:
    0
    Joined:
    Jul 25, 2011
    Messages:
    887
    Хендл иконки (как и любого user объекта) является публичным, не нужно вызывать DuplicatHandle которая предназначена для kernel объектов.
    А кто сказал что HICON должен быть <216? Это хендл, его передают в функции отрисовки иконок. Тебе в итоге что нужно с иконкой сделать? Отрисовать или получить какие-то данные типа размера и т.п.?
     
  12. rmn

    rmn Well-Known Member

    Blog Posts:
    0
    Joined:
    Nov 23, 2004
    Messages:
    2,347
    Наверное, тот же, кто сказал, что HICON потом нужно передавать в LoadIcon (жэпэтэ, кто же еще?) :)

    mazik7512,
    API-функции возвращают не идентификатор иконки в ресурсах, а уже готовый к использованию хендл загруженной иконки.
     
  13. aa_dav

    aa_dav Active Member

    Blog Posts:
    0
    Joined:
    Dec 24, 2008
    Messages:
    525
  14. Thetrik

    Thetrik UA6527P

    Blog Posts:
    0
    Joined:
    Jul 25, 2011
    Messages:
    887
    Да уже не первый раз слышу что он с winapi не умеет корректно работать.

    Есть разница иконка приложения и иконка окна. ТСу нужны именно иконки окон.
     
  15. mazik7512

    mazik7512 New Member

    Blog Posts:
    0
    Joined:
    Oct 22, 2022
    Messages:
    9
    Всем спасибо, за помощь. Handle иконки получить удалось,
    Отдельное спасибо ormoulu с наводкой на функцию CopyIcon
    но возникла другая проблема, не совсем по теме форума, а с WinAPI-шной оберткой на питоне (win32).

    После получения хендла иконки, мне нужно получить ее bitmap, чтобы отрисовать её в другом месте другими средствами (не через winapi). Получил её ICONINFO структуру, и в ней должны лежать указатели на ч/б битовую маску и данные о цвете, но загвоздка в том, что в обертке там лежат указатели на PyBITMAP объекты, а указатель на сам битмап отсутствует (хотя в документации указано обратное) . Опытным путем я выяснил, что поле без имени называется bmBits, но оно всегда = 0.
     
  16. Thetrik

    Thetrik UA6527P

    Blog Posts:
    0
    Joined:
    Jul 25, 2011
    Messages:
    887
    Получаешь ICONINFO через GetIconInfo, затем через GetDiBits получаешь пиксели в нужном формате для маски и для самого изображения.
     
  17. mazik7512

    mazik7512 New Member

    Blog Posts:
    0
    Joined:
    Oct 22, 2022
    Messages:
    9
    Так GetDiBits берет хендл битмапа, а хендла на битмап у меня нет.
    --- Сообщение объединено, May 3, 2023 ---
    В этом то и заключается проблема, что я не могу получить битмап.
     
  18. ormoulu

    ormoulu Well-Known Member

    Blog Posts:
    0
    Joined:
    Jan 24, 2011
    Messages:
    1,206
    Где-то вы намудрили с вызовами, ищите способ сделать чистый WinAPI-вызов и получить оригинальную структуру, либо проверяйте еще раз, что у вас там возвращается. Может быть, обертка позволяет вытащить битмап или хендл к нему.
    --- Сообщение объединено, May 4, 2023 ---
    Случаем не путаете указатель с хендлом?
     
  19. Thetrik

    Thetrik UA6527P

    Blog Posts:
    0
    Joined:
    Jul 25, 2011
    Messages:
    887
    mazik7512, хендл битмапа получите через GetIconInfo, я же написал.
     
  20. mazik7512

    mazik7512 New Member

    Blog Posts:
    0
    Joined:
    Oct 22, 2022
    Messages:
    9
    может и путаю, но проблема не в этом, а в обёртке. Там в ICONINFO структуре просто отсутсвует поле с хендлом.
    --- Сообщение объединено, May 4, 2023 ---
    Так я и вам написал, несколькими сообщениями выше, что я использовал функцию GetIconInfo, и в этой обёртке(win32gui) отсутсвует хендл на битмап.