现在的位置: 首页 > 综合 > 正文

写个类操作窗口(句柄操作)

2012年10月19日 ⁄ 综合 ⁄ 共 13068字 ⁄ 字号 评论关闭

 

写个类操作窗口(句柄操作)

前言:本店绝不含地沟油

顾客:“老板,你这油怎么这么亮呀,跟我平常吃的不一样,不会是地沟油吧?”

回答:“你平常吃的是地沟油!”

 

继续缅怀逝去的程序员生涯

倒腾WinForm,
是这样的俺想做个方便的类来控制其他程序的窗口,具体就是操作句柄。

这里以改变窗口的输入框(Text)举例,其他自己搞吧,就是调用WinAPI。

 

实现过程:

过程一:找到当前鼠标位置的句柄

您的使用2个WinAPI(俺喜欢自己封装下来用):

[DllImport("user32.dll", EntryPoint = "GetCursorPos")]
public static extern bool GetCursorPos(out Point pt);

[DllImport("user32.dll", EntryPoint = "WindowFromPoint")]
public static extern IntPtr WindowFromPoint(Point pt);

//鼠标位置的坐标
public static Point GetCursorPosPoint()
{
Point p = new Point();
if (GetCursorPos(out p))
{
return p;
}
return default(Point);
}

///<summary>
/// 找到句柄
///</summary>
///<param name="p">坐标</param>
///<returns></returns>
public static IntPtr GetHandle(Point p)
{
return WindowFromPoint(p);
}

 

 

过程二:改变窗口的Text

您的使用1个WinAPI:

[DllImport("user32.dll", EntryPoint = "SendMessage")]
        private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, string lParam);

        ///<summary>
        /// 给窗口发送内容
        ///</summary>
        ///<param name="hWnd">句柄</param>
        ///<param name="lParam">要发送的内容</param>
        public static void SetText(IntPtr hWnd, string lParam)
        {
            SendMessage(hWnd, WM_SETTEXT, IntPtr.Zero, lParam);
        }
        private const int WM_SETTEXT = 0x000C;

通过这个方法就能改变Text的值了。

 

思考:如果俺把这个窗口的句柄记录下来,下次不用鼠标获取,直接就能改变值不蛮好的嘛。

例如:我有个桌面系统老叫我输入用户名,密码。我记录用户名和密码的窗口句柄,然后改变他们的输入值,这样多省事。(只是举例,不考虑安全性)

问题:你会告诉我,窗口句柄的每次重建会变的呀,咋办。

回答:类名不变呀。

 

过程三:您的准备一些工具吧,例如:句柄找类名呀,类名找句柄什么的等等,下面会用到一些WinAPI

 

 [DllImport("user32.dll", EntryPoint = "FindWindow")]
        private static extern IntPtr FindWindow(string IpClassName, string IpWindowName);

        [DllImport("user32.dll", EntryPoint = "FindWindowEx")]
        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

        [DllImport("user32.dll", EntryPoint = "GetParent")]
        public static extern IntPtr GetParent(IntPtr hWnd);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

        ///<summary>
        /// 找到句柄
        ///</summary>
        ///<param name="IpClassName">类名</param>
        ///<returns></returns>
        public static IntPtr GetHandle(string IpClassName)
        {
            return FindWindow(IpClassName, null);
        }

        ///<summary>
        /// 子窗口句柄
        ///</summary>
        ///<param name="hwndParent">父窗口句柄</param>
        ///<param name="hwndChildAfter">前一个同目录级同名窗口句柄</param>
        ///<param name="lpszClass">类名</param>
        ///<returns></returns>
        public static IntPtr GetChildHandle(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass)
        {
            return FindWindowEx(hwndParent, hwndChildAfter, lpszClass, null);
        }

        ///<summary>
        /// 全部子窗口句柄
        ///</summary>
        ///<param name="hwndParent">父窗口句柄</param>
        ///<param name="className">类名</param>
        ///<returns></returns>
        public static List<IntPtr> GetChildHandles(IntPtr hwndParent, string className)
        {
            List<IntPtr> resultList = new List<IntPtr>();
            for (IntPtr hwndClient = GetChildHandle(hwndParent, IntPtr.Zero, className); hwndClient != IntPtr.Zero; hwndClient = GetChildHandle(hwndParent, hwndClient, className))
            {
                resultList.Add(hwndClient);
            }

            return resultList;
        }

        ///<summary>
        /// 找类名
        ///</summary>
        ///<param name="hWnd">句柄</param>
        ///<returns></returns>
        public static string GetClassName(IntPtr hWnd)
        {
            StringBuilder lpClassName = new StringBuilder(128);
            if (GetClassName(hWnd, lpClassName, lpClassName.Capacity) == 0)
            {
                throw new Exception("not found IntPtr!");
            }
            return lpClassName.ToString();
        }
 

 


