从另一个进程中的SysHeader32控件获取列名

时间:2014-04-30 14:38:45

标签: c++ winapi interprocess common-controls

我正在制作一个程序(program1),它将读取位于另一个程序(program2)的报告样式列表(SysListView32)中的标题(SysHeader32)列的名称。

所以基本上我希望我的程序进入另一个程序并读取我找到的所有标题(SysHeader32)的标题名称。由于程序对每个列表都有很多不同的列表和标题,因此我决定使用带有EnumChildWindows回调函数的EnumChildProc函数来查看子窗口的所有句柄。使用这些句柄我使用GetClassName()来查看类名是什么,当我看到它是一个SysHeader32时,我知道我发现了一个可以包含各种标题名称的标题......但我不知道我能用什么代码用来从这些不同的标题中获取文本,我也不知道如何识别每个标题......

以下是我到目前为止找到的每个SysHeader32标头的句柄:

BOOL CALLBACK EnumChildProc (HWND hWnd, LPARAM lParam)
{
  char myBuffer [100];//buffer that will get the class name
  GetClassName(hWnd, myBuffer, 100);
  string myString (myBuffer);//converting myBuffer into a readable string

  if (myString == "SysHeader32")
  {
    ///here is where I am currently lost
    ///I just don't know how to get the text from the different titles/items
    ///in the header found
  }
}

问题1 ::如何查看标题中有多少不同的标题/项目?

问题2 ::如何获取标题中找到的每个标题/项目的文本?

请提供一些示例代码。

1 个答案:

答案 0 :(得分:0)

不幸的是,当访问由另一个程序创建的窗口时,这是不可能的,因为系统没有执行必要的窗口消息编组指针。您需要从共享的DLL文件(在其中创建一些系统范围的Windows Hook以将其加载到其他进程中)或使用其他黑客(如进程间内存访问)中执行此操作。


如果在同一程序中访问SysHeader32窗口,它将很简单:

  1. 发送消息HDM_GETITEMCOUNT,它会返回项目数。

  2. 发送消息HDM_GETITEM,其中wParam设置为要检索的项目的索引,lParam设置为指向适当设置HDITEM结构的指针。特别将mask设置为HDI_TEXT并为pszText准备一个缓冲区,并将其长度设置为cchTextMax

  3. 示例:

    int count = SendMessage(hWnd, HDM_GETITEMCOUNT, 0, 0);
    std::cout << "There are " << count << " items.\n";
    
    for (int i = 0; i < count; i++) {
      TCHAR name[260];
      HDITEM hdi;
      hdi.mask = HDI_TEXT;
      hdi.pszText = name;
      hdi.cchTextMax = 260;
      SendMessage(hWnd, HDM_GETITEM, i, reinterpret_cast<LPARAM>(&hdi));
      std::cout << "  " << i << ") " << hdi.pszText << "\n";
    } 
    

    因为我们需要将输入和输出内存存储在另一个程序的空间中,所以需要这样的东西(请根据自己的喜好添加错误检查等):

    struct InterProcessData {
      HDITEM hdi;
      TCHAR buffer[260];
    };
    
    // Open the owning process and allocate a buffer big enough for
    // our inter-process communication
    DWORD dwProcessId;
    GetWindowThreadProcessId(hWnd, &dwProcessId);
    HANDLE hProcess = OpenProcess(
      PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
      FALSE, dwProcessId);
    InterProcessData* pRemoteData = reinterpret_cast<InterProcessData*>(
      VirtualAllocEx(hProcess, NULL, sizeof(InterProcessData), MEM_COMMIT, PAGE_READWRITE));
    
    int count = SendMessage(hWnd, HDM_GETITEMCOUNT, 0, 0);
    std::cout << "There are " << count << " items.\n";
    
    for (int i = 0; i < count; i++) {
      InterProcessData data;
      data.hdi.mask = HDI_TEXT;
      data.hdi.pszText = pRemoteData->buffer;
      data.hdi.cchTextMax = 260;
    
      // Write the HDITEM structure to the space in the remote process
      // (without the buffer, its contents are undefined anyway)
      WriteProcessMemory(hProcess, pRemoteData, &data, sizeof(data.hdi), NULL);
    
      // Send the message itself, passing the remote address in lParam
      SendMessage(hWnd, HDM_GETITEM, i, reinterpret_cast<LPARAM>(&pRemoteData->hdi));
    
      // Read the data back, HDITEM and the buffer
      ReadProcessMemory(hProcess, pRemoteData, &data, sizeof(data), NULL);
    
      // The documentation says that the pszText can point elsewhere -
      // copy it to our buffer in that case
      if (data.hdi.pszText != pRemoteData->buffer)
        ReadProcessMemory(hProcess, data.hdi.pszText, data.buffer, data.hdi.cchTextMax * sizeof(TCHAR), NULL);
    
      std::cout << "  " << i << ") " << data.buffer << "\n";
    }
    
    // Cleanup
    VirtualFreeEx(hProcess, pRemoteData, 0, MEM_RELEASE);
    CloseHandle(hProcess);