现有一个外部程序,其界面上有个LISTVIEW控件,里面有若干行数据,我想通过自己的程序,捕获该外部程序中LISTVIEW的鼠标点击事件,同时获取其当前选中行的某列的值。现在的初步思路是使用  SetWindowsHookEx 进行注入,但是不确定是使用 WH_MOUSE,还是 WH_CALLWNDPROC 来实现。或者,我本身的思路就问题,请大家多指教,谢谢。

解决方案 »

  1.   

    WH_MOUSE,并判断点击的是否为TListView,然后进一步可以做其他处理
      

  2.   

    转一个伴水的帖子:获取不同进程ListView的内容~~(*//标题:获取不同进程ListView的内容说明:适用于WindowsNT日期:2003-02-27设计:Zswang//*) unit Unit1; interface uses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  Dialogs, StdCtrls, ComCtrls; type  TForm1 = class(TForm)    MemoText: TMemo;    EditCount: TEdit;    LabelNote: TLabel;    procedure FormCreate(Sender: TObject);    procedure FormDestroy(Sender: TObject);  private    { Private declarations }    procedure WMHOTKEY(var Msg: TWMHOTKEY); message WM_HOTKEY;  public    { Public declarations }  end; var  Form1: TForm1; implementation {$R *.dfm} uses CommCtrl; function VirtualAllocEx(hProcess: Cardinal; lpAddress: Pointer;  dwSize, flAllocationType, flProtect: Cardinal): Pointer; stdcall;  external kernel32 name ''VirtualAllocEx'';function VirtualFreeEx(hProcess: Cardinal; lpAddress: Pointer;  dwSize, dwFreeType: Cardinal): Boolean; stdcall;  external kernel32 name ''VirtualFreeEx'';    const cHotKeyWinF2 = 1; procedure TForm1.FormCreate(Sender: TObject);begin  Application.Title := ''获取ListView内容 1.0'';  Caption := Application.Title;  RegisterHotKey(Handle, cHotKeyWinF2, MOD_WIN, VK_F2);end; procedure TForm1.WMHOTKEY(var Msg: TWMHOTKEY);var  I, J: Integer;  S: string;  vItem: TLVItem;  vCount: Integer;  vHandle: THandle;  vBuffer: array[0..255] of Char;  pBuffer: PChar;  vProcess: THandle;  vProcessId: DWORD;  vPointer: Pointer;  vNumberOfBytesRead: Cardinal;begin  case Msg.HotKey of    cHotKeyWinF2: begin      MemoText.Clear;      FillChar(vBuffer, 256, 0);      vHandle := WindowFromPoint(Point(Mouse.CursorPos.X, Mouse.CursorPos.Y));      vCount := ListView_GetItemCount(vHandle);      if vCount = 0 then Exit;      GetWindowThreadProcessId(vHandle, @vProcessId);      vProcess := OpenProcess(PROCESS_VM_OPERATION or PROCESS_VM_READ or        PROCESS_VM_WRITE, False, vProcessId);      vPointer := VirtualAllocEx(vProcess, nil, 4096, MEM_RESERVE or MEM_COMMIT,        PAGE_READWRITE);      try        for I := 0 to vCount - 1 do begin          S := '''';          for J := 0 to StrToIntDef(EditCount.Text, 0) - 1 do begin            with vItem do begin              mask := LVIF_TEXT;              iItem := I;              iSubItem := J;              cchTextMax := 255;              pszText := Pointer(Cardinal(vPointer) + SizeOf(TLVItem));            end;            WriteProcessMemory(vProcess, vPointer, @vItem,              SizeOf(TLVItem), vNumberOfBytesRead);            SendMessage(vHandle, LVM_GETITEM, I, lparam(vPointer));            pBuffer := vBuffer;            ReadProcessMemory(vProcess, Pointer(Cardinal(vPointer) + SizeOf(TLVItem)),              pBuffer, DWORD(256), vNumberOfBytesRead);            S := S + #9 + vBuffer;          end;          Delete(S, 1, 1);          MemoText.Lines.Add(S);        end;      finally        VirtualFreeEx(vProcess, vPointer, 0, MEM_RELEASE);        CloseHandle(vProcess);      end;    end;  end;end; procedure TForm1.FormDestroy(Sender: TObject);begin  UnRegisterHotKey(Handle, cHotKeyWinF2);end; end.
      

  3.   

    WH_MOUSE,并判断点击的是否为TListView
      

  4.   

    下面是钩子回调函数,在里面捕捉右键抬起,在外部程序的TListView上右键点击后,会被截住,并获得所点击的ListView组件,你可以将其数据传递给你自己的程序function HookProc(code:Integer;wParam:WPARAM;lParam:LPARAM):LRESULT;stdcall;
    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;
      

  5.   

    注入DLL, Subclass这个窗口就可以了
      

  6.   

    参考http://bbs.aisnote.com/viewtopic.php?f=2&t=14
      

  7.   

    用WH_MOUSE吧!
     WH_CALLWNDPROC可以吗?我记得 WH_CALLWNDPROC只能捕获SendMessage的消息,
    而鼠标消息是系统PostMessage的消息。
    当然你还可以用WH_GETMESSAGE。从性能来说,不要使用全局钩子,太耗资源,用线程钩子。
    更好的方法如楼上说的,注入后再子类化那个窗口(前提是你这个窗口
    的生存期是整个程序的,否则还是用钩子好),这样就不需要钩子了。
      

  8.   

    使用WriteProcessMemory()和ReadProcessMemory()读写其他程序内存信息。从国外网站COPY的(英文)
     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);
      

  9.   

    原来老妖有一个minispy想必你应该知道,能够捕获外部句柄,并能取出一些简单控件中的内容,源码可以从老妖网站下载。我曾因为需要作了个读取listview的内容地例子。
    在狗狗图标的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;
    }
    这样应该够你用了,根据自己的需要调整使用吧
      

  10.   

    对了,以上是cb代码,你把它转成delphi就好了
      

  11.   

    这个更简单,几句代码搞定http://www.aau.cn/thread-58-1-1.html
      

  12.   

    看了大家的回复,很多都是取LISTVIEW的内容的,这个不是我要的,我要的是捕获外部LISTVIEW的鼠标双击事件,截获这个才是我需要的,谢谢大家,请继续