文章目录
- 1.隐藏控制台程序
- 1.1.控制台程序生成即隐藏
- 1.2.调用程序隐藏控制台
- 2.QProcess
- 2.1.基础用法-start和startDetached
- 2.2.获取子进程的标准输出
- 3.代码范例
- 3.1.等待进程执行完毕,获取所有的输出
- 3.2.子进程返回信号
- 3.3.进程是否启动
- 3.4.执行命令行
- 3.5.与子进程交互
- 4.作者答疑
1.隐藏控制台程序
1.1.控制台程序生成即隐藏
创建控制台项目,修改项目属性,然后在子系统中选择链接器》系统 选择窗口子系统,下面高级中,入口点选择mainCRTStartup,如下图所示:
这样生成的程序,窗口需要程序编码创建,不创建则没有窗口,从而达到无显示的隐藏效果。
1.2.调用程序隐藏控制台
在父进程调用时,即指定隐藏控制台窗口,注意这种模式对于窗口子系统是不能隐藏的。
#include "windows.h"
#include <iostream>
//执行并等待控制台程序
static DWORD ExecAndWaitConsole(LPCTSTR lpszAppPath, LPCTSTR lpParameters, LPCTSTR lpszDirectory, DWORD dwMilliseconds)
{
SHELLEXECUTEINFO ShExecInfo = { 0 };
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = NULL;
ShExecInfo.lpFile = lpszAppPath;
ShExecInfo.lpParameters = lpParameters;
ShExecInfo.lpDirectory = lpszDirectory;
ShExecInfo.nShow = SW_HIDE;
ShExecInfo.hInstApp = NULL;
if (!ShellExecuteEx(&ShExecInfo))
{
return 0;
}
// 指定时间没结束
if (WaitForSingleObject(ShExecInfo.hProcess, dwMilliseconds) == WAIT_TIMEOUT)
{ // 强行杀死进程
TerminateProcess(ShExecInfo.hProcess, 0);
return 0; //强行终止
}
DWORD dwExitCode;
if (!GetExitCodeProcess(ShExecInfo.hProcess, &dwExitCode))
{
return 0;
}
return dwExitCode;
}
int main()
{
ExecAndWaitConsole(L"console1.exe",
NULL,
NULL, 10000);
std::cout << "Hello World!\n";
Sleep(100000);
}
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();
4.作者答疑
如有疑问,敬请留言。