Search code examples
python-3.xwindows64-bitctypes

Notification icon(NIIF_INFO, NIIF_WARNING) is not visible in notification in 64bit python


I am using this structure for notifyicondata in python using ctypes

class NOTIFYICONDATA(Structure):
    _fields_ = [
        ('cbSize', c_uint32),
        ('hWnd', HWND),
        ('uID', c_uint32),
        ('uFlags', c_uint32),
        ('uCallbackMessage', c_uint32),
        ('hIcon', c_void_p),
        ('szTip', c_wchar * 128),
        ('dwState', c_uint32),
        ('dwStateMask', c_uint32),
        ('szInfo', c_wchar * 256),
        ('union', _timeout_or_version),
        ('uVersion', c_uint32),
        ('szInfoTitle', c_wchar * 64),
        ('dwInfoFlags', c_uint32),
        ('guidItem', GUID),
        ('hBalloonIcon', c_uint32),
    ]

It was working in 32bit python but NIIF_WARNING or NIIF_INFO icon is not visible in 64bit python is my structure wrong?


Solution

  • Errors are uVersion should be part of the union (union not shown) and the last parameter should be an HICON. Use the pre-defined ctypes.wintypes for accuracy. I added the missing GUID type as well.

    Since this defines the wide version of the structure, make sure to use the wide version of the Shell_NotifyIconW function as well.

    import ctypes as ct
    import ctypes.wintypes as w
    
    NIF_MESSAGE  = 0x00000001
    NIF_ICON     = 0x00000002
    NIF_TIP      = 0x00000004
    NIF_STATE    = 0x00000008
    NIF_INFO     = 0x00000010
    NIF_GUID     = 0x00000020
    NIF_REALTIME = 0x00000040
    NIF_SHOWTIP  = 0x00000080
    
    NIS_HIDDEN     = 0x00000001
    NIS_SHAREDICON = 0x00000002
    
    NIIF_NONE = 0x00000000
    
    NIIF_INFO               = 0x00000001
    NIIF_WARNING            = 0x00000002
    NIIF_ERROR              = 0x00000003
    NIIF_USER               = 0x00000004
    NIIF_NOSOUND            = 0x00000010
    NIIF_LARGE_ICON         = 0x00000020
    NIIF_RESPECT_QUIET_TIME = 0x00000080
    NIIF_ICON_MASK          = 0x0000000F
    
    class GUID(ct.Structure):
        _fields_ = (('Data1', ct.c_ulong),
                    ('Data2', ct.c_ushort),
                    ('Data3', ct.c_ushort),
                    ('Data4', ct.c_ubyte * 8))
    
        def __repr__(self):
            return f'GUID(Data1=0x{self.Data1:08x}, Data2=0x{self.Data2:04x}, Data3=0x{self.Data3:04x}, ' \
                        f'Data4=[{", ".join([f"0x{n:02x}" for n in self.Data4])}])'
    
        def __str__(self):
            return f'{{{self.Data1:08x}-{self.Data2:04x}-{self.Data3:04x}-' \
                   f'{self.Data4[0]:02x}{self.Data4[1]:02x}-{bytes(self.Data4[2:]).hex()}}}'
    
        def __init__(self, Data1, Data2, Data3, Data4):
            self.Data1 = Data1
            self.Data2 = Data2
            self.Data3 = Data3
            self.Data4[:] = Data4
    
    class U(ct.Union):
        _fields_ = (('uTimeout', w.UINT),
                    ('uVersion', w.UINT))
    
    class NOTIFYICONDATAW(ct.Structure):
        _fields_ = (('cbSize', w.DWORD),
                    ('hWnd', w.HWND),
                    ('uID', w.UINT),
                    ('uFlags', w.UINT),
                    ('uCallbackMessage', w.UINT),
                    ('hIcon', w.HICON),
                    ('szTip', w.WCHAR * 128),
                    ('dwState', w.DWORD),
                    ('dwStateMask', w.DWORD),
                    ('szInfo', w.WCHAR * 256),
                    ('u', U),
                    ('szInfoTitle', w.WCHAR * 64),
                    ('dwInfoFlags', w.DWORD),
                    ('guidItem', GUID),
                    ('hBalloonIcon', w.HICON))