简体   繁体   English

在c#中将键击发送到应用程序(sendkeys,postmessage,sendmessage都不起作用)

[英]Send keystroke to application in c# (sendkeys, postmessage, sendmessage all not working)

I am trying to do one of the following 1. open desired program and press a key programmatically 2. find open window of program and press a key programmatically (either is fine) 我正在尝试执行以下操作之一1.打开所需程序并以编程方式按键2​​.找到程序打开窗口并以编程方式按键(或者很好)

I have tried numerous implementations of SendKeys.SendWait(), PostMessage(), and SendMessage() unsuccessfully. 我尝试了很多SendKeys.SendWait(),PostMessage()和SendMessage()的实现失败。 Below are my code snippets 以下是我的代码片段

    //included all these for attempts 
    [DllImport("User32.dll")] 
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);  

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

    [DllImport("User32.Dll", EntryPoint = "PostMessageA")]
    static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);

    [DllImport("user32.dll")]
    static extern byte VkKeyScan(char ch);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

Get handle of window, variables used by sendmessage/postmessage/sendkeys 获取sendmessage / postmessage / sendkeys使用的窗口,变量的句柄

IntPtr ptrOBS = proc.Handle;//this works properly, proc is instantiated properly
//IntPtr ptrOBS = FindWindow(null, "Open Broadcaster Software v0.472b");
SetForegroundWindow(ptrOBS);
const UInt32 WM_CHAR = 0x0102;
const uint WM_KEYDOWN = 0x100;
const int VK_R = 0x52; // taken from http://msdn.microsoft.com/en-us/library/dd375731(v=vs.85).aspx
const int VK_S = 0x53;

SendMessage attempt: SendMessage尝试:

SendMessage(ptrOBS, WM_KEYDOWN, (IntPtr)VK_R, (IntPtr)1);//tried both WM_CHAR and WM_KEYDOWN

PostMessage attempt: PostMessage尝试:

string message = "rs";
bool sent = PostMessage(ptrOBS, WM_KEYDOWN, VkKeyScan(message[0]), 0);

SendKeys attempt: SendKeys尝试:

SendKeys.SendWait("{r}");

Tried SetFocus on the parent window (application) and child window (button triggered by keypress im trying to send): 在父窗口(应用程序)和子窗口上尝试SetFocus(由按键触发的按钮即可尝试发送):

static void SetFocus(IntPtr hwndTarget, string childClassName)
    {
        // hwndTarget is the other app's main window 
        // ...
        IntPtr targetThreadID = GetWindowThreadProcessId(hwndTarget, IntPtr.Zero); //target thread id
        IntPtr myThreadID = GetCurrentThread(); // calling thread id, our thread id
        try
        {
            bool lRet = AttachThreadInput(myThreadID, targetThreadID, -1); // attach current thread id to target window

            // if it's not already in the foreground...
            lRet = BringWindowToTop(hwndTarget);
            SetForegroundWindow(hwndTarget);

            // if you know the child win class name do something like this (enumerate windows using Win API again)...
            IntPtr hwndChild = (IntPtr)1183492;//(IntPtr)EnumAllWindows(hwndTarget, childClassName).FirstOrDefault();

            if (hwndChild == IntPtr.Zero)
            {
                // or use keyboard etc. to focus, i.e. send keys/input...
                // SendInput (...);
                return;
            }

            // you can use also the edit control's hwnd or some child window (of target) here
            SetFocus(hwndChild); // hwndTarget);
            SendKeys.SendWait("{r}");
        }
        finally
        {
            SendKeys.SendWait("{r}");
            bool lRet = AttachThreadInput(myThreadID, targetThreadID, 0); //detach from foreground window
            SendKeys.SendWait("{r}");
        }
    }

For NSGaga: 对于NSGaga:

    string windowName = "Open Broadcaster Software v0.472b";
IntPtr outerPtr = FindWindow(null, windowName);
IntPtr ptrOBS = (IntPtr)527814;//button that im trying to trigger keypress on
SetForegroundWindow(outerPtr);
SetForegroundWindow(ptrOBS);
SetFocus(outerPtr, "OBSWindowClass");//SetFocus(ptrOBS, "Button");
const UInt32 WM_CHAR = 0x0102;
const int VK_R = 0x52; // taken from http://msdn.microsoft.com/en-us/library/dd375731(v=vs.85).aspx
const int VK_S = 0x53;

//SetForegroundWindow(ptrOBS);
System.Threading.Thread.Sleep(3000);
SendKeys.SendWait("{r}");
SendMessage(outerPtr, WM_KEYDOWN, (IntPtr)VK_R, (IntPtr)1);
PostMessage(outerPtr, WM_KEYDOWN, VkKeyScan('r'), 0);

