EnumWindows not finding hWnd from PID if program is started using QProcess
-
I am trying to get a hWnd from a process id with Win32 APIs.
HWND myHWND; static BOOL CALLBACK enumWindowCallback(HWND hWnd, LPARAM lparam) { DWORD pid; GetWindowThreadProcessId(hWnd, &pid); if (pid == lparam) { myHWND = hWnd; qDebug() << pid << myHWND; return FALSE; } return TRUE; } ProgramStarter::ProgramStarter(QObject *parent) : QObject{parent} { QProcess *qpr = new QProcess(this); QString executable = "C:\\Path\\to\\program.exe"; qpr->start(executable); qpr->waitForStarted(-1); qDebug() << qpr->processId(); EnumWindows(enumWindowCallback, qpr->processId()); qpr->terminate(); }
But this does not seem to work. However, if I manually start the program and type in the PID instead of using QProcess then it works.
// this works EnumWindows(enumWindowCallback, 12345); // this does not work EnumWindows(enumWindowCallback, qpr->processId());
What am I doing wrong? How can I make it work?
-
Looks like using the
QProcess::stateChanged
signal (and removingterminate()
) works.
It usesQThread::msleep()
so its not ideal, but its fine for me.HWND myHWND; static BOOL CALLBACK enumWindowCallback(HWND hWnd, LPARAM lparam) { DWORD pid; GetWindowThreadProcessId(hWnd, &pid); if (pid == lparam) { myHWND = hWnd; return FALSE; } return TRUE; } ProgramStarter::ProgramStarter(QObject *parent) : QObject{parent} { QProcess *qpr = new QProcess(this); connect(qpr, &QProcess::stateChanged, this, [=](QProcess::ProcessState newState){ if (newState == QProcess::Running) { QThread::msleep(250); EnumWindows(enumWindowCallback, qpr->processId()); } }); QString executable = "C:\\path\\to\\program.exe"; qpr->start(executable); qDebug() << myHWND; }
-
@Waoweens said in EnumWindows not finding hWnd from PID if program is started using QProcess:
// this works
EnumWindows(enumWindowCallback, 12345);
// this does not work
EnumWindows(enumWindowCallback, qpr->processId());Then check what qpr->processId() returns, also take a look in the TaskManager to see if you can find qpr->processId() there.
-
@Christian-Ehrlicher qpr->processId() returns 16228 and task manager also says 16228
qDebug() << qpr->processId()
-
@Waoweens said in EnumWindows not finding hWnd from PID if program is started using QProcess:
GetWindowThreadProcessId
So this doesn't seem to return what you're expecting. Don't think Qt and the task manager lies...
-
@Christian-Ehrlicher I modified it to list every open window
static BOOL CALLBACK enumWindowCallback(HWND hWnd, LPARAM lparam) { DWORD pid; GetWindowThreadProcessId(hWnd, &pid); qDebug() << hWnd << pid return TRUE; } //... EnumWindows(enumWindowCallback, 0);
If the program is launched manually, it appears on the list.
If the program is started with QProcess, it does not appear on the list. -
@Waoweens said in EnumWindows not finding hWnd from PID if program is started using QProcess:
If the program is launched manually, it appears on the list.
How do you know the PID in this case? Also from the task manager?
-
@hskoglund said in EnumWindows not finding hWnd from PID if program is started using QProcess:
Hi, it could be that QProcess launches your program not as a top-level window but as a child
How should it work otherwise - the Qt process is starting the process and therefore it's the creator. startDetached might work but must not.
The msdn documentation also tells which windows are evaluated: "Retrieves the identifier of the thread that created the specified window and, optionally, the identifier of the process that created the window."
-
@Christian-Ehrlicher said in EnumWindows not finding hWnd from PID if program is started using QProcess:
@Waoweens said in EnumWindows not finding hWnd from PID if program is started using QProcess:
If the program is launched manually, it appears on the list.
How do you know the PID in this case? Also from the task manager?
Yes, task manager.
@hskoglund said in EnumWindows not finding hWnd from PID if program is started using QProcess:
Hi, it could be that QProcess launches your program not as a top-level window but as a child, and then EnumWindows() never sees it :-(
Perhaps QProcess startDetached() works better?using startDetached() makes processId() return 0.
-
@Waoweens said in EnumWindows not finding hWnd from PID if program is started using QProcess:
using startDetached() makes processId() return 0.
As properly documented...
I don't understand the need at all for this.
-
@Christian-Ehrlicher said in EnumWindows not finding hWnd from PID if program is started using QProcess:
I don't understand the need at all for this.
I want to embed an external program in a QWidget, but to do that you need the hWid of the program.
QWindow *embed = QWindow::fromWinId(hWid); QWidget *widget = QWidget::createWindowContainer(embed)
-
Then you've to find another WinAPI function or modify the external program to return the winId to the caller.
-
Looks like adding a delay of 1 second makes it works, so maybe it was too fast?
But now the external program closes after 1 second. I removedqpr->terminate
but now the QMainWindow wont start unless the external program is closed first.
Is there a way to make them both run at the same time? -
Looks like using the
QProcess::stateChanged
signal (and removingterminate()
) works.
It usesQThread::msleep()
so its not ideal, but its fine for me.HWND myHWND; static BOOL CALLBACK enumWindowCallback(HWND hWnd, LPARAM lparam) { DWORD pid; GetWindowThreadProcessId(hWnd, &pid); if (pid == lparam) { myHWND = hWnd; return FALSE; } return TRUE; } ProgramStarter::ProgramStarter(QObject *parent) : QObject{parent} { QProcess *qpr = new QProcess(this); connect(qpr, &QProcess::stateChanged, this, [=](QProcess::ProcessState newState){ if (newState == QProcess::Running) { QThread::msleep(250); EnumWindows(enumWindowCallback, qpr->processId()); } }); QString executable = "C:\\path\\to\\program.exe"; qpr->start(executable); qDebug() << myHWND; }