0

我正在尝试访问另一个应用程序中的 ListView 控件(位于对话框中),并从控件中获取数据。这是我正在编写的 Win32 代码(带有适当的注释):

        HWND hListView32 = hRoot;   //HANDLE to the ListView control within the Dialog, having class name - "SysListView32"
        int cnt = (int) ::SendMessage(hListView32, LVM_GETITEMCOUNT, 0, 0L); //returns CORRECT item count of the ListView Control
        int nItem=0,nRes;

        for(int nItem=0;nItem<cnt;nItem++)
        {
            LVITEM LvItem;  // ListView Item struct
              char Text[255]={0};  
              char Temp[255]={0};
              char Temp1[255]={0};

                memset(&LvItem,0,sizeof(LvItem));
          LvItem.mask=LVIF_TEXT;
              LvItem.iSubItem=1;    //Trying to get the 2nd Colomn text

              LvItem.pszText=Text;  //Does not returns any Text, after the below SendMessage is executed???

              LvItem.cchTextMax=256;
              LvItem.iItem=nItem;
              nRes  = (int)::SendMessage(hListView32,LVM_GETITEMTEXT, nItem, (LPARAM)&LvItem);
              DWORD dd = ::GetLastError();  //returns 0
        }

虽然代码正在执行,但我没有从控件中获取任何数据。但是,我能够从控件中检索正确的项目计数,但没有数据。

另一种方法可能是使用 MSAA 挂钩来获取数据。但这将是一个非常漫长和繁琐的过程。这里的想法用完了。请帮忙。

谢谢,

4

3 回答 3

1

有几种可能。

  1. DLL Injection使用 windows 挂钩。优点:简单直接。缺点:许多进程都加载了这个 dll。

  2. DLL Injection通过打开库进行调试来加载库,VallocEx在该进程的上下文中分配一块虚拟内存,写入它的内存WriteProcessMemory并创建一个具有LoadLibrary函数起始地址的远程线程。优点:单个进程受到影响。缺点:比钩子解决方案复杂一点。

  3. 读取进程内存。与选项 2 相同,但不是编写此内存并远程执行代码,而是将消息发送LVM_GETITEMTEXT到有问题的窗口,提供有效的已知内存位置,然后使用ReadProcessMemory.

于 2012-10-01T20:03:20.947 回答
1

传递缓冲区的 ListView 消息仅在拥有 ListView 的进程的地址空间内工作。您将不得不使用VirtualAllocEx()在同一个进程中分配一个内存块,然后您可以写入它WriteProcessMemory()并让 ListView 根据需要填充它,然后您可以读取它ReadProcessMemory()并使用VirtualFreeEx().

试试这个(为简洁起见省略了错误处理):

HWND hListView32 = hRoot;

int cnt = (int) ::SendMessage(hListView32, LVM_GETITEMCOUNT, 0, 0);
if (cnt > 0)
{
    DWORD dwProcessId;
    GetWindowThreadProcessId(hListView32, &dwProcessId);

    HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, dwProcessId);

    LVITEM *pLvItem = (LVITEM*) VirtualAllocEx(hProcess, NULL, sizeof(LVITEM), MEM_COMMIT, PAGE_READWRITE);
    LPTSTR pText = (LPTSTR) VirtualAllocEx(hProcess, NULL, sizeof(TCHAR)*256, MEM_COMMIT, PAGE_READWRITE);

    for(int nItem = 0; nItem < cnt; ++nItem) 
    { 
        TCHAR Text[256] = {0};

        LVITEM LvItem = {0}; 
        LvItem.mask = LVIF_TEXT; 
        LvItem.iSubItem = 1;
        LvItem.pszText = pText;
        LvItem.cchTextMax = 256; 
        LvItem.iItem = nItem; 

        WriteProcessMemory(hProcess, pLvItem, &LvItem, sizeof(LVITEM), NULL);

        int nRes = (int) ::SendMessage(hListView32, LVM_GETITEMTEXT, nItem, (LPARAM)pLvItem);
        if (nRes > 0)
            ReadProcessMemory(hProcess, pText, &Text[0], sizeof(TCHAR)*nRes, NULL);

        // use Text as needed...
    }

    VirtualFreeEx(hProcess, pText, 0, MEM_RELEASE);
    VirtualFreeEx(hProcess, pLvItem, 0, MEM_RELEASE);
    CloseHandle(hProcess);
}
于 2012-10-02T00:49:29.017 回答
0

我复制了 Remy Lebeau 的代码,但在我的特殊情况下它的工作方式非常奇怪。元素的数量通过 SendMessage(listview, LVM_GETITEMCOUNT, 0, 0) 正确检索,但循环每次都读取相同的元素!它不是第一个或最后一个元素,不是被选中的,但似乎是随机的。这是我的代码:

HWND win=FindWindowEx(NULL, NULL, _("TEventLogView"), NULL);
HWND listview=FindWindowEx(win, NULL, _("TListView"), NULL);
int cnt = (int) ::SendMessage(listview, LVM_GETITEMCOUNT, 0, 0);
if (cnt > 0)
{
    DWORD dwProcessId;
    GetWindowThreadProcessId(listview, &dwProcessId);
    int n = grdEvents->GetNumberRows();
    HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, dwProcessId);
    LVITEM *pLvItem = (LVITEM*) VirtualAllocEx(hProcess, NULL, sizeof(LVITEM), MEM_COMMIT, PAGE_READWRITE);
    LPTSTR pText = (LPTSTR) VirtualAllocEx(hProcess, NULL, sizeof(TCHAR)*255, MEM_COMMIT, PAGE_READWRITE);
   for(int nItem = 0; nItem < cnt; ++nItem)
   {
      // need to read 1 - 3 subitems
      for (int j = 1; j < 4; j++)
      {
         TCHAR Text[255] = {0};
         LVITEM LvItem = {0};
         LvItem.mask = LVIF_STATE | LVIF_TEXT;
         LvItem.pszText = pText;
         LvItem.cchTextMax = sizeof(TCHAR)*255;
         LvItem.iItem = nItem;
         LvItem.iSubItem = j;
         int nRes1 = WriteProcessMemory(hProcess, pLvItem, &LvItem, sizeof(LVITEM), NULL);
         int nRes2 = (int) ::SendMessage(listview, LVM_GETITEMTEXT, (WPARAM)nItem, (LPARAM)pLvItem);
         if (nRes2 > 0)
         {
             ReadProcessMemory(hProcess, pText, &Text[0], sizeof(TCHAR)*nRes2, NULL);
             // insert into wxWidgets grid
             grdEvents->SetCellValue(nItem, j - 1, Text);
        }
      }
      VirtualFreeEx(hProcess, pText, 0, MEM_RELEASE);
      VirtualFreeEx(hProcess, pLvItem, 0, MEM_RELEASE);
      CloseHandle(hProcess);
   }
}
于 2016-04-08T06:21:51.910 回答