Я пытаюсь использовать Qt для создания графического интерфейса, чтобы обернуть Rip Grep как проект, чтобы лучше познакомиться с Qt, C ++ и Win32 API.У меня есть класс с именем RunCommand
, который я пишу, чтобы содержать функциональность запуска программы командной строки и захвата ее вывода в строку для использования в графическом интерфейсе.В RunCommand
у меня есть несколько методов, которые инкапсулируют различные части работы, которую RunCommand
должен выполнить.Я пытаюсь, чтобы конструктор делал всю работу, вызывая методы.Проблема в том, что когда я вызываю методы из конструктора, программа зависает на неопределенное время, но когда я копирую и вставляю код из методов в конструктор напрямую, все работает как положено.Что мне здесь не хватает?
Я заметил, что код работает нормально, если метод вставлен прямо в конструктор.RunCommand
запускается, когда пользователь нажимает helloButton
.У меня есть сообщение, которое я пишу в QTextEdit
виджет для отладки, который я поместил в метод класса, вызываемый конструктором, прежде чем любой фактический код в этом методе запустится, а затем сразу же возвращается, и я все еще испытываю зависание, поэтомуЯ думаю, что проблема заключается в том, как я вызываю метод, а не в том, что метод пытается сделать.Я могу записать другой текст в виджет QTextEdit
, если не буду вызывать методы класса из конструктора.
easyrip.cpp
#include "easyrip.h"
#include "ui_easyrip.h"
#include "runcommand.h"
#include "synchapi.h"
using namespace std;
EasyRip::EasyRip(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::EasyRip)
{
ui->setupUi(this);
connect(ui->helloButton, &QPushButton::pressed, this, &EasyRip::testHello);
}
EasyRip::~EasyRip()
{
delete ui;
}
void EasyRip::testHello()
{
ui->cmdDisplay->setText("Running rg help command...");
string cmdOutput = "";
RunCommand(R"(C:\Users\Name\OneDrive\RipGrep\rg.exe --help)", cmdOutput);
ui->cmdDisplay->setText(cmdOutput.c_str());
}
runcommand.h
#ifndef CMDRUNNER_H
#define CMDRUNNER_H
#include <Windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#include <string>
class RunCommand
{
public:
RunCommand(const std::string cmd, std::string& cmdOutput);
~RunCommand();
private:
void CreateChildProcess(const std::string cmd, std::string& cmdOutput);
void ReadFromPipe(std::string& cmdOutput);
HANDLE _hChildStd_OUT_Rd = nullptr;
HANDLE _hChildStd_OUT_Wr = nullptr;
};
#endif
runcommand.cpp
#include "runcommand.h"
constexpr int BUFSIZE = 4096;
using namespace std;
RunCommand::~RunCommand()
{
CloseHandle(_hChildStd_OUT_Rd);
CloseHandle(_hChildStd_OUT_Wr);
}
// Runs cmd and returns the command output on cmdOutput.
RunCommand::RunCommand(const string cmd, string& cmdOutput)
{
// Set the bInheritHandle flag so pipe handles are inherited by the child process.
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = nullptr;
// Create a pipe for the child process's STDOUT.
if (!CreatePipe(&_hChildStd_OUT_Rd, &_hChildStd_OUT_Wr, &saAttr, 0))
{
cmdOutput.assign("Error: StdoutRd CreatePipe failed");
return;
}
// Ensure the read handle to the pipe for STDOUT is not inherited.
// We want the child process to only inherit the write end of the PIPE
// we created above. Then it can write to the inherited write end of
// the PIPE, and we can read from the non-inherited read end.
if (!SetHandleInformation(_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, FALSE))
{
cmdOutput.assign("Error: Stdout SetHandleInformation failed");
return;
}
// If "Debug point" is assigned to cmdOutput here and returned,
// the text is successfully displayed in the QTextEdit widget,
// and the code does not hang.
// Create the child process.
// I have also tried calling this as RunCommand::CreateChildProcess
this->CreateChildProcess(cmd, cmdOutput);
// Read the standard output from the child process.
this->ReadFromPipe(cmdOutput);
}
// Create a child process that uses the previously created pipes for STDOUT.
void RunCommand::CreateChildProcess(const string cmd, string& cmdOutput)
{
cmdOutput.assign("Debug point"); // Issue: Never reaches this line.
return;
...
}
// Read output from the child process's pipe for STDOUT
// and copy it to the referenced std::string.
// Stop when there is no more data.
void RunCommand::ReadFromPipe(std::string& cmdOutput)
{
...
}
Ожидаемый результат: содержимое команды rg --help
копируется в строку cmdOutput, а затем отображается в виджете QTextEdit.
Фактический результат: программа зависает на неопределенное время и должна быть принудительно закрыта, когда конструктор RunCommand пытается вызвать методы класса.
Любые предложения приветствуются, спасибо.