Opened 15 years ago
Closed 15 years ago
#69 closed defect (fixed)
QProcess cannot start process
Reported by: | Dmitry A. Kuminov | Owned by: | |
---|---|---|---|
Priority: | blocker | Milestone: | Qt Beta 2 |
Component: | QtCore | Version: | 4.5.1 Beta 1 |
Severity: | Keywords: | ||
Cc: | psmedley |
Description
The following simple program:
qDebug() << "Starting..."; QProcess proc; proc.start("cmd.exe"); qDebug() << "Waiting for finished..."; proc.waitForFinished(); qDebug() << "DONE";
terminates immediately with the following output:
Starting... Waiting for finished... DONE QProcess: Destroyed while process is still running.
Apparently, nothing is started.
Change History (13)
comment:1 by , 15 years ago
comment:2 by , 15 years ago
OK, it generally works. I successfully started view.exe and other applications. However, it seems that spawnvpe() (internally used by Qt on OS/2) cannot start some particular binaries, for example, e.exe from eComStation 2.0: spawnvpe() returns a pid of 0 (which means no error, but the pid is of course invalid) and nothing happens. Doing "cmd /c e.exe" works. I will have to investigate it (probably later, after other tasks are done).
comment:3 by , 15 years ago
Another problem is that QProcess cannot wait for the process to finish: select() on pipe handles always returns "-1 Invalid argument". I have no idea why, I've checked the arguments a hundred times.
comment:4 by , 15 years ago
Even in this simple (non-Qt) program:
#include <sys/process.h> #include <sys/select.h> int main() { int fdin = fileno(stdin); fd_set fdwrite; FD_ZERO(&fdwrite); FD_SET(fdin, &fdwrite); int rc = ::select(fdin + 1, NULL, &fdwrite, NULL, NULL); return 0; }
select() returns -1. Grrr.
comment:5 by , 15 years ago
In libc, select() can only be used on socket handles. It cannot be used on pipe()
You can however use socketpair() instead of pipe() which will achieve the same thing, and you can select() on it.
I use this workaround for CUPS.
comment:6 by , 15 years ago
Cc: | added |
---|
comment:8 by , 15 years ago
Thanks guys, this is what I came up with after studying kLibc sources as well.
comment:9 by , 15 years ago
Ok, socketpair() seems to solve the select() failure but QProcess::waitForFinished() still doesn't work as designed. Investigating.
comment:10 by , 15 years ago
I must have forgotten that spawn* in kLIBC only implements P_WAIT, P_NOWAIT and P_OVERLAY modes (it uses DosExecPgm for them). This means that processes of different type cannot be created with spawn* at the moment (and it explains why we can't spawn PM programs from non-PM ones as in case of e.exe).
The question is what to do. We may detect cases when the target process would have a different process type and prepend 'cmd /c' to make sure it can be started. I tend to do it like this because an equivalent Qt console program on Windows can easily start a GUI application such as notepad.exe w/o prepending it with 'cmd /c'.
comment:11 by , 15 years ago
i guess it would be best to do like that, as to add cmd /c in such qt app's seems a bit strange to me. the question is more is it easy to detect if a app needs that?
comment:12 by , 15 years ago
Yes, we may detect this using DosQueryAppType.
There is another problem: non-kLIBC child applications (for example, cmd.exe) cannot write to (and possibly read from) the redirected standard streams we prepare for them using socketpair() and dup2(). Interesting that after dup2(), the output of the child application disappears from the console but it doesn't appear at the other end of the socket pair. I can't find a good explanation for that. For sure, this is because the kLIBC inheritance processor doesn't get executed in a non-kLIBC child, but I would expect stdin/err/out redirection to work anyway (aren't standard stream's kLIBC file handles backed up by real file handles?).
In any case, it seems that we will have to forget about socketpair() and dup2() and use native pipes for redirection as in Qt3. This is a lot of work...
comment:13 by , 15 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
I'm wrong, it works. At least if I change "cmd.exe" to "cmd.exe /c dir >aaa" I get the current directory's listing in "aaa".
I will try some more sophisticated example.