如何构建一个拦截并通过击键和鼠标点击其他应用程序的Windows应用程序?

时间:2011-04-20 18:32:39

标签: wpf winforms winapi topmost

我正在与想要为遗留应用程序添加功能的客户合作。供应商无用的应用程序具有Windows窗体UI。我的客户想要的是当用户点击应用程序中的一条信息时触发此应用程序之外的某些功能。

我已经看到为另一位客户完成此操作的简单版本。在这种情况下,有一个应用程序包含一个使用SetWindowPos设置为最顶层窗口的表单。当用户单击此表单上的按钮时,应用程序会找到旧版应用程序的窗口,并从窗口的标题中获取信息。这是不优雅的 - 即使传统的应用程序没有打开,这个浮动按钮永远不会消失 - 但它确实有效。

我想知道是否可以使用带有Topmost属性集的无边框透明WPF窗口执行类似的操作。我正在考虑的应用程序将分析遗留应用程序窗口中的内容并定义热点列表。它会截取并处理热点中的任何鼠标点击,并将所有剩余的鼠标点击传递到旧版应用程序。

我对Windows API并不十分熟悉,所以我不知道实现这种功能是否简单(甚至可能)。在我看来,如果我正在编写反恶意软件工具,我想到的应用程序正是我试图削弱的那种东西。

如果这实际上是一个可行的项目,那么最好的方法是什么?我应该注意哪些意想不到的问题?

5 个答案:

答案 0 :(得分:3)

这可以通过WH_CALLWNDPROC和/或WH_GETMESSAGE钩子覆盖按钮而无需任何诡计。

答案 1 :(得分:1)

我肯定会尝试UI Automation。它可能不起作用,但至少,它应该相当容易尝试。并且,大多数情况下,如果它不起作用,则意味着不会有任何其他“简单”的方式。

UI自动化在残障人士的辅助技术中找到了根源,这大部分时间我们想要对我们不拥有的应用程序做什么:从外部应用程序执行操作,而无法真正执行此操作“标准方式“。

它在逻辑上也有事件的概念,请参阅此处的官方文件: UI Automation Events Overview

答案 2 :(得分:1)

在我看来,子类化就是你要找的东西。

创建Windows应用程序时,它会生成一个Window,然后将子Windows添加到该窗口(子Windows称为控件,并且像Windows一样完全正常!它们可以是按钮,文本区域等...) 。

每个窗口都有一个Window过程,每次用户/程序与窗口交互时,窗口过程都会收到一条消息,其中包含有关交互的信息。通常,控件将与其父窗口共享一个窗口过程,并且在该窗口过程内,代码根据消息所描述的窗口/控件的ID(hwnd)确定要执行的操作 - 也就是说:“关闭程序,如果“点击”消息描述退出按钮控制。如果“点击”消息描述父窗口,则不执行任何操作。“

要了解有关Windows的更多信息,请查看此处:http://msdn.microsoft.com/en-us/library/aa383738%28v=vs.85%29.aspx

子类化是拦截和/或捕获发往另一个Window过程的消息的过程。它通常用作扩展第三方应用程序的控件和窗口行为的方法。可以使用 DLL GetWindowLong()SetWindowLong()CallWindowProcedure()以及您自己的自定义窗口过程对另一个进程进行子类化。这很简单 - 这就是你要做的事情:

  • 使用FindWindow()
  • 找到您希望子类化的目标窗口
  • 获取上一个窗口过程并存储它。

WNDPROC wpOrigEditProc = GetWindowLong(hTargetWnd, GWL_WNDPROC)

  • 使用您自己的窗口过程覆盖窗口过程。

SetWindowLong(hTargetWnd, GWL_WNDPROC, HookWndProcedure);

然后,当您卸载时,再次恢复旧窗口过程。窗口程序是你所有魔法发生的地方。您将能够在该函数内部决定您希望处理哪些消息以及您希望将哪些消息传递给旧窗口过程。这是一个示例窗口过程:

LRESULT APIENTRY HookWndProcedure(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 
    if(hwnd == hTargetWndButton_OK) {
        // This is the button we wish to intercept... do some processing, then send it back to Windows
        return DefWindowProc(hwnd, uMsg, wParam, lParam); 
    } else {
        // Allow the message to pass through to the original application's window procedure.
        return CallWindowProc(wpOrigEditProc, hwnd, uMsg, 
            wParam, lParam); 
    }
} 

`

然后,诀窍是将您的DLL加载到目标进程中。我相信最好的方法是添加一个导入条目,指向您的DLL到应用程序,因为应用程序和您的DLL应该保持捆绑在一起。要添加导入,请使用CFF Explorer!

我相信你会有更多问题,因为可能会遗漏一些信息。我将尝试回答我的帖子中出现的任何问题,但如果我没有立即回复,请阅读上面的MSDN链接:D。希望这对你来说将是一次很棒的学习经历:)

答案 3 :(得分:0)

davids建议的另一种方法是使用GetWindowLongSetWindowLongCallWindowProc挂钩应用程序窗口proc,它比使用'windows hooking'方法稍微简单一点但是它仍然可以通过该方法挂钩和/或再次进行子类化。请参阅msdn的子类化窗口,以获得一个简短示例:http://msdn.microsoft.com/en-us/library/ms633570(v=vs.85).aspx#subclassing_window

答案 4 :(得分:0)

检查diz:http://www.autohotkey.com/

它是可编写脚本的,可以阅读窗口标题等等。(当我使用MS-Windows时,我写了一个小小的脚本,它增加了一个窗口,其中包含项目价格和p + p成本之和,从ebay网页的选择中解析了价值。另外,我已将其更改为我的货币。所以,我只是标记了商品的价格和p + p,按了一个键,然后瞧。)