Any chance to have an updated code for Win64 systray icon?

Started by fielder, February 14, 2025, 09:25:33

Previous topic - Next topic

Henri

- Got 01100011 problems, but the bit ain't 00000001

fielder

Sure!

Import MaxGUI.drivers
Import Pub.Win32

Const NIM_ADD:Int          = 0
Const NIM_MODIFY:Int        = 1
Const NIM_DELETE:Int        = 2
Const NIM_SETFOCUS:Int      = 3
Const NIM_SETVERSION:Int    = 4

Const NIF_MESSAGE:Int  = $00000001
Const NIF_ICON:Int      = $00000002
Const NIF_TIP:Int      = $00000004
Const NIF_STATE:Int = $00000008
Const NIF_INFO:Int      = $00000010
Const NIF_GUID:Int      = $00000020

Type TNotifyIconData
    Field Size:Int
    Field HWND:Byte Ptr
    Field id:Int
    Field flags:Int
    Field CallbackMessage:Int
    Field Icon:Byte Ptr              ' HICON
    Field Tip:Long              ' array [0..63] of AnsiChar;
    Field Tip2:Long
    Field Tip3:Long
    Field Tip4:Long
    Field Tip5:Long
    Field Tip6:Long
    Field Tip7:Long
    Field Tip8:Long
EndType


Extern "WIN32"
    Function Shell_NotifyIcon:Int( message:Int, notifyicondata:Byte Ptr) = "INT Shell_NotifyIconA(INT, BYTE*)!"
EndExtern

Function SetNotifyIconDataTip( nid:TNotifyIconData, s:String)
    MemClear( Varptr nid.Tip, 64)
    If s.length > 0 Then
        Local p:Byte Ptr = s.ToCString()
        If s.length < 64 Then
            'MemCopy( Varptr nid.Tip, p, s.length)
            MemCopy( Varptr nid.Tip, p, Size_T(s.length))

        Else         
            MemCopy( Varptr nid.Tip, p, 63)       
        EndIf
        MemFree( p)
    EndIf
EndFunction

'Windows callback function to get/post events
Function SysTrayWndProc:Byte Ptr(hwnd:Byte Ptr, msg:UInt, wp:WParam, lp:LParam) "win32"

    Select msg

    Case WM_MOUSEMOVE
          Local owner:TGadget = TWindowsGUIDriver.GadgetFromHwnd(hwnd)
          If owner Then
              Select lp
              Case WM_MOUSELEAVE
                    PostGuiEvent( EVENT_MOUSELEAVE, owner )
              Case WM_MOUSEMOVE
                    PostGuiEvent( EVENT_MOUSEMOVE, owner )
              Case WM_RBUTTONDOWN
                    PostGuiEvent( EVENT_MOUSEDOWN, owner, MOUSE_RIGHT )
              Case WM_LBUTTONDOWN
                    PostGuiEvent( EVENT_MOUSEDOWN, owner, MOUSE_LEFT )
              Case WM_RBUTTONDOWN   
                    PostGuiEvent( EVENT_MOUSEDOWN, owner, MOUSE_RIGHT )
              Case WM_LBUTTONDBLCLK
                    PostGuiEvent( EVENT_MOUSEUP, owner )
              EndSelect
          EndIf
    EndSelect

    Return TWindowsGUIDriver.ClassWndProc(hwnd, msg, wp, lp)
EndFunction

'
' window messages (allso used by tray icon)
'
Const WM_MOUSEMOVE:Int        = $0200
Const WM_LBUTTONDOWN:Int      = $0201
Const WM_LBUTTONUP:Int        = $0202
Const WM_LBUTTONDBLCLK:Int    = $0203
Const WM_RBUTTONDOWN:Int      = $0204
Const WM_RBUTTONUP:Int        = $0205
Const WM_RBUTTONDBLCLK:Int    = $0206
Const WM_MBUTTONDOWN:Int      = $0207
Const WM_MBUTTONUP:Int        = $0208
Const WM_MBUTTONDBLCLK:Int    = $0209

'
' icon resources
'
Const IMAGE_BITMAP:Int      = 0
Const IMAGE_ICON:Int        = 1
Const IMAGE_CURSOR:Int      = 2
Const IMAGE_ENHMETAFILE:Int = 3

Const LR_DEFAULTSIZE:Int      = 64
Const LR_DEFAULTCOLOR:Int    = 0
Const LR_MONOCHROME:Int      = 1
Const LR_COLOR:Int            = 2
Const LR_COPYRETURNORG:Int    = 4
Const LR_COPYDELETEORG:Int    = 8
Const LR_LOADFROMFILE:Int    = 16
Const LR_LOADTRANSPARENT:Int  = 32
Const LR_LOADREALSIZE:Int    = 128
Const LR_LOADMAP3DCOLORS:Int  = 4096
Const LR_CREATEDIBSECTION:Int = 8192
Const LR_COPYFROMRESOURCE:Int = $4000 ' 0x4000
Const LR_SHARED:Int          = 32768         

Global nid:TNotifyIconData

Extern "WIN32"

    Function LoadImage_:Int( Instance:Int, Name$z, Type_:Int, DesiredX:Int, DesiredY:Int, Load:Int) = "INT LoadImageA(INT,BBSTRING,INT,INT,INT,INT)!"

