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

SPi*_*lai 4 .net c# windows sendkeys keyboard-events

我正在尝试执行以下操作之一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);
Run Code Online (Sandbox Code Playgroud)

获取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;
Run Code Online (Sandbox Code Playgroud)

SendMessage尝试:

SendMessage(ptrOBS, WM_KEYDOWN, (IntPtr)VK_R, (IntPtr)1);//tried both WM_CHAR and WM_KEYDOWN
Run Code Online (Sandbox Code Playgroud)

PostMessage尝试:

string message = "rs";
bool sent = PostMessage(ptrOBS, WM_KEYDOWN, VkKeyScan(message[0]), 0);
Run Code Online (Sandbox Code Playgroud)

SendKeys尝试:

SendKeys.SendWait("{r}");
Run Code Online (Sandbox Code Playgroud)

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

对于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);
Run Code Online (Sandbox Code Playgroud)

Cod*_*ray 5

您无法可靠地使用SendMessagePostMessage合成键盘输入.它们不是为此而设计的.这些消息(WM_CHAR,WM_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
Run Code Online (Sandbox Code Playgroud)

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

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

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


NSG*_*aga 3

为了让它工作,需要进行很多试验和错误,
这是我之前发布的一些代码,您可能想尝试一下(并且附加了更多信息)...

Pinvoke SetFocus 到特定控件

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

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

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