有个程序是C++写的,类名:SysListView32,样式带有以下样式
LVS_OWNERDATA
LVS_OWNERDRAWFIXED用以下代码能取到Delphi自带例子"Virtual Listview"中的数据(转自刘麻子在DFW的回贴)function ListView_GetItemText_Mz(hListView: HWnd; iItem, iSubItem: Integer; pszText: PChar; cchTextMax: Integer): Integer;
var
  DispInfo: TLVDispInfo;
begin
  DispInfo.hdr.hwndFrom := hListView;
  DispInfo.hdr.idFrom := GetDlgCtrlID(hListView);
  DispInfo.hdr.code := LVN_GETDISPINFO;  ZeroMemory(@DispInfo.item, SizeOf(DispInfo.item));  
  DispInfo.item.mask := LVIF_TEXT;
  DispInfo.item.iItem := iItem;
  DispInfo.item.iSubItem := iSubItem;
  DispInfo.item.pszText := pszText;
  DispInfo.item.cchTextMax := cchTextMax;  Result := SendMessage(GetParent(hListView), WM_NOTIFY, GetDlgCtrlID(hListView), Integer(@DispInfo));
end;但取不到C++写的这个程序中ListView的内容,想请教下这种内容如何取

解决方案 »

  1.   

    PS:已经将获取数据的代码放到DLL中并插入到目标进程中执行,所以不是跨进程读写内存的问题
      

  2.   

    既然不用跨进程读写数据,那可以试一下CommCtrl里面的函数如ListView_GetItem,ListView_GetItemText,理论上应该是可以的
      

  3.   

    ownerDraw的确是有点麻烦,不能按一般的方法获取。 只能用钩子了。
      

  4.   

    ListView_GetItem,ListView_GetItemText是不行的
    至于发送LVN_GETDISPINFO消息,我上面贴的代码就是,不过它能取Delphi的虚拟列表数据,但C++的取不到
    想知道C++的怎么取,有兴趣的可以试试,我就是试不出
      

  5.   


    (*//
    标题:获取其他进程中TreeView的文本
    说明:Window2000+Delphi6调试通过
    设计:Zswang
    支持:[email protected]
    日期:2004-03-26
    //*)
    function TreeNodeGetNext(mHandle: THandle; mTreeItem: HTreeItem): HTreeItem;
    var
      vParentID: HTreeItem;
    begin
      Result := nil;
      if (mHandle <> 0) and (mTreeItem <> nil) then begin
        Result := TreeView_GetChild(mHandle, mTreeItem);
        if Result = nil then
          Result := TreeView_GetNextSibling(mHandle, mTreeItem);
        vParentID := mTreeItem;
        while (Result = nil) and (vParentID <> nil) do begin
          vParentID := TreeView_GetParent(mHandle, vParentID);
          Result := TreeView_GetNextSibling(mHandle, vParentID);
        end;
      end;
    end;  { TreeNodeGetNext }function TreeNodeGetLevel(mHandle: THandle; mTreeItem: HTreeItem): Integer;
    var
      vParentID: HTreeItem;
    begin
      Result := -1;
      if (mHandle <> 0) and (mTreeItem <> nil) then begin
        vParentID := mTreeItem;
        repeat
          Inc(Result);
          vParentID := TreeView_GetParent(mHandle, vParentID);
        until vParentID = nil;
      end;
    end; { TreeNodeGetLevel }function GetTreeViewText(mHandle: THandle; mStrings: TStrings): Boolean;
    var
      vItemCount: Integer;
      vBuffer: array[0..255] of Char;
      vProcessId: DWORD;
      vProcess: THandle;
      vPointer: Pointer;
      vNumberOfBytesRead: Cardinal;
      I: Integer;
      vItem: TTVItem;
      vTreeItem: HTreeItem;
    begin
      Result := False;
      if not Assigned(mStrings) then Exit;
      GetWindowThreadProcessId(mHandle, @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);
      mStrings.BeginUpdate;
      try
        mStrings.Clear;
        vItemCount := TreeView_GetCount(mHandle);
        vTreeItem := TreeView_GetRoot(mHandle);
        for I := 0 to vItemCount - 1 do
        begin
          with vItem do
          begin
            mask := TVIF_TEXT;
            cchTextMax := SizeOf(vBuffer);
            pszText := Pointer(Cardinal(vPointer) + SizeOf(vItem));
            hItem := vTreeItem;
          end;
          WriteProcessMemory(vProcess, vPointer, @vItem, SizeOf(vItem), vNumberOfBytesRead);
          SendMessage(mHandle, TVM_GETITEM, 0, lparam(vPointer));
          ReadProcessMemory(vProcess, Pointer(Cardinal(vPointer) + SizeOf(TLVItem)),
            @vBuffer[0], SizeOf(vBuffer), vNumberOfBytesRead);
          mStrings.Add(StringOfChar(#9, TreeNodeGetLevel(mHandle, vTreeItem)) + vBuffer);
          vTreeItem := TreeNodeGetNext(mHandle, vTreeItem);
        end;
      finally
        VirtualFreeEx(vProcess, vPointer, 0, MEM_RELEASE);
        CloseHandle(vProcess);
        mStrings.EndUpdate;
      end;
      Result := True;
    end; { GetTreeViewText }
      

  6.   

    本来想自己研究一下的,结果在找资料的时候发现了伴水写的程序,用VC6.0写了一个测试程序测试通过了,感谢Zswang.
      

  7.   

    TO 9楼:
    你这是取TreeView的,实际上,取其它程序中ListView中的数据我已经做到,但是取带LVS_OWNERDATA标志的ListView就不行了TO 10楼:
    能共享一下吗?(伴水写的程序)
      

  8.   

    我找到的就是那段代码了,没有程序了,LVS_OWNERDATA这个标志位是怎么设定的,我把VC6.0的Tree Control控制属性全都选上了也没有这个属性,而且用上面的代码也是可以取到的
      

  9.   

    不是treeview,是listview.....
    虚拟列表:
    http://blog.vckbase.com/zgf/archive/2005/11/25/15271.aspx
      

  10.   

    试试这段,function ListView_GetItemText_Ex(hwndLV: HWND; i, iSubItem: Integer;
      pszText: PChar; cchTextMax: Integer): Integer;
    var
      LVItem: TLVItem;
      ProcessID, ProcessHD, Temp: DWORD;
      MemPoint: Pointer;
    begin
      GetWindowThreadProcessId(hwndLV, ProcessID);  ProcessHD := OpenProcess(
        PROCESS_VM_OPERATION or PROCESS_VM_READ or PROCESS_VM_WRITE,
        FALSE, ProcessID);  MemPoint := VirtualAllocEx(ProcessHD, nil, SizeOf(TLVItem) + cchTextMax,
        MEM_COMMIT, PAGE_READWRITE);  LVItem.iSubItem := iSubItem;
      LVItem.cchTextMax := cchTextMax;
      LVItem.pszText := PChar(Integer(MemPoint) + SizeOf(TLVItem));  WriteProcessMemory(ProcessHD, MemPoint, @LVItem, SizeOf(TLVItem), Temp);
      Result := SendMessage(hwndLV, LVM_GETITEMTEXT, i, Integer(MemPoint));  ReadProcessMemory(ProcessHD, Pointer(Integer(MemPoint) + SizeOf(TLVItem)),
        pszText, cchTextMax, Temp);  VirtualFreeEx(ProcessHD, MemPoint, SizeOf(TLVItem) + cchTextMax, MEM_DECOMMIT);
      VirtualFreeEx(ProcessHD, MemPoint, 0, MEM_RELEASE);
    end;procedure TForm1.Button1Click(Sender: TObject);
    var
      TextBuffer: array[0..100] of Char;
      iCount: Integer;
      aHandle: HWND;
    begin
      aHandle := $000509D0;
      iCount := ListView_GetItemCount(aHandle);
      for iCount := 0 to iCount -1 do
      begin
        ListView_GetItemText_Ex(aHandle, iCount, 0, TextBuffer, 100);
        Memo1.Lines.Add(TextBuffer)
      end;
    end;
      

  11.   

    上面的代码也不行,已经说过了,不是跨进程内存读写的问题,而是LVS_OWNERDATA根本不响应LVM_GETITEM,LVM_GETITEMTEXT消息据说发LVN_GETDISPINFO可以获取内容,而且我发的代码获取Delphi例子中的虚拟列表数据也成功了,但C++中的不成.
      

  12.   

    to楼上
    已经注入到目标exe了,所以跨进程不是问题,问题是如何取
      

  13.   

    那个代码我也用来跨进程来取过数据,没出现楼主说的问题
    LVS_OWNERDATA  取出来是空的?
    Integer设为1也没数据?
      

  14.   

    前段因为需要,在大富翁看过刘麻子以前发的,另外还有修改,定位
    对了,你试试取SysListView32的数目可以取到吗
      

  15.   

    取条数是能取出的,就是取不出数据
    刘麻子说了可以取Delphi例子中的虚拟列表数据,我试过了也可以,但取C++写的虚拟列表就不行,不知道它们之间有啥区别
      

  16.   

    哥们儿最近也在弄这个玩意儿,两天了,没半点进展
    我是这么做的:
    1.用C++写了个DLL注入到目标进程
    2.找到ListView的父窗口
    3.子类化父窗口,把旧窗口过程存到old_proc
    4.响应code == LVN_GETDISPINFO的WM_NOTIFY
    {
      NMLVDISPINFO* d = (NMLVDISPINFO*)lParam;
      if(d->item.mask & LVIF_TEXT)
         CallWndProc(old_proc,...);//让目标进程把文字设进来
      OutputDebugString(d->item.pszText);//郁闷的是每次d->item.pszText[0]总被设成了0
    }    经过我的分析,推断出LVS_GETDISPINFO获取不了文字信息。因为目标进程的ListView设成了LVS_OWNERDATA和LVS_OWNERDRAWFIXED风格,那么它在WM_DRAWITEM的时候,WM_DRAWITEM的参数里有它需要的全部信息(是否选中、行绘制矩形、行号),又因为是LVS_OWNERDATA,它自然会保存数据。根据行号也就知道要显示什么文字、图片。我还试过不调用目标进程的窗口过程,自己往里写文本,但显示出来的,还是目标里程里的数据。
         但为什么它还要响应GetDispInfo呢?我猜测是为了获取行高,不然LVM_GETCOUNTPERPAGE算不出来,自然WM_DRAWITEM里的参数rcItem也算不出来了。可我这个目标进程里没返回文字,怎么算行高呢?它是没返回文字,但返回了图片ID,根据这个应该可以算出行高。
         到目前为止,我能想到的获取数据的方法,只有是用WinDebug或者Softice跟到WM_DRAWITEM的响应代码里面去找出数据在哪了,并且还要先分析出来数据结构
      

  17.   

    楼主的DELPHI做的ListView响应了GETDEISPINFO,并且把文字设上去了
    而C++版没设上去,这样一点也不影响它实际显示,而且效率还更高
    所以楼主得不到数据