How to open or show a running application from the Traybar
I won't be able to offer you any code but if you are working with XP or greater, it is possible to send clicks to the tray Notification Area from a PB app.
Here's a little sample I cut out from one of my apps. I tested with XP and Vista. Some icons may not be exact duplicates and some icons may not even be listed. Having all icons listed isn't a problem but I just didin't have time to redo the entire code for this example.
Sample app >>> http://www.heysparkie.com/Apps/TrayClicks.exe
Here's a little sample I cut out from one of my apps. I tested with XP and Vista. Some icons may not be exact duplicates and some icons may not even be listed. Having all icons listed isn't a problem but I just didin't have time to redo the entire code for this example.
Sample app >>> http://www.heysparkie.com/Apps/TrayClicks.exe
What goes around comes around.
PB 5.21 LTS (x86) - Windows 8.1
PB 5.21 LTS (x86) - Windows 8.1
-
- Enthusiast
- Posts: 135
- Joined: Sat Aug 18, 2007 7:09 am
- Location: Netherlands
Yeah works great ;-PSparkie wrote:I won't be able to offer you any code but if you are working with XP or greater, it is possible to send clicks to the tray Notification Area from a PB app.
Here's a little sample I cut out from one of my apps. I tested with XP and Vista. Some icons may not be exact duplicates and some icons may not even be listed. Having all icons listed isn't a problem but I just didin't have time to redo the entire code for this example.
Sample app >>> http://www.heysparkie.com/Apps/TrayClicks.exe
Seems like a solution, what's the point
of showing me and not sharing the code?
Gr,
Phil.
Here you have food, but you can't eat it.
The code is ripped from one of my apps and in it's current state it's a mess. If I get some free time I'll be glad to reduce the code down to something you can use.
In the meantime, here's the heart of the code. hIcons is the handle to the Toolbar (in the Notification Area) where the icons reside.
In the meantime, here's the heart of the code. hIcons is the handle to the Toolbar (in the Notification Area) where the icons reside.
Code: Select all
Macro MakeLong(low, high)
low | high <<16
EndMacro
If clickit > -1
index = SendMessage_(hIcons, #TB_COMMANDTOINDEX, iCmd, 0)
SendMessage_(hIcons, #TB_GETITEMRECT, index, *Buff2)
ReadProcessMemory_(tbPrc, *Buff2, @rc.RECT, SizeOf(RECT), @result)
Select clickit
Case #PB_EventType_LeftClick
SetForegroundWindow_(hIcons)
PostMessage_(hIcons, #WM_LBUTTONDOWN, 0, MakeLong(rc\left, rc\top))
PostMessage_(hIcons, #WM_LBUTTONUP, 0, MakeLong(rc\left, rc\top))
PostMessage_(hIcons, #WM_LBUTTONDOWN, 0, MakeLong(rc\left, rc\top))
PostMessage_(hIcons, #WM_LBUTTONUP, 0, MakeLong(rc\left, rc\top))
PostMessage_(hIcons, #WM_LBUTTONDBLCLK, 0, MakeLong(rc\left, rc\top))
clickit = -1
EndSelect
EndIf
What goes around comes around.
PB 5.21 LTS (x86) - Windows 8.1
PB 5.21 LTS (x86) - Windows 8.1
-
- Enthusiast
- Posts: 135
- Joined: Sat Aug 18, 2007 7:09 am
- Location: Netherlands
Hey Tnx man...Sparkie wrote:The code is ripped from one of my apps and in it's current state it's a mess. If I get some free time I'll be glad to reduce the code down to something you can use.
In the meantime, here's the heart of the code. hIcons is the handle to the Toolbar (in the Notification Area) where the icons reside.Code: Select all
Macro MakeLong(low, high) low | high <<16 EndMacro If clickit > -1 index = SendMessage_(hIcons, #TB_COMMANDTOINDEX, iCmd, 0) SendMessage_(hIcons, #TB_GETITEMRECT, index, *Buff2) ReadProcessMemory_(tbPrc, *Buff2, @rc.RECT, SizeOf(RECT), @result) Select clickit Case #PB_EventType_LeftClick SetForegroundWindow_(hIcons) PostMessage_(hIcons, #WM_LBUTTONDOWN, 0, MakeLong(rc\left, rc\top)) PostMessage_(hIcons, #WM_LBUTTONUP, 0, MakeLong(rc\left, rc\top)) PostMessage_(hIcons, #WM_LBUTTONDOWN, 0, MakeLong(rc\left, rc\top)) PostMessage_(hIcons, #WM_LBUTTONUP, 0, MakeLong(rc\left, rc\top)) PostMessage_(hIcons, #WM_LBUTTONDBLCLK, 0, MakeLong(rc\left, rc\top)) clickit = -1 EndSelect EndIf
This is very usefull to me..
Gr,
Phil.
Here's some code for you to use. I only coded in a simulated left doubleclick. You can easily add support for single left or right clicks as needed.
Code: Select all
;/============================================================
;/ Code : Simulate Doubleclick on Notification Area icon
;/ Author : Sparkie
;/ Date : 03/16/2008
;/ PB Support : PB 4.00 or later
;/ OS Support : Windows XP or later
;/ License : Free to use with no restrictions
;/============================================================
If OSVersion() < #PB_OS_Windows_XP
MessageRequester("Sorry", "WinXP or later is required", #PB_MessageRequester_Ok | #MB_ICONEXCLAMATION)
End
EndIf
;/ Constants ========================================================
#ICON_SMALL = 0
;/ Enumerations =====================================================
Enumeration
#WindowMain
EndEnumeration
Enumeration
#TextInfo
#ListIcons
#ButtonRefresh
EndEnumeration
;/ Macros ===========================================================
Macro MakeLong(low, high)
low | high <<16
EndMacro
;/ ========================= Structures ==========================
Structure EXTRAINFO
hwnd.l
dummy0.l
dummy1.l
dummy2.l
dummy3.l
exePath.l
dummy5.l
EndStructure
;/ ========================= Procedures ==========================
;- Find Taskbar and enumerate buttons
Procedure.l TaskBarList(clickit.l, iCmd.l)
cf.CHARFORMAT
cf\cbSize = SizeOf(CHARFORMAT)
cf\dwMask = #CFM_COLOR
Protected hIcons.l = 0
Protected hTray.l = 0
Protected hNotify.l = 0
Protected hPager.l = 0
result.l = 0
;- Find the Notification Area Toolbar that holds the icons
hTray = FindWindow_("Shell_TrayWnd", 0)
If hTray
result + 1
hNotify = FindWindowEx_(hTray, 0, "TrayNotifyWnd", 0)
If hNotify
result + 1
hPager = FindWindowEx_(hNotify, 0, "SysPager", 0)
If hPager
result + 1
hIcons = FindWindowEx_(hPager, 0, "ToolbarWindow32", 0)
If hIcons
result + 1
EndIf
EndIf
EndIf
EndIf
If result < 4
MessageRequester("Error Code " + Str(result), "Unable to locate Taskbar", #MB_OK | #MB_ICONERROR)
End
EndIf
result=0
;- Get the Notification icon (button) count
buttonCount.l = SendMessage_(hIcons, #TB_BUTTONCOUNT, 0, 0)
;- Open taskbar process
pid.l = 0
GetWindowThreadProcessId_(hIcons, @pid)
If pid
result + 1
Protected trayProc.l = 0
trayProc.l = OpenProcess_(#PROCESS_VM_OPERATION | #PROCESS_VM_READ | #PROCESS_VM_WRITE, #False, pid)
If trayProc
result + 1
;- Create buffer to hold result for reading taskbar info
*Buff1 = VirtualAllocEx_(trayProc, 0, 2048, #MEM_COMMIT, #PAGE_READWRITE)
If *Buff1
result + 1
EndIf
EndIf
EndIf
If result < 3
MessageRequester("Error Code " + Str(result), "Unable to init Taskbar", #MB_OK | #MB_ICONERROR)
End
EndIf
;- Write TBBUTTONINFO from tray icons
tbi.TBBUTTONINFO
tbi\cbSize = SizeOf(TBBUTTONINFO)
tbi\dwMask = #TBIF_BYINDEX | #TBIF_LPARAM | #TBIF_SIZE | #TBIF_STATE | #TBIF_STYLE | #TBIF_COMMAND
If *Buff1
WriteProcessMemory_(trayProc, *Buff1, @tbi, SizeOf(TBBUTTONINFO), @result)
Else
MessageRequester("Error", "unable to write to Buffer", #MB_OK | #MB_ICONERROR)
End
EndIf
result = 0
;- Loop through all taskbar buttons
For i = 0 To buttonCount - 1
;--- Read the TBBUTTONINFO
SendMessage_(hIcons, #TB_GETBUTTONINFO, i, *Buff1)
If *Buff1
ReadProcessMemory_(trayProc, *Buff1, @tbi, SizeOf(TBBUTTONINFO), @result)
Else
MessageRequester("Error", "unable to write to buffer", #MB_OK | #MB_ICONERROR)
End
EndIf
result = 0
;- Get the extra button info found within lparam (hwnd, exepath)
eInfo.EXTRAINFO
If tbi\lParam
ReadProcessMemory_(trayProc, tbi\lParam, @eInfo, SizeOf(EXTRAINFO), @result)
Else
MessageRequester("Error", "unable to read memory", #MB_OK | #MB_ICONERROR)
End
EndIf
result = 0
;- Get the Notification icon tooltip text
bLen = SendMessage_(hIcons, #TB_GETBUTTONTEXT, tbi\idCommand, 0)
If bLen > 0
button$ = Space(bLen)
SendMessage_(hIcons, #TB_GETBUTTONTEXT, tbi\idCommand, *Buff1 + SizeOf(TBBUTTONINFO))
If *Buff1
ReadProcessMemory_(trayProc, *Buff1 + SizeOf(TBBUTTONINFO), @button$, bLen, @result)
Else
MessageRequester("Error", "unable to read memory", #MB_OK | #MB_ICONERROR)
End
EndIf
Else
button$ = "hidden"
EndIf
;- Get the icon
If button$ <> "hidden"
hIconSmall.l = 0
;- First try to get icon
hIconSmall = SendMessage_(eInfo\hwnd, #WM_GETICON, #ICON_SMALL, 0)
If hIconSmall = 0
;- Second try to get icon
hIconSmall = GetClassLong_(eInfo\hwnd, #GCL_HICONSM)
If hIconSmall = 0
;- Third try to get icon
GetWindowThreadProcessId_(eInfo\hwnd, @ctpid.l)
hProcess = OpenProcess_(#PROCESS_QUERY_INFORMATION | #PROCESS_VM_READ, #False, ctpid)
If OpenLibrary(0, "psapi.dll")
exepath$ = Space(#MAX_PATH)
CallFunction(0, "GetModuleFileNameExA", hProcess, 0, @exepath$, #MAX_PATH)
CloseLibrary(0)
EndIf
CloseHandle_(hProcess)
ExtractIconEx_(@exepath$, 0, 0, @hIconSmall, 1)
di = 1
If hIconSmall = 0
;- When all else fails
hIconSmall = LoadIcon_(0, #IDI_WINLOGO)
EndIf
EndIf
EndIf
EndIf
;- Fill our ListIconGadget with visible Notification icons
If tbi\fsState & #TBSTATE_ENABLED And Not tbi\fsState & #TBSTATE_HIDDEN And clickit = -2
;- Some text may contain Chr(10) so we will remove it
tt$ = ReplaceString(button$, Chr(10), " ")
AddGadgetItem(#ListIcons, -1, tt$, hIconSmall)
;- Store the command id for our icon
SetGadgetItemData(#ListIcons, CountGadgetItems(#ListIcons) - 1, tbi\idCommand)
EndIf
;- Destroy Icon if we extracted it from exepath
If di
DestroyIcon_(hIconSmall)
di = 0
EndIf
;- If we detect a click on our ListIconGadget
If clickit > -1
;- Get the Notification icon position/coordinates
index = SendMessage_(hIcons, #TB_COMMANDTOINDEX, iCmd, 0)
SendMessage_(hIcons, #TB_GETITEMRECT, index, *Buff1)
ReadProcessMemory_(trayProc, *Buff1, @rc.RECT, SizeOf(RECT), @result)
;- Convert the ListIconGadget click to a doubleclick on Notification icon
Select clickit
Case #PB_EventType_LeftClick
SetForegroundWindow_(hIcons)
PostMessage_(hIcons, #WM_LBUTTONDOWN, 0, MakeLong(rc\left, rc\top))
PostMessage_(hIcons, #WM_LBUTTONUP, 0, MakeLong(rc\left, rc\top))
PostMessage_(hIcons, #WM_LBUTTONDOWN, 0, MakeLong(rc\left, rc\top))
PostMessage_(hIcons, #WM_LBUTTONUP, 0, MakeLong(rc\left, rc\top))
PostMessage_(hIcons, #WM_LBUTTONDBLCLK, 0, MakeLong(rc\left, rc\top))
clickit = -1
EndSelect
EndIf
ct + 1
Next
;- Clean up
If *Buff1
VirtualFreeEx_(trayProc, *Buff1, 0, #MEM_RELEASE)
EndIf
If trayProc
CloseHandle_(trayProc)
EndIf
EndProcedure
;/ Main Window ======================================================
If OpenWindow(#WindowMain, 0, 0, 400, 500, "Tray Icon Test by Sparkie", #PB_Window_SizeGadget | #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_TitleBar) And CreateGadgetList(WindowID(#WindowMain))
info$ = "Click on any item to simulate a doubleclick on the tray icon."
TextGadget(#TextInfo, 10, 10, 380, 50, info$, #PB_Text_Center)
ButtonGadget(#ButtonRefresh, 10, 60, 72, 25, "Refresh list")
ListIconGadget(#ListIcons, 10, 90, 380, 400, "Tray Icon ToolTip Text", 375, #PB_ListIcon_FullRowSelect | #PB_ListIcon_GridLines)
;- Get Notification Area icons and fill our ListIcon
TaskBarList(-2, -1)
;/ Main Event Loop ==================================================
Repeat
event = WaitWindowEvent()
eType = EventType()
Select event
Case #PB_Event_Gadget
Select EventGadget()
Case #ListIcons
;- Get the Notification icon command id
iCmd = GetGadgetItemData(#ListIcons, GetGadgetState(#ListIcons))
Select eType
Case #PB_EventType_LeftClick
TaskBarList(EventType(), iCmd)
EndSelect
Case #ButtonRefresh
ClearGadgetItemList(#ListIcons)
TaskBarList(-2, -1)
EndSelect
EndSelect
Until event = #PB_Event_CloseWindow
EndIf
End
Last edited by Sparkie on Sun Mar 16, 2008 10:52 pm, edited 1 time in total.
What goes around comes around.
PB 5.21 LTS (x86) - Windows 8.1
PB 5.21 LTS (x86) - Windows 8.1
-
- Enthusiast
- Posts: 135
- Joined: Sat Aug 18, 2007 7:09 am
- Location: Netherlands
Re: How to open or show a running application from the Trayb
10 years later...
Who can change this great code by Sparkie to getting tooltip-text for each button ?
Thanks in advance.
Who can change this great code by Sparkie to getting tooltip-text for each button ?
Thanks in advance.
-
- Addict
- Posts: 4527
- Joined: Thu Jun 07, 2007 3:25 pm
- Location: Berlin, Germany
Re: How to open or show a running application from the Trayb
First steps to adapt the code by Sparkie to PureBasic 5.62 (x64) on Windows 10:
Before proceeding with additional changes, I recommend to write EnableExplicit as the first executable line, and then declare all variables accordingly. When doing so, change most if not all variables of type .l to type .i, so that the code is compatible with both 32-bit and 64-bit versions of PureBasic.
- In line 145, replace ReadProcessMemory_(trayProc, *Buff1 + SizeOf(TBBUTTONINFO), @button$, bLen, @result)
with ReadProcessMemory_(trayProc, *Buff1 + SizeOf(TBBUTTONINFO), @button$, 2 * bLen, @result).
This is required, because in PB 5.62 all strings are in Unicode format. - In line 161, replace GetClassLong_ with GetClassLongPtr_.
This way, the code is compatible with both 32-bit and 64-bit versions of Windows. - In line 168, replace GetModuleFileNameExA with GetModuleFileNameExW.
- In line 225, remove And CreateGadgetList(WindowID(#WindowMain)).
This is obsolete now and not needed anymore. - In line 248, replace ClearGadgetItemList(#ListIcons) with ClearGadgetItems(#ListIcons).
Before proceeding with additional changes, I recommend to write EnableExplicit as the first executable line, and then declare all variables accordingly. When doing so, change most if not all variables of type .l to type .i, so that the code is compatible with both 32-bit and 64-bit versions of PureBasic.
Re: How to open or show a running application from the Trayb
Little John, good day!
In this case, probably line 122 also needs to be changed
SendMessage_(hIcons, #TB_GETBUTTONINFO, i, *Buff1)
to
SendMessage_(hIcons, #TB_GETBUTTONINFOW, i, *Buff1)
for unicode. And lines 140, 143: #TB_GETBUTTONTEXT -> #TB_GETBUTTONTEXTW.
Thanks a lot for reply, edit, comments and tip, but...
It's still not enough for my task
For some reason on my test application I get memory read error message. Program stopped on line 135. I had to exclude lines 129 to 137. And variable bLen is always equal to -1. Perhaps because of fact that text on button is drawn. But each of them has a unique tooltip-text. This is what I need to get in order determine what kind of button it is. Well ... I looking for this solution.
In this case, probably line 122 also needs to be changed
SendMessage_(hIcons, #TB_GETBUTTONINFO, i, *Buff1)
to
SendMessage_(hIcons, #TB_GETBUTTONINFOW, i, *Buff1)
for unicode. And lines 140, 143: #TB_GETBUTTONTEXT -> #TB_GETBUTTONTEXTW.
Thanks a lot for reply, edit, comments and tip, but...
It's still not enough for my task
For some reason on my test application I get memory read error message. Program stopped on line 135. I had to exclude lines 129 to 137. And variable bLen is always equal to -1. Perhaps because of fact that text on button is drawn. But each of them has a unique tooltip-text. This is what I need to get in order determine what kind of button it is. Well ... I looking for this solution.
-
- Addict
- Posts: 4527
- Joined: Thu Jun 07, 2007 3:25 pm
- Location: Berlin, Germany
Re: How to open or show a running application from the Trayb
Hi ZX80!
The main problem here is, that after clicking at some entries in the ListIconGadget the simulated doubleclick goes to the proper program, while after clicking at other entries the simulated doubleclick goes to a wrong program.
Which PB version and which Windows version are you using?
I'm not an expert in this field, so unfortunately I can't offer more help, sorry. I only listed the simple problems that I could detect. But here are other people with good knowledge of the Windows API, who probably can give you more information.
That's strange. Here with PB 5.62 (x64) on Windows 10, after applying the modifications that I had mentioned, I'm getting a Window with a ListIconGadget that contains the correct tooltip texts of all icons in the noticication area. The ListIconGadget also contains almost all regarding icons.ZX80 wrote:For some reason on my test application I get memory read error message. Program stopped on line 135. I had to exclude lines 129 to 137. And variable bLen is always equal to -1. Perhaps because of fact that text on button is drawn. But each of them has a unique tooltip-text. This is what I need to get in order determine what kind of button it is.
The main problem here is, that after clicking at some entries in the ListIconGadget the simulated doubleclick goes to the proper program, while after clicking at other entries the simulated doubleclick goes to a wrong program.
Which PB version and which Windows version are you using?
I'm not an expert in this field, so unfortunately I can't offer more help, sorry. I only listed the simple problems that I could detect. But here are other people with good knowledge of the Windows API, who probably can give you more information.
Re: How to open or show a running application from the Trayb
Thank you anyway.I'm not an expert in this field, so unfortunately I can't offer more help, sorry.
Yes, I know. And I hope that they see/read this theme.But here are other people with good knowledge of the Windows API
Code: Select all
Which PB version and which Windows version are you using?
I'am very sorry. I did not say at once...That's strange.
With noticication area - all is okay. No problem/error messages.
I wanted to use this wonderful code for toolbar.
i.e. I want press target-button on toolbar of third-party application. Because that program have not menu item or hotkey for action I need. Only button on toolbar. Otherwise it would not be a problem.
That's all I wanted to do.
Last edited by ZX80 on Sun Sep 16, 2018 1:54 pm, edited 1 time in total.
Re: How to open or show a running application from the Trayb
Аll buttons are visible and accessible (from ListIconGadget), but none has a specific text or icon. In this case how do you determine which button you need pressed ? All - faceless (text is - "hidden"). This is a problem. Because some of them can be added or removed time by time.