附加窗口到正在运行的应用

时间:2010-01-02 13:10:42

标签: user-interface winapi controls spy++ cross-application

我的客户使用较旧的定制ERP应用程序,他们没有源代码,开发它的公司不再存在。应用程序是在2000年开发的,它是用Delphi构建的。由于最后一个可执行文件是从2003开始,它可能是D6或D7。

在一个重要的表格中,有一些字段,客户希望显示来自其他数据库的其他数据,并询问我是否可以在现有表格上“输送胶带”数据。

我得到的第一个想法是构建应用程序:

  • 浏览目标应用程序窗口列表,在窗体上创建和查找控件
  • 附加“some”事件何时在显示目标表单时收到通知
  • 附加“some”事件何时在目标表单上的字段更改时得到通知
  • 在覆盖目标表格的小窗口中显示其他信息

有没有关于如何做这样的事情的例子。我搜索谷歌与这个问题标题的变体,但没有成功。

注意 - 没有计划重写ERP应用程序。

关于语言 - 我可以使用C#或Delphi来完成。

1 个答案:

答案 0 :(得分:4)

我将从纯粹的C& C中回答这个问题。 Win32的观点,因为我不知道Delphi或它的库。将其转换为C#可以通过p / invoke完成,但某些部分可能/将需要不受管理。

首先,无保证。如果目标应用程序正在执行无窗口控件(如果每个屏幕控件下都没有HWND),那么你几乎没有运气。这并不是那么罕见,所以是啊...

步骤1,注册一个窗口挂钩,监听目标进程创建的新窗口*:

//dllHMod is an HMODULE that refers to the DLL containing ShellHookProc
HHOOK hook = SetWindowsHookEx(WH_SHELL, ShellHookProc, dllHMod, 0);
// error handling, stashing hook away for unregistering later, etc...

LRESULT CALLBACK ShellHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
  if(nCode < 0) return CallNextHookEx(NULL, nCode, wParam, lParam);

  if(nCode == HSHELL_WINDOWCREATED)
  {
    WindowCreate((HWND)wParam);
  }

  return 0;
}
如果正确的过程(通过GetWindowThreadProcessId确定)拥有它,

WindowCreated(HWND)应该将HWND藏匿起来。此时,您将能够获得目标进程拥有的每个顶级窗口。请注意,注册一个全局钩子会带来显着的性能损失,并不是说它在你的情况下真的很重要,但你应该期待它。

现在为有趣的部分。没有可靠的方法来判断窗口是完全构造的,还是完成渲染的时候(有很多方法可以告诉它何时渲染,但这并没有真正帮助)。我的建议,猜测。只需在那里抛出一些任意的等待,然后尝试枚举所有的子窗口。

要枚举子窗口(如果您对目标窗口有足够的了解,有更好的方法可以做到这一点;但我假设搜索最简单):

//targetHWND is an HWND of one of the top-level windows you've found
EnumChildWindows(targetHWND, ChildWindowCallback, NULL);
//more code...

BOOL ChildWindowCallback(HWND window, LPARAM ignored)
{
  if(IsTargetWindow(window)) { /* Do something */ }

  return TRUE;
}

实施IsTargetWindow是另一个棘手的部分。希望你能找到一些可靠的测试(比如检查班级名称,窗口名称,样式等等;看看GetWindowInfo)。

获得要监控的窗口后,您可以使用SetWindowLongPtrGWLP_WNDPROC来查看收到的所有邮件。这将需要代码注入(因此非托管代码)并且非常低级别。如果你可以避免它,我会反对它,但缺乏来源......

我认为这个答案是一个不错的起点,但是再一次这将是非常痛苦的如果它甚至可能的话。祝你好运。

*或者,如果您知道目标应用在启动时(或在可检测/可预测的时间点)不创建窗口,则可以使用EnumWindows