思考:遍历桌面上所有的窗口,然后找类名,然后改他的Text,扯淡嘛,相同的类名太多了,找毛呀

实现:不仅记录类名,而且记录类名在父窗口出现的位置,然后通过桌面一层层找下来,最后找到这个句柄。(虽然不是太准,但是一般的还是能解决了,如果你有什么好方式一起研究)。

 

过程四:实现一个WinHWND的类,可以把他的规则,他的父窗口类名,以及在父窗口中同类名出现的顺序记录下来,然后通过这些记录的信息还原句柄。

 

public class WinHWND
    {
        public IntPtr HWND { get; set; }
        public string ClassName { get; set; }
        public WinHWND Parent { get; set; }
        public int InParentSequence { get; set; }

        private WinHWND() { }

        public WinHWND(IntPtr hWnd)
        {
            this.HWND = hWnd;
            this.ClassName = GetClassName();
            this.Parent = GetParent();
            this.InParentSequence = GetInParentSequence();
        }

        private string GetClassName()
        {
            return WinAPI.GetClassName(this.HWND);
        }
        private WinHWND GetParent()
        {
            if (WinAPI.GetParent(this.HWND) == null)
            {
                throw new Exception("not found IntPtr!");
            }

            if (WinAPI.GetParent(this.HWND) == IntPtr.Zero)
            {
                return null;
            }

            return new WinHWND(WinAPI.GetParent(this.HWND));
        }
        private int GetInParentSequence()
        {
            IntPtr IntprtParent = this.Parent == null ? IntPtr.Zero : this.Parent.HWND;
            return WinAPI.GetChildHandles(IntprtParent, this.ClassName).IndexOf(this.HWND);
        }

        public override string ToString()
        {
            StringBuilder result = new StringBuilder();
            for (WinHWND winHandle = this; winHandle != null; winHandle = winHandle.Parent)
            {
                result.Append(string.Format("{0}:{1};", Escape(winHandle.ClassName), winHandle.InParentSequence.ToString()));
                if (winHandle.InParentSequence == -1) break;
            }
            return result.ToString().TrimEnd(';');
        }

        private static string GetBaseMark(string sMark)
        {
            string[] sMarks = sMark.Split(';');
            return sMarks[sMarks.Length - 1].Split(':')[0];
        }

        private static string[] GetChildMarks(string sMark)
        {
            string[] sMarks = sMark.Split(';');
            string[] sChildMarks = new string[sMarks.Length - 1];
            for (int i = 0; i < sChildMarks.Length; i ++ )
            {
                sChildMarks[i] = sMarks[i ];
            }
            return sChildMarks;
        }

        //我一直觉得这段写很丑陋,谁能帮帮我改改
        public static WinHWND GetWinHWND(string sMark)
        {
            List<IntPtr> baseHwnds = WinAPI.GetChildHandles(IntPtr.Zero, GetBaseMark(sMark));
            string[] sChildMarks = GetChildMarks(sMark);
            //由于主窗口在桌面出现所以很可能同名,所以要看看他的儿子和孙子...是不是都匹配
            foreach (IntPtr baseHwnd in baseHwnds)
            {
                IntPtr handle = baseHwnd;
                for (int i = sChildMarks.Length - 1; i >= 0; i--)
                {
                    string[] sChildMark = sChildMarks[i].Split(':');
                    try
                    {
                        handle = WinAPI.GetChildHandles(handle, UnEscape(sChildMark[0]))[int.Parse(sChildMark[1])];
                    }
                    catch
                    {
                        break;
                    }

                    if (i == 0) return new WinHWND(handle);
                }
                continue;
            }

            return null;
        }

        #region 转义
        private static string Escape(string arg)
        {
            return arg.Replace(":", "\\:").Replace(";","\\;");
        }

        private static string UnEscape(string arg)
        {
            return arg.Replace("\\:", ":").Replace("\\;", ";");
        }
        #endregion

        public static WinHWND GetWinHWND()
        {
            return new WinHWND(WinAPI.GetHandle(WinAPI.GetCursorPosPoint()));
        }
    }

 

上全部代码,里面加了窗口的部分属性,扩展其他的属性,自己发挥吧,就是搞WinAPI

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Collections;

