UI自动化 - ElementFromHandle找不到元素

时间:2014-04-09 03:50:13

标签: delphi ui-automation delphi-xe3

我正在尝试使用UIAutomation访问/控制Chrome浏览器(根据其他人使用的方法使用该方法 - 例如获取当前网址)。

为了练习的目的,我试图在Delphi中复制这个问题 - Retrieve current URL from C# windows forms application。我已经导入TLB了。但是,我对ElementFromHandle的调用永远不会找到一个元素。

ElementFromHandle方法的签名是:

function ElementFromHandle(hwnd: Pointer; out element: IUIAutomationElement): HResult; stdcall;

我的测试很简单:

procedure TForm3.Button1Click(Sender: TObject);
var
  UIAuto: IUIAutomation;
  element: IUIAutomationElement;
  value: WideString;
  h: PInteger;
begin
  new(h);
  h^ := $1094E;
  SetForegroundWindow(h^);
  ShowWindow(h^, SW_SHOW);
  UIAuto := CoCUIAutomation.Create;
  UIAuto.ElementFromHandle(h, element);
  if Assigned(element) then
  begin
    element.Get_CurrentName(value);
    showmessage('found -' + value);
  end
  else
    showMessage('not found');
end;

调用SetForegroundWindow和ShowWindow只是在需要焦点的情况下(但我怀疑它会有所作为并且没有)。我可以确认传递的句柄($ 1094E)是"正确"尽管Spy ++显示了Chrome标签我尝试访问的价值。 Chrome中的有效标签始终会报告Handle。

我的实施是否正确?使用UIAutomation还有比我上面实现的更多吗?我以前从未探索过它。

由于

修改

我发现如果我使用ElementFromPoint并传入一个(硬编码)值,我知道我的Tab位于X,Y的位置 - 它确实有效。即:

  UIAuto := CoCUIAutomation.Create;
  p.x := 2916;
  p.y := 129;
  UIAuto.ElementFromPoint(p, element);
  if Assigned(element) then

如果放在上面的OnClick事件中,上面的片段确实会返回一个元素实例和我期待的那个(这是一个奖励)。那么也许我在ElementFromHandle中为Hwnd传递了一个不正确的值?即,我使用" top"找到我的MS Spy ++的Chrome级别句柄:

enter image description here

它直接位于Spy ++中的(桌面)。

1 个答案:

答案 0 :(得分:1)

您的错误在于将窗口句柄传递给ElementFromHandle。您打算通过HWND。而是传递HWND的地址。

该功能应该是:

function ElementFromHandle(hwnd: HWND; 
    out element: IUIAutomationElement): HResult; stdcall;

您应该删除对New的调用,而是执行:

var
  window: HWND;
....
window := HWND($1094E);

然后调用这个函数:

if Succeeded(UIAuto.ElementFromHandle(window, element)) then
  ....

也许你最大的根本问题是完全没有错误检查。我认为您需要调整您的思维方式,以便意识到这些API调用不会引发异常。他们通过返回值报告失败。您必须检查每个API调用是否失败。

执行此操作的一种常见方法是,在调用HRESULT失败的情况下,将OleCheck值转换为异常。例如:

var
  UIAuto: IUIAutomation;
  element: IUIAutomationElement;
  value: WideString;
  window: HWND;
....
window := HWND($1094E);
SetForegroundWindow(window);
ShowWindow(window, SW_SHOW);
UIAuto := CoCUIAutomation.Create;
OleCheck(UIAuto.ElementFromHandle(window, element));
OleCheck(element.Get_CurrentName(value));
ShowMessage('found -' + value);