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

160 阅读3分钟

业务场景

最近接到一个需求,向一个程序(简称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;

效果展示