From a611c355ce732961c2a9ba1a8909f0c144afa860 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Fri, 20 Oct 2017 20:27:06 -0500 Subject: Basic ESL updates --- src/organizercore.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index d9ed6ab6..c55504a8 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1413,6 +1413,20 @@ void OrganizerCore::updateModActiveState(int index, bool active) m_PluginList.enableESP(esm, active); } int enabled = 0; + for (const QString &esl : + dir.entryList(QStringList() << "*.esl", QDir::Files)) { + const FileEntry::Ptr file = m_DirectoryStructure->findFile(ToWString(esl)); + if (file.get() == nullptr) { + qWarning("failed to activate %s", qPrintable(esl)); + continue; + } + + if (active != m_PluginList.isEnabled(esl) + && file->getAlternatives().empty()) { + m_PluginList.enableESP(esl, active); + ++enabled; + } + } QStringList esps = dir.entryList(QStringList() << "*.esp", QDir::Files); for (const QString &esp : esps) { const FileEntry::Ptr file = m_DirectoryStructure->findFile(ToWString(esp)); @@ -1429,7 +1443,7 @@ void OrganizerCore::updateModActiveState(int index, bool active) } if (active && (enabled > 1)) { MessageDialog::showMessage( - tr("Multiple esps activated, please check that they don't conflict."), + tr("Multiple esps/esls activated, please check that they don't conflict."), qApp->activeWindow()); } m_PluginList.refreshLoadOrder(); @@ -1723,7 +1737,7 @@ QString OrganizerCore::shortDescription(unsigned int key) const { switch (key) { case PROBLEM_TOOMANYPLUGINS: { - return tr("Too many esps and esms enabled"); + return tr("Too many esps, esms, and esls enabled"); } break; default: { return tr("Description missing"); -- cgit v1.3.1 From ebe6011174767687f3b575c08132a720ecccbf55 Mon Sep 17 00:00:00 2001 From: LePresidente Date: Sat, 28 Oct 2017 08:30:23 +0200 Subject: Fixes the handle leak in the OrganizerCore::waitForProcessCompletion --- src/organizercore.cpp | 103 +++++++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 51 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index c55504a8..9ae8beae 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1239,7 +1239,7 @@ bool OrganizerCore::waitForApplication(HANDLE handle, LPDWORD exitCode) bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) { HANDLE processHandle = handle; - + static const DWORD maxCount = 5; size_t numProcesses = maxCount; LPDWORD processes = new DWORD[maxCount]; @@ -1250,62 +1250,63 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) DWORD res; // Wait for a an event on the handle, a key press, mouse click or timeout //TODO: Remove MOBase::isOneOf from this query as it was always returning true. + while ( - res = ::MsgWaitForMultipleObjects(1, &handle, false, 500, - QS_KEY | QS_MOUSE), - ((res != WAIT_FAILED) || (res != WAIT_OBJECT_0)) && - ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) { - - if (!::GetVFSProcessList(&numProcesses, processes)) { - break; - } - - bool found = false; - size_t count = - std::min(static_cast(maxCount), numProcesses); - for (size_t i = 0; i < count; ++i) { - std::wstring processName = getProcessName(processes[i]); - if (!boost::starts_with(processName, L"ModOrganizer.exe")) { - currentProcess = processes[i]; - m_UserInterface->setProcessName(QString::fromStdWString(processName)); - processHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, currentProcess); - found = true; + res = ::MsgWaitForMultipleObjects(1, &handle, false, 500, + QS_KEY | QS_MOUSE), + ((res != WAIT_FAILED) || (res != WAIT_OBJECT_0)) && + ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) { + + if (!::GetVFSProcessList(&numProcesses, processes)) { + break; + } + bool found = false; + size_t count = + std::min(static_cast(maxCount), numProcesses); + for (size_t i = 0; i < count; ++i) { + std::wstring processName = getProcessName(processes[i]); + if (!boost::starts_with(processName, L"ModOrganizer.exe")){ + currentProcess = processes[i]; + m_UserInterface->setProcessName(QString::fromStdWString(processName)); + processHandle = ::OpenProcess(SYNCHRONIZE, FALSE, currentProcess); + found = true; + ::CloseHandle(processHandle); + } } - } - if (!found) { - // it's possible the previous process has deregistered before - // the new one has registered, so we should try one more time - // with a little delay - if (tryAgain) { - tryAgain = false; - QThread::msleep(500); - continue; + if (!found) { + // it's possible the previous process has deregistered before + // the new one has registered, so we should try one more time + // with a little delay + if (tryAgain) { + tryAgain = false; + QThread::msleep(500); + continue; + } else { + break; + } } else { - break; + tryAgain = true; + } + // keep processing events so the app doesn't appear dead + + QCoreApplication::processEvents(); + + + if (exitCode != nullptr) { + //This is actually wrong if the process we started finished before we + //got the event and so we end up with a job handle. + if (! ::GetExitCodeProcess(processHandle, exitCode)) + { + DWORD error = ::GetLastError(); + qDebug() << "Failed to get process exit code: Error " << error; + } } - } else { - tryAgain = true; - } - - // keep processing events so the app doesn't appear dead - QCoreApplication::processEvents(); - } - if (exitCode != nullptr) { - //This is actually wrong if the process we started finished before we - //got the event and so we end up with a job handle. - if (! ::GetExitCodeProcess(processHandle, exitCode)) - { - DWORD error = ::GetLastError(); - qDebug() << "Failed to get process exit code: Error " << error; + ::CloseHandle(processHandle); + if (handle != processHandle) { + ::CloseHandle(handle); + } } - } - - ::CloseHandle(processHandle); - if (handle != processHandle) { - ::CloseHandle(handle); - } - return res == WAIT_OBJECT_0; } -- cgit v1.3.1 From 2f1d270c08eb43f043e342accc64b1cd1bbff25f Mon Sep 17 00:00:00 2001 From: LePresidente Date: Tue, 31 Oct 2017 12:13:25 +0200 Subject: multiple fixes to waitForProcessCompletion. --- src/organizercore.cpp | 87 +++++++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 41 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 9ae8beae..cba92d8f 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1265,48 +1265,53 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) std::min(static_cast(maxCount), numProcesses); for (size_t i = 0; i < count; ++i) { std::wstring processName = getProcessName(processes[i]); - if (!boost::starts_with(processName, L"ModOrganizer.exe")){ - currentProcess = processes[i]; - m_UserInterface->setProcessName(QString::fromStdWString(processName)); - processHandle = ::OpenProcess(SYNCHRONIZE, FALSE, currentProcess); - found = true; - ::CloseHandle(processHandle); - } - } - if (!found) { - // it's possible the previous process has deregistered before - // the new one has registered, so we should try one more time - // with a little delay - if (tryAgain) { - tryAgain = false; - QThread::msleep(500); - continue; - } else { - break; - } - } else { - tryAgain = true; - } - // keep processing events so the app doesn't appear dead - - QCoreApplication::processEvents(); - - - if (exitCode != nullptr) { - //This is actually wrong if the process we started finished before we - //got the event and so we end up with a job handle. - if (! ::GetExitCodeProcess(processHandle, exitCode)) - { - DWORD error = ::GetLastError(); - qDebug() << "Failed to get process exit code: Error " << error; - } - } + if (!boost::starts_with(processName, L"ModOrganizer.exe")) { + currentProcess = processes[i]; + m_UserInterface->setProcessName(QString::fromStdWString(processName)); + processHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, currentProcess); + found = true; + } + } + if (!found) { + // it's possible the previous process has deregistered before + // the new one has registered, so we should try one more time + // with a little delay + if (tryAgain) { + tryAgain = false; + QThread::msleep(500); + continue; + } + else { + break; + } + } + else { + tryAgain = true; + } + //Cleanup + if (processHandle != INVALID_HANDLE_VALUE) { + if (exitCode != nullptr) { + //This is actually wrong if the process we started finished before we + //got the event and so we end up with a job handle. + if (!::GetExitCodeProcess(processHandle, exitCode)) + { + DWORD error = ::GetLastError(); + qDebug() << "Failed to get process exit code: Error " << error; + } + } + if (handle != processHandle) { + ::CloseHandle(processHandle); + } + } - ::CloseHandle(processHandle); - if (handle != processHandle) { - ::CloseHandle(handle); - } - } + // keep processing events so the app doesn't appear dead + QCoreApplication::processEvents(); + } + //Final Cleanup + if (handle != INVALID_HANDLE_VALUE) { + ::CloseHandle(handle); + } + delete[] processes; return res == WAIT_OBJECT_0; } -- cgit v1.3.1 From 6c54ef5ec2a1b5395f4292fd33e4dcddf748a145 Mon Sep 17 00:00:00 2001 From: LePresidente Date: Tue, 31 Oct 2017 16:00:58 +0200 Subject: More fixes to waitForProcessCompletion --- src/organizercore.cpp | 73 +++++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 35 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index cba92d8f..48e2f98a 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1254,7 +1254,7 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) while ( res = ::MsgWaitForMultipleObjects(1, &handle, false, 500, QS_KEY | QS_MOUSE), - ((res != WAIT_FAILED) || (res != WAIT_OBJECT_0)) && + ((res != WAIT_FAILED) && (res != WAIT_OBJECT_0)) && ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) { if (!::GetVFSProcessList(&numProcesses, processes)) { @@ -1263,47 +1263,50 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) bool found = false; size_t count = std::min(static_cast(maxCount), numProcesses); - for (size_t i = 0; i < count; ++i) { - std::wstring processName = getProcessName(processes[i]); - if (!boost::starts_with(processName, L"ModOrganizer.exe")) { - currentProcess = processes[i]; - m_UserInterface->setProcessName(QString::fromStdWString(processName)); - processHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, currentProcess); - found = true; + if (count > 0) { + for (size_t i = 0; i < count; ++i) { + std::wstring processName = getProcessName(processes[i]); + if (!boost::starts_with(processName, L"ModOrganizer.exe")) { + if (!boost::starts_with(processName, L"unknown")) { + currentProcess = processes[i]; + m_UserInterface->setProcessName(QString::fromStdWString(processName)); + processHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, currentProcess); + found = true; + } + } } - } - if (!found) { - // it's possible the previous process has deregistered before - // the new one has registered, so we should try one more time - // with a little delay - if (tryAgain) { - tryAgain = false; - QThread::msleep(500); - continue; + if (!found) { + // it's possible the previous process has deregistered before + // the new one has registered, so we should try one more time + // with a little delay + if (tryAgain) { + tryAgain = false; + QThread::msleep(500); + continue; + } + else { + break; + } } else { - break; + tryAgain = true; } - } - else { - tryAgain = true; - } - //Cleanup - if (processHandle != INVALID_HANDLE_VALUE) { - if (exitCode != nullptr) { - //This is actually wrong if the process we started finished before we - //got the event and so we end up with a job handle. - if (!::GetExitCodeProcess(processHandle, exitCode)) - { - DWORD error = ::GetLastError(); - qDebug() << "Failed to get process exit code: Error " << error; + //Cleanup + if (processHandle != INVALID_HANDLE_VALUE) { + if (exitCode != nullptr) { + //This is actually wrong if the process we started finished before we + //got the event and so we end up with a job handle. + if (!::GetExitCodeProcess(processHandle, exitCode)) + { + DWORD error = ::GetLastError(); + qDebug() << "Failed to get process exit code: Error " << error; + } + } + if (handle != processHandle) { + ::CloseHandle(processHandle); } - } - if (handle != processHandle) { - ::CloseHandle(processHandle); } } - // keep processing events so the app doesn't appear dead QCoreApplication::processEvents(); } -- cgit v1.3.1 From 0825cd0f203af00a074203dde469bf40102e821d Mon Sep 17 00:00:00 2001 From: Al12rs Date: Tue, 31 Oct 2017 23:20:06 +0100 Subject: Added !found condition to for loop to ensure that a valid processHandle can't be overwritten to avoid handle leaks. --- src/organizercore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/organizercore.cpp') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 48e2f98a..05da9f83 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1264,7 +1264,7 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) size_t count = std::min(static_cast(maxCount), numProcesses); if (count > 0) { - for (size_t i = 0; i < count; ++i) { + for (size_t i = 0; i < count && !found; ++i) { std::wstring processName = getProcessName(processes[i]); if (!boost::starts_with(processName, L"ModOrganizer.exe")) { if (!boost::starts_with(processName, L"unknown")) { -- cgit v1.3.1 From 51ad72c74d89b630e3091e7cb7d6e7dfdcb7b78b Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Thu, 2 Nov 2017 01:41:11 -0500 Subject: Process completion fixes * Closes all old handles * Hides 'unknown' processes * Correctly detects process chains --- src/organizercore.cpp | 154 +++++++++++++++++++++++++------------------------- 1 file changed, 76 insertions(+), 78 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 05da9f83..f77d7356 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1238,84 +1238,82 @@ bool OrganizerCore::waitForApplication(HANDLE handle, LPDWORD exitCode) bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) { - HANDLE processHandle = handle; - - static const DWORD maxCount = 5; - size_t numProcesses = maxCount; - LPDWORD processes = new DWORD[maxCount]; - - DWORD currentProcess = 0UL; - bool tryAgain = true; - - DWORD res; - // Wait for a an event on the handle, a key press, mouse click or timeout - //TODO: Remove MOBase::isOneOf from this query as it was always returning true. - - while ( - res = ::MsgWaitForMultipleObjects(1, &handle, false, 500, - QS_KEY | QS_MOUSE), - ((res != WAIT_FAILED) && (res != WAIT_OBJECT_0)) && - ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) { - - if (!::GetVFSProcessList(&numProcesses, processes)) { - break; - } - bool found = false; - size_t count = - std::min(static_cast(maxCount), numProcesses); - if (count > 0) { - for (size_t i = 0; i < count && !found; ++i) { - std::wstring processName = getProcessName(processes[i]); - if (!boost::starts_with(processName, L"ModOrganizer.exe")) { - if (!boost::starts_with(processName, L"unknown")) { - currentProcess = processes[i]; - m_UserInterface->setProcessName(QString::fromStdWString(processName)); - processHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, currentProcess); - found = true; - } - } - } - if (!found) { - // it's possible the previous process has deregistered before - // the new one has registered, so we should try one more time - // with a little delay - if (tryAgain) { - tryAgain = false; - QThread::msleep(500); - continue; - } - else { - break; - } - } - else { - tryAgain = true; - } - //Cleanup - if (processHandle != INVALID_HANDLE_VALUE) { - if (exitCode != nullptr) { - //This is actually wrong if the process we started finished before we - //got the event and so we end up with a job handle. - if (!::GetExitCodeProcess(processHandle, exitCode)) - { - DWORD error = ::GetLastError(); - qDebug() << "Failed to get process exit code: Error " << error; - } - } - if (handle != processHandle) { - ::CloseHandle(processHandle); - } - } - } - // keep processing events so the app doesn't appear dead - QCoreApplication::processEvents(); - } - //Final Cleanup - if (handle != INVALID_HANDLE_VALUE) { - ::CloseHandle(handle); - } - delete[] processes; - return res == WAIT_OBJECT_0; + HANDLE processHandle = handle; + + static const DWORD maxCount = 5; + size_t numProcesses = maxCount; + LPDWORD processes = new DWORD[maxCount]; + + DWORD currentProcess = 0UL; + bool tryAgain = true; + + DWORD res; + // Wait for a an event on the handle, a key press, mouse click or timeout + //TODO: Remove MOBase::isOneOf from this query as it was always returning true. + while ( + res = ::MsgWaitForMultipleObjects(1, &handle, false, 500, + QS_KEY | QS_MOUSE), + ((res != WAIT_FAILED) || (res != WAIT_OBJECT_0)) && + ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) { + + if (!::GetVFSProcessList(&numProcesses, processes)) { + break; + } + + bool found = false; + size_t count = + std::min(static_cast(maxCount), numProcesses); + for (size_t i = 0; i < count; ++i) { + std::wstring processName = getProcessName(processes[i]); + if (!boost::starts_with(processName, L"ModOrganizer.exe")) { + currentProcess = processes[i]; + if (processHandle != INVALID_HANDLE_VALUE) + ::CloseHandle(processHandle); + processHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, currentProcess); + found = true; + if (!boost::starts_with(processName, L"unknown")) { + m_UserInterface->setProcessName(QString::fromStdWString(processName)); + } + } + } + if (!found) { + // it's possible the previous process has deregistered before + // the new one has registered, so we should try one more time + // with a little delay + if (tryAgain) { + tryAgain = false; + QThread::msleep(500); + continue; + } else { + break; + } + } else { + tryAgain = true; + } + + // keep processing events so the app doesn't appear dead + QCoreApplication::processEvents(); + } + + if (exitCode != nullptr) { + //This is actually wrong if the process we started finished before we + //got the event and so we end up with a job handle. + if (! ::GetExitCodeProcess(processHandle, exitCode)) + { + DWORD error = ::GetLastError(); + qDebug() << "Failed to get process exit code: Error " << error; + } + } + + //Cleanup + if (processHandle != INVALID_HANDLE_VALUE) { + ::CloseHandle(processHandle); + } + if (handle != processHandle) { + ::CloseHandle(handle); + } + + return res == WAIT_OBJECT_0; } bool OrganizerCore::onAboutToRun( -- cgit v1.3.1 From 00af56f7c7e8b233ba6a466b23bb907ba9ca4648 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Thu, 2 Nov 2017 16:01:55 -0500 Subject: Fix remaining handle leaks --- src/organizercore.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index f77d7356..26b726e9 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -104,17 +104,20 @@ static std::wstring getProcessName(DWORD processId) HANDLE process = ::OpenProcess(PROCESS_QUERY_INFORMATION, false, processId); wchar_t buffer[MAX_PATH]; + wchar_t *fileName = L"unknown"; + + if (process == nullptr) return fileName; + if (::GetProcessImageFileNameW(process, buffer, MAX_PATH) != 0) { - wchar_t *fileName = wcsrchr(buffer, L'\\'); + fileName = wcsrchr(buffer, L'\\'); if (fileName == nullptr) { fileName = buffer; } else { fileName += 1; } - return fileName; - } else { - return std::wstring(L"unknown"); } + ::CloseHandle(process); + return fileName; } static void startSteam(QWidget *widget) @@ -363,6 +366,12 @@ bool OrganizerCore::testForSteam() PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processIDs[i]); if (process != nullptr) { + + ON_BLOCK_EXIT([&]() { + if (process != INVALID_HANDLE_VALUE) + ::CloseHandle(process); + }); + HMODULE module; DWORD ignore; @@ -1267,7 +1276,7 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) std::wstring processName = getProcessName(processes[i]); if (!boost::starts_with(processName, L"ModOrganizer.exe")) { currentProcess = processes[i]; - if (processHandle != INVALID_HANDLE_VALUE) + if (processHandle != INVALID_HANDLE_VALUE && processHandle != handle) ::CloseHandle(processHandle); processHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, currentProcess); found = true; -- cgit v1.3.1 From 901bf0059d68c0c84039a3bf248a308c243e4664 Mon Sep 17 00:00:00 2001 From: LePresidente Date: Sat, 4 Nov 2017 09:54:47 +0200 Subject: processes should be deleted at end of waitForProcessCompletion --- src/organizercore.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/organizercore.cpp') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 26b726e9..76fc3eef 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1321,6 +1321,7 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) if (handle != processHandle) { ::CloseHandle(handle); } + delete[] processes; return res == WAIT_OBJECT_0; } -- cgit v1.3.1 From 853c42081d9c7f14bea2ffe8ee076724fd5e3946 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Sun, 5 Nov 2017 01:45:57 -0600 Subject: Rework waitForProcessCompletion - reduce handle use and add delay --- src/organizercore.cpp | 202 +++++++++++++++++++++++++++----------------------- 1 file changed, 110 insertions(+), 92 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 76fc3eef..deb47d74 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -99,25 +99,24 @@ static bool renameFile(const QString &oldName, const QString &newName, return QFile::rename(oldName, newName); } -static std::wstring getProcessName(DWORD processId) +static std::wstring getProcessName(HANDLE process) { - HANDLE process = ::OpenProcess(PROCESS_QUERY_INFORMATION, false, processId); + wchar_t buffer[MAX_PATH]; + wchar_t *fileName = L"unknown"; - wchar_t buffer[MAX_PATH]; - wchar_t *fileName = L"unknown"; + if (process == nullptr) return fileName; - if (process == nullptr) return fileName; + if (::GetProcessImageFileNameW(process, buffer, MAX_PATH) != 0) { + fileName = wcsrchr(buffer, L'\\'); + if (fileName == nullptr) { + fileName = buffer; + } + else { + fileName += 1; + } + } - if (::GetProcessImageFileNameW(process, buffer, MAX_PATH) != 0) { - fileName = wcsrchr(buffer, L'\\'); - if (fileName == nullptr) { - fileName = buffer; - } else { - fileName += 1; - } - } - ::CloseHandle(process); - return fileName; + return fileName; } static void startSteam(QWidget *widget) @@ -1247,83 +1246,102 @@ bool OrganizerCore::waitForApplication(HANDLE handle, LPDWORD exitCode) bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) { - HANDLE processHandle = handle; - - static const DWORD maxCount = 5; - size_t numProcesses = maxCount; - LPDWORD processes = new DWORD[maxCount]; - - DWORD currentProcess = 0UL; - bool tryAgain = true; - - DWORD res; - // Wait for a an event on the handle, a key press, mouse click or timeout - //TODO: Remove MOBase::isOneOf from this query as it was always returning true. - while ( - res = ::MsgWaitForMultipleObjects(1, &handle, false, 500, - QS_KEY | QS_MOUSE), - ((res != WAIT_FAILED) || (res != WAIT_OBJECT_0)) && - ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) { - - if (!::GetVFSProcessList(&numProcesses, processes)) { - break; - } - - bool found = false; - size_t count = - std::min(static_cast(maxCount), numProcesses); - for (size_t i = 0; i < count; ++i) { - std::wstring processName = getProcessName(processes[i]); - if (!boost::starts_with(processName, L"ModOrganizer.exe")) { - currentProcess = processes[i]; - if (processHandle != INVALID_HANDLE_VALUE && processHandle != handle) - ::CloseHandle(processHandle); - processHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, currentProcess); - found = true; - if (!boost::starts_with(processName, L"unknown")) { - m_UserInterface->setProcessName(QString::fromStdWString(processName)); - } - } - } - if (!found) { - // it's possible the previous process has deregistered before - // the new one has registered, so we should try one more time - // with a little delay - if (tryAgain) { - tryAgain = false; - QThread::msleep(500); - continue; - } else { - break; - } - } else { - tryAgain = true; - } - - // keep processing events so the app doesn't appear dead - QCoreApplication::processEvents(); - } - - if (exitCode != nullptr) { - //This is actually wrong if the process we started finished before we - //got the event and so we end up with a job handle. - if (! ::GetExitCodeProcess(processHandle, exitCode)) - { - DWORD error = ::GetLastError(); - qDebug() << "Failed to get process exit code: Error " << error; - } - } - - //Cleanup - if (processHandle != INVALID_HANDLE_VALUE) { - ::CloseHandle(processHandle); - } - if (handle != processHandle) { - ::CloseHandle(handle); - } + DWORD startPID = ::GetProcessId(handle); + + static const DWORD maxCount = 5; + size_t numProcesses = maxCount; + LPDWORD processes = new DWORD[maxCount]; + std::map handles; + + DWORD currentProcess = 0UL; + bool tryAgain = true; + DWORD moProcess = -1; + + DWORD res; + // Wait for a an event on the handle, a key press, mouse click or timeout + //TODO: Remove MOBase::isOneOf from this query as it was always returning true. + while ( + res = ::MsgWaitForMultipleObjects(1, &handle, false, 500, + QS_KEY | QS_MOUSE), + ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) { + + if (!::GetVFSProcessList(&numProcesses, processes)) { + break; + } + + // Get USvFS processes, build a handle map, and allow to continue if invalid PIDs are supplied + bool found = false; + size_t count = + std::min(static_cast(maxCount), numProcesses); + for (size_t i = 0; i < count; ++i) { + DWORD currentProcess = processes[i]; + if (currentProcess != moProcess && handles.count(currentProcess) == 0) { + HANDLE currentHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, currentProcess); + std::wstring processName = getProcessName(currentHandle); + if (!boost::starts_with(processName, L"ModOrganizer.exe")) { + found = true; + if (currentHandle == nullptr || currentHandle == INVALID_HANDLE_VALUE) continue; + handles.insert(std::pair(currentProcess, currentHandle)); + } + else + { + moProcess = processes[i]; + ::CloseHandle(currentHandle); + } + } + } + + // Clean up tracked handles + for (std::map::iterator checkHandle = handles.begin(); checkHandle != handles.end(); ++checkHandle) { + if (checkHandle->second != nullptr && checkHandle->second != INVALID_HANDLE_VALUE) { + DWORD processExit; + BOOL codeCheck = ::GetExitCodeProcess(checkHandle->second, &processExit); + if (!codeCheck || processExit != STILL_ACTIVE) { + if (!codeCheck) qDebug() << "Checking the process failed: Error Code " << ::GetLastError(); + ::CloseHandle(checkHandle->second); + checkHandle = handles.erase(checkHandle); + } + } + } + + if (handles.size() > 0) + m_UserInterface->setProcessName(QString::fromStdWString(getProcessName(handles.begin()->second))); + + if ((res == WAIT_FAILED) || (res == WAIT_OBJECT_0)) { + if (handles.size() > 0) { + QThread::msleep(500); + } + } + + // If process handle is still closed, let's give it one more try... + if (handles.size() == 0 && !found) { + // it's possible the previous process has deregistered before + // the new one has registered, so we should try one more time + // with a little delay + if (tryAgain) { + tryAgain = false; + QThread::msleep(500); + continue; + } + else { + break; + } + } + else { + tryAgain = true; + } + + // keep processing events so the app doesn't appear dead + QCoreApplication::processEvents(); + } + + //Cleanup + if (handle != INVALID_HANDLE_VALUE) { + ::CloseHandle(handle); + } delete[] processes; - return res == WAIT_OBJECT_0; + return res == WAIT_OBJECT_0; } bool OrganizerCore::onAboutToRun( @@ -1676,8 +1694,8 @@ void OrganizerCore::loginSuccessful(bool necessary) task(); } - m_PostLoginTasks.clear(); - NexusInterface::instance()->loginCompleted(); + m_PostLoginTasks.clear(); + NexusInterface::instance()->loginCompleted(); } void OrganizerCore::loginSuccessfulUpdate(bool necessary) -- cgit v1.3.1 From a92fc98246f351ed6657788b9b12aca7cce4771a Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Sun, 5 Nov 2017 13:47:00 -0600 Subject: Remove cruft and reapply input event listening on subprocess delay --- src/organizercore.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index deb47d74..d12b77b9 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1253,13 +1253,11 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) LPDWORD processes = new DWORD[maxCount]; std::map handles; - DWORD currentProcess = 0UL; bool tryAgain = true; DWORD moProcess = -1; DWORD res; // Wait for a an event on the handle, a key press, mouse click or timeout - //TODO: Remove MOBase::isOneOf from this query as it was always returning true. while ( res = ::MsgWaitForMultipleObjects(1, &handle, false, 500, QS_KEY | QS_MOUSE), @@ -1304,20 +1302,22 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) } } + // Update the lock process name with the name of the lowest active PID - though this may not actually be the main process if (handles.size() > 0) m_UserInterface->setProcessName(QString::fromStdWString(getProcessName(handles.begin()->second))); + // If the main wait process dies, we need a backup wait process until the subprocesses close if ((res == WAIT_FAILED) || (res == WAIT_OBJECT_0)) { if (handles.size() > 0) { - QThread::msleep(500); + // By the time we get here, the main wait function should always immediately continue + // Passing in a handle doesn't seem to work for subprocesses + ::MsgWaitForMultipleObjects(0, NULL, FALSE, 500, QS_KEY | QS_MOUSE); } } - // If process handle is still closed, let's give it one more try... + // Give the process list a short time to populate + // Required for initial USVFS boot and process switching if (handles.size() == 0 && !found) { - // it's possible the previous process has deregistered before - // the new one has registered, so we should try one more time - // with a little delay if (tryAgain) { tryAgain = false; QThread::msleep(500); -- cgit v1.3.1 From 4cd09a2f3b25c1af5939f5de0153b1438241a874 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Sun, 5 Nov 2017 14:03:02 -0600 Subject: Wait for mousebutton to reduce MO cpu use while waiting --- src/organizercore.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/organizercore.cpp') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index d12b77b9..f8a368c9 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1260,7 +1260,7 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) // Wait for a an event on the handle, a key press, mouse click or timeout while ( res = ::MsgWaitForMultipleObjects(1, &handle, false, 500, - QS_KEY | QS_MOUSE), + QS_KEY | QS_MOUSEBUTTON), ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) { if (!::GetVFSProcessList(&numProcesses, processes)) { @@ -1311,7 +1311,7 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) if (handles.size() > 0) { // By the time we get here, the main wait function should always immediately continue // Passing in a handle doesn't seem to work for subprocesses - ::MsgWaitForMultipleObjects(0, NULL, FALSE, 500, QS_KEY | QS_MOUSE); + ::MsgWaitForMultipleObjects(0, NULL, FALSE, 500, QS_KEY | QS_MOUSEBUTTON); } } -- cgit v1.3.1