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

Тема в разделе "WASM.WIN32", создана пользователем mazik7512, 2 май 2023.

  1. mazik7512

    mazik7512 New Member

    Публикаций:
    0
    Регистрация:
    22 окт 2022
    Сообщения:
    9
    В общем занесла меня нелегкая программировать на питоне, да не просто на питоне, а на WinApi на питоне (конкретно модуль win32gui, win32api).

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

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

    alex_dz Active Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    458
    жопати уже спрашивали?
     
  3. mazik7512

    mazik7512 New Member

    Публикаций:
    0
    Регистрация:
    22 окт 2022
    Сообщения:
    9
    кого простите?
     
  4. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.796
  5. mazik7512

    mazik7512 New Member

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

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.796
    mazik7512,
    можно было и фрагмент программы приложить → шансы на успех возрастают на порядок...
     
  7. alex_dz

    alex_dz Active Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    458
    Ну как его (оно) еще звать то?
    ЧатЖоПаТи
     
  8. mazik7512

    mazik7512 New Member

    Публикаций:
    0
    Регистрация:
    22 окт 2022
    Сообщения:
    9
    Вы не подумайте, мне не жалко куска кода, просто тут стандартные WinAPI функции в обёртки пайтона.
    Код (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.  
    Вот например, несколько моих попыток получить иконку возвращающие в результате
    Код (Text):
    1. defwindowproc= 66997
    2. class_log= 131659
    , числа больше 216 и при дальнейшей попытке засунуть их в Load... функцию выдает ошибку:
    Код (Text):
    1. "Resource id/name must be unicode or int in the range 0-65536"
    Но даже если попытаться в LoadImage передать юникодовскую строку, для любого окна возникает ошибка
    Код (Text):
    1. (1812, 'FindResourceEx', 'Указанный файл образа не содержит секции ресурсов.')
    Сомневаюсь, что он поможет, он же умеет только типовой код генерировать, так что вряд ли его ответы будут чем-то отличаться от первой страницы поисковика.
     
  9. f13nd

    f13nd Well-Known Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    2.000
    Этот хендл актуален только в пределах самого процесса, создавшего его. Изучай DuplicateHandle, но как бы и с ней результат не гарантирован.
     
  10. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.208
    Если мне конечно память не изменяет, хендл должен быть не окна а модуля с ресурсом, кроме того меня терзают сомнения относительно того как это будет работать из внешнего процесса. Кмк DuplicateHandle тут не спасет, надо грузить модуль, это если брать иконку из ресурса. Но м.б. есть способ дернуть загруженный в ядро битмап, надо разбираться.
    HICON опять же не равняется ResourceId.
    Работает в 11 для Steam:
    Код (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

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

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    Наверное, тот же, кто сказал, что HICON потом нужно передавать в LoadIcon (жэпэтэ, кто же еще?) :)

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

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    462
  14. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    875
    Да уже не первый раз слышу что он с winapi не умеет корректно работать.

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

    mazik7512 New Member

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

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

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    875
    Получаешь ICONINFO через GetIconInfo, затем через GetDiBits получаешь пиксели в нужном формате для маски и для самого изображения.
     
  17. mazik7512

    mazik7512 New Member

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

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.208
    Где-то вы намудрили с вызовами, ищите способ сделать чистый WinAPI-вызов и получить оригинальную структуру, либо проверяйте еще раз, что у вас там возвращается. Может быть, обертка позволяет вытащить битмап или хендл к нему.
    --- Сообщение объединено, 4 май 2023 ---
    Случаем не путаете указатель с хендлом?
     
  19. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    875
    mazik7512, хендл битмапа получите через GetIconInfo, я же написал.
     
  20. mazik7512

    mazik7512 New Member

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