Win32-从另一个应用程序获取ListView控件内容

时间:2012-10-01 19:13:37

标签: winapi win32-process

我正在尝试访问另一个应用程序中的ListView控件(位于Dialog中),并从控件中获取数据。这是我写的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钩子来获取数据。但这将是一个非常漫长而繁琐的过程。这里没有想法。请帮助。

谢谢,

3 个答案:

答案 0 :(得分:1)

有几种可能性。

  1. DLL Injection使用Windows挂钩。优点:简单直接。缺点:许多进程都会加载此dll。

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

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

答案 1 :(得分:1)

传递缓冲区的ListView消息仅在拥有ListView的进程的地址空间内工作。您必须使用VirtualAllocEx()在同一进程中分配内存块,然后您可以使用WriteProcessMemory()向其写入并根据需要填充ListView,然后您可以使用{{1并使用ReadProcessMemory()解除分配。

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

VirtualFreeEx()

答案 2 :(得分: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);
   }
}