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

发布于 2024-08-16 12:27:27 字数 486 浏览 8 评论 0原文

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

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

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

  • 浏览 Windows 目标应用程序的列表,创建并查找表单上的控件
  • 附加“某些”事件 当显示目标表单时何时收到通知
  • 附加“某些”事件 当目标上的字段时何时收到通知表单已更改
  • 在覆盖目标表单的小窗口中显示附加信息

是否有任何关于如何执行此类操作的示例。我用这个问题标题的变体搜索了谷歌,但没有成功。

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

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

I have customer that uses older, custom built ERP application for which they don't have source code and company that developed it does not exist any more. Application is developed in 2000 and it's built with Delphi. Since last executable is from 2003, it could be D6 or D7.

On one important form there are some fields where customer would like to display additional data from other databases and asked me if it's possible to "duct tape" data over existing form.

First idea I got is to build application that will:

  • browse list of windows target application creates and find controls on form
  • attach "some" event when to get notified when target form is displayed
  • attach "some" event when to get notified when field on target form is changed
  • display additional information in small window overlaying target form

Are there any examples on how to do something like this. I searched google with variations of this question title, but without success.

Note - rewriting of ERP application is not planned.

About language - I can do it with C# or Delphi.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

苏大泽ㄣ 2024-08-23 12:27:27

我将从纯粹的 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;
}

如果正确,WindowCreated(HWND) 应该隐藏 HWND进程(通过 GetWindowThreadProcessId< 确定/a>) 拥有它。此时,您将能够获取目标进程拥有的每个顶级窗口。请注意,注册全局钩子会带来显着的性能损失,这对于您的情况来说并不重要,但您应该预料到它。

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

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

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

I'm going to answer this from a purely C & Win32 point of view, because I don't know Delphi or its libraries. Converting this to C# can be accomplished via p/invoke, but some parts may/will need to be unmanaged.

First off, no guarantees. If the target application is doing windows-less controls (if there isn't an HWND under every on-screen control) you're pretty much out of luck. This isn't all that uncommon, so yeah...

Step 1, register a window hook listening for new windows created by the target process*:

//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) should stash the HWND away if the correct process (determined via GetWindowThreadProcessId) owns it. At this point, you'll be able to get every top-level window owned by the target process. Note that registering a global hook carries a notable performance penalty, not that it really matters in your case but you should expect it.

Now for the fun part. There's no reliable way to tell when a window is fully constructed, or when its done rendering (there are ways to tell when it STARTS rendering, but that doesn't really help). My advice, guess. Just throw some arbitrary wait in there and then try and enumerate all the child windows.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文