Search code examples
c#asp.net-coreui-automation.net-5asp.net-core-5.0

How to use UIAutomation in .NET 5 or .NET 6


I created a Web API solution with 7 projects.

One of them is named FinanceApp.UIA, below is the SDK I'm using in this project. Please notice that 'Microsoft.WindowsDesktop.App' was included,

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <FrameworkReference Include="Microsoft.WindowsDesktop.App" />
  </ItemGroup>
  <ItemGroup>
    <Folder Include="SimulateType\" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\FinanceApp.Comon\FinanceApp.Common.csproj" />
    <ProjectReference Include="..\FinanceApp.IRepository\FinanceApp.IRepository.csproj" />
    <ProjectReference Include="..\FinanceApp.Model\FinanceApp.Model.csproj" />
  </ItemGroup>
</Project>

Why 'Microsoft.WindowsDesktop.App' is included? Below is what I want to do in this project

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Automation;
using System.Threading;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;
using FinanceApp.Common;

namespace FinanceApp.UIA
{
    public class BaseUia:IBaseUia
    {
        delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);

        [DllImport("user32.dll")]
        static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn,
            IntPtr lParam);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern IntPtr GetHwndByClassName(string lpClassName, string lpWindowName);



        /// <summary>
        /// Get handles by process ID
        /// </summary>
        /// <param name="processId"></param>
        /// <returns></returns>
        public IEnumerable<IntPtr> GetHwndFromPid(int processId)
        {
            var handles = new List<IntPtr>();

            foreach (ProcessThread thread in Process.GetProcessById(processId).Threads)
            {
                EnumThreadWindows(thread.Id,
                    (hWnd, lParam) =>
                        {
                            handles.Add(hWnd);
                            return true;
                        },
                    IntPtr.Zero);
            }
            return handles;
        }

        /// <summary>
        /// Get AutomationElement by process id
        /// </summary>
        /// <param name="processId"></param>
        /// <returns></returns>
        public IEnumerable<AutomationElement> GetElementsByPid(int processId)
        {
            var handles = GetHwndFromPid(processId);
            return handles.Select(hnd => AutomationElement.FromHandle(hnd));
        }
    }
}

Another project named 'FinanceApp.Service', the SDK and reference is as below:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <LangVersion>Latest</LangVersion>
  </PropertyGroup>
  
  <ItemGroup>
    <ProjectReference Include="..\FinanceApp.UIA\FinanceApp.UIA.csproj" />
  </ItemGroup>

</Project>

I get an error as below

The target platform must be set to Windows (usually by including '-windows' in the TargetFramework property) when using Windows Forms or WPF, or referencing projects or packages that do so. FinanceApp.Service C:\Program Files\dotnet\sdk\6.0.100-preview.1.21103.13\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.DefaultItems.targets 362


Solution

  • Changing the target framework to net5.0-windows for all projects in the solution as Simon suggested resolved my issue:

    Change target framework like this: <TargetFramework>net5.0-windows</TargetFramework> here is a full console app sample: pastebin.com/raw/AqBnQUsh
    - Simon Mourier