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

Posted

技术标签:

【中文标题】在另一个进程中从 SysHeader32 控件获取列名【英文标题】:Getting column names from SysHeader32 control in another process 【发布时间】:2014-04-30 14:38:45 【问题描述】:

我正在制作一个程序 (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】:

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


如果在同一个程序中访问一个 SysHeader32 窗口,就这么简单:

    发送消息HDM_GETITEMCOUNT,返回项目数。

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

例子:

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);

【讨论】:

当我使用代码时,它编译得很好,但是当我运行程序并在 program2 中搜索项目时,它会找到项目的 #(15),但是当它启动 SendMessage()要获取项目文本,program2 会关闭并开始为所有 15 个项目输出类似 (pisymbole)TTw% 的内容...任何想法为什么会发生这种情况? 好的,谢谢兄弟的所有信息。我确实调试了该程序在代码出现时完全存在: SendMessage(hWnd, HDM_GETITEM, i, reinterpret_cast(&hdi));用来。我猜出于某种原因,一条消息被发送到程序 2,导致程序 2 出现某种错误。有什么想法吗? 让我们continue this discussion in chat

以上是关于在另一个进程中从 SysHeader32 控件获取列名的主要内容,如果未能解决你的问题,请参考以下文章

在另一个进程中使用时删除文件

在 C# Webbrowser 控件 WPF 中从 Javascript 获取返回值

在 C# 中从外部应用程序获取 UI 文本

从后台进程打开窗口并在 WPF 中从用户那里获取输入

将一个组件显示在另一个组件之上

在 ASP.Net MVC5 中管理长时间运行的进程