Page 1 of 1

Enumerate System Tray Icons [Windows]

Posted: Sat Mar 04, 2023 10:04 pm
by RASHAD
PB x86 & x64 OK
Tested with PB 6.xx x86 & x64 - Windows 11 x64
Tested with with VM Windows 7,8,8.1,10

New :
- Code modified
- Tested OK with VM XP x64 too

Code: Select all

Global count,turn,hWnd

Global Dim Stray$(0),Dim Icon(0)

Structure TRAYDATA Align #PB_Structure_AlignC
  hwnd.i
  uID.l             
  uCallbackMessage.l
  Reserved.l[2]     
  hIcon.i           
EndStructure

Structure TRAYDATA_wow64 Align #PB_Structure_AlignC
  hwnd.q
  uID.l             
  uCallbackMessage.l
  Reserved.l[2]     
  hIcon.i           
EndStructure

Structure TBBUTTON_wow64 Align #PB_Structure_AlignC
  iBitmap.l
  idCommand.l
  fsState.b
  fsStyle.b
  bReserved.b[6]
  dwData.q
  iString.q
EndStructure 

Procedure Is64Bit()
  bIsWow64 = 0 
  If OpenLibrary(0,"kernel32.dll")
    *MAlloc = GetFunction(0, "IsWow64Process")
    CallFunctionFast(*MAlloc,GetCurrentProcess_(), @bIsWow64)
    CloseLibrary(0)
  EndIf 
  ProcedureReturn bIsWow64
EndProcedure

