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

我一直试图从一个标准的Windows应用程序中使用UIAutomationCore库作为TLB导入到Delphi中获取菜单子项目列表 - 即

File -> New | Exit
Help -> About

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

FindAll返回的集合的长度始终为0.我曾尝试在此代码之前展开菜单项,但似乎没有效果。

 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#中看到这方面的例子,它们实际上并没有与上面的代码有任何不同(据我所知)

提前致谢

更新 :它看起来非常类似于这个问题

Update2 :在这个例子中,它试图为另一个Delphi应用程序做这件事。 但是,如果我在记事本上尝试相同的事情(例如),则会出现同样的问题。

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

Name = Exit Ancestors = File(menu)Form1(pane)

我在扩展菜单(文件)后也尝试了这种方式,并且发生了同样的事情(或者没有发生)。


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

  • 菜单不会列出子菜单项,除非菜单被展开
  • 如果你想自动化你自己的应用程序,你必须在一个线程中完成。
  • 以下适用于我:

    // 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;
    
    链接地址: http://www.djcxy.com/p/91077.html

    上一篇: Getting list of underlying menu items via UIAutomation with Delphi

    下一篇: Add explorer context menu item for PDF files from delphi