您现在的位置是:网站首页> C/C++
Qt-QProcess-启动子进程-控制台进程隐藏-获取子进程标准输出和返回码
- C/C++
- 2023-10-07
- 585人已阅读
网上已经有很多教程了,这里再说一下:
//注意,mProcess为共享指针,要特别注意,信号和槽的连接要使用原始指针(也就是mProcess.get()函数)
std::shared_ptr<QProcess> mProcess;
mProcess = std::make_shared<QProcess>();
mProcess->setProgram(cmd);
mProcess->setArguments(splitProcessCommand(arguments));
mProcess->setProcessChannelMode(QProcess::MergedChannels); //设置读取标准输出模式
mProcess->setProcessEnvironment(env); //设置环境变量
mProcess->setWorkingDirectory(workingDir); //这种工作目录
ok = connect(mProcess.get(), &QProcess::readyReadStandardError,[this](){
this->log(QString::fromLocal8Bit( mProcess->readAllStandardError()));
});
ok = connect(mProcess.get(), &QProcess::readyReadStandardOutput,[this](){
//这样就实现把结果exe的信息给显示在控制台了
this->log(QString::fromLocal8Bit( mProcess->readAllStandardOutput()));
});
mProcess->start();
mProcess->waitForStarted(5000);
//这里可以给它传入一些数据
mProcess->write(readFileToByteArray(mInputFile));
mProcess->closeWriteChannel();
//如果啥时候想终止这个进程,还可以用下面的代码
mProcess->closeReadChannel(QProcess::StandardOutput);
mProcess->closeReadChannel(QProcess::StandardError);
mProcess->closeWriteChannel();
mProcess->terminate();
mProcess->kill();
//这里面就能获得启动的exe的标准输出信息了
void DebugTarget::log(const QString &msg)
{
emit debugTargetOutput(msg);
}
特别注意:
如果需要修改process的控制台窗口是否显示,则用下面的函数
mProcess->setCreateProcessArgumentsModifier([this](QProcess::CreateProcessArguments * args)
{
//下面这两行让后台exe弹出一个窗口
args->flags |= CREATE_NEW_CONSOLE;
args->flags &= ~CREATE_NO_WINDOW;
}
切记:在这个函数里,下面这一行,千万不要用,否则qprocess关闭了标准输出,我们就获取不到输出了(我踩了这个巨坑,一天才找出来)
args->startupInfo -> dwFlags &= ~STARTF_USESTDHANDLES;
当然,如果不通过信号与槽函数机制,自己主动去读取mProcee的标准输出也可以的,那就用
mProcee->readAll()
mProcee->write()
2.QProcess
QProcess是Qt提供的强大进程交互工具。简单的进程调用,采用上述模式即可解决,而父子进程之间更复杂的交互,QProcess提供了更好的解决方案。
2.1.基础用法-start和startDetached
start是一体式的:外部程序启动后,将随主程序的退出而退出;
startDetached是分离式的:外部程序启动后,不会随主程序的退出而退出。
重要区别:如果是start则回调都可以正常接收到信息;如果是startDetached则回调无法正常接收到信息。
如果是简单调用,建议采用startDetached,需要获取进程执行的各种状态,建议采用start。QProcess启动的控制台程序,都是隐藏窗口。范例代码如下:
#include <QProcess>
static void TestStartDetached(){
//startDetached是个静态函数,可以直接调用,一共有四种形式
QProcess::startDetached(QString::fromLocal8Bit("./TestConsoleApplication1.exe"));
QProcess::startDetached(QString::fromLocal8Bit("./TestConsoleApplication1.exe"),
QStringList() << "para1" << "para2");
}
static void TestStart(){
QProcess* tQProcess = new QProcess;
//子进程会随着tQProcess的销毁而关闭,如果不想随着函数的调用结束而关闭,需要在堆上申请内存。
tQProcess->start(QString::fromLocal8Bit("./TestConsoleApplication1.exe"),
QStringList()<<"para1"<<"para2" );
//tQProcess->deleteLater();
}
static void TestStart2(){
//显示窗口-极少使用
QProcess *tQProcess = new QProcess();
tQProcess->start("cmd.exe");
tQProcess->write("cd /d E:/work/CurrentProject/微博/QtConnect/x64/Release && start TestConsoleApplication1.exe\n");
}
2.2.获取子进程的标准输出
进程具有两个预定义的输出通道:标准输出通道(stdout)提供常规控制台输出。标准错误通道(stderr)通常提供由进程打印的错误。
这些通道代表两个单独的数据流,可以通过调⽤setReadChannel()函数在它们之间切换。当前读取通道上有可⽤数据时,QProcess发出readyRead()信号。当有新的标准输出数据可⽤时,它也会发出readyReadStandardOutput()信号,⽽当有新的标准错误数据可⽤时,它会发出readyReadStandardError()信号。⽆需调⽤read()函数,readLine()函数或getChar()函数,⽽是可以通过调⽤readAllStandardOutput()函数或readAllStandardError()函数显式地从两个通道之⼀读取所有数据。
进程同步API
waitForStarted()函数——阻塞直到进程开始。
waitForReadyRead()函数——阻塞直到有新数据可在当前读取通道上读取为⽌。
waitForBytesWritten()函数——阻塞直到将⼀个有效载荷数据写⼊该进程为⽌。
waitForFinished()函数——阻塞直到过程完成。
3.代码范例
3.1.等待进程执行完毕,获取所有的输出
代码如下所示:
#include <qDebug>
#include <QProcess>
static void TestGetOutData(){
QProcess process;
process.start("ping www.baidu.com");
process.waitForFinished();
QByteArray allOutData = process.readAll();
if (allOutData.isEmpty())
{
allOutData = process.readAllStandardOutput();
if (allOutData.isEmpty())
{
allOutData = process.readAllStandardError();
}
}
//中文乱码问题
qDebug() << QString::fromStdString(allOutData.data());
}
3.2.子进程返回信号
进程结束,返回进程结束参数。
void QtConnect::finished(int exitCode, QProcess::ExitStatus exitStatus)
{
qDebug() << "finished";
qDebug() << exitCode;// 被调用程序的main返回的int
qDebug() << exitStatus;// QProcess::ExitStatus(NormalExit)
}
void QtConnect::Test() {
QProcess* tQProcess = new QProcess;
tQProcess->start(QString::fromLocal8Bit("E:/work/CurrentProject/微博/QtConnect/x64/Debug/TestConsoleApplication1.exe"));
connect(tQProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(finished(int, QProcess::ExitStatus)));
}
3.3.进程是否启动
void QtConnect::Test() {
QProcess* tQProcess = new QProcess;
tQProcess->start(QString::fromLocal8Bit("E:/work/CurrentProject/微博/QtConnect/x64/Debug/TestConsoleApplication1.exe"));
if (!tQProcess->waitForStarted())
{
qDebug() << "成功!";
}
else
{
qDebug() << "失败!";
}
}
3.4.执行命令行
void QtConnect::Test() {
QStringList arguments;
arguments << "/c" << "dir";//
QProcess tProcess(this);
tProcess.setProcessChannelMode(QProcess::MergedChannels);
tProcess.start("cmd.exe", arguments);
tProcess.waitForStarted();
tProcess.waitForFinished();
QString strResult = QString::fromLocal8Bit(tProcess.readAll());
qDebug() << strResult;
}
3.5.与子进程交互
未来有需要再写,本质就是利用通道来进行数据的交互。
QProcess gzip;
gzip.start("gzip", QStringList() << "-c");
if (!gzip.waitForStarted())
return false;
gzip.write("Qt rocks!");
gzip.closeWriteChannel();
if (!gzip.waitForFinished())
return false;
QByteArray result = gzip.readAll();
上一篇:VC相关信息
下一篇:C++第三方库&开源软件