一、准备工作
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窗体是开启的另外一个程序