.NET WinApi 識別並監聽WinForm窗體文本內容

一、準備工作

VS2017創建winform項目,下載CSkin.dll庫並在項目中添加引用(主要使用MouseHook),創建兩個窗體頁面

二、功能實現

窗體識別信息實體類

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WinApiDemo
{
    internal class RecognitionData
    {
        private int index = -1;
        private string szPWindowName;
        private string szPClasName;
        private string szWindowName;
        private string szClassName;
        private Size size;
        private List<string> windows;
        public string SzWindowName
        {
            get
            {
                return this.szWindowName;
            }
            set
            {
                this.szWindowName = value;
            }
        }

        public string SzClassName
        {
            get
            {
                return this.szClassName;
            }
            set
            {
                this.szClassName = value;
            }
        }

        public string SzPWindowName
        {
            get
            {
                return this.szPWindowName;
            }
            set
            {
                this.szPWindowName = value;
            }
        }

        public string SzPClasName
        {
            get
            {
                return this.szPClasName;
            }
            set
            {
                this.szPClasName = value;
            }
        }

        public Size Size
        {
            get
            {
                return this.size;
            }
            set
            {
                this.size = value;
            }
        }

        public List<string> Windows
        {
            get
            {
                return this.windows;
            }
            set
            {
                this.windows = value;
            }
        }

        public int Index
        {
            get
            {
                return this.index;
            }
            set
            {
                this.index = value;
            }
        }
    }
}

 窗體識別WinApi實現代碼

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WinApiDemo.Common
{
    /// <summary>
    /// 窗體識別
    /// </summary>
    public class HWNDHelper
    {
        public struct POINTAPI
        {
            public int X;
            public int Y;
        }
        public struct Rect
        {
            public int Width
            {
                get
                {
                    return this.right - this.left;
                }
            }

            public int Height
            {
                get
                {
                    return this.bottom - this.top;
                }
            }

            public int left;

            public int top;

            public int right;

            public int bottom;
        }
        private static List<IntPtr> wndList = new List<IntPtr>();
        private static List<IntPtr> list = new List<IntPtr>();
        private delegate bool WNDENUMPROC(IntPtr hWnd, int lParam);
        public delegate bool EnumWindowsProc(IntPtr hWnd, int lParam);

        [DllImport("user32.dll")]
        public static extern IntPtr GetCursorPos(ref POINTAPI lpPoint);
        [DllImport("user32.dll")]
        public static extern IntPtr WindowFromPoint(int xPoint, int yPoint);
        [DllImport("user32.dll")]
        public static extern int InvalidateRect(IntPtr hWnd, IntPtr lpRect, int bErase);
        [DllImport("user32.dll")]
        public static extern int UpdateWindow(IntPtr hWnd);
        [DllImport("user32.dll")]
        public static extern int RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate, IntPtr hrgnUpdate, uint flags);
        [DllImport("user32.dll")]
        public static extern IntPtr SendMessage(IntPtr hWnd, int lParam, int nMaxCount, StringBuilder lpString);
        [DllImport("user32.dll")]
        public static extern bool GetWindowRect(IntPtr hwnd, ref Rect rectangle);
        [DllImport("user32.dll")]
        public static extern IntPtr GetWindowDC(IntPtr hwnd);
        [DllImport("user32.dll")]
        public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);
        [DllImport("user32.dll")]
        public static extern int GetWindowText(int hWnd, IntPtr lpString, int nMaxCount);
        [DllImport("user32.dll")]
        public static extern IntPtr GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
        [DllImport("user32.dll")]
        public static extern bool SetSystemCursor(IntPtr hcur, uint id);
        [DllImport("user32.dll")]
        public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni);
        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr GetParent(IntPtr hWnd);
        [DllImport("user32.dll")]
        private static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, int lParam);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
        [DllImport("user32.dll")]
        public static extern IntPtr GetClassName(IntPtr hWnd, StringBuilder lpString, int nMaxCont);
        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static IntPtr WindowFromPoint()
        {
            POINTAPI pointapi = default(POINTAPI);
            GetCursorPos(ref pointapi);
            return WindowFromPoint(pointapi.X, pointapi.Y);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hWnd"></param>
        public static void Refresh(IntPtr hWnd)
        {
            InvalidateRect(hWnd, IntPtr.Zero, 1);
            UpdateWindow(hWnd);
            RedrawWindow(hWnd, IntPtr.Zero, IntPtr.Zero, 1409U);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hwnd"></param>
        /// <returns></returns>
        public static string GetWindowTextByMessage(IntPtr hwnd)
        {
            StringBuilder stringBuilder = new StringBuilder(256);
            SendMessage(hwnd, 13, 256, stringBuilder);
            return stringBuilder.ToString();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hWnd"></param>
        /// <param name="tips"></param>
        public static void Highlight(IntPtr hWnd, string tips)
        {
            Rect rect = default(Rect);
            GetWindowRect(hWnd, ref rect);
            IntPtr windowDC = GetWindowDC(hWnd);
            if (windowDC != IntPtr.Zero)
            {
                using (Pen pen = new Pen(Color.Green, 3f))
                {
                    using (Graphics graphics = Graphics.FromHdc(windowDC))
                    {
                        Font font = new Font("微軟雅黑", 10f, FontStyle.Bold);
                        graphics.DrawRectangle(pen, 0, 0, rect.right - rect.left - 3, rect.bottom - rect.top - 3);
                        graphics.DrawString(tips, font, Brushes.Red, 10f, 10f);
                    }
                }
            }
            ReleaseDC(hWnd, windowDC);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hwnd"></param>
        /// <returns></returns>
        public static string GetWindowText(IntPtr hwnd)
        {
            StringBuilder stringBuilder = new StringBuilder(256);
            GetWindowText(hwnd, stringBuilder, 256);
            return stringBuilder.ToString();
        }
        /// <summary>
        /// 
        /// </summary>
        public static void SetSystemCursor()
        {
            SetSystemCursor(Cursors.SizeAll.CopyHandle(), 32512U);
        }
        /// <summary>
        /// 
        /// </summary>
        public static void SystemParametersInfo()
        {
            SystemParametersInfo(87U, 0U, IntPtr.Zero, 2U);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hwnd"></param>
        /// <param name="isGetDeskAll"></param>
        /// <returns></returns>
        public static IntPtr GetParent(IntPtr hwnd, bool isGetDeskAll = true)
        {
            if (isGetDeskAll)
            {
                GetAllDesktopWindows();
            }
            IntPtr parent = GetParent(hwnd);
            if (parent == IntPtr.Zero || parent == hwnd || wndList.Contains(hwnd))
            {
                return hwnd;
            }
            return GetParent(parent, false);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static List<IntPtr> GetAllDesktopWindows()
        {
            wndList.Clear();
            EnumWindows(delegate (IntPtr hWnd, int lParam)
            {
                wndList.Add(hWnd);
                return true;
            }, 0);
            return wndList;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="handle"></param>
        /// <returns></returns>
        public static List<IntPtr> EnumWindows(IntPtr handle)
        {
            list.Clear();
            EnumChildWindows(handle, new HWNDHelper.EnumWindowsProc(EnumWindowsMethod), IntPtr.Zero);
            return list;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hWnd"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        private static bool EnumWindowsMethod(IntPtr hWnd, int lParam)
        {
            if (hWnd != IntPtr.Zero)
            {
                list.Add(hWnd);
            }
            return true;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="handle"></param>
        /// <returns></returns>
        public static Size GetSize(IntPtr handle)
        {
            Size result = default(Size);
            try
            {
                if (handle != IntPtr.Zero)
                {
                    Rect rect = default(Rect);
                    GetWindowRect(handle, ref rect);
                    result.Height = rect.Height;
                    result.Width = rect.Width;
                }
            }
            catch
            {
            }
            return result;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="hwnd"></param>
        /// <returns></returns>
        public static string GetClassName(IntPtr hwnd)
        {
            StringBuilder stringBuilder = new StringBuilder(256);
            GetClassName(hwnd, stringBuilder, 256);
            return stringBuilder.ToString();
        }
    }
}

其他輔助類代碼

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WinApiDemo.Common
{
    /// <summary>
    /// 通用幫助類
    /// </summary>
    public class CommonUtil
    {
        /// <summary>
        /// 字符串轉Decimal
        /// </summary>
        /// <param name="str"></param>
        /// <param name="maxValue"></param>
        /// <returns></returns>
        public static string getDoubleByStr(string str, Decimal maxValue)
        {
            string str1 = "";
            if (!string.IsNullOrEmpty(str))
            {
                StringBuilder stringBuilder = new StringBuilder();
                foreach (char ch in str)
                {
                    if (Convert.ToInt32(ch) >= 48 && Convert.ToInt32(ch) <= 57)
                        stringBuilder.Append(ch);
                    else if (Convert.ToInt32(ch) == 44 || Convert.ToInt32(ch) == 46)
                    {
                        if (stringBuilder.Length != 0)
                        {
                            if (stringBuilder.ToString().IndexOf(".") == -1)
                                stringBuilder.Append(ch);
                            else
                                break;
                        }
                    }
                    else if (stringBuilder.Length != 0)
                        break;
                }
                string s = stringBuilder.ToString().Replace(",", "");
                if (string.IsNullOrEmpty(s))
                    return "";
                if (s.Contains("."))
                {
                    string[] strArray = s.Split('.');
                    if (strArray.Length >= 2)
                        s = strArray[0] + "." + (strArray[1].Length <= 2 ? strArray[1] : strArray[1].Substring(0, 2));
                }
                str1 = getDecimal(s).CompareTo(maxValue) != 1 ? s : decimal2String(maxValue);
            }
            return str1;
        }
        public static Decimal getDecimal(string s)
        {
            try
            {
                return Decimal.Parse(s);
            }
            catch
            {
                return Decimal.Zero;
            }
        }
        public static string decimal2String(Decimal d)
        {
            return Decimal.Parse(d.ToString("#0.00")).ToString();
        }
        /// <summary>
        /// 窗體傳參
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="action"></param>
        /// <param name="parameters"></param>
        /// <param name="isMoreParam"></param>
        public static void SendMsg<T>(int action, object parameters, bool isMoreParam = false)
        {
            Type type = typeof(T);
            object obj = Activator.CreateInstance(type);//實例化對象
            if (type.BaseType.FullName == "System.Windows.Forms.Form")
            {
                var frm = Application.OpenForms[type.Name];
                if (frm != null)
                {
                    obj = frm;
                }
            }
            //參數處理
            object[] paras = null;
            if (parameters != null)
            {
                if (!isMoreParam)
                {
                    paras = new object[1];
                    paras[0] = parameters;
                }
                else
                {
                    paras = (object[])parameters;
                }
            }
            MethodInfo[] methodInfos = type.GetMethods();
            foreach (var method in methodInfos)
            {
                var actionAttribute = method.GetCustomAttribute<ActionAttribute>();
                if (actionAttribute != null)
                {
                    if (actionAttribute.Action.Equals(action))
                    {
                        method.Invoke(obj, paras);
                        break;
                    }
                }
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WinApiDemo
{
    [AttributeUsage(AttributeTargets.Method)]
    internal sealed class ActionAttribute : Attribute
    {
        public int Action { get; set; }
    }
}

 獲取監聽結果頁面(啓動頁)

        /// <summary>
        /// 設置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSet_Click(object sender, EventArgs e)
        {
            frmSettings frm = new frmSettings();
            frm.Show();
        }
        /// <summary>
        /// 獲取監聽到的數字
        /// </summary>
        /// <param name="amount"></param>
        [Action(Action = 1)]
        public void GetAmount(string amount)
        {
            txtMoney.Text = amount;
        }

窗體識別及開啓監聽頁面

 

 

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using WinApiDemo.Common;
using CCWin.SkinControl;

namespace WinApiDemo
{
    public partial class frmSettings : Form
    {
        private MouseHook mouseHook;
        private IntPtr curHWND;//當前窗體的句柄
        private static System.Windows.Forms.Timer timer;//窗體信息識別定時器
        private static RecognitionData recognitionDataFull;//識別的窗體信息
        private static IntPtr parentHwnd;//識別的數字控件的窗體句柄
        private static IntPtr findHWND;//識別的數字控件句柄
        private static IntPtr parentHwndTemp;//記錄識別的數字控件的窗體句柄
        private static string amount = "";//監聽到的數字
        public frmSettings()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            curHWND = IntPtr.Zero;//當前窗體句柄默認爲0
        }
        private void btnDistinguish_Click(object sender, EventArgs e)
        {
            Visible = false;//當前窗體隱藏
            Thread.Sleep(200);
            if (mouseHook == null)
            {
                mouseHook = new MouseHook();
                mouseHook.MHookEvent += new MouseHook.MHookEventHandler(MHookEvent_Click);
            }
            HWNDHelper.SetSystemCursor();//改變系統鼠標            
            mouseHook.SetHook();//加載鉤子
        }

        private void MHookEvent_Click(object sender, MHookEventArgs e)
        {
            IntPtr num = HWNDHelper.WindowFromPoint();//獲取當前位置的窗體句柄 (PS:調用DeviceLib庫)
            string str = "";
            if (curHWND != IntPtr.Zero && curHWND != num)
            {
                HWNDHelper.Refresh(curHWND);
            }
            if (curHWND != num)
            {
                curHWND = num;
                str = HWNDHelper.GetWindowTextByMessage(num);
                HWNDHelper.Highlight(num, HWNDHelper.GetWindowText(num));
            }
            //如果不是左側鼠標按下後彈起的動作,則返回
            if (e.MButton != ButtonStatus.LeftUp)
            {
                return;
            }
            if (mouseHook != null)
            {
                mouseHook.UnLoadHook();//卸載鉤子
            }
            HWNDHelper.Refresh(num);
            string windowTextByMessage = HWNDHelper.GetWindowTextByMessage(num);
            HWNDHelper.SystemParametersInfo();
            if (string.IsNullOrEmpty(windowTextByMessage))
            {
                lblWindowInfo.Text = "當前選中窗體識別金額:無法識別金額,請確保選中窗體是有效的金額窗體";
                Visible = true;//顯示當前窗體
                return;
            }
            else
            {
                Visible = true;//顯示當前窗體
                lblWindowInfo.Text = "識別的窗體:" + windowTextByMessage;
                GetWinInfo();
            }
        }
        /// <summary>
        /// 獲取識別的窗體信息
        /// </summary>
        private void GetWinInfo()
        {
            if (curHWND == IntPtr.Zero)
            {
                MessageBox.Show("請選擇一個目標窗體作爲金額識別窗體");
                return;
            }
            IntPtr num2 = HWNDHelper.GetParent(curHWND, true);//獲取當前窗體句柄
            IntPtr num3 = curHWND;//選中的窗體句柄
            List<IntPtr> list = HWNDHelper.EnumWindows(num2);//獲取枚舉窗體
            int num4 = list.IndexOf(num3);
            string str1 = "";
            string str2 = "";
            if (num4 != -1)
            {
                if (num4 > 0)
                {
                    IntPtr num5 = list[num4 - 1];
                    Size size = HWNDHelper.GetSize(num5);
                    str1 = string.Format("{0}X{1}", HWNDHelper.GetClassName(num5), size.Height);
                }
                if (num4 < list.Count - 1)
                {
                    IntPtr num5 = list[num4 + 1];
                    Size size = HWNDHelper.GetSize(num5);
                    str2 = string.Format("{0}X{1}", HWNDHelper.GetClassName(num5), size.Height);
                }
            }
            RecognitionData recognitionData = new RecognitionData();
            recognitionData.SzPWindowName = HWNDHelper.GetWindowText(num2);//窗體名稱
            recognitionData.SzPClasName = HWNDHelper.GetClassName(num2);//窗體class
            recognitionData.SzWindowName = HWNDHelper.GetWindowTextByMessage(num3);//選中的識別窗體的控件名稱
            recognitionData.SzClassName = HWNDHelper.GetClassName(num3);//選中的識別窗體的控件class
            recognitionData.Size = HWNDHelper.GetSize(num3);//選中的識別窗體的控件
            recognitionData.Index = num4;
            recognitionData.Windows = new List<string>
            {
                str1,
                string.Format("{0}X{1}",  recognitionData.SzClassName,  recognitionData.Size.Height),
                str2
            };
            recognitionDataFull = recognitionData;
        }
        /// <summary>
        /// 開啓定時監聽
        /// </summary>
        private static void start()
        {
            stop();
            if (string.IsNullOrEmpty(recognitionDataFull.SzClassName) && string.IsNullOrEmpty(recognitionDataFull.SzWindowName))
            {
                return;
            }
            //開啓定時監測
            if (timer == null)
            {
                timer = new System.Windows.Forms.Timer();
                timer.Enabled = true;
                timer.Tick += new EventHandler(form_tick);
            }
            timer.Interval = 500;
            timer.Start();
        }

        /// <summary>
        /// 關閉定時監聽
        /// </summary>
        public static void stop()
        {
            findHWND = IntPtr.Zero;
            if (timer != null)
            {
                timer.Enabled = false;
                timer.Stop();
                timer = null;
            }
        }
        /// <summary>
        /// 定時監聽事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void form_tick(object sender, EventArgs e)
        {
            amount = "";//監聽輸入的金額     
            parentHwnd = HWNDHelper.FindWindow(recognitionDataFull.SzPClasName, recognitionDataFull.SzPWindowName);//選中的窗體的句柄
            if (parentHwnd == IntPtr.Zero)
            {
                findHWND = IntPtr.Zero;
            }
            else if (findHWND != IntPtr.Zero && parentHwndTemp == parentHwnd)
            {
                amount = CommonUtil.getDoubleByStr(HWNDHelper.GetWindowTextByMessage(findHWND), 999999.99M);
            }
            else
            {
                List<IntPtr> windowsList = HWNDHelper.EnumWindows(parentHwnd).Where(x => !x.Equals(IntPtr.Zero)).ToList();//枚舉窗體
                List<string> windowsInfoList = new List<string>();//記錄枚舉窗體信息
                foreach (IntPtr num in windowsList)
                {
                    string className = HWNDHelper.GetClassName(num);
                    Size size = HWNDHelper.GetSize(num);
                    windowsInfoList.Add(string.Format("{0}X{1}", className, size.Height));
                }
                //識別的窗體信息不爲null且識別的窗體枚舉數大於當前枚舉窗體信息數量時,從枚舉窗體中獲取與識別的窗體一致的窗體句柄
                if (recognitionDataFull.Windows == null || recognitionDataFull.Windows.Count > windowsInfoList.Count)
                {
                    string searchWindow = string.Format("{0}X{1}", recognitionDataFull.SzClassName, recognitionDataFull.Size.Height);
                    var getSameWindow = windowsInfoList.Where(x => x.Equals(searchWindow)).FirstOrDefault();
                    if (getSameWindow != null)
                    {
                        var index = windowsInfoList.FindIndex(x => x.Equals(searchWindow));
                        findHWND = windowsList[index];
                    }
                }
                else
                {
                    Dictionary<int, IntPtr> dictionaryWindow = new Dictionary<int, IntPtr>();
                    var inserWindow = windowsInfoList.Intersect(recognitionDataFull.Windows).ToList();//獲取枚舉窗體信息與識別的窗體信息交集
                    foreach (var windowinfo in inserWindow)
                    {
                        if (!string.IsNullOrEmpty(windowinfo))
                        {
                            var index = windowsInfoList.FindIndex(x => x.Equals(windowinfo));
                            dictionaryWindow.Add(index, windowsList[index]);
                        }
                    }
                    if (dictionaryWindow.Count > 0)
                    {
                        IOrderedEnumerable<KeyValuePair<int, IntPtr>> orderedEnumerable = Enumerable.OrderBy(dictionaryWindow, p => p.Key);
                        Func<KeyValuePair<int, IntPtr>, int> keySelector = p => p.Key;
                        Dictionary<int, IntPtr> dictionaryIntptr = Enumerable.ToDictionary(orderedEnumerable, keySelector, o => o.Value);
                        int index = recognitionDataFull.Index;
                        int absNum = -1;
                        int key = -1;
                        foreach (int intptrKey in dictionaryIntptr.Keys)
                        {
                            if (dictionaryIntptr.Count == 1 || index == -1)
                            {
                                key = intptrKey;
                                break;
                            }
                            if (absNum != -1)
                            {
                                if (absNum <= Math.Abs(intptrKey - index))
                                {
                                    break;
                                }
                            }
                            absNum = Math.Abs(intptrKey - index);
                            key = intptrKey;
                        }
                        if (dictionaryIntptr.ContainsKey(key))
                        {
                            findHWND = dictionaryIntptr[key];
                        }
                    }
                    else
                    {
                        findHWND = IntPtr.Zero;
                    }
                }
            }
            if (findHWND != IntPtr.Zero)
            {
                parentHwndTemp = parentHwnd;
                amount = CommonUtil.getDoubleByStr(HWNDHelper.GetWindowTextByMessage(findHWND), 999999.99M);
            }
            CommonUtil.SendMsg<frmListen>(1, amount);
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            start();
            Hide();
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            stop();
        }
    }
}

 三、最終效果展示

注:Form1窗體是開啓的另外一個程序

源碼:https://download.csdn.net/download/liwan09/12419660

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章