Qt-QProcess-启动子进程-控制台进程隐藏-获取子进程标准输出和返回码

20 篇文章 0 订阅

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.作者答疑

如有疑问,敬请留言。

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Qt中,可以使用QProcess进行子进程的创建和管理。然而,QProcess本身并不提供获取窗口句柄的功能。要获取子进程的窗口句柄,可以借助一些底层操作系统的API。 首先,在Qt启动子进程之后,可以使用QProcess的pid()函数获取子进程进程ID。然后,可以使用操作系统相关的API来获取子进程的窗口句柄。以下以Windows操作系统为例,介绍如何实现: 1. 使用QProcess启动子进程。 ``` QProcess process; process.start("your_executable_file"); ``` 2. 获取子进程进程ID。 ``` qint64 pid = process.pid(); ``` 3. 使用Windows API函数EnumWindows()遍历所有顶级窗口,并查找与子进程进程ID对应的窗口。 ```cpp #include <windows.h> HWND childWindow = nullptr; BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) { DWORD pid; GetWindowThreadProcessId(hwnd, &pid); if (pid == static_cast<DWORD>(lParam)) { childWindow = hwnd; return FALSE; // 找到目标窗口后,终止遍历 } return TRUE; } EnumWindows(EnumWindowsProc, static_cast<LPARAM>(pid)); ``` 4. 最后,可以使用获取到的窗口句柄进行后续操作,例如设置窗口属性、发送消息等。 ```cpp // 设置窗口标题 QString title = "New Window Title"; SetWindowText(childWindow, title.toStdWString().c_str()); // 发送消息到子进程窗口 std::wstring message = L"Hello from Parent"; SendMessage(childWindow, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(message.c_str())); ``` 需要注意的是,获取窗口句柄是操作系统相关的操作,不同平台可能有不同的实现方式。因此,上述代只适用于Windows平台。在其他平台上,可能需要使用不同的API函数或方法来获取窗口句柄。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值