0

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

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

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

  • 浏览 Windows 目标应用程序列表并在表单上查找控件
  • 在显示目标表单时附加“某些”事件何时得到通知
  • 附加“某些”事件何时在目标表单上的字段发生更改时得到通知
  • 以小窗口覆盖目标窗体显示附加信息

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

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

关于语言——我可以用 C# 或 Delphi 来做。

4

1 回答 1

4

我将从纯粹的 C 和 Win32 角度回答这个问题,因为我不了解 Delphi 或其库。可以通过 p/invoke 将其转换为 C#,但某些部分可能/将需要非托管。

首先,没有保证。如果目标应用程序正在执行无 Windows 控件(如果不是HWND每个屏幕控件下都有一个),那么您就很不走运了。这并不少见,所以是的......

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

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

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

现在是有趣的部分。没有可靠的方法来判断窗口何时完全构建,或何时完成渲染(有一些方法可以判断它何时开始渲染,但这并没有真正帮助)。我的建议,。只需在那里随意等待,然后尝试枚举所有子窗口。

To enumerate child windows (if you know enough about the target window, there are better ways to do this; but I'm assuming a search is easiest):

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

Implementing IsTargetWindow is another tricky part. Hopefully you'll find some reliable test for doing so (like checking the class name, window name, style, something; look at GetWindowInfo).

Once you have the window you want to monitor, you can use SetWindowLongPtr and GWLP_WNDPROC to watch all messages it receives. This will require code injection (and thus unmanaged code) and is awfully low level. I'd advise against it if you could possibly avoid it, but lacking the source...

I think this answers is a decent starting point, but once again this is going to be incredibly painful if its even possible at all. Good luck.

*Alternatively, if you know that the target app doesn't create windows except at startup (or at detectable/predictable points in time) you can use EnumWindows.

于 2010-01-02T19:19:56.260 回答