Как я могу использовать неуправляемый API автоматизации пользовательского интерфейса из PowerShell

API автоматизации пользовательского интерфейса для Windows доступен из двух библиотек DLL. Одна из них — это управляемая DLL, которая называется C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\UIAutomationClient.dll. Другая — неуправляемая DLL, которая называется C:\Windows\System32\UIAutomationCore.dll. Согласно это сообщение, неуправляемый API превосходит управляемый API с точки зрения количества видимых элементов, поэтому я хотел бы использовать неуправляемый API .

Я пробовал три подхода, но все они потерпели неудачу. Подскажите правильный подход?

Подход №1: New-Object -ComObject

$uia = New-Object -ComObject <ProgID of CUIAutomation>
$root = $uia.GetRootElement()

Ошибка, поскольку New-Object требует ProgID, но CUIAutomation не имеет ProgID.

Подход № 2: создание экземпляров из CLSID

CLSID CUIAutomation равен ff48dba4-60ef-4201-aa87-54103eef594e, тогда

$type = [Type]::GetTypeFromCLSID("ff48dba4-60ef-4201-aa87-54103eef594e")
$uia = [Activator]::CreateInstance($type)
$root = $uia.GetRootElement()

но не удалось со следующим сообщением об ошибке. Я до сих пор не знаю, почему.

Method invocation failed because [System.__ComObject] does not contain a method named 'GetRootElement'.
At line:1 char:1
+ $root = $uia.GetRootElement()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

Подход № 3: Add-Type

Add-Type -Path "C:\Windows\System32\UIAutomationCore.dll"
$uia = New-Object UIAutomationClient.CUIAutomation
$root = $uia.GetRootElement()

Ошибка, так как Add-Type ожидает управляемые библиотеки DLL.

Сообщение об ошибке:

Add-Type : Could not load file or assembly 'file:///C:\Windows\System32\UIAutomationCore.dll' or one of its dependencies. The module was expected to contain an assembly manifest. At line:1 char:1
+ Add-Type -Path "C:\Windows\System32\UIAutomationCore.dll"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Add-Type], BadImageFormatException
    + FullyQualifiedErrorId : System.BadImageFormatException,Microsoft.PowerShell.Commands.AddTypeCommand

Изменить (2018-06-12)

Я попробовал другой подход. (и не удалось)

Подход № 4: Interop DLL

Я не совсем понимаю, что такое Interop DLL, но powershell-cmdlets-for-managing-windows-updates-via-wuapilib#8041782c-9c37-4f3e-a7e7-819a41379809" rel="nofollow noreferrer">в этом посте говорится, что DLL Interop все равно помогла OP. Я установил Visual Studio и сгенерировал Interop.UIAutomationClient.dll, следуя процедурам, описанным в посте.

Add-Type -Path "Interop.UIAutomationClient.dll"
$uia = New-Object UIAutomationClient.CUIAutomationClass
$root = $uia.GetRootElement()
$children = $root.FindAll([UIAutomationClient.TreeScope]::TreeScope_Children, $uia.CreateTrueCondition())

Мне удалось получить $root, но мне не удалось получить строку $children со следующим сообщением об ошибке.

