有没有办法通过Windows API获取VCL Control的名称?

Dan*_*ula 13 delphi winapi

我有一个位于另一个进程窗口的VCL控件的Hwnd.有没有办法TControl.Name通过Windows API 获取该控件的VCL名称(属性)?我需要这个名称,因为该窗口上有几个TEdits,我需要识别我想要的那个以便WM_SETTEXT向它发送消息.

这两个应用程序都是使用Delphi 2010构建的.

小智 14

Delphi具有内置函数FindControl(),返回TWinControl指定的hWnd.但它适用于VCL的同一个实例.我想你应该调查一下.指向TWinControl对象后,其名称(字符串)位于+8偏移量处.您可以尝试使用ReadProcessMemory进行读取.这里的主要问题是创建FindControl()版本以满足您的需求.

编辑:(终于搞定了:D)调用GetWinControlName函数

// Get Pointer to TWinControl in another process
function GetWinControl(Wnd: HWND; out ProcessId: THandle): Pointer;
var
  WindowAtomString: String;
  WindowAtom: ATOM;
begin
  if GetWindowThreadProcessId(Wnd, ProcessId) = 0 then RaiseLastOSError;

  // This is atom for remote process (See controls.pas for details on this)
  WindowAtomString := Format('Delphi%.8X',[ProcessID]);
  WindowAtom := GlobalFindAtom(PChar(WindowAtomString));
  if WindowAtom = 0 then RaiseLastOSError;

  Result := Pointer(GetProp(Wnd, MakeIntAtom(WindowAtom)));
end;

function GetWinControlName(Wnd: HWND): string;
var
  ProcessId: THandle;
  ObjSelf: Pointer;
  Buf: Pointer;
  bytes: Cardinal;
  destProcess: THandle;
begin
  ObjSelf := GetWinControl(Wnd, ProcessId);

  destProcess := OpenProcess(PROCESS_VM_READ, TRUE, ProcessId);
  if destProcess = 0 then RaiseLastOSError;

  try
    GetMem(Buf, 256);
    try
      if not ReadProcessMemory(destProcess, Pointer(Cardinal(ObjSelf) + 8), Buf, 4, bytes) then RaiseLastOSError;
      if not ReadProcessMemory(destProcess, Pointer(Cardinal(Buf^)), Buf, 256, bytes) then RaiseLastOSError;
      Result := PChar(Buf);
    finally
      FreeMem(Buf);
    end;
  finally
    CloseHandle(destProcess);
  end;
end;
Run Code Online (Sandbox Code Playgroud)

  • @Samaliani它正在调用一个`FreeMem(Buf,256)`和一个`CloseHandle(destProcess)`但这个概念很有效,谢谢. (5认同)
  • [+1]非常好! (3认同)
  • @Daniel:仅供参考,`RM_GetObjectInstance`问题最终在XE3中修复,以便为所有VCL进程使用相同的消息ID,而不是为每个进程使用唯一的消息ID. (2认同)

Dav*_*nan 6

不,没有Windows API函数会产生控件的名称.这是一个私有的Delphi实现细节.

如果您控制目标进程的代码,那么显然您可以实现某种形式的IPC来解决问题.否则,任何产生控件名称的解决方案都将涉及相当卑鄙的黑客行为.一种方法是向进程注入使用相同版本的运行时构建的DLL.获取该DLL以从HWND中找到VCL控件引用并读出名称.这方面有很多变种ReadProcessMemory,@ Samaliani的回答提供了很好的诡计,这是你必须跳过的典型的箍.

但是,我可以想到一个更简单的解决方案来解决您的问题.找到所有编辑控件的句柄,并使用这些句柄接收控件的坐标.编辑控件的相对位置足以识别哪一个是所需目标.请阅读@dthorpe的评论,以获得更多有用的想法.

  • 一个男人的卑鄙黑客是另一个男人的专利测试自动化框架. (2认同)
  • 比较窗口是否适合手动确认("这是吗?")但长期不可靠.窗口大小和位置可以随本地化而变化.一旦识别出目标,记住其子窗口索引或Tab键顺序索引可能是一个更可靠的标记随着时间的推移.Tab键顺序通常不会在本地化中发生变化. (2认同)
  • @dthorpe所以你是那个人,我知道我之前听过那个名字.你是一位优秀的软件工程师,我是粉丝!当我读到德尔福及其内部时,你的名字时不时出现. (2认同)