啥是句柄?
简单粗暴的讲句柄就是程序在运行过程中的一个对象标识,可以通过此标识来找到相应的对象,进而进行控制处理;需要注意的是句柄并不是一成不变的,前一次运行的程序句柄和后一次执行的句柄可能完全不一样;
简单的应用案例
有A窗体程序在运行也不支持中间件,但B程序还想将一部分数据跑送到A程序中,类似这样的问题就可以用句柄来解决
示例: A窗体程序如下所示
主要功能:只要有数据输入到文本框,回车后会自动加入到下面的list标签中,代码如下所示
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
{
this.listBox1.Items.Add(textBox1.Text);
textBox1.Text = "";
textBox1.Focus();
}
}
到咱们核心的程序了,如何通过句柄进行控制,这种代码网上一堆一堆,
引入user32.dll,声明代码如下:
[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);
[DllImport("shell32.dll")]
public static extern int ShellExecute(IntPtr hwnd, StringBuilder lpszOp, StringBuilder lpszFile, StringBuilder lpszParams, StringBuilder lpszDir, int FsShowCmd);
[DllImport("user32.dll")]
private static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, int lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, string lparam);
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]//查找窗口
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")]
private static extern int GetWindowTextW(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")]
private static extern int GetClassNameW(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder lpString, int nMaxCount);
private delegate bool WNDENUMPROC(IntPtr hWnd, int lParam);
//查找子控件
[DllImport("user32.dll", EntryPoint = "FindWindowEx", SetLastError = true)]
public 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 = "SendMessage")]
private static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam);
[DllImport("User32.dll", EntryPoint = "SendMessage")]
public static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
//窗口置顶
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
//遍历子控件
[DllImport("user32.dll")]
public static extern int EnumChildWindows(IntPtr hWndParent, CallBack lpfn, int lParam);
//回调函数
public delegate bool CallBack(IntPtr hwnd, int lParam);
获取窗体句柄的代码
//用到的两个结构体
public struct WindowInfo
{
public IntPtr hWnd;
public string szWindowName;
public string szClassName;
}
public struct ControInfo
{
public IntPtr hWnd;
public string ControName;
public string ClassName;
}
/// <summary>
/// 根据名称获取对应的窗体
/// </summary>
/// <param name="soft"></param>
/// <param name="classname"></param>
/// <returns></returns>
public static IntPtr FindWindowInfo(string soft, string classname = "")
{
WindowInfo[] a = GetAllDesktopWindows();
int i = 0;
int index = 0;
for (i = 0; i < a.Length; i++)
{
if (!classname.Equals(""))
{
if (a[i].szWindowName.ToString().Contains(soft) && classname == a[i].szClassName.ToString())
{
index = i;
break;
}
}
else
{
if (a[i].szWindowName.ToString().Contains(soft))
{
index = i;
break;
}
}
}
if (i == 0)
{
return (IntPtr)0;
}
return a[index].hWnd;
}
/// <summary>
/// 根据句柄获取对应的控件信息
/// </summary>
public static ControInfo[] GetALLControls(IntPtr parent)
{
List<ControInfo> ConList = new List<ControInfo>();
EnumChildWindows(parent, delegate (IntPtr hWnd, int lParam)
{
ControInfo wnd = new ControInfo();
wnd.hWnd = hWnd;
StringBuilder sb = new StringBuilder(256);
GetClassNameW(hWnd, sb, sb.Capacity);
wnd.ClassName = sb.ToString();
GetWindowTextW(hWnd, sb, sb.Capacity);
wnd.ControName = sb.ToString();
ConList.Add(wnd);
return true;
}, 0);
return ConList.ToArray();
}
核心的输入代码
private void timer1_Tick(object sender, EventArgs e)
{
//根据窗体名称Form1,找到对应的句柄
IntPtr intPtr1 = FindWindowInfo("Form1");
if (intPtr1 != IntPtr.Zero)
{
//根据窗体句柄找到对应的控件信息
ControInfo[] xxxx = GetALLControls(intPtr1);
foreach (var item in xxxx)
{
//根据控件的句柄信息,判断哪个是文本输入框
IntPtr input = FindWindowEx(intPtr1, item.hWnd, null, null);
if (input == IntPtr.Zero)
{ //注入文字
SendMessage(item.hWnd, WM_SETTEXT, IntPtr.Zero, "我是测试");
//输入回车符
// SendKeys.Send("{ENTER}");可以用这个方式,但是这种方式受限光标在哪可以
SendMessage(item.hWnd, WM_CHAR, 0, VK_RETURN);
SendMessage(item.hWnd, WM_CHAR, (IntPtr)VK_RETURN, IntPtr.Zero);//Enter
}
}
}
}
private const int WM_KEYDOWN = 0X100;
private const int WM_KEYUP = 0X101;
private const int WM_SYSCHAR = 0X106;
private const int WM_SYSKEYUP = 0X105;
private const int WM_SYSKEYDOWN = 0X104;
private const int WM_CHAR = 0X102;
private const int VK_RETURN = 0X0d;
附源码下载地址: