Ark
asked on
Who lives in the system tray?
Hello, experts.
I'm trying to make app which enum all running applications with icon(s) in system tray. What I need is hWnd and uId of these applications. Knowing this, I can easyly Modify/Remove icons from system tray.
PS. I tried to get this info using tooltips. At this moment I have a code which determine tooltips quantity at TrayNotifyWnd. But I can not get TooltipInfo structure from Shell. May be there is another way to do this?
I'll wait for a few days for different solution and then show existing code.
I'm trying to make app which enum all running applications with icon(s) in system tray. What I need is hWnd and uId of these applications. Knowing this, I can easyly Modify/Remove icons from system tray.
PS. I tried to get this info using tooltips. At this moment I have a code which determine tooltips quantity at TrayNotifyWnd. But I can not get TooltipInfo structure from Shell. May be there is another way to do this?
I'll wait for a few days for different solution and then show existing code.
ping...
might wanna check this out:
http://www.allapi.net/vbasic/tray.zip.php
http://www.allapi.net/vbasic/tray.zip.php
First I want to make sure you know that for Windows 2000 (version 5.0 of the shell) some of the tray icon behavior has changed. Ive pasted the following from MSDN in case you dont have it. See the remarks section.
Shell_NotifyIcon
Sends a message to the taskbar's status area.
BOOL Shell_NotifyIcon(
DWORD dwMessage,
PNOTIFYICONDATA pnid
);
Parameters
dwMessage
[in] Variable of type DWORD that specifies the action to be taken. It can have one of the following values:
NIM_ADD
Adds an icon to the status area. The hWnd and uID members of the NOTIFYICONDATA structure pointed to by pnid will be used to identify the icon in future calls to Shell_NotifyIcon.
NIM_DELETE
Deletes an icon from the status area. Use the hWnd and uID members of the NOTIFYICONDATA structure pointed to by pnid to identify the icon to be deleted.
NIM_MODIFY
Modifies an icon in the status area. Use the hWnd and uID members of the NOTIFYICONDATA structure pointed to by pnid to identify the icon to be modified.
NIM_SETFOCUS
Version 5.0. Returns focus to the taskbar notification area. Taskbar icons should use this message when they have completed their user interface operation. For example, if the taskbar icon displays a context menu, but the user presses ESCAPE to cancel it, use NIM_SETFOCUS to return focus to the taskbar notification area.
NIM_SETVERSION
Version 5.0. Instructs the taskbar to behave according to the version number specified in the uVersion member of the structure pointed to by pnid. This message allows you to specify whether you want the version 5.0 behavior found on Microsoft. Windows. 2000 systems, or that found with earlier shell versions. The default value for uVersion is zero, indicating that the original Windows 95 notify icon behavior should be used. For details, see the Remarks section.
pnid
[in] Address of a NOTIFYICONDATA structure. The content of the structure depends on the value of dwMessage.
Return Values
Returns TRUE if successful, or FALSE otherwise. If dwMessage is set to NIM_SETVERSION, the function returns TRUE if the version was successfully changed, or FALSE if the requested version is not supported.
Remarks
The taskbar notification area is sometimes erroneously called the "tray."
Version 5.0 of the shell, found on Windows 2000, handles Shell_NotifyIcon mouse and keyboard events differently than earlier shell versions, found on Windows NT. 4.0, Windows 95, and Windows 98. The differences are:
7 If a user selects a notify icon's context menu with the keyboard, the version 5.0 shell sends the associated application a WM_CONTEXTMENU message. Earlier versions send WM_RBUTTONDOWN and WM_RBUTTONUP messages.
7 If a user selects a notify icon with the keyboard and activates it with the space bar or ENTER key, the version 5.0 shell sends the associated application an NIN_KEYSELECT notification. Earlier versions send WM_RBUTTONDOWN and WM_RBUTTONUP messages.
7 If a user selects a notify icon with the mouse and activates it with the ENTER key, the version 5.0 shell sends the associated application an NIN_SELECT notification. Earlier versions send WM_RBUTTONDOWN and WM_RBUTTONUP messages.
7 If a user passes the mouse pointer over an icon with which a balloon tooltip is associated, the version 5.0 shell sends the following messages:
7 NIN_BALLOONSHOW - Sent when the balloon is shown (balloons are queued).
7 NIN_BALLOONHIDE - Sent when the balloon disappearswhen the icon is deleted, for example. This message is not sent if the balloon is dismissed because of a timeout or mouse click by the user.
7 NIN_BALLOONTIMEOUT - Sent when the balloon is dismissed because of a timeout.
7 NIN_BALLOONUSERCLICK - Sent when the balloon is dismissed because the user clicked the mouse.
You can select which way the shell should behave by calling Shell_NotifyIcon with dwMessage set to NIM_SETVERSION. Set the uVersion member of the NOTIFYICONDATA structure to indicate whether you want version 5.0 or pre-version 5.0 behavior.
Note The messages discussed above are not conventional Windows messages. They are sent as the lParam value of the application-defined message that is specified when the icon is added with NIM_ADD.
Requirements
Version 4.00 and later of Shell32.dll
Windows NT/2000: Requires Windows NT 4.0 or later.
Windows 95/98: Requires Windows 95 or later.
Header: Declared in shellapi.h.
Import Library: shell32.lib.
The notifyicondata structure has also changed.
typedef struct _NOTIFYICONDATA {
DWORD cbSize;
HWND hWnd;
UINT uID;
UINT uFlags;
UINT uCallbackMessage;
HICON hIcon;
TCHAR szTip[64];
DWORD dwState; //Version 5.0
DWORD dwStateMask; //Version 5.0
TCHAR szInfo[256]; //Version 5.0
union {
UINT uTimeout; //Version 5.0
UINT uVersion; //Version 5.0
} DUMMYUNIONNAME;
TCHAR szInfoTitle[64]; //Version 5.0
DWORD dwInfoFlags; //Version 5.0
} NOTIFYICONDATA, *PNOTIFYICONDATA;
After researching this for a couple hours, I have not been able to pull off what you want. I was able to hack some handles to applications running with a task bar icon and tried to change their icons remove them, but nothing seemed to work. The running applications continue to maintain pointers to anything in the tray. I would think that if anything removed the tray icon, the application might have problems if it references it. To me it would be dangerous to force the removal of the icon.
To find an applications handle, I used the findwindow call. I assume you know how to do this. What I think is that the uID is private to the application for the reasons I mention above. If you find a way to do this, I would certainly like to know.
Here is the code Ive been using.
Private Sub Form_Load()
End Sub
'Declare a user-defined variable to pass to the Shell_NotifyIcon
'function.
Private Type NOTIFYICONDATA
cbSize As Long
hWnd As Long
uId As Long
uFlags As Long
uCallBackMessage As Long
hIcon As Long
szTip As String * 64
dwState As Long
dwStateMask As Long
szInfo As String * 256
uTimeout As Long
uVersion As Long
szInfoTitle As String * 64
dwInfoFlags As Long
End Type
'typedef struct _NOTIFYICONDATA {
' DWORD cbSize;
' HWND hWnd;
' UINT uID;
' UINT uFlags;
' UINT uCallbackMessage;
' HICON hIcon;
' TCHAR szTip[64];
' DWORD dwState; //Version 5.0
' DWORD dwStateMask; //Version 5.0
' TCHAR szInfo[256]; //Version 5.0
' union {
' UINT uTimeout; //Version 5.0
' UINT uVersion; //Version 5.0
' } DUMMYUNIONNAME;
' TCHAR szInfoTitle[64]; //Version 5.0
' DWORD dwInfoFlags; //Version 5.0
'} NOTIFYICONDATA, *PNOTIFYICONDATA;
'Declare the constants for the API function. These constants can be
'found in the header file Shellapi.h.
'The following constants are the messages sent to the
'Shell_NotifyIcon function to add, modify, or delete an icon from the
'taskbar status area.
Private Const NIM_ADD = &H0
Private Const NIM_MODIFY = &H1
Private Const NIM_DELETE = &H2
'The following constant is the message sent when a mouse event occurs
'within the rectangular boundaries of the icon in the taskbar status
'area.
Private Const WM_MOUSEMOVE = &H200
'The following constants are the flags that indicate the valid
'members of the NOTIFYICONDATA data type.
Private Const NIF_MESSAGE = &H1
Private Const NIF_ICON = &H2
Private Const NIF_TIP = &H4
'The following constants are used to determine the mouse input on the
'the icon in the taskbar status area.
'Left-click constants.
Private Const WM_LBUTTONDBLCLK = &H203 'Double-click
Private Const WM_LBUTTONDOWN = &H201 'Button down
Private Const WM_LBUTTONUP = &H202 'Button up
'Right-click constants.
Private Const WM_RBUTTONDBLCLK = &H206 'Double-click
Private Const WM_RBUTTONDOWN = &H204 'Button down
Private Const WM_RBUTTONUP = &H205 'Button up
'Declare the API function call.
Private Declare Function Shell_NotifyIcon Lib "shell32" _
Alias "Shell_NotifyIconA" _
(ByVal dwMessage As Long, pnid As NOTIFYICONDATA) As Boolean
'Dimension a variable as the user-defined data type.
Dim nid As NOTIFYICONDATA
Private Declare Function FindWindow Lib "user32" Alias _
"FindWindowA" (ByVal lpClassName As Any, _
ByVal lpWindowName As Any) As Long
Private Sub Command1_Click()
'Click this button to add an icon to the taskbar status area
'Set the individual values of the NOTIFYICONDATA data type.
nid.cbSize = Len(nid)
nid.hWnd = Form1.hWnd
nid.uId = vbNull
nid.uFlags = NIF_ICON Or NIF_TIP Or NIF_MESSAGE
nid.uCallBackMessage = WM_MOUSEMOVE
nid.hIcon = Form1.Icon
nid.szTip = "Taskbar Status Area Sample Program" & vbNullChar
'Call the Shell_NotifyIcon function to add the icon to the taskbar
'status area.
Shell_NotifyIcon NIM_ADD, nid
End Sub
Private Sub Command2_Click()
'Click this button to delete the added icon from the taskbar
'status area by calling the Shell_NotifyIcon function.
Shell_NotifyIcon NIM_DELETE, nid
End Sub
Private Sub Form_Load()
'Set the captions of the command button when the form loads.
Command1.Caption = "Add an Icon"
Command2.Caption = "Delete Icon"
End Sub
Private Sub Form_Terminate()
'Delete the added icon from the taskbar status area when the
'program ends.
Shell_NotifyIcon NIM_DELETE, nid
End Sub
Private Sub Form_MouseMove _
(Button As Integer, _
Shift As Integer, _
x As Single, _
Y As Single)
'Event occurs when the mouse pointer is within the rectangular
'boundaries of the icon in the taskbar status area.
Dim msg As Long
Dim sFilter As String
msg = x / Screen.TwipsPerPixelX
Select Case msg
Case WM_LBUTTONDOWN
Case WM_LBUTTONUP
Case WM_LBUTTONDBLCLK
CommonDialog1.DialogTitle = "Select an Icon"
sFilter = "Icon Files (*.ico)|*.ico"
sFilter = sFilter & "|All Files (*.*)|*.*"
CommonDialog1.Filter = sFilter
CommonDialog1.ShowOpen
If CommonDialog1.FileName <> "" Then
Form1.Icon = LoadPicture(CommonDialog1. FileName)
nid.hIcon = Form1.Icon
Shell_NotifyIcon NIM_MODIFY, nid
End If
Case WM_RBUTTONDOWN
Dim ToolTipString As String
ToolTipString = InputBox("Enter the new ToolTip:", _
"Change ToolTip")
If ToolTipString <> "" Then
nid.szTip = ToolTipString & vbNullChar
Shell_NotifyIcon NIM_MODIFY, nid
End If
Case WM_RBUTTONUP
Case WM_RBUTTONDBLCLK
End Select
End Sub
Shell_NotifyIcon
Sends a message to the taskbar's status area.
BOOL Shell_NotifyIcon(
DWORD dwMessage,
PNOTIFYICONDATA pnid
);
Parameters
dwMessage
[in] Variable of type DWORD that specifies the action to be taken. It can have one of the following values:
NIM_ADD
Adds an icon to the status area. The hWnd and uID members of the NOTIFYICONDATA structure pointed to by pnid will be used to identify the icon in future calls to Shell_NotifyIcon.
NIM_DELETE
Deletes an icon from the status area. Use the hWnd and uID members of the NOTIFYICONDATA structure pointed to by pnid to identify the icon to be deleted.
NIM_MODIFY
Modifies an icon in the status area. Use the hWnd and uID members of the NOTIFYICONDATA structure pointed to by pnid to identify the icon to be modified.
NIM_SETFOCUS
Version 5.0. Returns focus to the taskbar notification area. Taskbar icons should use this message when they have completed their user interface operation. For example, if the taskbar icon displays a context menu, but the user presses ESCAPE to cancel it, use NIM_SETFOCUS to return focus to the taskbar notification area.
NIM_SETVERSION
Version 5.0. Instructs the taskbar to behave according to the version number specified in the uVersion member of the structure pointed to by pnid. This message allows you to specify whether you want the version 5.0 behavior found on Microsoft. Windows. 2000 systems, or that found with earlier shell versions. The default value for uVersion is zero, indicating that the original Windows 95 notify icon behavior should be used. For details, see the Remarks section.
pnid
[in] Address of a NOTIFYICONDATA structure. The content of the structure depends on the value of dwMessage.
Return Values
Returns TRUE if successful, or FALSE otherwise. If dwMessage is set to NIM_SETVERSION, the function returns TRUE if the version was successfully changed, or FALSE if the requested version is not supported.
Remarks
The taskbar notification area is sometimes erroneously called the "tray."
Version 5.0 of the shell, found on Windows 2000, handles Shell_NotifyIcon mouse and keyboard events differently than earlier shell versions, found on Windows NT. 4.0, Windows 95, and Windows 98. The differences are:
7 If a user selects a notify icon's context menu with the keyboard, the version 5.0 shell sends the associated application a WM_CONTEXTMENU message. Earlier versions send WM_RBUTTONDOWN and WM_RBUTTONUP messages.
7 If a user selects a notify icon with the keyboard and activates it with the space bar or ENTER key, the version 5.0 shell sends the associated application an NIN_KEYSELECT notification. Earlier versions send WM_RBUTTONDOWN and WM_RBUTTONUP messages.
7 If a user selects a notify icon with the mouse and activates it with the ENTER key, the version 5.0 shell sends the associated application an NIN_SELECT notification. Earlier versions send WM_RBUTTONDOWN and WM_RBUTTONUP messages.
7 If a user passes the mouse pointer over an icon with which a balloon tooltip is associated, the version 5.0 shell sends the following messages:
7 NIN_BALLOONSHOW - Sent when the balloon is shown (balloons are queued).
7 NIN_BALLOONHIDE - Sent when the balloon disappearswhen the icon is deleted, for example. This message is not sent if the balloon is dismissed because of a timeout or mouse click by the user.
7 NIN_BALLOONTIMEOUT - Sent when the balloon is dismissed because of a timeout.
7 NIN_BALLOONUSERCLICK - Sent when the balloon is dismissed because the user clicked the mouse.
You can select which way the shell should behave by calling Shell_NotifyIcon with dwMessage set to NIM_SETVERSION. Set the uVersion member of the NOTIFYICONDATA structure to indicate whether you want version 5.0 or pre-version 5.0 behavior.
Note The messages discussed above are not conventional Windows messages. They are sent as the lParam value of the application-defined message that is specified when the icon is added with NIM_ADD.
Requirements
Version 4.00 and later of Shell32.dll
Windows NT/2000: Requires Windows NT 4.0 or later.
Windows 95/98: Requires Windows 95 or later.
Header: Declared in shellapi.h.
Import Library: shell32.lib.
The notifyicondata structure has also changed.
typedef struct _NOTIFYICONDATA {
DWORD cbSize;
HWND hWnd;
UINT uID;
UINT uFlags;
UINT uCallbackMessage;
HICON hIcon;
TCHAR szTip[64];
DWORD dwState; //Version 5.0
DWORD dwStateMask; //Version 5.0
TCHAR szInfo[256]; //Version 5.0
union {
UINT uTimeout; //Version 5.0
UINT uVersion; //Version 5.0
} DUMMYUNIONNAME;
TCHAR szInfoTitle[64]; //Version 5.0
DWORD dwInfoFlags; //Version 5.0
} NOTIFYICONDATA, *PNOTIFYICONDATA;
After researching this for a couple hours, I have not been able to pull off what you want. I was able to hack some handles to applications running with a task bar icon and tried to change their icons remove them, but nothing seemed to work. The running applications continue to maintain pointers to anything in the tray. I would think that if anything removed the tray icon, the application might have problems if it references it. To me it would be dangerous to force the removal of the icon.
To find an applications handle, I used the findwindow call. I assume you know how to do this. What I think is that the uID is private to the application for the reasons I mention above. If you find a way to do this, I would certainly like to know.
Here is the code Ive been using.
Private Sub Form_Load()
End Sub
'Declare a user-defined variable to pass to the Shell_NotifyIcon
'function.
Private Type NOTIFYICONDATA
cbSize As Long
hWnd As Long
uId As Long
uFlags As Long
uCallBackMessage As Long
hIcon As Long
szTip As String * 64
dwState As Long
dwStateMask As Long
szInfo As String * 256
uTimeout As Long
uVersion As Long
szInfoTitle As String * 64
dwInfoFlags As Long
End Type
'typedef struct _NOTIFYICONDATA {
' DWORD cbSize;
' HWND hWnd;
' UINT uID;
' UINT uFlags;
' UINT uCallbackMessage;
' HICON hIcon;
' TCHAR szTip[64];
' DWORD dwState; //Version 5.0
' DWORD dwStateMask; //Version 5.0
' TCHAR szInfo[256]; //Version 5.0
' union {
' UINT uTimeout; //Version 5.0
' UINT uVersion; //Version 5.0
' } DUMMYUNIONNAME;
' TCHAR szInfoTitle[64]; //Version 5.0
' DWORD dwInfoFlags; //Version 5.0
'} NOTIFYICONDATA, *PNOTIFYICONDATA;
'Declare the constants for the API function. These constants can be
'found in the header file Shellapi.h.
'The following constants are the messages sent to the
'Shell_NotifyIcon function to add, modify, or delete an icon from the
'taskbar status area.
Private Const NIM_ADD = &H0
Private Const NIM_MODIFY = &H1
Private Const NIM_DELETE = &H2
'The following constant is the message sent when a mouse event occurs
'within the rectangular boundaries of the icon in the taskbar status
'area.
Private Const WM_MOUSEMOVE = &H200
'The following constants are the flags that indicate the valid
'members of the NOTIFYICONDATA data type.
Private Const NIF_MESSAGE = &H1
Private Const NIF_ICON = &H2
Private Const NIF_TIP = &H4
'The following constants are used to determine the mouse input on the
'the icon in the taskbar status area.
'Left-click constants.
Private Const WM_LBUTTONDBLCLK = &H203 'Double-click
Private Const WM_LBUTTONDOWN = &H201 'Button down
Private Const WM_LBUTTONUP = &H202 'Button up
'Right-click constants.
Private Const WM_RBUTTONDBLCLK = &H206 'Double-click
Private Const WM_RBUTTONDOWN = &H204 'Button down
Private Const WM_RBUTTONUP = &H205 'Button up
'Declare the API function call.
Private Declare Function Shell_NotifyIcon Lib "shell32" _
Alias "Shell_NotifyIconA" _
(ByVal dwMessage As Long, pnid As NOTIFYICONDATA) As Boolean
'Dimension a variable as the user-defined data type.
Dim nid As NOTIFYICONDATA
Private Declare Function FindWindow Lib "user32" Alias _
"FindWindowA" (ByVal lpClassName As Any, _
ByVal lpWindowName As Any) As Long
Private Sub Command1_Click()
'Click this button to add an icon to the taskbar status area
'Set the individual values of the NOTIFYICONDATA data type.
nid.cbSize = Len(nid)
nid.hWnd = Form1.hWnd
nid.uId = vbNull
nid.uFlags = NIF_ICON Or NIF_TIP Or NIF_MESSAGE
nid.uCallBackMessage = WM_MOUSEMOVE
nid.hIcon = Form1.Icon
nid.szTip = "Taskbar Status Area Sample Program" & vbNullChar
'Call the Shell_NotifyIcon function to add the icon to the taskbar
'status area.
Shell_NotifyIcon NIM_ADD, nid
End Sub
Private Sub Command2_Click()
'Click this button to delete the added icon from the taskbar
'status area by calling the Shell_NotifyIcon function.
Shell_NotifyIcon NIM_DELETE, nid
End Sub
Private Sub Form_Load()
'Set the captions of the command button when the form loads.
Command1.Caption = "Add an Icon"
Command2.Caption = "Delete Icon"
End Sub
Private Sub Form_Terminate()
'Delete the added icon from the taskbar status area when the
'program ends.
Shell_NotifyIcon NIM_DELETE, nid
End Sub
Private Sub Form_MouseMove _
(Button As Integer, _
Shift As Integer, _
x As Single, _
Y As Single)
'Event occurs when the mouse pointer is within the rectangular
'boundaries of the icon in the taskbar status area.
Dim msg As Long
Dim sFilter As String
msg = x / Screen.TwipsPerPixelX
Select Case msg
Case WM_LBUTTONDOWN
Case WM_LBUTTONUP
Case WM_LBUTTONDBLCLK
CommonDialog1.DialogTitle = "Select an Icon"
sFilter = "Icon Files (*.ico)|*.ico"
sFilter = sFilter & "|All Files (*.*)|*.*"
CommonDialog1.Filter = sFilter
CommonDialog1.ShowOpen
If CommonDialog1.FileName <> "" Then
Form1.Icon = LoadPicture(CommonDialog1.
nid.hIcon = Form1.Icon
Shell_NotifyIcon NIM_MODIFY, nid
End If
Case WM_RBUTTONDOWN
Dim ToolTipString As String
ToolTipString = InputBox("Enter the new ToolTip:", _
"Change ToolTip")
If ToolTipString <> "" Then
nid.szTip = ToolTipString & vbNullChar
Shell_NotifyIcon NIM_MODIFY, nid
End If
Case WM_RBUTTONUP
Case WM_RBUTTONDBLCLK
End Select
End Sub
ASKER
Hello
First of all, sorry for my English, seems it's a reason for misunderstanding. I DON'T NEED CODE TO PUT APP INTO SYSTEM TRAY. I want to know which app already did this.
OK, here is my code:
'===bas module code===
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function EnumWindows& Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long)
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Dim tx As TextBox
Dim NWThreadID As Long, NWPid As Long
Private Function GetTrayNotifyWnd() As Long
GetTrayNotifyWnd = FindWindowEx(FindWindow("S hell_TrayW nd", vbNullString), 0, "TrayNotifyWnd", vbNullString)
End Function
Private Function GetWndClass(hWnd As Long) As String
Dim k As Long, sName As String
sName = Space$(128)
k = GetClassName(hWnd, sName, 128)
If k > 0 Then sName = Left$(sName, k) Else sName = "No class"
GetWndClass = sName
End Function
Function EnumWinProc(ByVal hWnd As Long, ByVal lParam As Long) As Long
Dim pid As Long, tid As Long
Dim nCount As Long
tid = GetWindowThreadProcessId(h Wnd, pid)
If pid = NWPid And GetWndClass(hWnd) = "tooltips_class32" And (lStyle And 2) <> 2 Then
nCount = SendMessage(hWnd, TTM_GETTOOLCOUNT, 0&, ByVal 0&)' Works fine! Return correct number of icons
ti.hWnd = hWnd
ti.uId = 1
ti.cbSize = Len(ti)
ti.lpszText = String$(80, 0)
' GPF Explorer and clear system tray :(
' x = SendMessage(hWnd, TTM_ENUMTOOLS, 1, ByVal memPtr)
tx = tx & "Icons count = " & nCount
' tx = tx & vbCrLf & GetStrFromBufferA(ti.lpszT ext)
EnumWinProc = 0
Exit Function
End If
EnumWinProc = 1
End Function
Public Sub GetTrayList(txt As TextBox)
Set tx = txt
tx = "Windows:"
NWThreadID = GetWindowThreadProcessId(G etTrayNoti fyWnd, NWPid)
EnumWindows AddressOf EnumWinProc, 0
Set tx = Nothing
End Sub
'===Form code===
Private Sub Command1_Click()
GetTrayList Text1
End Sub
Cheers
First of all, sorry for my English, seems it's a reason for misunderstanding. I DON'T NEED CODE TO PUT APP INTO SYSTEM TRAY. I want to know which app already did this.
OK, here is my code:
'===bas module code===
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function EnumWindows& Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long)
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Dim tx As TextBox
Dim NWThreadID As Long, NWPid As Long
Private Function GetTrayNotifyWnd() As Long
GetTrayNotifyWnd = FindWindowEx(FindWindow("S
End Function
Private Function GetWndClass(hWnd As Long) As String
Dim k As Long, sName As String
sName = Space$(128)
k = GetClassName(hWnd, sName, 128)
If k > 0 Then sName = Left$(sName, k) Else sName = "No class"
GetWndClass = sName
End Function
Function EnumWinProc(ByVal hWnd As Long, ByVal lParam As Long) As Long
Dim pid As Long, tid As Long
Dim nCount As Long
tid = GetWindowThreadProcessId(h
If pid = NWPid And GetWndClass(hWnd) = "tooltips_class32" And (lStyle And 2) <> 2 Then
nCount = SendMessage(hWnd, TTM_GETTOOLCOUNT, 0&, ByVal 0&)' Works fine! Return correct number of icons
ti.hWnd = hWnd
ti.uId = 1
ti.cbSize = Len(ti)
ti.lpszText = String$(80, 0)
' GPF Explorer and clear system tray :(
' x = SendMessage(hWnd, TTM_ENUMTOOLS, 1, ByVal memPtr)
tx = tx & "Icons count = " & nCount
' tx = tx & vbCrLf & GetStrFromBufferA(ti.lpszT
EnumWinProc = 0
Exit Function
End If
EnumWinProc = 1
End Function
Public Sub GetTrayList(txt As TextBox)
Set tx = txt
tx = "Windows:"
NWThreadID = GetWindowThreadProcessId(G
EnumWindows AddressOf EnumWinProc, 0
Set tx = Nothing
End Sub
'===Form code===
Private Sub Command1_Click()
GetTrayList Text1
End Sub
Cheers
hi Ark,
i think that maybe the index specified for ENUMTOOLS constant is not necessarily 1 and this can cause GPF. from http://www.microsoft.com/msj/defaultframe.asp?page=/msj/1298/controlspy3/controlspy3.htm&nav=/msj/1298/newnav.htm
"Despite its name, TTM_ENUMTOOLS is used to retrieve information on a single tool based on index. Tool index values are set internally by the control and are not unique. Indexes change as tools are inserted and removed. To get information about the tool in which a tip is being displayed, use TTM_GETCURRENTTOOL."
by this description of tools it seems that we cannot always gaurantee we can be well aware of available indexes?
i think that maybe the index specified for ENUMTOOLS constant is not necessarily 1 and this can cause GPF. from http://www.microsoft.com/msj/defaultframe.asp?page=/msj/1298/controlspy3/controlspy3.htm&nav=/msj/1298/newnav.htm
"Despite its name, TTM_ENUMTOOLS is used to retrieve information on a single tool based on index. Tool index values are set internally by the control and are not unique. Indexes change as tools are inserted and removed. To get information about the tool in which a tip is being displayed, use TTM_GETCURRENTTOOL."
by this description of tools it seems that we cannot always gaurantee we can be well aware of available indexes?
ASKER
Hello, AzraSound
I also tried TTM_GETTOOLINFO with same result.
Seems problem is in different process memory allocation. Same prb (GPF in explorer) occure when trying to receive RECT structures from desktop icons. I thing I need a way to inject my process into Shell process memory.
Recently I found SHLoadInProc API, but still donno how to work with it.
Cheers
I also tried TTM_GETTOOLINFO with same result.
Seems problem is in different process memory allocation. Same prb (GPF in explorer) occure when trying to receive RECT structures from desktop icons. I thing I need a way to inject my process into Shell process memory.
Recently I found SHLoadInProc API, but still donno how to work with it.
Cheers
i think that your hypothesis about different process memory is most likely the correct one.
>>Recently I found SHLoadInProc API, but still donno how to work with it.
from what i read, it seems you will create an ActiveX dll that performs your code above to grab info from tools in systray, simply pass SHLoadInProc the clsid of your component...i think using UUID structure.
>>Recently I found SHLoadInProc API, but still donno how to work with it.
from what i read, it seems you will create an ActiveX dll that performs your code above to grab info from tools in systray, simply pass SHLoadInProc the clsid of your component...i think using UUID structure.
ASKER
Yes, but I have first to compile dll to get UUID and only then test it. Is there any way to use SHLoadInProc with current process? I also can use ReadProcessMemory (and I'll try it) but AFAIK it works only under w9x.
Cheers
Cheers
>>Is there any way to use SHLoadInProc
with current process?
since it requires a guid as a parameter i dont see how we can make use of that function without first generating a component.
>>I also can use ReadProcessMemory (and I'll try it) but AFAIK it works only under
w9x.
according to MS, this function is valid for all wins:
http://msdn.microsoft.com/library/psdk/winbase/debug_2mpl.htm
however, b/c of tighter security features in NT, that may be why it is more difficult to ensure that it functions correctly
btw, ever think of trying to implement all of those debugging APIs w/ VB? recently came across a product, www.mutek.com, that reminded me of those functions
with current process?
since it requires a guid as a parameter i dont see how we can make use of that function without first generating a component.
>>I also can use ReadProcessMemory (and I'll try it) but AFAIK it works only under
w9x.
according to MS, this function is valid for all wins:
http://msdn.microsoft.com/library/psdk/winbase/debug_2mpl.htm
however, b/c of tighter security features in NT, that may be why it is more difficult to ensure that it functions correctly
btw, ever think of trying to implement all of those debugging APIs w/ VB? recently came across a product, www.mutek.com, that reminded me of those functions
You can use fgets (in stdio.h) to read a line :
char *fgets(char *s, int n, FILE *stream)
fgets reads characters from stream into the string s. It stops when it reads either n - 1 characters or a newline character, whichever comes first.
char *fgets(char *s, int n, FILE *stream)
fgets reads characters from stream into the string s. It stops when it reads either n - 1 characters or a newline character, whichever comes first.
Sorry, my above comment has nothig to do with this question - it's a mistake in window switching, ignore it.
My friend (and I'm sure, yours) Edanmo, has a link on his web site http://www.domaindlx.com/e_morcillo/scripts/cod/default.asp?page=grl#systray (look for "A form in the system tray") that might be of interest to you, Ark. It't not a straight-out answer to your question, but theres some code to get the hWnd of the system tray, which might lead you to a solution.
ASKER
Hi
AzraSound, there is a VBDebugger at morcillo's site. Donno if you speak about this functionality.
Anthony, thanks for link. I already surf the WEB for all about system tray. See my code above:
Private Function GetTrayNotifyWnd() As Long
GetTrayNotifyWnd = FindWindowEx(FindWindow("S hell_TrayW nd", vbNullString), 0, "TrayNotifyWnd", vbNullString)
End Function
Now I know all process of systray notification. I can replace SysTray with my own systray which belong to my process and all app will place their icons into my tray.
Other app co-operate with systray trough WM_COPYDATA message. SysTray process should store these data (I thing this is array of pointers) somewhere in local memory. When I use GETTOOLINFO, shell try to fill TOOLTIPINFO structure which belong to MY process and get GPF. But same thing occure when I allocate global memory block for this structure (?). (BTW, my code above have a typo in SendMessage(...TTM_ENUMTOO L) - last parameter should be ti ByRef - memPtr is Global memory block address).
No I look on another way - how to find this array of pointers where Tray store info about NOTIFYICON data.
Cheers
AzraSound, there is a VBDebugger at morcillo's site. Donno if you speak about this functionality.
Anthony, thanks for link. I already surf the WEB for all about system tray. See my code above:
Private Function GetTrayNotifyWnd() As Long
GetTrayNotifyWnd = FindWindowEx(FindWindow("S
End Function
Now I know all process of systray notification. I can replace SysTray with my own systray which belong to my process and all app will place their icons into my tray.
Other app co-operate with systray trough WM_COPYDATA message. SysTray process should store these data (I thing this is array of pointers) somewhere in local memory. When I use GETTOOLINFO, shell try to fill TOOLTIPINFO structure which belong to MY process and get GPF. But same thing occure when I allocate global memory block for this structure (?). (BTW, my code above have a typo in SendMessage(...TTM_ENUMTOO
No I look on another way - how to find this array of pointers where Tray store info about NOTIFYICON data.
Cheers
>>AzraSound, there is a VBDebugger at morcillo's site
yes i am familiar with it but i find its not very stable, in fact, i could not get it to work on my machine (Win2k Pro). it also does not make use of any of the debugging APIs that i was talking about...those included in imghlp.dll (and now the newer dbghelp.dll included with Win2k - this dll is redistributable so i can send it to you if interested)
>>I can replace SysTray with my own systray which belong
to my process and all app will place their icons into my tray
and what route did you end up taking to get there?
yes i am familiar with it but i find its not very stable, in fact, i could not get it to work on my machine (Win2k Pro). it also does not make use of any of the debugging APIs that i was talking about...those included in imghlp.dll (and now the newer dbghelp.dll included with Win2k - this dll is redistributable so i can send it to you if interested)
>>I can replace SysTray with my own systray which belong
to my process and all app will place their icons into my tray
and what route did you end up taking to get there?
ASKER
No problem to create new window with "Shell_TrayWnd" class and then send registered message "TaskbarCreated" to all windows (HWND_BROADCAST). All good applications should update their icon in tray. Since I own this window I can subclass it and wait for WM_COPYDATA and store NOTIFAYICON data in array/collection. But most applications don't monitor TaskbarCreated message (even MS sample doesn't!), so they wont restore icons and I can get only new created icons. Of course, I can run my app at startap, but I want a way to manage existing system tray.
Cheers
Cheers
what does lStyle refer to in your above code?
ASKER
Oops, sorry, forgot:
lStyle = GetWindowLong(hWnd, GWL_STYLE)
all tooltips in taskbar, except of tray icons tooltips, have TTS_NOPREFIX (&H2) stile included.
Cheers
lStyle = GetWindowLong(hWnd, GWL_STYLE)
all tooltips in taskbar, except of tray icons tooltips, have TTS_NOPREFIX (&H2) stile included.
Cheers
i am trying to implement your code using component and SHLoadInProc. i was simply testing SHLoadInProc with a dummy component to ensure it was working and it appears to work fine, but it seems explorer does not properly release the component after calling it. all the documentation i have read indicates it calls the component and then releases it immediately, but i can not recompile the component at this time as i receive "permission denied" errors. this tells me explorer must still have access to the object...any thoughts/ideas?
in my class for the component i simply wrote to a text file in the initialize and terminate events to show me that it was indeed called and destroyed in the call to SHLoadInProc. the text file indicates that the class was instantiated and destroyed, but as i stated, Windows is still holding on to it somehow...
ASKER
Hello, AzraSound
Recently downloaded a must have book:
"Programming Applications for Microsoft Windows" by Jeffrey Richter. If you need it - here is a link
http://retro3.newmail.ru/richter.rar1
it's in chm format(11M in archive). Rename .rar1 to .rar
Start Setup\Ebook\setup.exe
There are description how to inject your process into another (Chapter 22).
Cheers
Recently downloaded a must have book:
"Programming Applications for Microsoft Windows" by Jeffrey Richter. If you need it - here is a link
http://retro3.newmail.ru/richter.rar1
it's in chm format(11M in archive). Rename .rar1 to .rar
Start Setup\Ebook\setup.exe
There are description how to inject your process into another (Chapter 22).
Cheers
is the .chm file on your server? i havent been able to get to it all day...
ASKER
Hello
Go here:
http://ganz.newmail.ru/Dokz.html
First link is to Richter's book. This file is in rar format. After downloading rename it to *.rar, unrar it and start setup.
There are other interesting books at this site. Their description are in Russian. You can download them, but note - No.2(Programming Windows by Charles Petzold, 5th Edition) and No.7(Visual C++ 6.0) are in Russian. Other are in English.
Cheers
PS. Donno, may be this site allow downloading only from Russian servers? If you'll still have a problem with downloading, let me know, I'll download what you need and place at my server or post you via e-mail.
Cheers
Go here:
http://ganz.newmail.ru/Dokz.html
First link is to Richter's book. This file is in rar format. After downloading rename it to *.rar, unrar it and start setup.
There are other interesting books at this site. Their description are in Russian. You can download them, but note - No.2(Programming Windows by Charles Petzold, 5th Edition) and No.7(Visual C++ 6.0) are in Russian. Other are in English.
Cheers
PS. Donno, may be this site allow downloading only from Russian servers? If you'll still have a problem with downloading, let me know, I'll download what you need and place at my server or post you via e-mail.
Cheers
thanks Ark,
the download does start now, but stops transmitting after only a few kbytes. i am not sure what the reason may be, but it appears i can reach the site...i will continue to try tonight and tomorrow.
the download does start now, but stops transmitting after only a few kbytes. i am not sure what the reason may be, but it appears i can reach the site...i will continue to try tonight and tomorrow.
I don't know much about it
check this code,
Private Sub Form_Load()
Me.AutoRedraw = True
GetTrayNotifyWnd = FindWindow("Shell_TrayWnd" , vbNullString) ', 0, "TrayNotifyWnd", vbNullString)
EnumChildWindows GetTrayNotifyWnd, AddressOf EnumChildProc, ByVal 0&
End Sub
'in a module
Option Explicit
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
Public GetTrayNotifyWnd As Long
Public Function EnumChildProc(ByVal hwnd As Long, ByVal lParam As Long) As Long
Form1.Print hwnd
'continue enumeration
EnumChildProc = 1
End Function
check this code,
Private Sub Form_Load()
Me.AutoRedraw = True
GetTrayNotifyWnd = FindWindow("Shell_TrayWnd"
EnumChildWindows GetTrayNotifyWnd, AddressOf EnumChildProc, ByVal 0&
End Sub
'in a module
Option Explicit
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
Public GetTrayNotifyWnd As Long
Public Function EnumChildProc(ByVal hwnd As Long, ByVal lParam As Long) As Long
Form1.Print hwnd
'continue enumeration
EnumChildProc = 1
End Function
hi Ark, the same is for me. i can't download the files from that server.
Any help really aprecciated.
Any help really aprecciated.
ASKER
Hi, Richie
Unfortunatelly, same for me, seems this file have been removed. Give me your e-mail, I'll send it to you (11M total)
Cheers
Unfortunatelly, same for me, seems this file have been removed. Give me your e-mail, I'll send it to you (11M total)
Cheers
Hi Ark & AzraSound,
>There are description how to inject your process into another
It is possible, that make our process as a child process or thread of another process.
plz, tell me possible r not.I will ask a valuable question
>There are description how to inject your process into another
It is possible, that make our process as a child process or thread of another process.
plz, tell me possible r not.I will ask a valuable question
ricardo.simonetti@fmc-ag.c om
(Thanks, Ark)
(Thanks, Ark)
ping..
pong...
ASKER
So far so long...
What I have now:
Though I still can not get the list of programs in tray, I can safelly get infor from another processese. Here it is:
'============mSharedMemory .BAS module=============
Option Explicit
'Some API (SendMessage for example) use pointers to structures to be filled
'with some data. If you're sending such message to window belong to your
'process - no problem. But if you try to send this message to different
'process - GPF can occure, because structure address belong to calling process
'memory space and target process can not achive this address. Here is
'work around.
'For Win95/98/ME we can use File Mapping, because OS place mapped files
'into shareable memory space. But we can't use this trick for NT - NT map
'files into calling process memory area. In this case, we can use
'VirtualAllocEx function to reserve memory inside target process.
'=========Checking OS staff=============
Private Type OSVERSIONINFO
dwOSVersionInfoSize As Long
dwMajorVersion As Long
dwMinorVersion As Long
dwBuildNumber As Long
dwPlatformId As Long
szCSDVersion As String * 128
End Type
Private Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (LpVersionInformation As OSVERSIONINFO) As Long
'========= Win95/98/ME Shared memory staff===============
Private Declare Function CreateFileMapping Lib "kernel32" Alias "CreateFileMappingA" (ByVal hFile As Long, ByVal lpFileMappigAttributes As Long, ByVal flProtect As Long, ByVal dwMaximumSizeHigh As Long, ByVal dwMaximumSizeLow As Long, ByVal lpName As String) As Long
Private Declare Function MapViewOfFile Lib "kernel32" (ByVal hFileMappingObject As Long, ByVal dwDesiredAccess As Long, ByVal dwFileOffsetHigh As Long, ByVal dwFileOffsetLow As Long, ByVal dwNumberOfBytesToMap As Long) As Long
Private Declare Function UnmapViewOfFile Lib "kernel32" (lpBaseAddress As Any) As Long
Const STANDARD_RIGHTS_REQUIRED = &HF0000
Const SECTION_QUERY = &H1
Const SECTION_MAP_WRITE = &H2
Const SECTION_MAP_READ = &H4
Const SECTION_MAP_EXECUTE = &H8
Const SECTION_EXTEND_SIZE = &H10
Const SECTION_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED Or SECTION_QUERY Or SECTION_MAP_WRITE Or SECTION_MAP_READ Or SECTION_MAP_EXECUTE Or SECTION_EXTEND_SIZE
Const FILE_MAP_ALL_ACCESS = SECTION_ALL_ACCESS
'============NT Shared memory staff===================== =
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Const PROCESS_VM_OPERATION = &H8
Const PROCESS_VM_READ = &H10
Const PROCESS_VM_WRITE = &H20
Const PROCESS_ALL_ACCESS = 0
Private Declare Function VirtualAllocEx Lib "kernel32" (ByVal hProcess As Long, ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
Private Declare Function VirtualFreeEx Lib "kernel32" (ByVal hProcess As Long, lpAddress As Any, ByVal dwSize As Long, ByVal dwFreeType As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
'==========Memory access constants===========
Private Const PAGE_NOACCESS = &H1&
Private Const PAGE_READONLY = &H2&
Private Const PAGE_READWRITE = &H4&
Private Const PAGE_WRITECOPY = &H8&
Private Const PAGE_EXECUTE = &H10&
Private Const PAGE_EXECUTE_READ = &H20&
Private Const PAGE_EXECUTE_READWRITE = &H40&
Private Const PAGE_EXECUTE_WRITECOPY = &H80&
Private Const PAGE_GUARD = &H100&
Private Const PAGE_NOCACHE = &H200&
Public Function GetMemShared95(ByVal memSize As Long, hFile As Long) As Long
hFile = CreateFileMapping(&HFFFFFF FF, 0, PAGE_READWRITE, 0, memSize, vbNullString)
GetMemShared95 = MapViewOfFile(hFile, FILE_MAP_ALL_ACCESS, 0, 0, 0)
End Function
Public Sub FreeMemShared95(ByVal hFile As Long, ByVal lpMem As Long)
UnmapViewOfFile lpMem
CloseHandle hFile
End Sub
Public Function GetMemSharedNT(ByVal pid As Long, ByVal memSize As Long, hProcess As Long) As Long
hProcess = OpenProcess(PROCESS_VM_OPE RATION Or PROCESS_VM_READ Or PROCESS_VM_WRITE, False, pid)
GetMemSharedNT = VirtualAllocEx(ByVal hProcess, ByVal 0&, ByVal memSize, MEM_RESERVE Or MEM_COMMIT, PAGE_READWRITE)
End Function
Public Sub FreeMemSharedNT(ByVal hProcess As Long, ByVal MemAddress As Long, ByVal memSize As Long)
Call VirtualFreeEx(hProcess, ByVal MemAddress, memSize, MEM_RELEASE)
CloseHandle hProcess
End Sub
Public Function IsWindowsNT() As Boolean
Dim verinfo As OSVERSIONINFO
verinfo.dwOSVersionInfoSiz e = Len(verinfo)
If (GetVersionEx(verinfo)) = 0 Then Exit Function
If verinfo.dwPlatformId = 2 Then IsWindowsNT = True
End Function
'============END OF mSharedMemory.BAS MODULE===========
'============BAS MODULE FOR GETTING TOOLTIPINFO========
Option Explicit
'=========ToolTips and TrayFindow=========
Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Type TOOLINFO
cbSize As Long
uFlags As Long
hWnd As Long
uId As Long
cRect As RECT
hInst As Long
lpszText As Long 'LPCSTR
lParam As Long
End Type
Private Const WM_USER = &H400
Private Const TTM_GETTOOLCOUNT = (WM_USER + 13)
Private Const TTM_ENUMTOOLSA = (WM_USER + 14)
Private Const TTM_ENUMTOOLSW = (WM_USER + 58)
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function EnumWindows& Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long)
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetWindowLong& Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long)
Const GWL_STYLE = (-16)
Private Declare Function GetCurrentProcessId Lib "kernel32" () As Long
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpDest As Any, lpSource As Any, ByVal cBytes As Long)
Dim tx As TextBox
Dim NWThreadID As Long, NWPid As Long
Public Sub GetTrayList(txt As TextBox)
Set tx = txt
tx = "Windows:"
NWThreadID = GetWindowThreadProcessId(G etTrayNoti fyWnd, NWPid)
EnumWindows AddressOf EnumWinProc, 0
Set tx = Nothing
End Sub
Private Function GetTrayNotifyWnd() As Long
GetTrayNotifyWnd = FindWindowEx(FindWindow("S hell_TrayW nd", vbNullString), 0, "TrayNotifyWnd", vbNullString)
End Function
Function EnumWinProc(ByVal hWnd As Long, ByVal lParam As Long) As Long
Dim pid As Long, tid As Long, lStyle As Long
Dim hProcess As Long, lpSysShared As Long, dwSize As Long
Dim nCount As Long, lWritten As Long, hFileMapping As Long
Dim ti As TOOLINFO
tid = GetWindowThreadProcessId(h Wnd, pid)
lStyle = GetWindowLong(hWnd, GWL_STYLE)
If pid = NWPid And GetWndClass(hWnd) = "tooltips_class32" And (lStyle And 2) <> 2 Then
nCount = SendMessage(hWnd, TTM_GETTOOLCOUNT, 0&, ByVal 0&)
tx = tx & "Icons count = " & nCount
ti.cbSize = Len(ti)
dwSize = ti.cbSize
If IsWindowsNT Then
lpSysShared = GetMemSharedNT(pid, dwSize, hProcess)
WriteProcessMemory hProcess, ByVal lpSysShared, ti, dwSize, lWritten
For i = 0 To nCount - 1
Call SendMessage(hWnd, TTM_ENUMTOOLSW, i, ByVal lpSysShared)
ReadProcessMemory hProcess, ByVal lpSysShared, ti, dwSize, lWritten
Next i
FreeMemSharedNT hProcess, lpSysShared, dwSize
Else
lpSysShared = GetMemShared95(dwSize, hFileMapping)
CopyMemory ByVal lpSysShared, ti, dwSize
For i = 0 To nCount - 1
Call SendMessage(hWnd, TTM_ENUMTOOLSA, i, ByVal lpSysShared)
CopyMemory ti, ByVal lpSysShared, dwSize
Debug.Print ti.hWnd, ti.lpszText, ti.hInst, ti.uId, ti.lParam
Next i
FreeMemShared95 hFileMapping, lpSysShared
End If
EnumWinProc = 0
Exit Function
End If
EnumWinProc = 1
End Function
Private Function GetWndClass(hWnd As Long) As String
Dim k As Long, sName As String
sName = Space$(128)
k = GetClassName(hWnd, sName, 128)
If k > 0 Then sName = Left$(sName, k) Else sName = "No class"
GetWndClass = sName
End Function
'===============END OF BAS MODULE==================== ===
I've got correct TOOLIFO structure with TrayNotify hWnd as .hWnd, some .hInst and .uId (donno what are they), but lpszText member is -1 (LPSTR_CALLBACK). Damn! Now I have to dig deeper looking for this callback function which return text!
'========================= ========== ========== ==========
Sorry to all for long silence. To apologize, here is BONUS:
'Dancing desktop sample
'There is now problem to change desktop icons position - desktop is simple ListView control.
'But to restore it, you have to save previous position. Here is a problem -
'you need to pass structure to Shell. So we have to use above mSharedMemory.bas module.
'Add this module to your project
'Add second bas module:
'=====Desktop.Bas module code=======
Option Explicit
Public Enum SHUFFLE_TYPE
RANDOM
SINE
CIRCLES
'More depend on your fantasy and geomethry knowledge :)
End Enum
'=========Desktop SysListView staff=============
Type POINTAPI
x As Long
y As Long
End Type
Private Declare Function FindWindow& Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String)
Private Declare Function FindWindowEx& Lib "user32" Alias "FindWindowExA" (ByVal hWndParent As Long, ByVal hWndChildAfter As Long, ByVal lpClassName As String, ByVal lpWindowName As String)
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
Private Declare Function GetWindowLong& Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long)
Const GWL_STYLE = (-16)
Private Const LVS_AUTOARRANGE = &H100
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpDest As Any, lpSource As Any, ByVal cBytes As Long)
Private Declare Function GetParent Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function SendMessage& Lib "user32" Alias "SendMessageA" (ByVal hWnd&, ByVal wMsg&, ByVal wParam&, lParam As Any)
Private Const LVM_FIRST = &H1000
Private Const LVM_GETTITEMCOUNT& = (LVM_FIRST + 4)
Private Const LVM_SETITEMPOSITION& = (LVM_FIRST + 15)
Private Const LVM_GETITEMPOSITION& = (LVM_FIRST + 16)
Private Const WM_COMMAND = &H111
Private Const IDM_TOGGLEAUTOARRANGE = &H7041
'========================= ========== ========== ========== ======
Dim ptOriginal() As POINTAPI
Dim ptCurrent() As POINTAPI
Dim xScreen As Long, yScreen As Long
Dim bAutoArrange As Boolean
Public Sub ShuffleDesktopIcons(ByVal ShuffleType As SHUFFLE_TYPE)
Dim h As Long, nCount As Long, i As Long
Dim FactorX As Single, FactorY As Single, Radius As Single
Dim x As Long, y As Long, cx As Long, cy As Long
FactorX = Rnd
FactorY = Rnd
Radius = xScreen * Rnd / 2
h = GetSysLVHwnd
nCount = SendMessage(h, LVM_GETTITEMCOUNT, 0, 0&)
For i = 0 To nCount - 1
Select Case ShuffleType
Case RANDOM
x = Int(Rnd * xScreen)
y = Int(Rnd * yScreen)
Case SINE
x = FactorX * xScreen * i \ nCount
y = FactorY * yScreen * (1 - Sin(i * 6.28 / nCount)) \ 2
Case CIRCLES
x = xScreen / 2 - Radius * Cos(i * 6.28 / nCount)
y = yScreen / 2 - Radius * Sin(i * 6.28 / nCount)
End Select
Call SendMessage(h, LVM_SETITEMPOSITION, i, ByVal CLng(x + y * &H10000))
Next
End Sub
Public Sub RestoreDesktopIcons()
Dim h As Long, nCount As Long, i As Long
h = GetSysLVHwnd
nCount = SendMessage(h, LVM_GETTITEMCOUNT, 0, 0&)
For i = 0 To nCount - 1
Call SendMessage(h, LVM_SETITEMPOSITION, i, ByVal CLng(ptOriginal(i).x + ptOriginal(i).y * &H10000))
Next
If bAutoArrange Then
Call SendMessage(GetParent(h), WM_COMMAND, IDM_TOGGLEAUTOARRANGE, ByVal 0&)
End If
End Sub
Public Function StoreDeskTopInfo() As Boolean
Dim pid As Long, tid As Long, lStyle As Long
Dim hProcess As Long, lpSysShared As Long, dwSize As Long
Dim nCount As Long, lWritten As Long, hFileMapping As Long
Dim h As Long, i As Long
h = GetSysLVHwnd
If h = 0 Then Exit Function
If (GetWindowLong(h, GWL_STYLE) And LVS_AUTOARRANGE) = LVS_AUTOARRANGE Then
bAutoArrange = True
Call SendMessage(GetParent(h), WM_COMMAND, IDM_TOGGLEAUTOARRANGE, ByVal 0&)
End If
tid = GetWindowThreadProcessId(h , pid)
nCount = SendMessage(h, LVM_GETTITEMCOUNT, 0, 0&)
If nCount = 0 Then Exit Function
xScreen = Screen.Width \ Screen.TwipsPerPixelX
yScreen = Screen.Height \ Screen.TwipsPerPixelY
ReDim ptOriginal(nCount - 1)
ReDim ptCurrent(nCount - 1)
dwSize = Len(ptOriginal(0))
If IsWindowsNT Then
lpSysShared = GetMemSharedNT(pid, dwSize, hProcess)
WriteProcessMemory hProcess, ByVal lpSysShared, ptOriginal(0), dwSize, lWritten
For i = 0 To nCount - 1
SendMessage h, LVM_GETITEMPOSITION, i, ByVal lpSysShared
ReadProcessMemory hProcess, ByVal lpSysShared, ptOriginal(i), dwSize, lWritten
Next i
FreeMemSharedNT hProcess, lpSysShared, dwSize
Else
lpSysShared = GetMemShared95(dwSize, hFileMapping)
CopyMemory ByVal lpSysShared, ptOriginal(0), dwSize
For i = 0 To nCount - 1
SendMessage h, LVM_GETITEMPOSITION, i, ByVal lpSysShared
CopyMemory ptOriginal(i), ByVal lpSysShared, dwSize
ptCurrent(i).x = xScreen / 2
ptCurrent(i).y = yScreen / 2
Next i
FreeMemShared95 hFileMapping, lpSysShared
End If
StoreDeskTopInfo = True
End Function
Private Function GetSysLVHwnd() As Long
Dim h As Long
h = FindWindow("Progman", vbNullString)
h = FindWindowEx(h, 0, "SHELLDLL_defVIEW", vbNullString)
GetSysLVHwnd = FindWindowEx(h, 0, "SysListView32", vbNullString)
End Function
'==========Form code========
'add 2 command button, label, combobox(dropdown list) and timer to form (with default names).
Dim bRunning As Boolean
Private Sub Command1_Click()
If Not bRunning Then
If StoreDeskTopInfo Then Timer1.Enabled = True
Caption = "See your desktop dancing!"
bRunning = True
Command1.Enabled = False
Command2.Enabled = True
End If
End Sub
Private Sub Command2_Click()
If bRunning Then
Timer1.Enabled = False
RestoreDesktopIcons
bRunning = False
Caption = "Desktop shuffle sample"
Command1.Enabled = True
Command2.Enabled = False
End If
End Sub
Private Sub Form_Load()
Timer1.Interval = 200
Timer1.Enabled = False
Caption = "Desktop shuffle demo"
Label1 = "Desktop shuffling type"
With Combo1
.AddItem "RANDOM"
.AddItem "SINE"
.AddItem "CIRCLES"
.ListIndex = 0
End With
Command1.Caption = "&Start"
Command2.Caption = "&Stop"
Command1.Enabled = True
Command2.Enabled = False
End Sub
Private Sub Form_Unload(Cancel As Integer)
If bRunning Then RestoreDesktopIcons
End Sub
Private Sub Timer1_Timer()
ShuffleDesktopIcons Combo1.ListIndex
End Sub
'============End form code================
Tested on w98 - works OK. Not tested on NT, but should work too.
I'm going to close this question.
Cheers
What I have now:
Though I still can not get the list of programs in tray, I can safelly get infor from another processese. Here it is:
'============mSharedMemory
Option Explicit
'Some API (SendMessage for example) use pointers to structures to be filled
'with some data. If you're sending such message to window belong to your
'process - no problem. But if you try to send this message to different
'process - GPF can occure, because structure address belong to calling process
'memory space and target process can not achive this address. Here is
'work around.
'For Win95/98/ME we can use File Mapping, because OS place mapped files
'into shareable memory space. But we can't use this trick for NT - NT map
'files into calling process memory area. In this case, we can use
'VirtualAllocEx function to reserve memory inside target process.
'=========Checking OS staff=============
Private Type OSVERSIONINFO
dwOSVersionInfoSize As Long
dwMajorVersion As Long
dwMinorVersion As Long
dwBuildNumber As Long
dwPlatformId As Long
szCSDVersion As String * 128
End Type
Private Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (LpVersionInformation As OSVERSIONINFO) As Long
'========= Win95/98/ME Shared memory staff===============
Private Declare Function CreateFileMapping Lib "kernel32" Alias "CreateFileMappingA" (ByVal hFile As Long, ByVal lpFileMappigAttributes As Long, ByVal flProtect As Long, ByVal dwMaximumSizeHigh As Long, ByVal dwMaximumSizeLow As Long, ByVal lpName As String) As Long
Private Declare Function MapViewOfFile Lib "kernel32" (ByVal hFileMappingObject As Long, ByVal dwDesiredAccess As Long, ByVal dwFileOffsetHigh As Long, ByVal dwFileOffsetLow As Long, ByVal dwNumberOfBytesToMap As Long) As Long
Private Declare Function UnmapViewOfFile Lib "kernel32" (lpBaseAddress As Any) As Long
Const STANDARD_RIGHTS_REQUIRED = &HF0000
Const SECTION_QUERY = &H1
Const SECTION_MAP_WRITE = &H2
Const SECTION_MAP_READ = &H4
Const SECTION_MAP_EXECUTE = &H8
Const SECTION_EXTEND_SIZE = &H10
Const SECTION_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED Or SECTION_QUERY Or SECTION_MAP_WRITE Or SECTION_MAP_READ Or SECTION_MAP_EXECUTE Or SECTION_EXTEND_SIZE
Const FILE_MAP_ALL_ACCESS = SECTION_ALL_ACCESS
'============NT Shared memory staff=====================
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Const PROCESS_VM_OPERATION = &H8
Const PROCESS_VM_READ = &H10
Const PROCESS_VM_WRITE = &H20
Const PROCESS_ALL_ACCESS = 0
Private Declare Function VirtualAllocEx Lib "kernel32" (ByVal hProcess As Long, ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
Private Declare Function VirtualFreeEx Lib "kernel32" (ByVal hProcess As Long, lpAddress As Any, ByVal dwSize As Long, ByVal dwFreeType As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
'==========Memory access constants===========
Private Const PAGE_NOACCESS = &H1&
Private Const PAGE_READONLY = &H2&
Private Const PAGE_READWRITE = &H4&
Private Const PAGE_WRITECOPY = &H8&
Private Const PAGE_EXECUTE = &H10&
Private Const PAGE_EXECUTE_READ = &H20&
Private Const PAGE_EXECUTE_READWRITE = &H40&
Private Const PAGE_EXECUTE_WRITECOPY = &H80&
Private Const PAGE_GUARD = &H100&
Private Const PAGE_NOCACHE = &H200&
Public Function GetMemShared95(ByVal memSize As Long, hFile As Long) As Long
hFile = CreateFileMapping(&HFFFFFF
GetMemShared95 = MapViewOfFile(hFile, FILE_MAP_ALL_ACCESS, 0, 0, 0)
End Function
Public Sub FreeMemShared95(ByVal hFile As Long, ByVal lpMem As Long)
UnmapViewOfFile lpMem
CloseHandle hFile
End Sub
Public Function GetMemSharedNT(ByVal pid As Long, ByVal memSize As Long, hProcess As Long) As Long
hProcess = OpenProcess(PROCESS_VM_OPE
GetMemSharedNT = VirtualAllocEx(ByVal hProcess, ByVal 0&, ByVal memSize, MEM_RESERVE Or MEM_COMMIT, PAGE_READWRITE)
End Function
Public Sub FreeMemSharedNT(ByVal hProcess As Long, ByVal MemAddress As Long, ByVal memSize As Long)
Call VirtualFreeEx(hProcess, ByVal MemAddress, memSize, MEM_RELEASE)
CloseHandle hProcess
End Sub
Public Function IsWindowsNT() As Boolean
Dim verinfo As OSVERSIONINFO
verinfo.dwOSVersionInfoSiz
If (GetVersionEx(verinfo)) = 0 Then Exit Function
If verinfo.dwPlatformId = 2 Then IsWindowsNT = True
End Function
'============END OF mSharedMemory.BAS MODULE===========
'============BAS MODULE FOR GETTING TOOLTIPINFO========
Option Explicit
'=========ToolTips and TrayFindow=========
Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Type TOOLINFO
cbSize As Long
uFlags As Long
hWnd As Long
uId As Long
cRect As RECT
hInst As Long
lpszText As Long 'LPCSTR
lParam As Long
End Type
Private Const WM_USER = &H400
Private Const TTM_GETTOOLCOUNT = (WM_USER + 13)
Private Const TTM_ENUMTOOLSA = (WM_USER + 14)
Private Const TTM_ENUMTOOLSW = (WM_USER + 58)
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function EnumWindows& Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long)
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetWindowLong& Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long)
Const GWL_STYLE = (-16)
Private Declare Function GetCurrentProcessId Lib "kernel32" () As Long
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpDest As Any, lpSource As Any, ByVal cBytes As Long)
Dim tx As TextBox
Dim NWThreadID As Long, NWPid As Long
Public Sub GetTrayList(txt As TextBox)
Set tx = txt
tx = "Windows:"
NWThreadID = GetWindowThreadProcessId(G
EnumWindows AddressOf EnumWinProc, 0
Set tx = Nothing
End Sub
Private Function GetTrayNotifyWnd() As Long
GetTrayNotifyWnd = FindWindowEx(FindWindow("S
End Function
Function EnumWinProc(ByVal hWnd As Long, ByVal lParam As Long) As Long
Dim pid As Long, tid As Long, lStyle As Long
Dim hProcess As Long, lpSysShared As Long, dwSize As Long
Dim nCount As Long, lWritten As Long, hFileMapping As Long
Dim ti As TOOLINFO
tid = GetWindowThreadProcessId(h
lStyle = GetWindowLong(hWnd, GWL_STYLE)
If pid = NWPid And GetWndClass(hWnd) = "tooltips_class32" And (lStyle And 2) <> 2 Then
nCount = SendMessage(hWnd, TTM_GETTOOLCOUNT, 0&, ByVal 0&)
tx = tx & "Icons count = " & nCount
ti.cbSize = Len(ti)
dwSize = ti.cbSize
If IsWindowsNT Then
lpSysShared = GetMemSharedNT(pid, dwSize, hProcess)
WriteProcessMemory hProcess, ByVal lpSysShared, ti, dwSize, lWritten
For i = 0 To nCount - 1
Call SendMessage(hWnd, TTM_ENUMTOOLSW, i, ByVal lpSysShared)
ReadProcessMemory hProcess, ByVal lpSysShared, ti, dwSize, lWritten
Next i
FreeMemSharedNT hProcess, lpSysShared, dwSize
Else
lpSysShared = GetMemShared95(dwSize, hFileMapping)
CopyMemory ByVal lpSysShared, ti, dwSize
For i = 0 To nCount - 1
Call SendMessage(hWnd, TTM_ENUMTOOLSA, i, ByVal lpSysShared)
CopyMemory ti, ByVal lpSysShared, dwSize
Debug.Print ti.hWnd, ti.lpszText, ti.hInst, ti.uId, ti.lParam
Next i
FreeMemShared95 hFileMapping, lpSysShared
End If
EnumWinProc = 0
Exit Function
End If
EnumWinProc = 1
End Function
Private Function GetWndClass(hWnd As Long) As String
Dim k As Long, sName As String
sName = Space$(128)
k = GetClassName(hWnd, sName, 128)
If k > 0 Then sName = Left$(sName, k) Else sName = "No class"
GetWndClass = sName
End Function
'===============END OF BAS MODULE====================
I've got correct TOOLIFO structure with TrayNotify hWnd as .hWnd, some .hInst and .uId (donno what are they), but lpszText member is -1 (LPSTR_CALLBACK). Damn! Now I have to dig deeper looking for this callback function which return text!
'=========================
Sorry to all for long silence. To apologize, here is BONUS:
'Dancing desktop sample
'There is now problem to change desktop icons position - desktop is simple ListView control.
'But to restore it, you have to save previous position. Here is a problem -
'you need to pass structure to Shell. So we have to use above mSharedMemory.bas module.
'Add this module to your project
'Add second bas module:
'=====Desktop.Bas module code=======
Option Explicit
Public Enum SHUFFLE_TYPE
RANDOM
SINE
CIRCLES
'More depend on your fantasy and geomethry knowledge :)
End Enum
'=========Desktop SysListView staff=============
Type POINTAPI
x As Long
y As Long
End Type
Private Declare Function FindWindow& Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String)
Private Declare Function FindWindowEx& Lib "user32" Alias "FindWindowExA" (ByVal hWndParent As Long, ByVal hWndChildAfter As Long, ByVal lpClassName As String, ByVal lpWindowName As String)
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
Private Declare Function GetWindowLong& Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long)
Const GWL_STYLE = (-16)
Private Const LVS_AUTOARRANGE = &H100
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpDest As Any, lpSource As Any, ByVal cBytes As Long)
Private Declare Function GetParent Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function SendMessage& Lib "user32" Alias "SendMessageA" (ByVal hWnd&, ByVal wMsg&, ByVal wParam&, lParam As Any)
Private Const LVM_FIRST = &H1000
Private Const LVM_GETTITEMCOUNT& = (LVM_FIRST + 4)
Private Const LVM_SETITEMPOSITION& = (LVM_FIRST + 15)
Private Const LVM_GETITEMPOSITION& = (LVM_FIRST + 16)
Private Const WM_COMMAND = &H111
Private Const IDM_TOGGLEAUTOARRANGE = &H7041
'=========================
Dim ptOriginal() As POINTAPI
Dim ptCurrent() As POINTAPI
Dim xScreen As Long, yScreen As Long
Dim bAutoArrange As Boolean
Public Sub ShuffleDesktopIcons(ByVal ShuffleType As SHUFFLE_TYPE)
Dim h As Long, nCount As Long, i As Long
Dim FactorX As Single, FactorY As Single, Radius As Single
Dim x As Long, y As Long, cx As Long, cy As Long
FactorX = Rnd
FactorY = Rnd
Radius = xScreen * Rnd / 2
h = GetSysLVHwnd
nCount = SendMessage(h, LVM_GETTITEMCOUNT, 0, 0&)
For i = 0 To nCount - 1
Select Case ShuffleType
Case RANDOM
x = Int(Rnd * xScreen)
y = Int(Rnd * yScreen)
Case SINE
x = FactorX * xScreen * i \ nCount
y = FactorY * yScreen * (1 - Sin(i * 6.28 / nCount)) \ 2
Case CIRCLES
x = xScreen / 2 - Radius * Cos(i * 6.28 / nCount)
y = yScreen / 2 - Radius * Sin(i * 6.28 / nCount)
End Select
Call SendMessage(h, LVM_SETITEMPOSITION, i, ByVal CLng(x + y * &H10000))
Next
End Sub
Public Sub RestoreDesktopIcons()
Dim h As Long, nCount As Long, i As Long
h = GetSysLVHwnd
nCount = SendMessage(h, LVM_GETTITEMCOUNT, 0, 0&)
For i = 0 To nCount - 1
Call SendMessage(h, LVM_SETITEMPOSITION, i, ByVal CLng(ptOriginal(i).x + ptOriginal(i).y * &H10000))
Next
If bAutoArrange Then
Call SendMessage(GetParent(h), WM_COMMAND, IDM_TOGGLEAUTOARRANGE, ByVal 0&)
End If
End Sub
Public Function StoreDeskTopInfo() As Boolean
Dim pid As Long, tid As Long, lStyle As Long
Dim hProcess As Long, lpSysShared As Long, dwSize As Long
Dim nCount As Long, lWritten As Long, hFileMapping As Long
Dim h As Long, i As Long
h = GetSysLVHwnd
If h = 0 Then Exit Function
If (GetWindowLong(h, GWL_STYLE) And LVS_AUTOARRANGE) = LVS_AUTOARRANGE Then
bAutoArrange = True
Call SendMessage(GetParent(h), WM_COMMAND, IDM_TOGGLEAUTOARRANGE, ByVal 0&)
End If
tid = GetWindowThreadProcessId(h
nCount = SendMessage(h, LVM_GETTITEMCOUNT, 0, 0&)
If nCount = 0 Then Exit Function
xScreen = Screen.Width \ Screen.TwipsPerPixelX
yScreen = Screen.Height \ Screen.TwipsPerPixelY
ReDim ptOriginal(nCount - 1)
ReDim ptCurrent(nCount - 1)
dwSize = Len(ptOriginal(0))
If IsWindowsNT Then
lpSysShared = GetMemSharedNT(pid, dwSize, hProcess)
WriteProcessMemory hProcess, ByVal lpSysShared, ptOriginal(0), dwSize, lWritten
For i = 0 To nCount - 1
SendMessage h, LVM_GETITEMPOSITION, i, ByVal lpSysShared
ReadProcessMemory hProcess, ByVal lpSysShared, ptOriginal(i), dwSize, lWritten
Next i
FreeMemSharedNT hProcess, lpSysShared, dwSize
Else
lpSysShared = GetMemShared95(dwSize, hFileMapping)
CopyMemory ByVal lpSysShared, ptOriginal(0), dwSize
For i = 0 To nCount - 1
SendMessage h, LVM_GETITEMPOSITION, i, ByVal lpSysShared
CopyMemory ptOriginal(i), ByVal lpSysShared, dwSize
ptCurrent(i).x = xScreen / 2
ptCurrent(i).y = yScreen / 2
Next i
FreeMemShared95 hFileMapping, lpSysShared
End If
StoreDeskTopInfo = True
End Function
Private Function GetSysLVHwnd() As Long
Dim h As Long
h = FindWindow("Progman", vbNullString)
h = FindWindowEx(h, 0, "SHELLDLL_defVIEW", vbNullString)
GetSysLVHwnd = FindWindowEx(h, 0, "SysListView32", vbNullString)
End Function
'==========Form code========
'add 2 command button, label, combobox(dropdown list) and timer to form (with default names).
Dim bRunning As Boolean
Private Sub Command1_Click()
If Not bRunning Then
If StoreDeskTopInfo Then Timer1.Enabled = True
Caption = "See your desktop dancing!"
bRunning = True
Command1.Enabled = False
Command2.Enabled = True
End If
End Sub
Private Sub Command2_Click()
If bRunning Then
Timer1.Enabled = False
RestoreDesktopIcons
bRunning = False
Caption = "Desktop shuffle sample"
Command1.Enabled = True
Command2.Enabled = False
End If
End Sub
Private Sub Form_Load()
Timer1.Interval = 200
Timer1.Enabled = False
Caption = "Desktop shuffle demo"
Label1 = "Desktop shuffling type"
With Combo1
.AddItem "RANDOM"
.AddItem "SINE"
.AddItem "CIRCLES"
.ListIndex = 0
End With
Command1.Caption = "&Start"
Command2.Caption = "&Stop"
Command1.Enabled = True
Command2.Enabled = False
End Sub
Private Sub Form_Unload(Cancel As Integer)
If bRunning Then RestoreDesktopIcons
End Sub
Private Sub Timer1_Timer()
ShuffleDesktopIcons Combo1.ListIndex
End Sub
'============End form code================
Tested on w98 - works OK. Not tested on NT, but should work too.
I'm going to close this question.
Cheers
ASKER
Got It!!!!!!!!!!!!!!!
Add mSharedMemory.bas
Add second module:
'==========bas module code==========
Option Explicit
Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Type TOOLINFO
cbSize As Long
uFlags As Long
hWnd As Long
uId As Long
cRect As RECT
hInst As Long
lpszText As Long 'LPCSTR
lParam As Long
End Type
Private Const WM_USER = &H400
Private Const TTM_GETTOOLCOUNT = (WM_USER + 13)
Private Const TTM_ENUMTOOLSA = (WM_USER + 14)
Private Const TTM_ENUMTOOLSW = (WM_USER + 58)
Private Const TTM_GETTEXT = (WM_USER + 11)
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function EnumWindows& Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long)
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetWindowLong& Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long)
Const GWL_STYLE = (-16)
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpDest As Any, lpSource As Any, ByVal cBytes As Long)
Private Declare Function CopyStringA Lib "kernel32" Alias "lstrcpyA" (ByVal NewString As String, ByVal OldString As Long) As Long
Private Declare Function lstrlenW Lib "kernel32" (ByVal lpString As Long) As Long
Private Declare Function lstrlenA Lib "kernel32" (ByVal lpString As Long) As Long
Dim sTips() As String
Dim NWThreadID As Long, NWPid As Long
Public Function GetTrayList() As Variant
NWThreadID = GetWindowThreadProcessId(G etTrayNoti fyWnd, NWPid)
EnumWindows AddressOf EnumWinProc, 0
GetTrayList = sTips
End Function
Private Function GetTrayNotifyWnd() As Long
GetTrayNotifyWnd = FindWindowEx(FindWindow("S hell_TrayW nd", vbNullString), 0, "TrayNotifyWnd", vbNullString)
End Function
Function EnumWinProc(ByVal hWnd As Long, ByVal lParam As Long) As Long
Dim pid As Long, tid As Long, lStyle As Long
Dim hProcess As Long, nCount As Long, lWritten As Long, i As Long
Dim lpSysShared As Long, hFileMapping As Long, dwSize As Long
Dim lpSysShared2 As Long, hFileMapping2 As Long
Dim ti As TOOLINFO
Dim sTipText As String * 80
tid = GetWindowThreadProcessId(h Wnd, pid)
lStyle = GetWindowLong(hWnd, GWL_STYLE)
If pid = NWPid And GetWndClass(hWnd) = "tooltips_class32" And (lStyle And 2) <> 2 Then
nCount = SendMessage(hWnd, TTM_GETTOOLCOUNT, 0&, ByVal 0&)
ReDim sTips(nCount - 1)
ti.cbSize = Len(ti)
dwSize = ti.cbSize
If IsWindowsNT Then
lpSysShared = GetMemSharedNT(pid, dwSize, hProcess)
lpSysShared2 = GetMemSharedNT(pid, LenB(sTipText), hProcess)
WriteProcessMemory hProcess, ByVal lpSysShared, ti, dwSize, lWritten
WriteProcessMemory hProcess, ByVal lpSysShared2, sTipText, LenB(sTipText), lWritten
For i = 0 To nCount - 1
Call SendMessage(hWnd, TTM_ENUMTOOLSW, i, ByVal lpSysShared)
ReadProcessMemory hProcess, ByVal lpSysShared, ti, dwSize, lWritten
ti.lpszText = lpSysShared2
WriteProcessMemory hProcess, ByVal lpSysShared, ti, dwSize, lWritten
Call SendMessage(hWnd, TTM_GETTEXT, 0&, ByVal lpSysShared)
ReadProcessMemory hProcess, ByVal lpSysShared, ti, dwSize, lWritten
sTips(i) = StrFromPtrW(ti.lpszText)
Next i
FreeMemSharedNT hProcess, lpSysShared, dwSize
FreeMemSharedNT hProcess, lpSysShared2, LenB(sTipText)
Else
lpSysShared = GetMemShared95(dwSize, hFileMapping)
lpSysShared2 = GetMemShared95(LenB(sTipTe xt), hFileMapping2)
CopyMemory ByVal lpSysShared, ti, dwSize
CopyMemory ByVal lpSysShared2, sTipText, LenB(sTipText)
For i = 0 To nCount - 1
Call SendMessage(hWnd, TTM_ENUMTOOLSA, i, ByVal lpSysShared)
CopyMemory ti, ByVal lpSysShared, dwSize
ti.lpszText = lpSysShared2
CopyMemory ByVal lpSysShared, ti, dwSize
Call SendMessage(hWnd, TTM_GETTEXT, 0&, ByVal lpSysShared)
CopyMemory ti, ByVal lpSysShared, dwSize
sTips(i) = StrFromPtrA(ti.lpszText)
Next i
FreeMemShared95 hFileMapping, lpSysShared
FreeMemShared95 hFileMapping2, lpSysShared2
End If
EnumWinProc = 0
Exit Function
End If
EnumWinProc = 1
End Function
Private Function GetWndClass(hWnd As Long) As String
Dim k As Long, sName As String
sName = Space$(128)
k = GetClassName(hWnd, sName, 128)
If k > 0 Then sName = Left$(sName, k) Else sName = "No class"
GetWndClass = sName
End Function
Private Function StrFromPtrA(ByVal lpszA As Long, Optional nSize As Long = 0) As String
Dim s As String, bTrim As Boolean
If nSize = 0 Then
nSize = lstrlenA(lpszA)
bTrim = True
End If
s = String(nSize, Chr$(0))
CopyStringA s, ByVal lpszA
If bTrim Then s = TrimNULL(s)
StrFromPtrA = s
End Function
Private Function StrFromPtrW(ByVal lpszW As Long, Optional nSize As Long = 0) As String
Dim s As String, bTrim As Boolean
If nSize = 0 Then
nSize = lstrlenW(lpszW)
bTrim = True
End If
s = String(nSize, Chr$(0))
CopyMemory ByVal StrPtr(s), ByVal lpszW, nSize
If bTrim Then s = TrimNULL(s)
StrFromPtrW = s
End Function
Private Function TrimNULL(ByVal str As String) As String
If InStr(str, Chr$(0)) > 0& Then
TrimNULL = Left$(str, InStr(str, Chr$(0)) - 1&)
Else
TrimNULL = str
End If
End Function
'========Form code=======
'add label,ListBox and command button on form
Private Sub Command1_Click()
Dim sTrayList As Variant
sTrayList = GetTrayList
Label1 = "Icons in tray: " & UBound(sTrayList) + 1
List1.Clear
For i = 0 To UBound(sTrayList)
List1.AddItem i + 1 & ". " & sTrayList(i)
Next i
End Sub
Private Sub Form_Load()
Caption = "Who lives in the system tray?"
Command1.Caption = "&Get List"
Label1 = "Icons in tray: "
End Sub
'Not sure for NT (not tested). If tips text stored in ANSI, we should change StrFromPtrW to StrFromPtrA.
Tada!!
PS Can anybody test code on NT please?
Cheers
Add mSharedMemory.bas
Add second module:
'==========bas module code==========
Option Explicit
Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Type TOOLINFO
cbSize As Long
uFlags As Long
hWnd As Long
uId As Long
cRect As RECT
hInst As Long
lpszText As Long 'LPCSTR
lParam As Long
End Type
Private Const WM_USER = &H400
Private Const TTM_GETTOOLCOUNT = (WM_USER + 13)
Private Const TTM_ENUMTOOLSA = (WM_USER + 14)
Private Const TTM_ENUMTOOLSW = (WM_USER + 58)
Private Const TTM_GETTEXT = (WM_USER + 11)
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function EnumWindows& Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long)
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetWindowLong& Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long)
Const GWL_STYLE = (-16)
Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpDest As Any, lpSource As Any, ByVal cBytes As Long)
Private Declare Function CopyStringA Lib "kernel32" Alias "lstrcpyA" (ByVal NewString As String, ByVal OldString As Long) As Long
Private Declare Function lstrlenW Lib "kernel32" (ByVal lpString As Long) As Long
Private Declare Function lstrlenA Lib "kernel32" (ByVal lpString As Long) As Long
Dim sTips() As String
Dim NWThreadID As Long, NWPid As Long
Public Function GetTrayList() As Variant
NWThreadID = GetWindowThreadProcessId(G
EnumWindows AddressOf EnumWinProc, 0
GetTrayList = sTips
End Function
Private Function GetTrayNotifyWnd() As Long
GetTrayNotifyWnd = FindWindowEx(FindWindow("S
End Function
Function EnumWinProc(ByVal hWnd As Long, ByVal lParam As Long) As Long
Dim pid As Long, tid As Long, lStyle As Long
Dim hProcess As Long, nCount As Long, lWritten As Long, i As Long
Dim lpSysShared As Long, hFileMapping As Long, dwSize As Long
Dim lpSysShared2 As Long, hFileMapping2 As Long
Dim ti As TOOLINFO
Dim sTipText As String * 80
tid = GetWindowThreadProcessId(h
lStyle = GetWindowLong(hWnd, GWL_STYLE)
If pid = NWPid And GetWndClass(hWnd) = "tooltips_class32" And (lStyle And 2) <> 2 Then
nCount = SendMessage(hWnd, TTM_GETTOOLCOUNT, 0&, ByVal 0&)
ReDim sTips(nCount - 1)
ti.cbSize = Len(ti)
dwSize = ti.cbSize
If IsWindowsNT Then
lpSysShared = GetMemSharedNT(pid, dwSize, hProcess)
lpSysShared2 = GetMemSharedNT(pid, LenB(sTipText), hProcess)
WriteProcessMemory hProcess, ByVal lpSysShared, ti, dwSize, lWritten
WriteProcessMemory hProcess, ByVal lpSysShared2, sTipText, LenB(sTipText), lWritten
For i = 0 To nCount - 1
Call SendMessage(hWnd, TTM_ENUMTOOLSW, i, ByVal lpSysShared)
ReadProcessMemory hProcess, ByVal lpSysShared, ti, dwSize, lWritten
ti.lpszText = lpSysShared2
WriteProcessMemory hProcess, ByVal lpSysShared, ti, dwSize, lWritten
Call SendMessage(hWnd, TTM_GETTEXT, 0&, ByVal lpSysShared)
ReadProcessMemory hProcess, ByVal lpSysShared, ti, dwSize, lWritten
sTips(i) = StrFromPtrW(ti.lpszText)
Next i
FreeMemSharedNT hProcess, lpSysShared, dwSize
FreeMemSharedNT hProcess, lpSysShared2, LenB(sTipText)
Else
lpSysShared = GetMemShared95(dwSize, hFileMapping)
lpSysShared2 = GetMemShared95(LenB(sTipTe
CopyMemory ByVal lpSysShared, ti, dwSize
CopyMemory ByVal lpSysShared2, sTipText, LenB(sTipText)
For i = 0 To nCount - 1
Call SendMessage(hWnd, TTM_ENUMTOOLSA, i, ByVal lpSysShared)
CopyMemory ti, ByVal lpSysShared, dwSize
ti.lpszText = lpSysShared2
CopyMemory ByVal lpSysShared, ti, dwSize
Call SendMessage(hWnd, TTM_GETTEXT, 0&, ByVal lpSysShared)
CopyMemory ti, ByVal lpSysShared, dwSize
sTips(i) = StrFromPtrA(ti.lpszText)
Next i
FreeMemShared95 hFileMapping, lpSysShared
FreeMemShared95 hFileMapping2, lpSysShared2
End If
EnumWinProc = 0
Exit Function
End If
EnumWinProc = 1
End Function
Private Function GetWndClass(hWnd As Long) As String
Dim k As Long, sName As String
sName = Space$(128)
k = GetClassName(hWnd, sName, 128)
If k > 0 Then sName = Left$(sName, k) Else sName = "No class"
GetWndClass = sName
End Function
Private Function StrFromPtrA(ByVal lpszA As Long, Optional nSize As Long = 0) As String
Dim s As String, bTrim As Boolean
If nSize = 0 Then
nSize = lstrlenA(lpszA)
bTrim = True
End If
s = String(nSize, Chr$(0))
CopyStringA s, ByVal lpszA
If bTrim Then s = TrimNULL(s)
StrFromPtrA = s
End Function
Private Function StrFromPtrW(ByVal lpszW As Long, Optional nSize As Long = 0) As String
Dim s As String, bTrim As Boolean
If nSize = 0 Then
nSize = lstrlenW(lpszW)
bTrim = True
End If
s = String(nSize, Chr$(0))
CopyMemory ByVal StrPtr(s), ByVal lpszW, nSize
If bTrim Then s = TrimNULL(s)
StrFromPtrW = s
End Function
Private Function TrimNULL(ByVal str As String) As String
If InStr(str, Chr$(0)) > 0& Then
TrimNULL = Left$(str, InStr(str, Chr$(0)) - 1&)
Else
TrimNULL = str
End If
End Function
'========Form code=======
'add label,ListBox and command button on form
Private Sub Command1_Click()
Dim sTrayList As Variant
sTrayList = GetTrayList
Label1 = "Icons in tray: " & UBound(sTrayList) + 1
List1.Clear
For i = 0 To UBound(sTrayList)
List1.AddItem i + 1 & ". " & sTrayList(i)
Next i
End Sub
Private Sub Form_Load()
Caption = "Who lives in the system tray?"
Command1.Caption = "&Get List"
Label1 = "Icons in tray: "
End Sub
'Not sure for NT (not tested). If tips text stored in ANSI, we should change StrFromPtrW to StrFromPtrA.
Tada!!
PS Can anybody test code on NT please?
Cheers
Need a couple constants:
MEM_RESERVE
MEM_COMMIT
MEM_RESERVE
MEM_COMMIT
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Hello Tony
I'm very glad you're fine. Hope all your family and friends are fine too.
God bless America.
Regards
I'm very glad you're fine. Hope all your family and friends are fine too.
God bless America.
Regards
Thanks Ark...luckily, I live in the southern U.S. and was not harmed, physically, by the attacks. The friends of ours in N.Y. have contacted us and are ok. At this time, we are simply taking it day by day and trying to recover physically, emotionally, and psychologically. I thank you deeply for your kind words.
Is there anyway to enumerate a list with the name of the executable from which the icon in the systray comes from? Such as
1. Outlook.exe
2. Norton.exe
etc.
1. Outlook.exe
2. Norton.exe
etc.
ASKER
Working on this but still without success.
Hi Experts
I too have been looking into doing this, and unfortunately am very new to the API and its workings, I asked on:
https://www.experts-exchange.com/questions/21145831/Where-do-the-systray-items-come-from.html
Basically I just need to figure out how to make it work on W2k/WXP
I also need to be able to get the icon info, tooltip, context menu, parent application to be able to activate or close the running app
250 points up for grabs, if you wanna answer on the new question (Q_21145831)
Thanks
I too have been looking into doing this, and unfortunately am very new to the API and its workings, I asked on:
https://www.experts-exchange.com/questions/21145831/Where-do-the-systray-items-come-from.html
Basically I just need to figure out how to make it work on W2k/WXP
I also need to be able to get the icon info, tooltip, context menu, parent application to be able to activate or close the running app
250 points up for grabs, if you wanna answer on the new question (Q_21145831)
Thanks