1

在此处输入图像描述

问题

这是我在后台发送击键的功能。

class SendMessage
{

[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

public static void sendKeystroke(string appName)
{
    const int WM_KEYDOWN = 0x100; 
    IntPtr hWnd = FindWindow(null, appName);
    IntPtr editx = FindWindowEx(hWnd, IntPtr.Zero, "edit", null);
    PostMessage(editx, WM_KEYDOWN, (IntPtr)Keys.A, (IntPtr)0);  
}

}

此代码可以正常工作notepad,例如 let appName = "notepad"。

但是,我可以设法在其他应用程序中做到这一点..我练习在 LINE 应用程序上做。

正如您在图片中看到的lpszClass variable=“编辑”(红色小圆圈)用于记事本。

我需要为 LINE 应用程序找到它,所以我用它WinSpy++来捕获那些类名。

我发现它的类名是“ATL:00B53BE8”(大红色圆圈),我可以输入消息

在 WinSpy++ 中输入,它将出现在 Line 文本框(蓝色圆圈)中。

综上所述

我尝试用“编辑”替换捕获类名,但没有希望。

我不明白为什么捕获类名不可用,请帮助或给我一些提示。

我不知道这可能是关于系统应用程序的层次结构不同(粉红色的)

而且我不知道 FindWindowEx 中的哪些参数意义重大。

我的最终目标是将击键发送到其他应用程序而不关注它们。

4

2 回答 2

1

您不能期望WM_KEYDOWN发送到没有焦点的应用程序的消息会产生预期的效果。根本不支持。根据 Windows 的规则,接收WM_KEYDOWN消息意味着您的应用程序具有焦点。只有专注的应用程序才能获得键盘输入。

所以你正在尝试的东西在某些情况下可能会起作用,但不能保证它会起作用。如果应用程序正在接收键盘输入,它可能会做出相当合理的假设,即它具有焦点。

如果它在记事本中“有效”,那是因为记事本是一个非常愚蠢的简单应用程序。它只是一个带有菜单栏的编辑控件。它对WM_KEYDOWN消息的处理可能只是将由消息参数指示的键表示的字符添加到编辑控件。大多数其他应用程序更复杂。甚至记事本也不能保证在所有情况下都能正常工作。例如,当它的窗口最小化时。在本网站和 Interwebz 的其他地方有大量关于此类问题的报告。

简单地说:发送WM_KEYDOWN和它的朋友不是你在 Windows 中模拟键盘输入的方式。有两种基本方法。一是使用SendInput功能;另一种是安装WH_JOURNALPLAYBACK挂钩。SendKeys.NET中的类的不同实现版本已经采用了这两种方法。它们都将合成的输入发送到焦点窗口,因为在 Windows 中,这是接收所有输入的窗口。

如果要这样做,您绝对必须找到另一种方法。在评论中,David 建议使用UI Automation,这是一个为此目的而设计的工具。它由 .NET Framework 方便地包装。目前还不清楚你为什么拒绝这个建议。借助 UI 自动化,您可以使用嵌套树结构轻松浏览应用程序中的窗口层次结构。该树是根据进程中的所有窗口句柄自动构建的。这使您可以轻松找到要操作的控件。然后,您获得适当的控制模式,并执行您想要的任何操作。

于 2014-09-08T07:35:00.323 回答
0

从与讨论David Herffernan

“您需要多次调用才能遍历父子层次结构”

现在,我可以让我的代码工作了。但是,这似乎不是正确的做法(黑客)

但是,我想回答这个问题以供参考

关键是使用FindWindowEx它的工作方式David Herffernan

而不是这个..

public static void sendKeystroke(string appName)
{
    const int WM_KEYDOWN = 0x100; 
    IntPtr hWnd = FindWindow(null, appName);
    IntPtr editx = FindWindowEx(hWnd, IntPtr.Zero, "edit", null);
    PostMessage(editx, WM_KEYDOWN, (IntPtr)Keys.A, (IntPtr)0);  
}

我编辑到这个..

public static void sendKeystroke(string appName)
{
    const int WM_KEYDOWN = 0x100; 
    IntPtr hWnd = FindWindow(null, appName);
    IntPtr editx1 = FindWindowEx(hWnd, IntPtr.Zero, "SkinScrollWnd", null);
    IntPtr editx2 = FindWindowEx(editx1, IntPtr.Zero, "SkinScrollMidWnd", null);
    IntPtr editx3 = FindWindowEx(editx2, IntPtr.Zero, "ATL:00B53BE8", null);
    PostMessage(editx3, WM_KEYDOWN, (IntPtr)Keys.A, (IntPtr)0);  
}
于 2014-09-08T07:48:38.473 回答