将密钥发送到后台 [英] Send Keys to background

查看:127
本文介绍了将密钥发送到后台的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将密钥发送到后台应用程序,但似乎无法使它起作用:(

通过使我的应用程序将另一个应用程序放在最前面,我可以使我的应用程序将密钥发送到另一个应用程序,但是我似乎无法将其发送到非活动窗口.有人能指出我的正确方向吗?我不熟悉使用发送密钥/发布消息进行编程的习惯,所以很好:)感谢您的帮助.

然后,我用于发送密钥的代码如下.

I am trying to send keys to a background application and I cannot seem to get it to work :(

I can make my application send keys to another application, by making my application bring the other application to the front, but I can''t seem to make is send it to a non active window. Could anyone point me in a good direction? I am new to programing with send keys/post message and such so be nice :) Thanks for your help.

Then code I use for sending keys is as follows.

private void button1_Click(object sender, EventArgs e)
{



IntPtr findVulcan = FindWindow(null, GameWindow.Text);
SetForegroundWindow(findVulcan);
Thread.Sleep(1000);
SendKeys.SendWait(Username.Text);
SendKeys.SendWait("{TAB}");
SendKeys.SendWait(Password.Text);
SendKeys.SendWait("{ENTER}");
Thread.Sleep(5000);
SendKeys.SendWait("{ENTER}");
Thread.Sleep(5000);
SendKeys.SendWait("{ENTER}");
Thread.Sleep(5000);
SendKeys.SendWait("{ENTER}");

推荐答案

Fapsterx,

这应该给您一个想法.您的问题是:大多数情况下,您无法将输入发送到应用程序的主窗口.大多数应用程序使用某种子窗口进行编辑(文本框等).

因此,您只能向这些人发送输入消息.但是如何找到它们呢?那就是最困难的部分,我不知道最终的答案,您必须为每个应用程序找出答案(可以使用诸如spy ++之类的工具)
我的代码以记事本为例显示了所需的步骤.(编辑控件类为编辑").
这是一个完整的示例,只需复制到新的控制台项目,添加对WindowsForms的引用(或从WindowsForms项目开始). (我们在这里需要使用Clipboard类的参考).
然后启动记事本并运行代码(警告:不存在错误处理!)


Hi Fapsterx,

This should give you an idea. Your problem is: most times you can not send an input to the main window of an application. Most applications use some kind of child-window for editing (a TextBox, whatever).

So you can only send input messages to those. But how to find them? Thats the difficult part, and I dont know the ultimate answer, you have to find it out for every application (you could use tools like spy++)
My code shows the needed steps with notepad as an example.(the edit controls class is "Edit").
It''s a complete example just copy to a new console project, add a reference to WindowsForms (or start with a WindowsForms project). (We need the reference here for using the Clipboard class).
Then start notepad and run the code (caution no error handling present!)


using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace SendKeysToAnyApplication
{
    class Program
    {
        delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

        [DllImport("user32.dll")]
        static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam);
        [DllImport("user32.dll")]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("user32.dll")]
        static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
        [DllImport("user32.dll")]
        static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

        const uint WM_CHAR = 0x102;
        const uint WM_PASTE = 0x0302;

        static IntPtr m_hWndEdit = IntPtr.Zero;

        [STAThread]
        static void Main(string[] args)
        {
            // for a test we use the notepad window
            // ... so lets have a look if we find an opened notepad window (better you open one first...)
            IntPtr hWnd = FindWindow("Notepad", null);
            // But! we can not send text to the main-window, we have to find the subwindow where the text is entered
            // So lets enumerate all child windows:
            IntPtr hWndEdit = IntPtr.Zero;
            EnumChildWindows(hWnd, EnumChildWindowsCallback, hWndEdit);

            if (m_hWndEdit != null) // edit window found?
            {
                // Now you could use different messages to send text (WM_CHAR, WM_KEYDOWN, ...)
                // I decided to use the clipboard:
                // Copy some text to the clipboard
                Clipboard.SetText("this is magic!");
                // ... and just paste it to the target window
                SendMessage(m_hWndEdit, WM_PASTE, 0, 0);
            }
        }

        static bool EnumChildWindowsCallback(IntPtr hWnd, IntPtr lParam)
        {
            // Search for notepads edit window - if we find it "false" is returned (means stop enumerating windows)

            StringBuilder sb = new StringBuilder();
            GetClassName(hWnd, sb, 256);
            if (!sb.ToString().Contains("Edit"))
            {
                return true;
            }

            m_hWndEdit = hWnd; // Store the handle to notepads edit window (this is the window we want to send the messages to)
            return false;
        }
    }
}


您正在自己的应用程序窗口中调用SendKeys.尝试在使用FindWindow调用获取的窗口的窗口句柄上调用SendKeys. :)
You are calling SendKeys on your own appplication''s window. Try to call SendKeys on the window''s handle for the window that you are getting with the FindWindow call. :)


