我的客户使用较旧的定制ERP应用程序,他们没有源代码,开发它的公司不再存在。应用程序是在2000年开发的,它是用Delphi构建的。由于最后一个可执行文件是从2003开始,它可能是D6或D7。
在一个重要的表格中,有一些字段,客户希望显示来自其他数据库的其他数据,并询问我是否可以在现有表格上“输送胶带”数据。
我得到的第一个想法是构建应用程序:
有没有关于如何做这样的事情的例子。我搜索谷歌与这个问题标题的变体,但没有成功。
注意 - 没有计划重写ERP应用程序。
关于语言 - 我可以使用C#或Delphi来完成。
答案 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
)。
获得要监控的窗口后,您可以使用SetWindowLongPtr
和GWLP_WNDPROC
来查看收到的所有邮件。这将需要代码注入(因此非托管代码)并且非常低级别。如果你可以避免它,我会反对它,但缺乏来源......
我认为这个答案是一个不错的起点,但是再一次这将是非常痛苦的如果它甚至可能的话。祝你好运。
*或者,如果您知道目标应用在启动时(或在可检测/可预测的时间点)不创建窗口,则可以使用EnumWindows
。