不在同一程序内,如何在光标处(当前有焦点的窗体输入框)输入字符

因测试一个程序,该程序的安卓端执行扫描条码二维码操作,然后服务器端需要在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字面意思就是当前光标处的句柄。搞定,收工!

 

posted @   数据酷软件  阅读(3575)  评论(1编辑  收藏  举报
编辑推荐:
· 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语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示