我将提供一个解决方案,但是您将需要访问试图将消息发送到的应用程序代码.如果无法理解,那可能是您不走运.但是,我认为重要的是要理解为什么...

Windows在引擎盖下有一个控制器,可轮询键盘和鼠标缓冲区以确定用户何时提供输入.它接受这些输入并将其转换为事件,然后将其分派给当前正在运行的应用程序和服务(从活动应用程序开始……这是关键点).

依次在Windows中运行的应用程序每个都有一个主事件服务循环(消息泵).作为使用高级语言的开发人员,我们通常不与程序的那部分交互,而是向C ++ MFC/ATL人员询问有关它们的信息.消息泵接收传入的事件消息(该消息可以来自任何地方. (不仅是Windows控制器)按顺序进行处理,还可以选择通过事件将它们冒泡到应用程序层次结构中.树中的每个组件都可以选择使用事件,并将完成的位设置为true和/或将事件进一步传递到树中.这是应用程序执行注册事件处理程序的方式,而开发人员无需编写任何代码来解释鼠标和键盘事件.消息泵处理所有这些,仅调用适当的事件处理程序.

您遇到的问题是所有用户输入的Windows ASSUMES中的低级输入控制器都被定向到活动窗口.毕竟,这是Windows中的一种基本断言,例如,如果在不活动的窗口中滚动滚轮,则活动窗口将滚动而不是鼠标滚动的原因.超过. (例如,在x-windows中这是不同的,例如,移动鼠标会更改活动窗口).SendKeys命令将消息发送到低级Windows输入控制器,后者又将消息发送到活动窗口.消息泵.活动窗口将处理事件并将事件标记为完成.这就是为什么当您使用SendKeys时,它将仅与活动窗口一起使用的原因.在您的代码中,您将获得背景窗口的句柄,但没有调用SetForegroundWindow(使目标成为活动窗口),实际上,您是将键发送到当前处于活动状态的任何窗口.

据我所知,在托管代码中没有任何方法可以指示Windows输入控制器将消息发送到非活动窗口,也没有方法将消息直接发送到另一个窗口的消息泵. >
所以,您可以做两件事之一...

首先,抓住当前活动窗口的句柄,找到您的背景窗口,使其成为活动窗口,发送密钥,然后将原始活动窗口再次设为活动窗口(从而使桌面返回到原始状态).缺点是随着代码的延迟,该操作将可见,并且会中断用户的操作.

另外,一种干净的解决方案是进程间通信.有多种方法可以完成此操作,但是所有这些方法都需要您的目标"应用程序通过套接字或命名管道或其他某种机制来监听消息.这就是为什么我说您需要访问后台应用程序的源代码的原因……您将不得不添加此功能.希望这是您能够做到的.
I''ll offer a solution but you are going to need access to the application''s code that you are trying to send the message to. If you can''t get that you are probably out of luck. But, it is important, I think, to understand why...

Windows has a controller under the hood that polls the keyboard and mouse buffers to determine when the user has provided input. It takes these inputs and turns them into events that it dispatches out to the currently running applications and services (starting with the active application... this is a key point).

Application running in Windows, in turn, each have a main event servicing loop (the message pump). As developers in a higher-level language we don''t typically interact with that part of the program but ask a C++ MFC/ATL guy about them... The message pump receives the incoming event messages (which can come from anywhere... not just the Windows controller) in order and processes them, optionally bubbling them up through the application hierarchy via an event. Each component in the tree has the option of consuming the event and setting the completed bit to true and/or passing the event further up the tree. This is how applications execute registered event handlers without the developers having to write any code to interpret the mouse and keyboard events. The message pump handles all of that and just calls the appropriate event handlers.

The problem you have is that the low-level input controller in Windows ASSUMES that all user input is directed to the active window. That is, after all, one of the basic assertions in Windows and is the reason that, for example, if you roll the scroll wheel in a window that isn''t active, the active window will scroll rather than the one the mouse is over. (This is different in x-windows, for example, where moving the mouse changes the active window) The SendKeys command sends a message to the low-level Windows input controller which, in turn, sends the message to the active window''s message pump. The active window will handle the event and mark the event as complete. That is why when you use SendKeys it will only work with the active window. In your code, you get a handle to the background window but without the call to SetForegroundWindow which makes your target the active window, you are, in reality, sending your keys to whatever window is currently active.

There is, to my knowledge, no way in managed code of directing the windows input controller to send a message to the non-active window nor is there a way to send a message directly to another window''s message pump.

So, you could do one of two things...

First, grab a handle to the currently active window, find your background window, make it the active window, send your keys, then make the original active window the active window again (thereby returning the desktop to the original state). The drawback is that with the delays in your code, that operation will be visible and will interrupt whatever the user is doing.

Alternatively, a clean solution is inter-process communications. There are a number of ways to accomplish this but all of them will require your ''target'' application to be listening for the messages... via a socket or a named pipe or some other mechanism. That is why I said you need access to the background app''s source code... you will have to add this functionality. Hope that is something you''ll be able to do.


这篇关于将密钥发送到后台的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