繁体   English   中英

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

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

我正在尝试执行以下操作之一1.打开所需程序并以编程方式按键2​​.找到程序打开窗口并以编程方式按键(或者很好)

我尝试了很多SendKeys.SendWait(),PostMessage()和SendMessage()的实现失败。 以下是我的代码片段

    //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);

获取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尝试:

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

PostMessage尝试:

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

SendKeys尝试:

SendKeys.SendWait("{r}");

在父窗口(应用程序)和子窗口上尝试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}");
        }
    }

对于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);

您无法可靠地使用SendMessagePostMessage来合成键盘输入 它们不是为此而设计的。 这些消息( WM_CHARWM_KEYDOWN等)是在接收,处理并转发到适当的收件人的键盘输入时由较低级子系统引发的通知 自己发送或发布这些消息就像恶作剧一样。

SendKeys (与所有其他输入合成器方法一样,包括明确设计用于合成键盘输入的SendInput函数,至少在某些实现中是SendKeys实际使用的内容)仅当您希望接收键盘输入的窗口具有焦点。 在Windows中,只有聚焦(活动)窗口接收输入事件。

所以SendKeys可能是你要去的工作方式(无论是P / Invoking SendInput及其所有相关结构),但你需要尊重收件人窗口必须具有的警告。焦点。 否则,它不会得到任何东西。

从您的示例代码看,您尝试使用SetForegroundWindow函数来满足此前提条件。 不幸的是,你传递的是一个无效的值,并没有做任何可能提醒你注意这个错误的错误检查。 具体来说,这段代码是错误的:

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

即使我信任你正确初始化ptrOBS ,这也使它成为进程的有效句柄,这与窗口的有效句柄完全不同。 除了明显的名义差异外,进程可以有多个窗口,只有一个窗口可以有焦点(即“在前台”)。

在调用SetForegroundWindow之前,您需要获取特定窗口的句柄,并且假设我们知道一个进程可以有多个窗口,这可能很棘手。 您需要一些可靠的方法来确定您想要的窗口。 很多人通过将窗口的名称硬编码为字符串来实现这一目标,这种方法很有效,直到目标应用程序被重新编译并且此实现细节发生变化。 我能想到的唯一防弹方法是让用户单击目标窗口和代码来检索当前位于鼠标指针下的窗口的句柄。

当然,所有这些都假定您已经观察到使用SetForegroundWindow的限制,这些限制在链接的SDK文档的“备注”部分中列举。

为了让它发挥作用,有很多试验和错误
这里是我之前发布的一些代码,你可能想尝试一下(并附上一些更多的信息)......

Pinvoke SetFocus到特定的控件

首先尝试设置焦点(使用提到的机制) - 然后使用SendKeysSendInput

这是SendInput一些详细代码......

如何将字符串发送到其他应用程序,包括Microsoft Word

暂无
暂无

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

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