不在同一程序内,如何在光标处(当前有焦点的窗体输入框)输入字符
因测试一个程序,该程序的安卓端执行扫描条码二维码操作,然后服务器端需要在PC当前处于激活状态的窗体的当前光标处显示安卓程序扫描到的条形码。这是博主“小李飞菜刀”的扫描宝服务程序。场景就是苦于手边没有扫描枪,又想测试条码扫描。“小李飞菜刀”同学使用的是 "SendKeys"的“Send”方法。这是同一应用才能有效的办法。如果需要在其他应用的光标处输入字符,就只有使用"SendMessage"的windows api了。经过一番搜索,抄到段代码,测试了一下没有效果,TNND。请围观:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | [DllImport( "user32.dll" )] public static extern IntPtr GetForegroundWindow(); [DllImport( "user32.dll" , CharSet = CharSet.Auto)] public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); [DllImport( "user32.dll" )] static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId); [DllImport( "user32.dll" )] static extern bool GetGUIThreadInfo( uint idThread, ref GUITHREADINFO lpgui); [StructLayout(LayoutKind.Sequential)] public struct GUITHREADINFO { public int cbSize; public int flags; public IntPtr hwndActive; public IntPtr hwndFocus; public IntPtr hwndCapture; public IntPtr hwndMenuOwner; public IntPtr hwndMoveSize; public IntPtr hwndCaret; public RECT rectCaret; } public static GUITHREADINFO? GetGuiThreadInfo(IntPtr hwnd) { if (hwnd != IntPtr.Zero) { //Mbox.Info(GetTitle(hwnd), "O"); uint threadId = GetWindowThreadProcessId(hwnd, IntPtr.Zero); GUITHREADINFO guiThreadInfo = new GUITHREADINFO(); guiThreadInfo.cbSize = Marshal.SizeOf(guiThreadInfo); if (GetGUIThreadInfo(threadId, ref guiThreadInfo) == false ) return null ; return guiThreadInfo; } return null ; } public static void SendText( string text) { IntPtr hwnd = GetForegroundWindow(); if (String.IsNullOrEmpty(text)) return ; Hwindow.GUITHREADINFO? guiInfo = Hwindow.GetGuiThreadInfo(hwnd); if (guiInfo != null ) { IntPtr ptr = (IntPtr)guiInfo.Value.hwndCaret; if (ptr != IntPtr.Zero) { for ( int i = 0; i < text.Length; i++) { SendMessage(ptr, Message.WM_CHAR, (IntPtr)( int )text[i], IntPtr.Zero); } } } } |
这是csdn抄的,原文:C#怎么获得当前屏幕光标的位置,然后在光标的位置上输入想输入数据。
发现RECT没办法被感知,又一番搜索发现是个结构体:
1 2 3 4 5 6 7 8 | [StructLayout(LayoutKind.Sequential)] public struct RECT { int left; int top; int right; int bottom; } |
加上之后可以编译成功。但是没效果,仔细调试下来对方法“SendText”进行了修改。代码的主要思路:用GetForegroundWindow找到焦点窗体,
然后GetWindowThreadProcessId和GetGUIThreadInfo找到含有光标的控件句柄,即GUITHREADINFO中的hwndCaret,然后用该句柄发送消息。
下面贴上修改后有效果的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | [DllImport( "user32.dll" )] public static extern IntPtr GetForegroundWindow(); [DllImport( "user32.dll" , CharSet = CharSet.Auto)] public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); [DllImport( "user32.dll" )] static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId); [DllImport( "user32.dll" )] static extern bool GetGUIThreadInfo( uint idThread, ref GUITHREADINFO lpgui); [StructLayout(LayoutKind.Sequential)] public struct GUITHREADINFO { public int cbSize; public int flags; public IntPtr hwndActive; public IntPtr hwndFocus; public IntPtr hwndCapture; public IntPtr hwndMenuOwner; public IntPtr hwndMoveSize; public IntPtr hwndCaret; public RECT rectCaret; } [StructLayout(LayoutKind.Sequential)] public struct RECT { int left; int top; int right; int bottom; } public GUITHREADINFO? GetGuiThreadInfo(IntPtr hwnd) { if (hwnd != IntPtr.Zero) { uint threadId = GetWindowThreadProcessId(hwnd, IntPtr.Zero); GUITHREADINFO guiThreadInfo = new GUITHREADINFO(); guiThreadInfo.cbSize = Marshal.SizeOf(guiThreadInfo); if (GetGUIThreadInfo(threadId, ref guiThreadInfo) == false ) return null ; return guiThreadInfo; } return null ; } protected void SendText( string text) { IntPtr hwnd = GetForegroundWindow(); if (String.IsNullOrEmpty(text)) return ; GUITHREADINFO? guiInfo = GetGuiThreadInfo(hwnd); if (guiInfo != null ) { for ( int i = 0; i < text.Length; i++) { SendMessage(guiInfo.Value.hwndFocus, 0x0102, (IntPtr)( int )text[i], IntPtr.Zero); } } } |
主要发现 “IntPtr ptr = (IntPtr)guiInfo.Value.hwndCaret;”,这里始终是0.改成: SendMessage(guiInfo.Value.hwndFocus, 0x0102, (IntPtr)(int)text[i], IntPtr.Zero);
hwndFocus字面意思就是当前光标处的句柄。搞定,收工!
作者:数据酷软件
出处:https://www.cnblogs.com/datacool/p/win_api_sendmessage_hwndFocus.html
关于作者:20年编程从业经验,持续关注MES/ERP/POS/WMS/工业自动化
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明。
联系方式: qq:71008973;wx:6857740733
基于人脸识别的考勤系统 地址: https://gitee.com/afeng124/viewface_attendance_ext
自己开发安卓应用框架 地址: https://gitee.com/afeng124/android-app-frame
WPOS(warehouse+pos) 后台演示地址: http://47.239.106.75:8080/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构