diff options
| author | Brian Munro <brian.alexander.munro@gmail.com> | 2017-12-05 06:34:47 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-12-05 06:34:47 +0200 |
| commit | fa598e86dbce096b5439ae704dd18cc5b1289191 (patch) | |
| tree | 66f9ecd51775c9e184b1679fc2d6fecc74fb1d8a /src/organizercore.cpp | |
| parent | c64e12a289066c6b4834c43a49ff631a33b2f3ce (diff) | |
| parent | ffdc5ca7ccb24bc937ed5418b7a6e5a1b7d719dd (diff) | |
Merge pull request #135 from LePresidente/QT5.7
All changes done for 2.1.0
Diffstat (limited to 'src/organizercore.cpp')
| -rw-r--r-- | src/organizercore.cpp | 205 |
1 files changed, 127 insertions, 78 deletions
diff --git a/src/organizercore.cpp b/src/organizercore.cpp index d9ed6ab6..f8a368c9 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -99,22 +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];
- if (::GetProcessImageFileNameW(process, buffer, MAX_PATH) != 0) {
- wchar_t *fileName = wcsrchr(buffer, L'\\');
- if (fileName == nullptr) {
- fileName = buffer;
- } else {
- fileName += 1;
- }
- return fileName;
- } else {
- return std::wstring(L"unknown");
- }
+ if (process == nullptr) return fileName;
+
+ if (::GetProcessImageFileNameW(process, buffer, MAX_PATH) != 0) {
+ fileName = wcsrchr(buffer, L'\\');
+ if (fileName == nullptr) {
+ fileName = buffer;
+ }
+ else {
+ fileName += 1;
+ }
+ }
+
+ return fileName;
}
static void startSteam(QWidget *widget)
@@ -363,6 +365,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;
@@ -1238,75 +1246,102 @@ bool OrganizerCore::waitForApplication(HANDLE handle, LPDWORD exitCode) bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode)
{
- HANDLE processHandle = handle;
+ DWORD startPID = ::GetProcessId(handle);
- static const DWORD maxCount = 5;
- size_t numProcesses = maxCount;
- LPDWORD processes = new DWORD[maxCount];
+ static const DWORD maxCount = 5;
+ size_t numProcesses = maxCount;
+ LPDWORD processes = new DWORD[maxCount];
+ std::map<DWORD, HANDLE> handles;
- DWORD currentProcess = 0UL;
- bool tryAgain = true;
+ 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),
- ((res != WAIT_FAILED) || (res != WAIT_OBJECT_0)) &&
- ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) {
+ DWORD res;
+ // 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_MOUSEBUTTON),
+ ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) {
- if (!::GetVFSProcessList(&numProcesses, processes)) {
- break;
- }
+ if (!::GetVFSProcessList(&numProcesses, processes)) {
+ break;
+ }
- bool found = false;
- size_t count =
- std::min<size_t>(static_cast<size_t>(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 (!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;
- }
+ // Get USvFS processes, build a handle map, and allow to continue if invalid PIDs are supplied
+ bool found = false;
+ size_t count =
+ std::min<size_t>(static_cast<size_t>(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<DWORD, HANDLE>(currentProcess, currentHandle));
+ }
+ else
+ {
+ moProcess = processes[i];
+ ::CloseHandle(currentHandle);
+ }
+ }
+ }
- // keep processing events so the app doesn't appear dead
- QCoreApplication::processEvents();
- }
+ // Clean up tracked handles
+ for (std::map<DWORD, HANDLE>::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 (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;
- }
- }
+ // 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)));
- ::CloseHandle(processHandle);
- if (handle != processHandle) {
- ::CloseHandle(handle);
- }
+ // 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) {
+ // 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_MOUSEBUTTON);
+ }
+ }
- return res == WAIT_OBJECT_0;
+ // Give the process list a short time to populate
+ // Required for initial USVFS boot and process switching
+ if (handles.size() == 0 && !found) {
+ 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;
}
bool OrganizerCore::onAboutToRun(
@@ -1413,6 +1448,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 +1478,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();
@@ -1645,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)
@@ -1723,7 +1772,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");
|
