现有一个外部程序,其界面上有个LISTVIEW控件,里面有若干行数据,我想通过自己的程序,捕获该外部程序中LISTVIEW的鼠标点击事件,同时获取其当前选中行的某列的值。现在的初步思路是使用 SetWindowsHookEx 进行注入,但是不确定是使用 WH_MOUSE,还是 WH_CALLWNDPROC 来实现。或者,我本身的思路就问题,请大家多指教,谢谢。
调试欢乐多
var
MouseHookStruct: ^TMOUSEHOOKSTRUCT;
WC: TWinControl;
classname: array [0..99] of char;
i:Integer;
begin
Result := 0;
if code < 0 then
Result := CallNextHookEx(NextHook,code,wParam,lParam);
case wParam of
WM_LBUTTONDOWN:
begin end;
WM_LBUTTONUP:
begin end;
WM_LBUTTONDBLCLK:
begin end;
WM_RBUTTONDOWN:
begin
MouseHookStruct := Pointer(LParam);
//MouseHookStruct.hwnd为所点击组件的句柄,通过它得到它的类名
GetClassName(MouseHookStruct.hwnd,classname,100);
//如果是TLitView
if StrPas(classname) = 'TListView' then
begin
//获取该组件
WC := TListView(PInteger(Integer(GetWindowLong(MouseHookStruct.hwnd, GWL_WNDPROC)) + 9)^);
//循环显示item的Caption
for i := 0 to TListView(WC).Items.Count - 1 do
begin
ShowMessage(TListView(WC).Items[i].Caption);
end;
end;
end;
WM_RBUTTONUP:
begin end;
WM_NCMOUSEMOVE,WM_MOUSEMOVE:
begin
//给调用者发消息
SendMessage(CallHandle,MessageID,pMouseHookStruct(lParam)^.hwnd,Integer(@pMouseHookStruct(lParam)^));
end;
end;
end;
WH_CALLWNDPROC可以吗?我记得 WH_CALLWNDPROC只能捕获SendMessage的消息,
而鼠标消息是系统PostMessage的消息。
当然你还可以用WH_GETMESSAGE。从性能来说,不要使用全局钩子,太耗资源,用线程钩子。
更好的方法如楼上说的,注入后再子类化那个窗口(前提是你这个窗口
的生存期是整个程序的,否则还是用钩子好),这样就不需要钩子了。
The solution? Use WriteProcessMemory() and ReadProcessMemory() to use the other programs memory, perform LVM_GETITEMTEXT on it, and read it back. Hackish yes, but then again reading items from another program's listview control is one giant hack.
First, we get the process of the listview like this:
unsigned long pid;HANDLE process;
GetWindowThreadProcessId(listview, &pid);
process=OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|
PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION, FALSE, pid);Next We create three pointers, LVITEM *_lvi, char *_item, and char *_subitem and allocate them in the other program's virtual memory space with VirtualAllocEx():LVITEM *_lvi=(LVITEM*)VirtualAllocEx(process, NULL, sizeof(LVITEM),
MEM_COMMIT, PAGE_READWRITE);
char *_item=(char*)VirtualAllocEx(process, NULL, 512, MEM_COMMIT,
PAGE_READWRITE);
char *_subitem=(char*)VirtualAllocEx(process, NULL, 512, MEM_COMMIT,
PAGE_READWRITE);Now we point lvi.pszText to _item, and copy it's memory to _lvi using WriteMemoryProcess():
lvi.pszText=_item;
WriteProcessMemory(process, _lvi, &lvi, sizeof(LVITEM), NULL);Now that we have an LVITEM pointer that is valid in the other programs virtual memory, we can shoot off LVM_GETITEMTEXT to listview and copy _item's text into item so we can read it in our program:SendMessage(hwnd, LVM_GETITEMTEXT, (WPARAM)i, (LPARAM)_lvi);
ReadProcessMemory(process, _item, item, max, NULL);
在狗狗图标的MouseMove事件里增加下面的代码:(一些名称可能需要替换) //如果对象为ListView
if (edtName->Text.Pos("ListView")>0)
{
edtCaption->Text = "nocaption";
TLVItem *it = new TLVItem;
it->mask = LVIF_STATE;
it->state = LVIS_SELECTED + LVIS_FOCUSED + LVIS_ACTIVATING;
it->stateMask = DWord(-1);
int iItem;
iItem=SendMessage(hWindow,LVM_GETNEXTITEM,-1,LVNI_SELECTED);
if (iItem==-1)
MessageBox(NULL,"没有指定目标进程 !","错误!",NULL);
// char strCBStr[65535];
// SendMessage(hWindow, LVM_GETITEMTEXT, 0, (LPARAM)strCBStr); String s;
GetLvItemText(hWindow, iItem, 1, s);
Memo1->Lines->Add(s );
}其中GetLvItemText函数代码如下:
bool TForm3::GetLvItemText(HANDLE Lv, int Index, int SubItem, String& Text)
{
const int bufferLength = 4000;
bool result = false;
DWORD processId = NULL;
GetWindowThreadProcessId(Lv, &processId);
if (processId == NULL) return false;
HANDLE process = ::OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE, FALSE, processId);
if (process == NULL) return false;
PVOID buffer = VirtualAllocEx(process, NULL, bufferLength, MEM_COMMIT, PAGE_READWRITE);
if (buffer != NULL)
{
LPLVITEM item = (LPLVITEM)new BYTE[bufferLength];
item->mask = LVIF_TEXT;
item->iSubItem = SubItem;
item->pszText = (LPTSTR)((PBYTE)buffer+sizeof(LVITEM));
item->cchTextMax = (bufferLength - sizeof(LVITEM)) / sizeof(TCHAR);
WriteProcessMemory(process, buffer, item, sizeof(LVITEM), NULL);
if (SendMessage(Lv, LVM_GETITEMTEXT, Index, (LPARAM)buffer) != 0)
{
ReadProcessMemory(process, buffer, item, 1024, NULL);
Text = (LPTSTR)((PBYTE)item+sizeof(LVITEM));
result = true;
}
delete item;
VirtualFreeEx(process, buffer, sizeof(LVITEM), MEM_DECOMMIT);
}
CloseHandle(process);
return result;
}
这样应该够你用了,根据自己的需要调整使用吧