向非活动应用程序发送密钥

Posted

技术标签:

【中文标题】向非活动应用程序发送密钥【英文标题】:SendKeys to inactive application 【发布时间】:2014-02-15 20:24:28 【问题描述】:

我试图弄清楚如何让我的 C# 应用程序将密钥发送到另一个应用程序窗口,而不是关注它。 我有一个单词列表和 3 个记事本文件。 想象一下,我按顺序打开了所有 3 个记事本窗口,我的程序将获取列表框中的第一个单词并将其写入第一个记事本窗口。第二个记事本窗口中的第二个单词和第三个记事本窗口中的第三个单词。然后重新开始并继续。 所以我希望它在每个单词中发布 1 个单词,然后一遍又一遍地继续。

但我只知道如何使用 1 个记事本窗口(在它处于活动状态时)来做到这一点。

int i = 0;
i = listBox1.SelectedIndex;
i = i + 1;
if (i > listBox1.Items.Count - 1)
    i = 0;
listBox1.SelectedIndex = i;
string message = listBox1.SelectedItem.ToString();

SendKeys.Send(message);
SendKeys.Send("ENTER");

这需要我首先关注记事本窗口,启动计时器,然后继续关注记事本窗口。然后它会遍历列表并输入单词(每行 1)。它工作正常。但我希望能够在 3 个窗口上完成。

然后我需要以某种方式获取窗口标题,而不是进程名称。 那时我将有 3 个称为记事本的进程。 但是如果它们被命名为 Note1、Note2、Note3,我该怎么做呢?

我需要帮助来列出要写入哪些程序的列表:

listofprograms = ["Note1", "Note2", "Note3"];

它会发现以这些名称打开的应用程序窗口, 然后以某种方式将文本写入这些窗口。

谁能帮帮我?到目前为止还没有发现任何关于这方面的信息,相信我,我已经环顾四周了!

【问题讨论】:

【参考方案1】:

不幸的是,没有很好的方法来做到这一点。 SendKeys 是一个非常简单且理想的 API,但它仅适用于活动窗口。没有办法让它在非活动窗口上工作,也没有与在非活动窗口上工作一样易于访问的 API。

通常当人们遇到这个问题时,他们必须走两条路中的一条

    物理激活您想要一次将密钥发送到一个的应用程序 下拉到SendMessagePostMessage 的更低级别以发送键盘事件

第二个选项通常更可靠但更难实施。

【讨论】:

假设 1 你的意思是激活,这可能有助于 OP ***.com/questions/825651/… 我不想把注意力放在任何记事本窗口上。这很容易做到,但重点是我希望能够将列表框中的文本直接发送到这些窗口中。它们可以被最小化或其他。有没有简单的方法可以做到这一点? @user3036459 不,在这种情况下,您几乎必须求助于SendMessagePostMessage 来发送密钥【参考方案2】:

SendKeys 不适用于此类功能。要执行您要查找的操作,您需要在代码中使用一些 Win32 API 调用。参考How to send text to Notepad in C#/Win32?。

【讨论】:

【参考方案3】:

如果您正在寻找一种将密钥发送到应用程序的方法,可以选择使用 SendKeys.Send(keys),但您需要通过 SetForegroundWindow API 将窗口置于顶部。

因此,如果您继续使用您的方法,您可以使用 FindWindow、SetForegroundWindow 来强制激活记事本窗口并获得焦点,以便您可以发送密钥。

[DllImportAttribute("User32.dll")]
private static extern int FindWindow(String ClassName, String WindowName);

[DllImport("user32.dll")]
private static extern IntPtr SetForegroundWindow(int hWnd);

public int Activate(int hWnd)

   if (hWnd > 0) 
      SetForegroundWindow(hWnd);
      return hWnd;
   
   else 
       return -1;
   


public int GetWindowHwnd(string className, string windowName) 
     int hwnd = 0;
     string cls = className == string.Empty  ? null : className;
     string win = windowName == string.Empty ? null : windowName;

     hwnd = FindWindow(cls , win );
     return hwnd;

虽然还有另一种解决方案,可以帮助您。这里处理了所有记事本进程:

How to send text to Notepad in C#/Win32?

经过一些调整,它也应该适用于您的情况(基本上,您将迭代并循环通过找到的记事本实例并在每个实例中放置一个单词)。

您可能还想查看以下有关 FindWindow 的信息:

http://www.pinvoke.net/default.aspx/user32.findwindow

设置键盘状态

http://www.pinvoke.net/default.aspx/user32/SetKeyboardState.html

以及SendMessage

http://www.pinvoke.net/default.aspx/coredll/SendMessage.html

您应该在示例和说明中找到一些有用的提示。

【讨论】:

以上是关于向非活动应用程序发送密钥的主要内容,如果未能解决你的问题,请参考以下文章

是否可以构建应用程序以向非应用程序用户发送通知

向非 Stomp/Websocket 消费者发送消息

向非联系人发送谷歌群聊邀请

对“XXX::Invoke”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们

类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们的问题的解决方法

对“xxx”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们。 错误解决一例。(代码片段