Method invocation failed because [System.__ComObject] does not contain a method named 'FindAll'.
At line:1 char:1
+ $children = $root.FindAll([UIAutomationClient.TreeScope]::TreeScope_C ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

Я до сих пор не знаю, почему.


person anqooqie    schedule 11.06.2018    source источник
comment
Вы действительно хотите автоматизировать пользовательский интерфейс из PowerShell? Почему не Python + pywinauto, который использует неуправляемую UIAutomationCore.dll?   -  person Vasily Ryabov    schedule 12.06.2018
comment
Что касается ошибки FindAll, похоже, вам нужно преобразование типов. $root — это объект базового класса, а не объект AutomationElement.   -  person Vasily Ryabov    schedule 12.06.2018
comment
@VasilyRyabov На самом деле все в порядке, если нет необходимости в правах администратора производственной среды. Запрещено устанавливать Python или любое другое программное обеспечение, требующее прав администратора. Для простоты обслуживания интерпретируемый язык предпочтительнее компилируемого. Поэтому я думаю, что PowerShell подходит. / Я попробую преобразование типов позже.   -  person anqooqie    schedule 12.06.2018
comment
@VasilyRyabov [UIAutomationClient.IUIAutomationElement]($root) не работает с ConvertToFinalInvalidCastException, поскольку IUIAutomationElement несовместим с типом $root, то есть System.__ComObject. Во-первых, почему GetRootElement возвращает System.__ComObject, а не IUIAutomationElement?   -  person anqooqie    schedule 14.06.2018
comment
Я недостаточно знаком с PowerShell, извините.   -  person Vasily Ryabov    schedule 14.06.2018


Ответы (3)


Я еще не решил проблему, но наконец нашел альтернативу, то есть C # Interactive. Я оставлю этот вопрос для пользователей PowerShell, но если вы можете использовать C# Interactive в качестве альтернативы PowerShell, следующий раздел может вам помочь.

Подход № 5: интерактивный C#

  1. Установите визуальную студию.
  2. Создайте Interop.UIAutomationClient.dll, следуя процедурам этот пост.
  3. Запустите следующий скрипт на csi.exe.
#r "Interop.UIAutomationClient.dll"
var uia = new UIAutomationClient.CUIAutomation();
var root = uia.GetRootElement();
var children = root.FindAll(UIAutomationClient.TreeScope.TreeScope_Children, uia.CreateTrueCondition());

К вашему сведению, C# Interactive работает, если в одной папке существуют только следующие файлы (т. е. вы можете использовать C# Interactive где угодно, просто перенеся следующие файлы из среды разработки).

  • C:\Program Files (x86)\MSBuild\14.0\Bin\csi.exe
  • C:\Program Files (x86)\MSBuild\14.0\Bin\csi.rsp
  • C:\Program Files (x86)\MSBuild\14.0\Bin\Microsoft.CodeAnalysis.CSharp.dll
  • C:\Program Files (x86)\MSBuild\14.0\Bin\Microsoft.CodeAnalysis.CSharp.Scripting.dll
  • C:\Program Files (x86)\MSBuild\14.0\Bin\Microsoft.CodeAnalysis.dll
  • C:\Program Files (x86)\MSBuild\14.0\Bin\Microsoft.CodeAnalysis.Scripting.dll
  • C:\Program Files (x86)\MSBuild\14.0\Bin\System.AppContext.dll
  • C:\Program Files (x86)\MSBuild\14.0\Bin\System.Collections.Immutable.dll
  • C:\Program Files (x86)\MSBuild\14.0\Bin\System.Diagnostics.StackTrace.dll
  • C:\Program Files (x86)\MSBuild\14.0\Bin\System.IO.FileSystem.dll
  • C:\Program Files (x86)\MSBuild\14.0\Bin\System.Reflection.Metadata.dll
person anqooqie    schedule 14.06.2018

Подход 2, вы должны попасть в интерфейс

IID_IUIAutomation = "{30CBE57D-D9D0-452A-AB13-7AC5AC4825EE}"

CLSID_UIAutomationClient = "{944DE083-8FB8-45CF-BCB7-C477ACB2F897}"
;CoClasses
CLSID_CUIAutomation = "{FF48DBA4-60EF-4201-AA87-54103EEF594E}"

MS Doc заявляет

Примечания

Каждое клиентское приложение автоматизации пользовательского интерфейса должно получить этот интерфейс к объекту CUIAutomation, чтобы получить доступ к функциям автоматизации пользовательского интерфейса.

В следующем примере функция создает объект CUIAutomation и получает интерфейс IUIAutomation.

IUIAutomation *g_pAutomation; 

BOOL InitializeUIAutomation() 
{ 
CoInitialize(NULL); 
HRESULT hr = CoCreateInstance(__uuidof(CUIAutomation), NULL, CLSCTX_INPROC_SERVER,  
    __uuidof(IUIAutomation), (void**)&g_pAutomation); 
return (SUCCEEDED(hr)); 
} 

Мне не удалось заставить его работать в PS, но, возможно, эти ответы частично помогают в правильном направлении (у меня он работает в AutoIt, но работает по-другому, вы можете найти его с помощью AutoIt IUIAutomation в Google)

$objCUI=[System.Runtime.InteropServices.Marshal]::GetTypeFromCLSID("30CBE57D-D9D0-452A-AB13-7AC5AC4825EE")

or

$Type = [Type]::GetTypeFromCLSID('30CBE57D-D9D0-452A-AB13-7AC5AC4825EE')
$objCUI = [System.Activator]::CreateInstance($Type)

оба бегут, но когда я прихожу в себя

$rootEl = $objCUI.GetType().InvokeMember(
"GetRootElement", 
"InvokeMethod", 
$Null, 
$objCUI, 
@()
)  

я получаю ошибки

person junkew    schedule 21.10.2018

Что насчет этого?:

Add-Type -AssemblyName 'UIAutomationClient'
$ae = [System.Windows.Automation.AutomationElement]
$cTrue = [System.Windows.Automation.PropertyCondition]::TrueCondition
$root = $ae::RootElement
$winNames = $root.FindAll("Children", $cTrue).current.name
person Carsten    schedule 01.05.2020