delphi - 使用 Delphi 通过 UIAutomation 获取底层菜单项的列表

标签 delphi microsoft-ui-automation

我一直在尝试使用作为 TLB 导入 Delphi 的 UIAutomationCore 库从标准 Windows 应用程序获取菜单子(monad)项列表 - 即

File -> New | Exit
Help -> About

我可以获取应用程序菜单,然后将顶级项目放入列表中(即在上面的示例中,"file"和“帮助”,但我无法获取这些菜单项下的任何控件的列表。我的代码如下 - FElement 代表我正在检查的实际菜单项。

FindAll 返回的集合的长度始终为 0。在这段代码之前我已经尝试过扩展 menuitem,但似乎没有效果。

 UIAuto.CreateTrueCondition(condition);

 FItems := TObjectList<TAutomationMenuItem>.create;

 self.Expand;
 sleep(3000);

 // Find the elements
 self.FElement.FindAll(TreeScope_Descendants, condition, collection);

 collection.Get_Length(length);

 for count := 0 to length -1 do
 begin
   collection.GetElement(count, itemElement);
   itemElement.Get_CurrentControlType(retVal);

   if (retVal = UIA_MenuItemControlTypeId) then
   begin
     item := TAutomationMenuItem.Create(itemElement);
     FItems.Add(item);
   end;
 end;

我可以在 C# 中看到这样的示例,并且它们实际上并没有做任何与上面的代码不同的事情(据我所知)

提前致谢

更新:它看起来与此非常相似question

Update2:在此示例中,它尝试对另一个 Delphi 应用程序执行此操作。但是,如果我在记事本上尝试相同的操作(例如),则会出现相同的问题。

Update3:使用 Inspect(然后使用 UI Automation),我有以下结构...

名称 = 退出 Ancestors = 文件(菜单)Form1( Pane )

在展开菜单(文件)后我也尝试过此操作,并且发生了相同的事情(或没有发生)。

最佳答案

我认为您有以下两个问题:

  1. 除非展开菜单,否则菜单不会列出子菜单项
  2. 如果您尝试自动化自己的应用程序,则必须在线程中执行此操作。

以下内容对我有用:

// Careful: the code might not be 100% threadsafe, but should work for the purpose of demonstration
const
  UIA_MenuItemControlTypeId =   50011;
  UIA_ControlTypePropertyId =   30003;
  UIA_NamePropertyId    =   30005;
  UIA_ExpandCollapsePatternId   =   10005;

procedure TForm1.Button1Click(Sender: TObject);
begin
  TThread.CreateAnonymousThread(procedure begin CoInitializeEx(nil, 2); FindItems(true); CoUninitialize; end).Start;
end;

procedure TForm1.FindItems(Recurse: Boolean);
var
  UIAuto: TCUIAutomation;
  condition: IUIAutomationCondition;
  collection: IUIAutomationElementArray;
  Length: Integer;
  Count: Integer;
  itemElement: IUIAutomationElement;
  retVal: Integer;
  val: WideString;

  ExpandCollapsePattern: IUIAutomationExpandCollapsePattern;
  FElement: IUIAutomationElement;
begin
  UIAuto := TCUIAutomation.Create(nil);   

  UIAuto.CreateTrueCondition(condition);

  // Find the elements
  UIAuto.ElementFromHandle(Pointer(Handle), FElement);

  FElement.FindAll(TreeScope_Descendants, condition, collection);

  collection.Get_Length(length);

  for Count := 0 to length - 1 do
  begin
    collection.GetElement(Count, itemElement);
    itemElement.Get_CurrentControlType(retVal);

    if (retVal = UIA_MenuItemControlTypeId) then
    begin
      ItemElement.Get_CurrentName(val);
      TThread.Synchronize(nil,
        procedure
        begin
          memo1.lines.Add(val);
        end);

      itemElement.GetCurrentPattern(UIA_ExpandCollapsePatternId, IInterface(ExpandCollapsePattern));
      if Assigned(ExpandCollapsePattern) then
      begin
        ExpandCollapsePattern.Expand;
        if Recurse = True then
          FindItems(False);
      end;
    end;
  end;
  UIAuto.Free;
end;

关于delphi - 使用 Delphi 通过 UIAutomation 获取底层菜单项的列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29694033/

相关文章:

delphi - 如何禁用整个项目的断言?

sql - 'GO' 附近的语法不正确 - TADOQuery

c# - UI 自动化是否有任何依赖项?

c# - 怀特如何处理已经运行的应用程序?

c# - Windows UI 自动化 API

delphi - 无法在 XE8 中部署 Ad Hoc Release

delphi - 在 TWebModule Handler 中生成新的线程/进程

delphi - 如何将运行时创建的按钮添加到数组中?

c# - 使用 Microsoft UI Automation 获取任何应用程序的 TitleBar Caption?

c# - 为什么在 UI 自动化客户端中捕获的异常会出现在正在自动化的 UI 中?