这篇文章同样是想要继续尝试加速UI Tree的获取...不说别的了,直接说怎么实现吧。

过程

对用得上的Win32API进行封装

值得注意的是:官方文档C++中的LONG,在C#中是int,麻了。

public class Win32API
{

    public struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }


    /// <summary>
    /// Find the hWnd of the window by ClassName or WindowName
    /// </summary>
    /// <param name="lpClassName">ClassName of window</param>
    /// <param name="lpWindowName">WindowName of window</param>
    /// <returns></returns>
    [DllImport("User32.dll", EntryPoint = "FindWindow")]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);


    /// <summary>
    /// Find the hWnd of the window
    /// </summary>
    /// <param name="hwndParent">Parent hWnd</param>
    /// <param name="hwndChildAfter">hWnd of last sibling</param>
    /// <param name="lpszClass">ClassName of Window</param>
    /// <param name="lpszWindow">WindowName of Window</param>
    /// <returns></returns>
    [DllImport("user32.dll", EntryPoint = "FindWindowEx")]
    public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);



    [DllImport("user32.dll", SetLastError = true)]
    public static extern int GetWindowTextLength(IntPtr hWnd);


    [DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int nMaxCount);


    [DllImport("user32.dll")]
    public static extern int GetWindowRect(IntPtr hwnd, out RECT lpRect);
}

抽象一个包含位置和名称的类

public class GUIElement
{
    public Rect BoundingRectangle = new Rect(0, 0, 0, 0);
    public String Name = "";


    public GUIElement(Rect rect)
    {
        BoundingRectangle = rect;
    }

    public GUIElement(String name)
    {
        Name = name;
    }


    public GUIElement(Rect rect, String name)
    {
        BoundingRectangle = rect;
        Name = name;
    }
}

火速写一个DFS

这次还没写并发,主要是为了验证功能。

public static class GRawUIManager
{

    public static String GetElementName(IntPtr hWnd)
    {
        int length = Win32API.GetWindowTextLength(hWnd);
        StringBuilder name = new StringBuilder(length);
        Win32API.GetWindowText(hWnd, name, name.Capacity);
        return name.ToString();
    }


    public static Rect GetElementBounds(IntPtr hWnd)
    {
        Win32API.GetWindowRect(hWnd, out Win32API.RECT rect);
        return new Rect(new Point(rect.Left, rect.Top), new Point(rect.Right, rect.Bottom));
    }


    public static GUIElement GetUIElement(IntPtr hWnd)
    {
        return new GUIElement(GetElementBounds(hWnd), GetElementName(hWnd));
    }


    public static List<GUIElement> GetLeafElements(IntPtr hWnd)
    {
        List<GUIElement> res = new List<GUIElement>();
        try
        {
            Rect bounds = GetElementBounds(hWnd);
            if (!JudgeBounding(bounds)) return res;
            GetLeafElementsDFS(hWnd, res, bounds);
        }
        catch (Exception)
        {
            return res;
        }
        return res;
    }


    private static bool JudgeBounding(Rect bounds)
    {
        try
        {
            if (bounds == null)
                return false;
            if (bounds.Width == 0 || bounds.Height == 0)
                return false;
            if (bounds.IsEmpty)
                return false;
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }


    private static void GetLeafElementsDFS(IntPtr hWnd, List<GUIElement> res, Rect bounds)
    {
        IntPtr childHWnd = IntPtr.Zero;
        int child_cnt = 0;
        while (true)
        {
            childHWnd = Win32API.FindWindowEx(hWnd, childHWnd, null, null);
            if (childHWnd == IntPtr.Zero) break;
            child_cnt ++;
            Rect rect = GetElementBounds(childHWnd);
            if (!JudgeBounding(rect)) continue;
            if (rect.Bottom <= bounds.Top || rect.Right <= bounds.Left) continue;
            if (rect.Top >= bounds.Bottom || rect.Left >= bounds.Right) continue;
            GetLeafElementsDFS(childHWnd, res, rect);
        }
        if (child_cnt == 0) res.Add(GetUIElement(hWnd));
    }
}

测试与结果

跑了一下,速度:很快,快上天了。但是一看输出:这都是啥和啥呀(悲)。大部分窗口只能获取最上面的句柄,只有少量窗口还能搞出几个控件(悲)。所以总结一下,基本上是没法用了,估计还得爬回UIAutomation.

↑:速度很快但啥都没有...

最后修改:2021 年 08 月 02 日 12 : 36 AM
真的不买杯奶茶嘛....qwq