0

I'm trying to add an icon to every menu option in a systray library in Python, pystray. For that I'm using win32 functions, I can sucessfully load an icon with extension .ico using the LoadImage function and I get an handle (HBITMAP) to it, next time I try to use that handle in a MENUITEMINFO structure which is passed as the 4th parameter in the InsertMenuItem function gives error WinError 87.

Now about the details, for example:

            icon = win32.LoadImage(
                None,
                iconpath,
                win32.IMAGE_ICON,
                ico_x,
                ico_y,
                win32.LR_LOADFROMFILE)

returns a HBITMAP sucessfully, but after filling the MENUITEMINFO structure:


menu_item = win32.MENUITEMINFO(
            cbSize=ctypes.sizeof(win32.MENUITEMINFO),

            fMask=win32.MIIM_ID | win32.MIIM_STRING | win32.MIIM_STATE
            | win32.MIIM_FTYPE | win32.MIIM_SUBMENU | win32.MIIM_BITMAP ,

            wID=len(callbacks),

            dwTypeData=descriptor.text,

            fState=0
                  | (win32.MFS_DEFAULT if descriptor.default else 0)
                  | (win32.MFS_CHECKED if descriptor.checked else 0)
                  | (win32.MFS_DISABLED if not descriptor.enabled else 0),

            fType=0
                 | (win32.MFT_RADIOCHECK if descriptor.radio else 0)
                 | (win32.MFT_STRING if descriptor.text else 0) ,

                 hbmpItem= icon if descriptor.icon else None,

                 hSubMenu=self._create_menu(descriptor.submenu, callbacks)
                     if descriptor.submenu
                     else None)

descriptor here is a variable that holds the parameters for a menu entry (its text, if it has a check mark, etc.).

everything goes up to:

                win32.InsertMenuItem(hmenu, i, True, ctypes.byref(menu_item))

where menu_item is the variable of type MENUITEMINFO filled above. When I debug I can see the hbmpItem correctly filled with the HBITMAP long value. But this function fails with OSError:WinError 87: The parameter is incorrect.

Strangely, if i use a BMP file, and in the LoadImage function I do:

           icon = win32.LoadImage(
                None,
                bmppath,
                win32.IMAGE_BITMAP,
                ico_x,
                ico_y,
                win32.LR_LOADFROMFILE)

Everything runs fine with the InserMenuItem function.

Can somebody experienced with the win32 API give me an hint about what I'm doing wrong ?

digfish
  • 316
  • 2
  • 11
  • 1
    `fMask` makes promises on which fields contain valid data. The code then moves on to conditionally *not* set some of those values. – IInspectable Mar 08 '23 at 10:12
  • 3
    When you pass `IMAGE_ICON` to `LoadImage` it gives you back a `HICON`, not a `HBITMAP`. The two types are not interchangeable. The menu API only accepts bitmaps. – Jonathan Potter Mar 08 '23 at 11:38
  • 1
    As @JonathanPotter and [MENUITEMINFO](https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-menuiteminfoa) says, (HBITMAP) *hbmpItem* is *A handle to the bitmap to be displayed, or it can be one of the values in the following table*. Even [LoadImage](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadimagea) highlights different Release functions. – YangXiaoPo-MSFT Mar 10 '23 at 08:25

0 Answers0