I am trying to simulate a right mouse click on a listview item in another application. I simplified the following code to exclude the steps I'm taking to get the hwnd and position of the listview item I want selected. Everything works fine except for the right click--the item is selected and the SendMessage for the left click highlights the item. When I SendMessage for the right click, though, it opens the pop-up menu for the listview, not the pop-up menu for the selected item, which is different. It appears that the right click is ignoring the 3rd parameter (1ItemPos), even though it works fine for the left click. Can anyone tell me where I'm going wrong? Thanks for any help.
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 SendMessageLong Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long) 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 GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
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 WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare Function ReadProcessMemoryLong Lib "kernel32" _
Alias "ReadProcessMemory" _
(ByVal hProcess As Long, _
ByVal lpBaseAddress As Long, _
ByVal lpBuffer As Long, _
ByVal nSize As Long, _
lpNumberOfBytesWritten As Long) As Long
Private Declare Function WriteProcessMemoryLong Lib "kernel32" _
Alias "WriteProcessMemory" _
(ByVal hProcess As Long, _
ByVal lpBaseAddress As Long, _
ByVal lpBuffer As Long, _
ByVal nSize As Long, _
lpNumberOfBytesWritten As Long) As Long
Private Type LV_ITEM
mask As Long
iItem As Long
iSubitem As Long
state As Long
stateMask As Long
pszText As String
cchTextMax As Long
iImage As Long
lParam As Long
iIndent As Long
End Type
Private Const LVM_FIRST = &H1000&
Private Const LVM_SETITEMSTATE = (LVM_FIRST + 43)
Private Const LVIF_STATE = &H8&
Private Const LVIS_SELECTED = &H2&
Private Const PROCESS_VM_OPERATION = &H8
Private Const PROCESS_VM_READ = &H10
Private Const PROCESS_VM_WRITE = &H20
Private Const PAGE_READWRITE = &H4&
Private Const MEM_RESERVE = &H2000
Private Const MEM_COMMIT = &H1000
Private Const MEM_RELEASE = &H8000
Private Const MAX_LVMSTRING = 255&
Private Const LVM_GETCOLUMNA = LVM_FIRST + 25
Private Const LVCF_TEXT = &H4
Private hWndlvw As Long
Public Function MessageCrossProcess()
Dim lProcID As Long
Dim hProc As Long
Dim lxprocLVITEM As Long
Dim LVITEM As LV_ITEM
Dim lItemPos As Long
Const WM_LBUTTONDOWN As Long = &H201
Const WM_LBUTTONUP As Long = &H202
Const WM_LBUTTONDBLCLK As Long = &H203
Const VK_RETURN = &HD
Const WM_RBUTTONDOWN = &H204
Const WM_RBUTTONUP = &H205
Dim hwnd As Long
hwnd = 66788
tag = 6188411
GetWindowThreadProcessId hwnd, lProcID ' Get the process ID in which the ListView is running
If lProcID <> 0 Then
hProc = OpenProcess(PROCESS_VM_OPERATION Or PROCESS_VM_READ Or PROCESS_VM_WRITE, False, lProcID) ' make sure we have read write permissions in the process space
If hProc <> 0 Then
lxprocLVITEM = VirtualAllocEx(hProc, 0, LenB(LVITEM), MEM_RESERVE Or MEM_COMMIT, PAGE_READWRITE) ' Grab enough memory in the other procedure's space to hold our LV_ITEM
' Set up our local LV_ITEM to change the selected item
LVITEM.mask = LVIF_STATE
LVITEM.state = True
LVITEM.stateMask = LVIS_SELECTED
' Copy the local LV_ITEM into the space we reserved in the foreign process
WriteProcessMemory hProc, ByVal lxprocLVITEM, ByVal VarPtr(LVITEM), LenB(LVITEM), 0
' Now send the message, but pass the address of the copy of our LV_ITEM that now exists in the foreign process instead of our local version
lItemPos = 0
SendMessage hwnd, LVM_SETITEMSTATE, lItemPos, ByVal lxprocLVITEM
SendMessage hwnd, WM_LBUTTONDOWN, lItemPos, ByVal lxprocLVITEM
SendMessage hwnd, WM_LBUTTONUP, lItemPos, ByVal lxprocLVITEM
SendMessage hwnd, WM_RBUTTONDOWN, lItemPos, ByVal lxprocLVITEM
SendMessage hwnd, WM_RBUTTONUP, lItemPos, ByVal lxprocLVITEM
' Clean up
VirtualFreeEx hProc, ByVal lxprocLVITEM, LenB(LVITEM), MEM_RELEASE
CloseHandle hProc
End If
End If
End Function
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 SendMessageLong Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long) 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 GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
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 WriteProcessMemory Lib "kernel32" (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare Function ReadProcessMemoryLong Lib "kernel32" _
Alias "ReadProcessMemory" _
(ByVal hProcess As Long, _
ByVal lpBaseAddress As Long, _
ByVal lpBuffer As Long, _
ByVal nSize As Long, _
lpNumberOfBytesWritten As Long) As Long
Private Declare Function WriteProcessMemoryLong Lib "kernel32" _
Alias "WriteProcessMemory" _
(ByVal hProcess As Long, _
ByVal lpBaseAddress As Long, _
ByVal lpBuffer As Long, _
ByVal nSize As Long, _
lpNumberOfBytesWritten As Long) As Long
Private Type LV_ITEM
mask As Long
iItem As Long
iSubitem As Long
state As Long
stateMask As Long
pszText As String
cchTextMax As Long
iImage As Long
lParam As Long
iIndent As Long
End Type
Private Const LVM_FIRST = &H1000&
Private Const LVM_SETITEMSTATE = (LVM_FIRST + 43)
Private Const LVIF_STATE = &H8&
Private Const LVIS_SELECTED = &H2&
Private Const PROCESS_VM_OPERATION = &H8
Private Const PROCESS_VM_READ = &H10
Private Const PROCESS_VM_WRITE = &H20
Private Const PAGE_READWRITE = &H4&
Private Const MEM_RESERVE = &H2000
Private Const MEM_COMMIT = &H1000
Private Const MEM_RELEASE = &H8000
Private Const MAX_LVMSTRING = 255&
Private Const LVM_GETCOLUMNA = LVM_FIRST + 25
Private Const LVCF_TEXT = &H4
Private hWndlvw As Long
Public Function MessageCrossProcess()
Dim lProcID As Long
Dim hProc As Long
Dim lxprocLVITEM As Long
Dim LVITEM As LV_ITEM
Dim lItemPos As Long
Const WM_LBUTTONDOWN As Long = &H201
Const WM_LBUTTONUP As Long = &H202
Const WM_LBUTTONDBLCLK As Long = &H203
Const VK_RETURN = &HD
Const WM_RBUTTONDOWN = &H204
Const WM_RBUTTONUP = &H205
Dim hwnd As Long
hwnd = 66788
tag = 6188411
GetWindowThreadProcessId hwnd, lProcID ' Get the process ID in which the ListView is running
If lProcID <> 0 Then
hProc = OpenProcess(PROCESS_VM_OPERATION Or PROCESS_VM_READ Or PROCESS_VM_WRITE, False, lProcID) ' make sure we have read write permissions in the process space
If hProc <> 0 Then
lxprocLVITEM = VirtualAllocEx(hProc, 0, LenB(LVITEM), MEM_RESERVE Or MEM_COMMIT, PAGE_READWRITE) ' Grab enough memory in the other procedure's space to hold our LV_ITEM
' Set up our local LV_ITEM to change the selected item
LVITEM.mask = LVIF_STATE
LVITEM.state = True
LVITEM.stateMask = LVIS_SELECTED
' Copy the local LV_ITEM into the space we reserved in the foreign process
WriteProcessMemory hProc, ByVal lxprocLVITEM, ByVal VarPtr(LVITEM), LenB(LVITEM), 0
' Now send the message, but pass the address of the copy of our LV_ITEM that now exists in the foreign process instead of our local version
lItemPos = 0
SendMessage hwnd, LVM_SETITEMSTATE, lItemPos, ByVal lxprocLVITEM
SendMessage hwnd, WM_LBUTTONDOWN, lItemPos, ByVal lxprocLVITEM
SendMessage hwnd, WM_LBUTTONUP, lItemPos, ByVal lxprocLVITEM
SendMessage hwnd, WM_RBUTTONDOWN, lItemPos, ByVal lxprocLVITEM
SendMessage hwnd, WM_RBUTTONUP, lItemPos, ByVal lxprocLVITEM
' Clean up
VirtualFreeEx hProc, ByVal lxprocLVITEM, LenB(LVITEM), MEM_RELEASE
CloseHandle hProc
End If
End If
End Function