我有Application A
这是使用Qt库的第三方Windows应用程序(带有GUI)。
我想写Application B
,负责启动Application A
。我希望Application B
也能找到Application B
(QWidgets
)上的按钮并发送鼠标输入(点击,双击等)。
我可以使用Application A
上的start
功能运行QProcess
。
如何从QProcess
注意 - 我知道如何使用Windows API执行此操作,但要求通过Qt的方法。有问题的Application A
不使用本机窗口系统,因此窗口句柄不会显示在Spy ++或Windows API函数中。
更新1 - 似乎无法通过流程的孩子获得任何有意义的对象
我尝试为此过程获取子窗口小部件:
QProcess* process = new QProcess();
QString program = "\"C:\\Program Files (x86)\\foo\\bar.exe\"";
process->start(program);
auto widgets = process->findChildren<QWidget*>("", Qt::FindChildrenRecursively);
auto i = widgets.count();
// i = 0
如果我找到<QObject*>
类型的孩子,我会得到4个结果。我用metaObject()->className()
看到我有两对QWindowsPipeReader和QWinOverlappedIoNotifier对象。
更新2 - 无法从其他进程创建/注入窗口
我注意到当我运行QProcess时,我可以使用Windows API函数来获取顶级窗口(仅限顶级)。我在Qt文档中读到,您可以使用QWindow::fromWinId从另一个进程中的窗口句柄创建QWindow。
使用此功能会抛出0xC0000005: Access violation reading location 0x00000000.
错误。我没有传入一个空句柄。我正在使用reinterpret_cast将HWND
转换为WId
类型。它只在我事先创建QApplication时才创建QWindow。
新的QWindow将没有孩子(使用window->findChildren<QObject*>("", Qt::FindChildrenRecursively);
我认为QWindow的创建不会带来相关的子窗口小部件。
更新3 - 我目前正在阅读是否可以使用进程间通信
我遇到过有关ICP in Qt的各种主题,问题和代码段。到目前为止,我没有看到任何明确表明当其中一个流程是第三方时ICP可能的情况。
我已经看到Squish Gui测试工具可以让你查询QWidget属性。
答案 0 :(得分:1)
This will never work the way you intend it to.
If you really wish to take direct control over the other application, you must inject your code into that application. Let's assume that the application uses a dynamically linked Qt. Then:
Build a binary-compatible version of Qt, using the same compiler that was used to build the application you intend to tweak.
Replace the application's Qt with yours. Everything should still work fine, given that yours should be binary compatible. If not, the binary compatibility isn't there, and you must tweak things until they work.
Edit your Qt to add a hook to initialize your code at the end of QApplication
constructor. This makes the Qt module that provides QApplication
dependent on your code.
Put your code into a dll that the widgets (for Qt 5) or gui (for Qt 4) module is now dependent on.
Again replace the app's Qt with yours, with hooks that start your code.
Your code will of course need to be asynchronous, and will be monitoring the application's progress by inspecting the qApp->activeWindow()
, qApp->allWidgets()
, etc.
That's pretty much the only way to do it. You can of course inject your code in any other way you desire, but you will need to work with a binary-compatible version of Qt just to compile your code. Note that binary compatibility encompasses more than merely using the same compiler version and Qt version. Many of the configure
switches must be the same, too.