我实现了一个程序向另一程序数据输入

简介: 本文介绍了通过自动扫码设备向A程序文本框输入数据的实现方案。主要解决用户无感对接需求,采用Windows API函数获取A程序窗口句柄及文本框地址,完成自动化键盘输入。工具选择上使用了精益编程助手,通过具体代码示例展示了如何枚举窗口、查找控件并发送消息。最终效果实现了条码数据自动输入,不影响电脑正常使用,提升了用户体验和程序专业性。

业务场景

最近接到一个需求,向一个程序(简称A程序)指定的文本框输入数据。其实是一个扫码输入场景,之前是通过手持扫码枪通过USB连接电脑,然后光标放入A程序文本框以后,手动扫码就可以输入了。这个需求是通过自动扫码设备,读取条码数据自动输入到A程序的文本框。考虑到有几种解决方案,有自动化脚本,实现自动点击自动输入,其实作为我这个场景,更多的需求是用户体验,无感对接。经过比对以后,采用句柄的窗口进行键盘输入。这样的方案,主要是通过Windows API函数,获取A程序窗口句柄,然后获取文本框的具体地址,进行输入实现。这样实现方式,不影响电脑正常使用,让程序显得更加专业化。

工具选择

获取窗口句柄的工具有很多,本文精益编程助手为例。

实现过程

首先我们就要获取A程序的窗口句柄。

A程序窗口

打开精益编程助手,找到要输入的窗口。

引入Window API

[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);
//根据窗体名称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;

效果展示



目录
相关文章
|
数据挖掘 定位技术
男性多项身体维度数据探索
男性多项身体维度数据探索
559 0
|
C# 编解码
WPF C# 多屏情况下,实现窗体显示到指定的屏幕内
原文:WPF C# 多屏情况下,实现窗体显示到指定的屏幕内 针对于一个程序,需要在两个显示屏上显示不同的窗体,(亦或N个显示屏N个窗体),可以使用如下的方式实现。
5470 0
|
存储 安全 Android开发
F-Droid:尊重自由与隐私的安卓应用商店
F-Droid 是安卓平台上的自由开源应用商店,专为关注隐私和数据安全的用户设计。本文详细介绍了 F-Droid 的特点,包括其对自由和隐私的重视、无广告和无追踪代码的承诺、强大的应用搜索与管理功能,以及对开源社区的支持。用户可以通过 F-Droid 安全地浏览、安装和管理应用程序,并且开发者也可以发布开源应用。未来,F-Droid 将继续提升用户体验,鼓励更多的开发者与用户参与其中,推动自由开源软件的发展。
1448 1
|
存储 分布式计算 Apache
阿里云 EMR 基于 Paimon 和 Hudi 构建 Streaming Lakehouse
Apache Paimon 和 Apache Hudi 作为数据湖存储格式,有着高吞吐的写入和低延迟的查询性能,是构建数据湖的常用组件。本文在阿里云EMR上,针对数据实时入湖场景,对 Paimon 和 Hudi 的性能进行比对,并分别以 Paimon 和 Hudi 作为统一存储搭建准实时数仓。
65627 1
阿里云 EMR 基于 Paimon 和 Hudi 构建 Streaming Lakehouse
|
关系型数据库 Shell Nacos
【SpringCloud-Alibaba系列教程】16.动态配置yml以及分布式事务
动态配置yml、分布式事务以及使用seata。
1303 1
【SpringCloud-Alibaba系列教程】16.动态配置yml以及分布式事务
|
SQL 存储 设计模式
如何与死锁斗争!!!
尽量不要改动线上数据库的字段,因为会触发锁表影响业务,严重时还可能出现死锁!数据库真的出现了死锁,业务全挂了,这种时候应该怎么办呢?本文就给大家分享一下数据库死锁的排查思路,万一出了问题,也有底气去解决。
147 1
|
机器学习/深度学习 文字识别 算法
[Halcon&图像] 基于多层神经网络MLP分类器的思想提取颜色区域
[Halcon&图像] 基于多层神经网络MLP分类器的思想提取颜色区域
574 0
|
监控 安全 NoSQL
一文搞懂并学会使用SpringBoot的Actuator运行状态监控组件
微服务之后,系统结构拆分随着业务发展越来越微型化,也意味着节点会呈现几何数量级增长。每个一个节点都是系统组成部分,如何保持如此多节点的可用性是一件非常有挑战的工作。
891 0
|
存储 DataX C语言
数据结构——单链表
数据结构——单链表