namespace InformationCollectionDataFill
{
public class WinAPI
{
#region WinodwsAPI
[DllImport(
"user32.dll", EntryPoint = "FindWindow")]
private static extern IntPtr FindWindow(string IpClassName, string IpWindowName);

[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

[DllImport("user32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, string lParam);

[DllImport("user32.dll", EntryPoint = "GetParent")]
public static extern IntPtr GetParent(IntPtr hWnd);

[DllImport("user32.dll", EntryPoint = "GetCursorPos")]
public static extern bool GetCursorPos(out Point pt);

[DllImport("user32.dll", EntryPoint = "WindowFromPoint", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr WindowFromPoint(Point pt);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowText(IntPtr hWnd, [Out, MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpString, int nMaxCount);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowRect(IntPtr hwnd, ref Rectangle rc);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetClientRect(IntPtr hwnd, ref Rectangle rc);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int MoveWindow(IntPtr hwnd, int x, int y, int nWidth, int nHeight, bool bRepaint);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
public static extern int ScreenToClient(IntPtr hWnd, ref Rectangle rect);
#endregion

#region 封装API方法
///<summary>
/// 找到句柄
///</summary>
///<param name="IpClassName">类名</param>
///<returns></returns>
public static IntPtr GetHandle(string IpClassName)
{
return FindWindow(IpClassName, null);
}

///<summary>
/// 找到句柄
///</summary>
///<param name="p">坐标</param>
///<returns></returns>
public static IntPtr GetHandle(Point p)
{
return WindowFromPoint(p);
}

//鼠标位置的坐标
public static Point GetCursorPosPoint()
{
Point p
= new Point();
if (GetCursorPos(out p))
{
return p;
}
return default(Point);
}

///<summary>
/// 子窗口句柄
///</summary>
///<param name="hwndParent">父窗口句柄</param>
///<param name="hwndChildAfter">前一个同目录级同名窗口句柄</param>
///<param name="lpszClass">类名</param>
///<returns></returns>
public static IntPtr GetChildHandle(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass)
{
return FindWindowEx(hwndParent, hwndChildAfter, lpszClass, null);
}

///<summary>
/// 全部子窗口句柄
///</summary>
///<param name="hwndParent">父窗口句柄</param>
///<param name="className">类名</param>
///<returns></returns>
public static List<IntPtr> GetChildHandles(IntPtr hwndParent, string className)
{
List
<IntPtr> resultList = new List<IntPtr>();
for (IntPtr hwndClient = GetChildHandle(hwndParent, IntPtr.Zero, className); hwndClient != IntPtr.Zero; hwndClient = GetChildHandle(hwndParent, hwndClient, className))
{
resultList.Add(hwndClient);
}

return resultList;
}

///<summary>
/// 给窗口发送内容
///</summary>
///<param name="hWnd">句柄</param>
///<param name="lParam">要发送的内容</param>
public static void SetText(IntPtr hWnd, string lParam)
{
SendMessage(hWnd, WM_SETTEXT, IntPtr.Zero, lParam);
}
private const int WM_SETTEXT = 0x000C;

///<summary>
/// 获得窗口内容或标题
///</summary>
///<param name="hWnd">句柄</param>
///<returns></returns>
public static string GetText(IntPtr hWnd)
{
StringBuilder result
= new StringBuilder(128);
GetWindowText(hWnd, result, result.Capacity);
return result.ToString();
}

///<summary>
/// 找类名
///</summary>
///<param name="hWnd">句柄</param>
///<returns></returns>
public static string GetClassName(IntPtr hWnd)
{
StringBuilder lpClassName
= new StringBuilder(128);
if (GetClassName(hWnd, lpClassName, lpClassName.Capacity) == 0)
{
throw new Exception("not found IntPtr!");
}
return lpClassName.ToString();
}

///<summary>
/// 窗口在屏幕位置
///</summary>
///<param name="hWnd">句柄</param>
///<returns></returns>
public static Rectangle GetWindowRect(IntPtr hWnd)
{
Rectangle result
= default(Rectangle);
GetWindowRect(hWnd,
ref result);
return result;
}

///<summary>
/// 窗口相对屏幕位置转换成父窗口位置
///</summary>
///<param name="hWnd"></param>
///<param name="rect"></param>
///<returns></returns>
public static Rectangle ScreenToClient(IntPtr hWnd, Rectangle rect)
{
Rectangle result
= rect;
ScreenToClient(hWnd,
ref result);
return result;
}

///<summary>
/// 窗口大小
///</summary>
///<param name="hWnd"></param>
///<returns></returns>
public static Rectangle GetClientRect(IntPtr hWnd)
{
Rectangle result
= default(Rectangle);
GetClientRect(hWnd,
ref result);
return result;
}
#endregion
}

public class WinHWND
{
public IntPtr HWND { get; set; }
public string ClassName { get; set; }
public WinHWND Parent { get; set; }
public int InParentSequence { get; set; }

private Rectangle _currentRect;
private string _Text;
private int _Left;
private int _Top;
private int _Width;
private int _Height;

public string Text
{
get
{
return _Text == default(string) ? WinAPI.GetText(this.HWND) : _Text;
}
set
{
_Text
= value;
WinAPI.SetText(
this.HWND, value);
}
}
public int Left
{
get
{
return _Left == default(int) ? _currentRect.Left : _Left;
}
set
{
_Left
= value;
WinAPI.MoveWindow(
this.HWND, value, this.Top, this.Width, this.Height, true);
}
}
public int Top
{
get
{
return _Top == default(int) ? _currentRect.Top : _Top;
}
set
{
_Top
= value;
WinAPI.MoveWindow(
this.HWND, this.Left, value, this.Width, this.Height, true);
}
}
public int Width
{
get
{
return _Width == default(int) ? _currentRect.Width : _Width;
}
set
{
_Width
= value;
WinAPI.MoveWindow(
this.HWND, this.Left, this.Top, value, this.Height, true);
}
}
public int Height
{
get
{
return _Height == default(int) ? _currentRect.Height : _Height;
}
set
{
_Height
= value;
WinAPI.MoveWindow(
this.HWND, this.Left, this.Top, this.Width, value, true);
}
}

private WinHWND() { }
public WinHWND(IntPtr hWnd)
{
this.HWND = hWnd;
this.ClassName = GetClassName();
this.Parent = GetParent();
this.InParentSequence = GetInParentSequence();
this._currentRect = GetRect();
}

private string GetClassName()
{
return WinAPI.GetClassName(this.HWND);
}
private WinHWND GetParent()
{
if (WinAPI.GetParent(this.HWND) == null)
{
throw new Exception("not found IntPtr!");
}

if (WinAPI.GetParent(this.HWND) == IntPtr.Zero)
{
return null;
}

return new WinHWND(WinAPI.GetParent(this.HWND));
}
private int GetInParentSequence()
{
IntPtr IntprtParent
= this.Parent == null ? IntPtr.Zero : this.Parent.HWND;
return WinAPI.GetChildHandles(IntprtParent, this.ClassName).IndexOf(this.HWND);
}
private Rectangle GetRect()
{
if (this.Parent == null) return default(Rectangle);
Rectangle clientSize
= WinAPI.GetClientRect(this.HWND);
Rectangle clientPoint
= WinAPI.ScreenToClient(this.Parent.HWND, WinAPI.GetWindowRect(this.HWND));
return new Rectangle(clientPoint.X, clientPoint.Y, clientSize.Width, clientSize.Height);
}

public static WinHWND GetWinHWND()
{
return new WinHWND(WinAPI.GetHandle(WinAPI.GetCursorPosPoint()));
}

public override string ToString()
{
StringBuilder result
= new StringBuilder();
for (WinHWND winHandle = this; winHandle != null; winHandle = winHandle.Parent)
{
result.Append(
string.Format("{0}:{1};", Escape(winHandle.ClassName), winHandle.InParentSequence.ToString()));
if (winHandle.InParentSequence == -1) break;
}
return result.ToString().TrimEnd(';');
}

private static string GetBaseMark(string sMark)
{
string[] sMarks = sMark.Split(';');
return sMarks[sMarks.Length - 1].Split(':')[0];
}

private static string[] GetChildMarks(string sMark)
{
string[] sMarks = sMark.Split(';');
string[] sChildMarks = new string[sMarks.Length - 1];
for (int i = 0; i < sChildMarks.Length; i ++ )
{
sChildMarks[i]
= sMarks[i];
}
return sChildMarks;
}

//我一直觉得这段写很丑陋,谁能帮帮我改改
public static WinHWND GetWinHWND(string sMark)
{
List
<IntPtr> baseHwnds = WinAPI.GetChildHandles(IntPtr.Zero, GetBaseMark(sMark));
string[] sChildMarks = GetChildMarks(sMark);
//由于主窗口在桌面出现所以很可能同名,所以要看看他的儿子和孙子...是不是都匹配
foreach (IntPtr baseHwnd in baseHwnds)
{
IntPtr handle
= baseHwnd;
for (int i = sChildMarks.Length - 1; i >= 0; i--)
{
string[] sChildMark = sChildMarks[i].Split(':');

抱歉!评论已关闭.