Enumerate System Tray Icons [Windows]
Posted: Sat Mar 04, 2023 10:04 pm
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
Sorry copy paste error as usual
Edit : Bug fixed
Edit2 : Bug fixed
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

Edit : Bug fixed
Edit2 : Bug fixed