EndExtern

Function LoadIcon:Int( filename:String, width:Int=16,height:Int=16, flags:Int=LR_SHARED)
    Return LoadImage_( 0, filename, IMAGE_ICON, width,height, LR_LOADFROMFILE| flags)
EndFunction

?

' Register tray icon
Function RegisterTrayIcon(window:TGadget, toolTip:String, iconFile:String)


    nid = New TNotifyIconData
    nid.Size = SizeOf(TNotifyIconData)
    nid.hwnd = QueryGadget(window, QUERY_HWND)
    nid.id = 0
    nid.CallbackMessage = WM_MOUSEMOVE
    nid.Icon = LoadIcon( iconFile)
    nid.flags = NIF_MESSAGE | NIF_TIP | NIF_ICON



    SetNotifyIconDataTip( nid, toolTip )

    Shell_NotifyIcon( NIM_ADD, nid)

    SetWindowLongW(nid.hwnd, GWL_WNDPROC, Int(Byte Ptr(SysTrayWndProc)) )

End Function 

'Remove tray icon
Function RemoveTrayIcon() 

    Shell_NotifyIcon(NIM_DELETE, nid)

End Function


' EXAMPLE
'
Local window:TGadget = CreateWindow( "Window", 80, 80, 220, 220)
Local panel:TGadget = CreatePanel( 0, 0, 0, 0, window, PANEL_ACTIVE)

RegisterTrayIcon(panel, "Green ICON", "green.ico")


Repeat
    WaitEvent()

    'Print CurrentEvent.ToString()

    Select EventID()

    Case EVENT_MOUSEMOVE
          Print "Mouse moved!"

    Case EVENT_MOUSEDOWN
          Select EventData()

          Case MOUSE_LEFT
              Print "Left mousebutton down"

          Case MOUSE_RIGHT
              Print "Right mousebutton down, exiting!"; Exit
          EndSelect

    Case EVENT_MOUSEUP    'There is no doubleclick event so we are using mouse_up
          Print "change color icon"
 RemoveTrayIcon()
          RegisterTrayIcon(panel, "RED icon", "red.ico")

          ShowGadget(window)

    Case EVENT_WINDOWCLOSE
          HideGadget(window)
    EndSelect

Forever

' unregister tray icon
RemoveTrayIcon()

End

i just added that a double click change the tray icon color, and right mouse button close the app

Henri

Okay, I noticed that you have to use SetWindowLongPtrW for 64-bit version so just change SetWindowLongW to this:

SetWindowLongPtrW(nid.hwnd, GWL_WNDPROC, Byte Ptr(SysTrayWndProc) )
-Henri
- Got 01100011 problems, but the bit ain't 00000001


fielder

i have also a new question... how i can make the icon changing color/image by it's own (witjout a mouse event?)


Repeat

    WaitEvent()

    'Print CurrentEvent.ToString()

    Select EventID()

    Case EVENT_MOUSEMOVE
          'Print "Mouse moved!"

    Case EVENT_MOUSEDOWN
          Select EventData()

          Case MOUSE_LEFT
              Print "Left mousebutton down"

          Case MOUSE_RIGHT
              Print "Right mousebutton down, exit!"; Exit
          EndSelect

    Case EVENT_MOUSEUP    'There is no doubleclick event so we are using mouse_up
          Print "double click change the color"
 RemoveTrayIcon()
          RegisterTrayIcon(canvas, "RED", "red.ico")

          ShowGadget(MainWindow)

    Case EVENT_WINDOWCLOSE
          HideGadget(MainWindow)
    EndSelect

Forever

' unregister tray icon
RemoveTrayIcon()

End

if i remeber well, there was a sort of timer that can be used to refresh a window ( tick? )

fielder

ok solved using the Peekevent() :)

but.. again a question, everything is working fine.. but i can't use as a icon one stored on the main executable using"incbin"

Function LoadIcon:Int( filename:String, width:Int=16,height:Int=16, flags:Int=LR_SHARED)
    Return LoadImage_( 0, "incbin::"+filename, IMAGE_ICON, width,height, LR_LOADFROMFILE| flags)
EndFunction

the incbin, placed on this function, or used a string (like this: incbin::icon.ico )
is making the icon not visible (empty space)
there is a way to store the image icon on another image format.. or i need to change something elese  (for example LR_LOADFROMFILE  )

??/ very thank you for any answer.


fielder

i've tried all the night, the only way is found is from here: https://www.syntaxbomb.com/maxgui/change-window-icon-via-extracticona-using-incbin/

and basically is just a way to create a phisical icon file extracting it from the EXE... and placing as a icon like usual..  a little bit tricky.

Incbin "icon.ico"

Function extracticon(fIn:String)
  Local fOut:String
  Local fOD:TStream
  ' extract IncBin'd iconfile to disk
  Local iPtr:Byte Ptr=IncbinPtr(fIn)
  Local iLen:Long=IncbinLen(fIn)
  Local iDat:String=String.FromBytes(iPtr,iLen)
  If iDat Then
    fOut="_"+StripDir(fIn)
Print StripDir(fIn)
    fOD=WriteFile(fOut)
    If fOD Then
      WriteString(fOD,iDat)
      CloseStream(fOD)
    EndIf
  EndIf
End Function

extracticon ("icon.ico")

any other idea??