You cannot reliably use SendMessage and PostMessage for synthesizing keyboard input . 您无法可靠地使用SendMessagePostMessage来合成键盘输入 They are just not designed for this. 它们不是为此而设计的。 These messages ( WM_CHAR , WM_KEYDOWN , etc.) are notifications raised by lower-level subsystems when keyboard input has been received, processed, and forwarded on to the appropriate recipient. 这些消息( WM_CHARWM_KEYDOWN等)是在接收,处理并转发到适当的收件人的键盘输入时由较低级子系统引发的通知 Sending or posting these messages yourself is like prank-calling someone. 自己发送或发布这些消息就像恶作剧一样。

SendKeys (like all other input synthesizer methods, including the SendInput function which was explicitly designed for synthesizing keyboard input and in at least some implementation is what SendKeys actually uses under the hood) works only when the window you wish to receive the keyboard input has the focus. SendKeys (与所有其他输入合成器方法一样,包括明确设计用于合成键盘输入的SendInput函数,至少在某些实现中是SendKeys实际使用的内容)仅当您希望接收键盘输入的窗口具有焦点。 In Windows, only focused (active) windows receive input events. 在Windows中,只有聚焦(活动)窗口接收输入事件。

So SendKeys is probably the way to go if you're ever going to get this to work (either that or P/Invoking SendInput and all of its associated structures), but you do need to respect the caveat that the recipient window must have the focus. 所以SendKeys可能是你要去的工作方式(无论是P / Invoking SendInput及其所有相关结构),但你需要尊重收件人窗口必须具有的警告。焦点。 Otherwise, it's not going to get anything. 否则,它不会得到任何东西。

It looks like from your sample code that you're trying to use the SetForegroundWindow function to meet this precondition. 从您的示例代码看,您尝试使用SetForegroundWindow函数来满足此前提条件。 Unfortunately, you're passing it an invalid value, and not doing any error checking that might alert you to this mistake. 不幸的是,你传递的是一个无效的值,并没有做任何可能提醒你注意这个错误的错误检查。 Specifically, this code is wrong: 具体来说,这段代码是错误的:

IntPtr ptrOBS = proc.Handle;//this works properly, proc is instantiated properly
SetForegroundWindow(ptrOBS); // WRONG, ptrOBS is not a window handle

Even if I trust you on ptrOBS being initialized correctly, that makes it a valid handle to a process , which is a very different thing than a valid handle to a window . 即使我信任你正确初始化ptrOBS ,这也使它成为进程的有效句柄,这与窗口的有效句柄完全不同。 Aside from the obvious nominal differences, processes can have multiple windows and only a single window can have the focus (ie, be "in the foreground"). 除了明显的名义差异外,进程可以有多个窗口,只有一个窗口可以有焦点(即“在前台”)。

You will need to obtain the handle to a particular window before calling SetForegroundWindow , and given that we know a process can have multiple windows, that can be tricky. 在调用SetForegroundWindow之前,您需要获取特定窗口的句柄,并且假设我们知道一个进程可以有多个窗口,这可能很棘手。 You need some reliable way of determining which window you want. 您需要一些可靠的方法来确定您想要的窗口。 Lots of people accomplish this by hard-coding the name of the window as a string, which works great until the target app is recompiled and this implementation detail changes. 很多人通过将窗口的名称硬编码为字符串来实现这一目标,这种方法很有效,直到目标应用程序被重新编译并且此实现细节发生变化。 The only bulletproof way that I can think of is to have the user click the target window and your code to retrieve the handle of the window that is currently under the mouse pointer. 我能想到的唯一防弹方法是让用户单击目标窗口和代码来检索当前位于鼠标指针下的窗口的句柄。

And of course all of this assumes that you've observed the restrictions on the use of SetForegroundWindow , enumerated in the "Remarks" section of the linked SDK documentation. 当然,所有这些都假定您已经观察到使用SetForegroundWindow的限制,这些限制在链接的SDK文档的“备注”部分中列举。

There is lot of trial and error with that, to get it working 为了让它发挥作用,有很多试验和错误
Here is a bit of code I posted before, you might wanna give a try (and there is some more info attached)... 这里是我之前发布的一些代码,你可能想尝试一下(并附上一些更多的信息)......

Pinvoke SetFocus to a particular control Pinvoke SetFocus到特定的控件

Try setting focus first (using the mechanism mentioned) - and then using SendKeys or SendInput . 首先尝试设置焦点(使用提到的机制) - 然后使用SendKeysSendInput

Here is some detailed code for SendInput ... 这是SendInput一些详细代码......

How to send a string to other application including Microsoft Word 如何将字符串发送到其他应用程序,包括Microsoft Word

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM