diff options
| author | isanae <14251494+isanae@users.noreply.github.com> | 2019-11-16 23:05:24 -0500 |
|---|---|---|
| committer | isanae <14251494+isanae@users.noreply.github.com> | 2019-11-16 23:05:24 -0500 |
| commit | d686a61a7a72a8d4f6e7df7a4136757397cae3ae (patch) | |
| tree | aeb10b7406a0d9ecbd7a456f68d0af580b4bf8d2 /src/loot.cpp | |
| parent | b8eab5d248272cab886bc800f2d619a49d8af54a (diff) | |
removed unused job stuff
don't emit error when the process terminates because it's cancelled
Diffstat (limited to 'src/loot.cpp')
| -rw-r--r-- | src/loot.cpp | 204 |
1 files changed, 90 insertions, 114 deletions
diff --git a/src/loot.cpp b/src/loot.cpp index ab152b80..36d8c8f9 100644 --- a/src/loot.cpp +++ b/src/loot.cpp @@ -76,12 +76,12 @@ public: void cancel() { + addOutput(QObject::tr("Stopping LOOT...")); m_loot.cancel(); } int exec() override { - m_loot.start(); QDialog::exec(); if (m_errorMessages.length() > 0) { @@ -174,9 +174,17 @@ private: }; -Loot::Loot(QWidget* parent, OrganizerCore& core, bool didUpdateMasterList) : - m_thread(nullptr), m_cancel(false), m_result(false), - m_lootProcess(INVALID_HANDLE_VALUE), m_stdOutRead(INVALID_HANDLE_VALUE) +Loot::Loot() + : m_thread(nullptr), m_cancel(false), m_result(false) +{ +} + +Loot::~Loot() +{ + m_thread->wait(); +} + +bool Loot::start(QWidget* parent, OrganizerCore& core, bool didUpdateMasterList) { m_outPath = QDir::temp().absoluteFilePath("lootreport.json"); @@ -191,8 +199,28 @@ Loot::Loot(QWidget* parent, OrganizerCore& core, bool didUpdateMasterList) : parameters << "--skipUpdateMasterlist"; } - HANDLE stdOutWrite = INVALID_HANDLE_VALUE; - createStdoutPipe(&m_stdOutRead, &stdOutWrite); + SECURITY_ATTRIBUTES secAttributes; + secAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); + secAttributes.bInheritHandle = TRUE; + secAttributes.lpSecurityDescriptor = nullptr; + + env::HandlePtr readPipe, writePipe; + + { + HANDLE read = INVALID_HANDLE_VALUE; + HANDLE write = INVALID_HANDLE_VALUE; + + if (!::CreatePipe(&read, &write, &secAttributes, 0)) { + log::error("failed to create stdout reroute"); + } + + readPipe.reset(read); + writePipe.reset(write); + + if (!::SetHandleInformation(read, HANDLE_FLAG_INHERIT, 0)) { + log::error("failed to correctly set up the stdout reroute"); + } + } core.prepareVFS(); @@ -201,12 +229,17 @@ Loot::Loot(QWidget* parent, OrganizerCore& core, bool didUpdateMasterList) : sp.arguments = parameters.join(" "); sp.currentDirectory.setPath(qApp->applicationDirPath() + "/loot"); sp.hooked = true; - sp.stdOut = stdOutWrite; + sp.stdOut = writePipe.get(); + + m_stdout = std::move(readPipe); - m_lootProcess = spawn::startBinary(parent, sp); + HANDLE lootHandle = spawn::startBinary(parent, sp); + if (lootHandle == INVALID_HANDLE_VALUE) { + emit error(QObject::tr("failed to start loot")); + return false; + } - // we don't use the write end - ::CloseHandle(stdOutWrite); + m_lootProcess.reset(lootHandle); core.pluginList()->clearAdditionalInformation(); @@ -214,16 +247,10 @@ Loot::Loot(QWidget* parent, OrganizerCore& core, bool didUpdateMasterList) : lootThread(); emit finished(); })); -} -Loot::~Loot() -{ - m_thread->wait(); -} - -void Loot::start() -{ m_thread->start(); + + return true; } void Loot::cancel() @@ -236,24 +263,7 @@ bool Loot::result() const return m_result; } -void Loot::createStdoutPipe(HANDLE *stdOutRead, HANDLE *stdOutWrite) -{ - SECURITY_ATTRIBUTES secAttributes; - secAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); - secAttributes.bInheritHandle = TRUE; - secAttributes.lpSecurityDescriptor = nullptr; - - if (!::CreatePipe(stdOutRead, stdOutWrite, &secAttributes, 0)) { - log::error("failed to create stdout reroute"); - } - - if (!::SetHandleInformation(*stdOutRead, HANDLE_FLAG_INHERIT, 0)) { - log::error("failed to correctly set up the stdout reroute"); - *stdOutWrite = *stdOutRead = INVALID_HANDLE_VALUE; - } -} - -std::string Loot::readFromPipe(HANDLE stdOutRead) +std::string Loot::readFromPipe() { static const int chunkSize = 128; std::string result; @@ -263,7 +273,7 @@ std::string Loot::readFromPipe(HANDLE stdOutRead) DWORD read = 1; while (read > 0) { - if (!::ReadFile(stdOutRead, buffer, chunkSize, &read, nullptr)) { + if (!::ReadFile(m_stdout.get(), buffer, chunkSize, &read, nullptr)) { break; } if (read > 0) { @@ -323,90 +333,54 @@ void Loot::lootThread() try { m_result = false; - DWORD retLen; - JOBOBJECT_BASIC_PROCESS_ID_LIST info; - HANDLE processHandle = m_lootProcess; + HANDLE waitHandle = m_lootProcess.get(); + DWORD res = ::MsgWaitForMultipleObjects(1, &waitHandle, false, 100, QS_KEY | QS_MOUSE); - if (m_lootProcess != INVALID_HANDLE_VALUE) { - bool isJobHandle = true; - ULONG lastProcessID; - DWORD res = ::MsgWaitForMultipleObjects(1, &m_lootProcess, false, 100, QS_KEY | QS_MOUSE); - while ((res != WAIT_FAILED) && (res != WAIT_OBJECT_0)) { - if (isJobHandle) { - if (::QueryInformationJobObject(m_lootProcess, JobObjectBasicProcessIdList, &info, sizeof(info), &retLen) > 0) { - if (info.NumberOfProcessIdsInList == 0) { - log::debug("no more processes in job"); - break; - } else { - if (lastProcessID != info.ProcessIdList[0]) { - lastProcessID = info.ProcessIdList[0]; - if (processHandle != m_lootProcess) { - ::CloseHandle(processHandle); - } - processHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, lastProcessID); - } - } - } else { - // the info-object I passed only provides space for 1 process id. but since this code only cares about whether there - // is more than one that's good enough. ERROR_MORE_DATA simply signals there are at least two processes running. - // any other error probably means the handle is a regular process handle, probably caused by running MO in a job without - // the right to break out. - if (::GetLastError() != ERROR_MORE_DATA) { - isJobHandle = false; - } - } - } + while ((res != WAIT_FAILED) && (res != WAIT_OBJECT_0)) { + if (m_cancel) { + ::TerminateProcess(m_lootProcess.get(), 1); + } - if (m_cancel) { - if (isJobHandle) { - ::TerminateJobObject(m_lootProcess, 1); - } else { - ::TerminateProcess(m_lootProcess, 1); - } - } + std::string lootOut = readFromPipe(); + processLOOTOut(lootOut); - // keep processing events so the app doesn't appear dead - QCoreApplication::processEvents(); - std::string lootOut = readFromPipe(m_stdOutRead); - processLOOTOut(lootOut); + res = ::MsgWaitForMultipleObjects(1, &waitHandle, false, 100, QS_KEY | QS_MOUSE); + } - res = ::MsgWaitForMultipleObjects(1, &m_lootProcess, false, 100, QS_KEY | QS_MOUSE); - } + std::string remainder = readFromPipe(); + if (remainder.length() > 0) { + processLOOTOut(remainder); + } - std::string remainder = readFromPipe(m_stdOutRead).c_str(); - if (remainder.length() > 0) { - processLOOTOut(remainder); - } + DWORD exitCode = 0UL; + ::GetExitCodeProcess(m_lootProcess.get(), &exitCode); - DWORD exitCode = 0UL; - ::GetExitCodeProcess(processHandle, &exitCode); - ::CloseHandle(processHandle); - if (exitCode != 0UL) { + if (exitCode != 0UL) { + if (!m_cancel) { emit error(QObject::tr("loot failed. Exit code was: %1").arg(exitCode)); - m_result = false; - return; - } else { - m_result = true; - QFile outFile(m_outPath); - outFile.open(QIODevice::ReadOnly); - QJsonDocument doc = QJsonDocument::fromJson(outFile.readAll()); - QJsonArray array = doc.array(); - for (auto iter = array.begin(); iter != array.end(); ++iter) { - QJsonObject pluginObj = (*iter).toObject(); - QJsonArray pluginMessages = pluginObj["messages"].toArray(); - for (auto msgIter = pluginMessages.begin(); msgIter != pluginMessages.end(); ++msgIter) { - QJsonObject msg = (*msgIter).toObject(); - emit information( - pluginObj["name"].toString(), - QString("%1: %2").arg(msg["type"].toString(), msg["message"].toString())); - } - if (pluginObj["dirty"].toString() == "yes") { - emit information(pluginObj["name"].toString(), "dirty"); - } - } } - } else { - emit error(QObject::tr("failed to start loot")); + + return; + } + + m_result = true; + QFile outFile(m_outPath); + outFile.open(QIODevice::ReadOnly); + QJsonDocument doc = QJsonDocument::fromJson(outFile.readAll()); + QJsonArray array = doc.array(); + + for (auto iter = array.begin(); iter != array.end(); ++iter) { + QJsonObject pluginObj = (*iter).toObject(); + QJsonArray pluginMessages = pluginObj["messages"].toArray(); + for (auto msgIter = pluginMessages.begin(); msgIter != pluginMessages.end(); ++msgIter) { + QJsonObject msg = (*msgIter).toObject(); + emit information( + pluginObj["name"].toString(), + QString("%1: %2").arg(msg["type"].toString(), msg["message"].toString())); + } + if (pluginObj["dirty"].toString() == "yes") { + emit information(pluginObj["name"].toString(), "dirty"); + } } } catch (const std::exception &e) { emit error(QObject::tr("failed to run loot: %1").arg(e.what())); @@ -424,9 +398,11 @@ bool runLoot(QWidget* parent, OrganizerCore& core, bool didUpdateMasterList) //Need to figure out how I want to do that. try { - Loot loot(parent, core, didUpdateMasterList); + Loot loot; LootDialog dialog(parent, core, loot); + loot.start(parent, core, didUpdateMasterList); + dialog.setText(QObject::tr("Please wait while LOOT is running")); dialog.setIndeterminate(); dialog.exec(); |