Procedure.s GetImageName(hWnd,PID)
  OpenLibrary(0, "psapi.dll")
  filename$ = Space(#MAX_PATH) 
  CompilerIf #PB_Compiler_Unicode
    *fn = GetFunction(0, "GetProcessImageFileNameW")
  CompilerElse
    *fn = GetFunction(0, "GetProcessImageFileNameA")
  CompilerEndIf
  GetWindowThreadProcessId_(hWnd, @processID.i)
  hProc = OpenProcess_(#PROCESS_ALL_ACCESS	, #False, processID)
  If hProc 
    CallFunctionFast(*fn, hProc, @filename$, #MAX_PATH)
    CloseHandle_(hProc)
  EndIf
  CloseLibrary(hDLL)
  ProcedureReturn filename$
EndProcedure

Procedure Find_PB_TrayIcons()
  Protected hwnd
  For n = 1 To 2
    If n = 1
      hWnd = FindWindow_("Shell_TrayWnd", #Null)
      If hWnd
        hWnd = FindWindowEx_(hWnd, #Null, "TrayNotifyWnd", #Null)
        If hWnd
          hWnd = FindWindowEx_(hWnd,#Null, "SysPager", #Null)
          If hWnd
            hTray = FindWindowEx_(hWnd, #Null, "ToolbarWindow32", #Null)
          Else
            ProcedureReturn 0
          EndIf
        Else
          ProcedureReturn 0
        EndIf
      Else
        ProcedureReturn 0
      EndIf
      count = SendMessage_(hTray, #TB_BUTTONCOUNT, 0, 0)
    ElseIf n = 2
      hWnd = FindWindow_("NotifyIconOverflowWindow", #Null)
      If hWnd
          hTray = FindWindowEx_(hWnd, #Null, "ToolbarWindow32", #Null)
      Else
        ProcedureReturn 0
      EndIf
      count = count + SendMessage_(hTray, #TB_BUTTONCOUNT, 0, 0)
    EndIf
      
  If Is64Bit()
    Dim button_td2.TRAYDATA_wow64(count*2)
    Dim button2.TBBUTTON_wow64   (count*2)
  Else
    Dim button_td.TRAYDATA(count*2)
    Dim button.TBBUTTON   (count*2)
  EndIf
  
  ReDim Stray$(count*2)
  ReDim Icon(count*2)  
 
  dwExplorerThreadId=GetWindowThreadProcessId_(hTray, @dwExplorerProcessId)
  hProc = OpenProcess_(#PROCESS_ALL_ACCESS, #False, dwExplorerProcessId)
  If Is64Bit()
    *lpData = VirtualAllocEx_(hProc, #Null, SizeOf(TBBUTTON_wow64)*count, #MEM_COMMIT, #PAGE_READWRITE)
  Else
    *lpData = VirtualAllocEx_(hProc, #Null, SizeOf(TBBUTTON)*count, #MEM_COMMIT, #PAGE_READWRITE)
  EndIf
  
  For i = 0 To count - 1
    If Is64Bit()
      SendMessage_(hTray, #TB_GETBUTTON, i, *lpData+i*SizeOf(TBBUTTON_wow64) )
      ReadProcessMemory_(hProc, *lpData+(i*SizeOf(TBBUTTON_wow64)), @button2.TBBUTTON_wow64(i), SizeOf(TBBUTTON_wow64), #Null)
      ReadProcessMemory_(hProc, button2(i)\dwData, @button_td2.TRAYDATA_wow64(i), SizeOf(TRAYDATA_wow64), #Null)
      hIcon = button_td2.TRAYDATA_wow64(i)\hIcon
      hWnd = button_td2.TRAYDATA_wow64(i)\hwnd
      uID = button_td2.TRAYDATA_wow64(i)\uID
      iState = button2.TBBUTTON_wow64(i)\fsState
      IconName$ = GetImageName(hWnd,uID)      
      win$ = Space(#MAX_PATH)
      GetWindowsDirectory_(@win$,#MAX_PATH)
      win$ = RemoveString(win$, "\Windows",#PB_String_NoCase)
      If Trim(IconName$) = ""
        IconName$ = "System Icon"
      Else
        ;IconName$ = RemoveString(IconName$,"\Windows",#PB_String_NoCase)
        left$ = Left(IconName$,23)
        IconName$ = ReplaceString(IconName$,left$,win$)
      EndIf
      If n = 1
        turn = i
        STray$(turn) = "     " + Str(hIcon) +  Chr(10) + Str(hWnd) + Chr(10) + Str(iState) + Chr(10) + Str(uID) + Chr(10) + IconName$
      Else
        turn = turn + 1
        STray$(turn) = "     " + Str(hIcon) +  Chr(10) + Str(hWnd) + Chr(10) + "OFN" + Chr(10) + Str(uID) + Chr(10) + IconName$
      EndIf        
        Icon(turn) = hIcon
    Else
      SendMessage_(hTray, #TB_GETBUTTON, i, *lpData+i*SizeOf(TBBUTTON) )
      ReadProcessMemory_(hProc, *lpData+(i*SizeOf(TBBUTTON)), @button.TBBUTTON(i), SizeOf(TBBUTTON), #Null)
      ReadProcessMemory_(hProc, button(i)\dwData, @button_td.TRAYDATA(i), SizeOf(TRAYDATA), #Null)
      hIcon = button_td.TRAYDATA(i)\hIcon
      hWnd = button_td.TRAYDATA(i)\hwnd
      uID = button_td.TRAYDATA(i)\uID
      iState = button.TBBUTTON(i)\fsState
      IconName$ = GetImageName(hWnd,uID)
      win$ = Space(#MAX_PATH)
      GetWindowsDirectory_(@win$,#MAX_PATH)
      win$ = RemoveString(win$, "\Windows",#PB_String_NoCase)
      If Trim(IconName$) = ""
        IconName$ = "System Icon"
      Else
        ;IconName$ = RemoveString(IconName$,"\Windows",#PB_String_NoCase)
        left$ = Left(IconName$,23)
        IconName$ = ReplaceString(IconName$,left$,win$)
      EndIf
      If n = 1
         turn = i
         STray$(turn) = "     " + Str(hIcon)  + Chr(10) + Str(hWnd) + Chr(10) + Str(iState) + Chr(10) + Str(uID) + Chr(10) + IconName$
      Else
        turn = turn + 1
        STray$(turn) = "     " + Str(hIcon)  + Chr(10) + Str(hWnd) + Chr(10) + "OFN" + Chr(10) + Str(uID) + Chr(10) + IconName$
      EndIf        
        Icon(turn) = hIcon
    EndIf
  Next
    
  Next
 
  VirtualFreeEx_(hProc, *lpData, #Null, #MEM_RELEASE)
  VirtualFreeEx_(hProc, *lpRect, #Null, #MEM_RELEASE)
  CloseHandle_(hProc)  
 
EndProcedure

OpenWindow(0, 0, 0, 600, 300, "SysTray Notification Icons", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)

ListIconGadget(0,10,10,580,280,"Icon-Icon Handle", 130, #PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect )
;SetGadgetColor(0, #PB_Gadget_FrontColor, $FD4B0B)
;SetGadgetColor(0, #PB_Gadget_BackColor, $E8FEFE)
   
AddGadgetColumn(0, 1, "Win Handle", 100)
AddGadgetColumn(0, 2, "Status", 55)
AddGadgetColumn(0, 3, "PID", 60)
AddGadgetColumn(0, 4, "Image name", 600)

Find_PB_TrayIcons()

For x = 0 To count-1
  AddGadgetItem(0,-1, STray$(x), Icon(x))
Next

Repeat
     iEvent = WaitWindowEvent()
     
     Select iEvent
         Case #PB_Event_Gadget
             Select EventGadget()
             EndSelect
     EndSelect       
Until iEvent = #PB_Event_CloseWindow 

Sorry copy paste error as usual :wink:
Edit : Bug fixed
Edit2 : Bug fixed

Re: Enumerate System Tray Icons [Windows]

Posted: Sun Mar 05, 2023 5:19 am
by AZJIO
RASHAD
[ERROR] Array index out of bounds.

Re: Enumerate System Tray Icons [Windows]

Posted: Sun Mar 05, 2023 5:29 am
by RASHAD
How many icons you have?
See if the problem solved or not

Previous post Updated to consider any no.of system tray buttons

Re: Enumerate System Tray Icons [Windows]

Posted: Sun Mar 05, 2023 7:27 am
by AZJIO
It's ok now, link.
Where there are no icons - explorer.exe. Should be a network and sound icon, not explorer.exe
Once gave an error, it was not possible to repeat the error how many did not run. On line "AddGadgetItem(0,-1, STray$(x), Icon(x))"
[ERROR] AddGadgetItem(): The specified 'ImageID' is not valid.

Re: Enumerate System Tray Icons [Windows]

Posted: Wed Mar 08, 2023 8:38 pm
by Kwai chang caine
AZJIO wrote: I On line "AddGadgetItem(0,-1, STray$(x), Icon(x))"
[ERROR] AddGadgetItem(): The specified 'ImageID' is not valid.
The same problem :cry:
Count = 11 here

Re: Enumerate System Tray Icons [Windows]

Posted: Wed Mar 08, 2023 9:42 pm
by RASHAD
Hi KCC
I can't guess what kind of icon cause the error
Try the next turn then report

Code: Select all


Find_PB_TrayIcons()

For x = 0 To count-1
  icoH = CopyImage_(Icon(x),#IMAGE_ICON,16,16,#LR_COPYDELETEORG)
  If icoH
    AddGadgetItem(0,-1, STray$(x), icoH)
  Else
    AddGadgetItem(0,-1, STray$(x), 0)
  EndIf
Next


Re: Enumerate System Tray Icons [Windows]

Posted: Thu Mar 09, 2023 12:22 am
by AZJIO
The "sound" and "network" icons are not visible to me, because the background is white. It is necessary to read the color of the taskbar in the registry and make the same background for the icon.

Code: Select all

		icoH = CopyImage_(Icon(x), #IMAGE_ICON, 16, 16, #LR_COPYDELETEORG)
		If icoH
			AddGadgetItem(0,  -1, STray$(x), icoH)
			DestroyIcon_(icoH)
		Else
			AddGadgetItem(0,  -1, STray$(x), 0)
		EndIf

Re: Enumerate System Tray Icons [Windows]

Posted: Thu Mar 09, 2023 12:37 am
by RASHAD
The icons background color is fine with Windows 7,9,10
No need to spend more effort for just small glitch
Why don't you try to solve that glitch and add it here instead of try to be smart
I just solved the main topic while nobody else did
Be careful :wink:

Re: Enumerate System Tray Icons [Windows]

Posted: Thu Mar 09, 2023 7:37 am
by RASHAD
Solved the back ground color of some Windows 10,11 icons without playing with the registry [Too dangerous] :wink:
That is enough for me ,any more work to do is your turn

Code: Select all


Global count,turn,hWnd

Global Dim Stray$(0),Dim Icon(0)

Structure TRAYDATA Align #PB_Structure_AlignC
  hwnd.i
  uID.l             
  uCallbackMessage.l
  Reserved.l[2]     
  hIcon.i           
EndStructure

Structure TRAYDATA_wow64 Align #PB_Structure_AlignC
  hwnd.q
  uID.l             
  uCallbackMessage.l
  Reserved.l[2]     
  hIcon.i           
EndStructure

Structure TBBUTTON_wow64 Align #PB_Structure_AlignC
  iBitmap.l
  idCommand.l
  fsState.b
  fsStyle.b
  bReserved.b[6]
  dwData.q
  iString.q
EndStructure 

Procedure Is64Bit()
  bIsWow64 = 0 
  If OpenLibrary(0,"kernel32.dll")
    *MAlloc = GetFunction(0, "IsWow64Process")
    CallFunctionFast(*MAlloc,GetCurrentProcess_(), @bIsWow64)
    CloseLibrary(0)
  EndIf 
  ProcedureReturn bIsWow64
EndProcedure

Procedure.s GetImageName(hWnd,PID)
  OpenLibrary(0, "psapi.dll")
  filename$ = Space(#MAX_PATH) 
  CompilerIf #PB_Compiler_Unicode
    *fn = GetFunction(0, "GetProcessImageFileNameW")
  CompilerElse
    *fn = GetFunction(0, "GetProcessImageFileNameA")
  CompilerEndIf
  GetWindowThreadProcessId_(hWnd, @processID.i)
  hProc = OpenProcess_(#PROCESS_ALL_ACCESS	, #False, processID)
  If hProc 
    CallFunctionFast(*fn, hProc, @filename$, #MAX_PATH)
    CloseHandle_(hProc)
  EndIf
  CloseLibrary(hDLL)
  ProcedureReturn filename$
EndProcedure

Procedure Find_PB_TrayIcons()
  Protected hwnd
  CreateImage(100,16,16,32,#PB_Image_Transparent)
  For n = 1 To 2
    If n = 1
      hWnd = FindWindow_("Shell_TrayWnd", #Null)
      If hWnd
        hWnd = FindWindowEx_(hWnd, #Null, "TrayNotifyWnd", #Null)
        If hWnd
          hWnd = FindWindowEx_(hWnd,#Null, "SysPager", #Null)
          If hWnd
            hTray = FindWindowEx_(hWnd, #Null, "ToolbarWindow32", #Null)
          Else
            ProcedureReturn 0
          EndIf
        Else
          ProcedureReturn 0
        EndIf
      Else
        ProcedureReturn 0
      EndIf
      count = SendMessage_(hTray, #TB_BUTTONCOUNT, 0, 0)
    ElseIf n = 2
      hWnd = FindWindow_("NotifyIconOverflowWindow", #Null)
      If hWnd
          hTray = FindWindowEx_(hWnd, #Null, "ToolbarWindow32", #Null)
      Else
        ProcedureReturn 0
      EndIf
      count = count + SendMessage_(hTray, #TB_BUTTONCOUNT, 0, 0)
    EndIf
      
  If Is64Bit()
    Dim button_td2.TRAYDATA_wow64(count*2)
    Dim button2.TBBUTTON_wow64   (count*2)
  Else
    Dim button_td.TRAYDATA(count*2)
    Dim button.TBBUTTON   (count*2)
  EndIf
  
  ReDim Stray$(count*2)
  ReDim Icon(count*2)  
 
  dwExplorerThreadId=GetWindowThreadProcessId_(hTray, @dwExplorerProcessId)
  hProc = OpenProcess_(#PROCESS_ALL_ACCESS, #False, dwExplorerProcessId)
  If Is64Bit()
    *lpData = VirtualAllocEx_(hProc, #Null, SizeOf(TBBUTTON_wow64)*count, #MEM_COMMIT, #PAGE_READWRITE)
  Else
    *lpData = VirtualAllocEx_(hProc, #Null, SizeOf(TBBUTTON)*count, #MEM_COMMIT, #PAGE_READWRITE)
  EndIf
  
  For i = 0 To count - 1
    If Is64Bit()
      SendMessage_(hTray, #TB_GETBUTTON, i, *lpData+i*SizeOf(TBBUTTON_wow64) )
      ReadProcessMemory_(hProc, *lpData+(i*SizeOf(TBBUTTON_wow64)), @button2.TBBUTTON_wow64(i), SizeOf(TBBUTTON_wow64), #Null)
      ReadProcessMemory_(hProc, button2(i)\dwData, @button_td2.TRAYDATA_wow64(i), SizeOf(TRAYDATA_wow64), #Null)      
      hIcon = button_td2.TRAYDATA_wow64(i)\hIcon
      hWnd = button_td2.TRAYDATA_wow64(i)\hwnd
      uID = button_td2.TRAYDATA_wow64(i)\uID
      iState = button2.TBBUTTON_wow64(i)\fsState
      IconName$ = GetImageName(hWnd,uID)      
      win$ = Space(#MAX_PATH)
      GetWindowsDirectory_(@win$,#MAX_PATH)
      win$ = RemoveString(win$, "\Windows",#PB_String_NoCase)
      If Trim(IconName$) = ""
        IconName$ = "System Icon"
      Else
        left$ = Left(IconName$,23)
        IconName$ = ReplaceString(IconName$,left$,win$)
      EndIf
      If n = 1
        turn = i
        STray$(turn) = "     " + Str(hIcon) +  Chr(10) + Str(hWnd) + Chr(10) + Str(iState) + Chr(10) + Str(uID) + Chr(10) + IconName$
      Else
        turn = turn + 1
        STray$(turn) = "     " + Str(hIcon) +  Chr(10) + Str(hWnd) + Chr(10) + "OFN" + Chr(10) + Str(uID) + Chr(10) + IconName$
      EndIf        
        Icon(turn) = hIcon
    Else
      SendMessage_(hTray, #TB_GETBUTTON, i, *lpData+i*SizeOf(TBBUTTON) )
      ReadProcessMemory_(hProc, *lpData+(i*SizeOf(TBBUTTON)), @button.TBBUTTON(i), SizeOf(TBBUTTON), #Null)
      ReadProcessMemory_(hProc, button(i)\dwData, @button_td.TRAYDATA(i), SizeOf(TRAYDATA), #Null)
      hIcon = button_td.TRAYDATA(i)\hIcon
      hWnd = button_td.TRAYDATA(i)\hwnd
      uID = button_td.TRAYDATA(i)\uID
      iState = button.TBBUTTON(i)\fsState
      IconName$ = GetImageName(hWnd,uID)
      win$ = Space(#MAX_PATH)
      GetWindowsDirectory_(@win$,#MAX_PATH)
      win$ = RemoveString(win$, "\Windows",#PB_String_NoCase)
      If Trim(IconName$) = ""
        IconName$ = "System Icon"
      Else
        ;IconName$ = RemoveString(IconName$,"\Windows",#PB_String_NoCase)
        left$ = Left(IconName$,23)
        IconName$ = ReplaceString(IconName$,left$,win$)
      EndIf
      If n = 1
         turn = i
         STray$(turn) = "     " + Str(hIcon)  + Chr(10) + Str(hWnd) + Chr(10) + Str(iState) + Chr(10) + Str(uID) + Chr(10) + IconName$
      Else
        turn = turn + 1
        STray$(turn) = "     " + Str(hIcon)  + Chr(10) + Str(hWnd) + Chr(10) + "OFN" + Chr(10) + Str(uID) + Chr(10) + IconName$
      EndIf        
        Icon(turn) = hIcon
    EndIf
  Next
    
  Next
 
  VirtualFreeEx_(hProc, *lpData, #Null, #MEM_RELEASE)
  VirtualFreeEx_(hProc, *lpRect, #Null, #MEM_RELEASE)
  CloseHandle_(hProc)  
 
EndProcedure

OpenWindow(0, 0, 0, 600, 300, "SysTray Notification Icons", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)

ListIconGadget(0,10,10,580,280,"Icon-Icon Handle", 130, #PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect )
;SetGadgetColor(0, #PB_Gadget_FrontColor, $FD4B0B)
;SetGadgetColor(0, #PB_Gadget_BackColor, $E8FEFE)
   
AddGadgetColumn(0, 1, "Win Handle", 100)
AddGadgetColumn(0, 2, "Status", 55)
AddGadgetColumn(0, 3, "PID", 60)
AddGadgetColumn(0, 4, "Image name", 600)

Find_PB_TrayIcons()

For x = 0 To count - 1
  icoH = CopyIcon_(Icon(x))
  If icoH
    If OSVersion() >= #PB_OS_Windows_10
      CreateImage(100,16,16,24,$889145)      
      hdc = StartDrawing(ImageOutput(100))
        DrawIconEx_(hdc,0,0,Icon(x),16,16,0,0,#DI_NORMAL)
      StopDrawing()
      AddGadgetItem(0,-1, STray$(x), ImageID(100))
      FreeImage(100)
    Else
      AddGadgetItem(0,-1, STray$(x), Icon(x))
    EndIf      
  Else
    AddGadgetItem(0,-1, STray$(x), 0)
  EndIf
  DestroyIcon_(icoH)
Next

Repeat
     iEvent = WaitWindowEvent()
     
     Select iEvent
         Case #PB_Event_Gadget
             Select EventGadget()
             EndSelect
     EndSelect       
Until iEvent = #PB_Event_CloseWindow