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

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

  1. mazik7512

    mazik7512 New Member

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

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

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

    alex_dz Active Member

    Blog Posts:
    0
    жопати уже спрашивали?
     
  3. mazik7512

    mazik7512 New Member

    Blog Posts:
    0
    кого простите?
     
  4. Mikl___

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

    Blog Posts:
    14
  5. mazik7512

    mazik7512 New Member

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

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

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

    alex_dz Active Member

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

    mazik7512 New Member

    Blog Posts:
    0
    Вы не подумайте, мне не жалко куска кода, просто тут стандартные 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
    Этот хендл актуален только в пределах самого процесса, создавшего его. Изучай DuplicateHandle, но как бы и с ней результат не гарантирован.
     
  10. ormoulu

    ormoulu Well-Known Member

    Blog Posts:
    0
    Если мне конечно память не изменяет, хендл должен быть не окна а модуля с ресурсом, кроме того меня терзают сомнения относительно того как это будет работать из внешнего процесса. Кмк 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
    Хендл иконки (как и любого user объекта) является публичным, не нужно вызывать DuplicatHandle которая предназначена для kernel объектов.
    А кто сказал что HICON должен быть <216? Это хендл, его передают в функции отрисовки иконок. Тебе в итоге что нужно с иконкой сделать? Отрисовать или получить какие-то данные типа размера и т.п.?
     
  12. rmn

    rmn Well-Known Member

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

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

    aa_dav Active Member

    Blog Posts:
    0
  14. Thetrik

    Thetrik UA6527P

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

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

    mazik7512 New Member

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

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

    Thetrik UA6527P

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

    mazik7512 New Member

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

    ormoulu Well-Known Member

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

    Thetrik UA6527P

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

    mazik7512 New Member

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