我有一个位于另一个进程窗口的VCL控件的Hwnd。有没有办法通过Windows API获取该控件的VCL名称(TControl.Name
属性)?
我需要这个名称,因为该窗口上有几个TEdits,我需要识别我想要的那个,以便向它发送WM_SETTEXT
消息。
这两个应用程序都是使用Delphi 2010构建的。
答案 0 :(得分:14)
Delphi内置函数FindControl()
,返回指定hWnd的TWinControl
。但它适用于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;
答案 1 :(得分:6)
不,没有Windows API函数会产生控件的名称。这是一个私有的Delphi实现细节。
如果您控制目标进程的代码,那么显然您可以实现某种形式的IPC来解决问题。否则,任何产生控件名称的解决方案都将涉及相当卑鄙的黑客行为。一种方法是向进程注入使用相同版本的运行时构建的DLL。获取该DLL以从HWND中找到VCL控件引用并读出名称。有很多变种,@ Samaliani的答案提供的很好的ReadProcessMemory
诡计是你必须跳过的箍的典型。
但是,我可以想到一个更简单的问题解决方案。找到所有编辑控件的句柄,并使用这些句柄接收控件的坐标。编辑控件的相对位置足以识别哪一个是所需目标。请阅读@dthorpe的评论,以获得更多有用的想法。