因测试一个程序,该程序的安卓端执行扫描条码二维码操作,然后服务器端需要在PC当前处于激活状态的窗体的当前光标处显示安卓程序扫描到的条形码。这是博主“小李飞菜刀”的扫描宝服务程序。场景就是苦于手边没有扫描枪,又想测试条码扫描。“小李飞菜刀”同学使用的是 "SendKeys"的“Send”方法。这是同一应用才能有效的办法。如果需要在其他应用的光标处输入字符,就只有使用"SendMessage"的windows api了。经过一番搜索,抄到段代码,测试了一下没有效果,TNND。请围观:
[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没办法被感知,又一番搜索发现是个结构体:
[StructLayout(LayoutKind.Sequential)] public struct RECT { int left; int top; int right; int bottom; }
加上之后可以编译成功。但是没效果,仔细调试下来对方法“SendText”进行了修改。代码的主要思路:用GetForegroundWindow找到焦点窗体,
然后GetWindowThreadProcessId和GetGUIThreadInfo找到含有光标的控件句柄,即GUITHREADINFO中的hwndCaret,然后用该句柄发送消息。
下面贴上修改后有效果的代码:
[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字面意思就是当前光标处的句柄。搞定,收工!