Mercurial > trustbridge
view ui/installwrapper.cpp @ 392:8090a1bc1b5b
Add a space in the command line
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Tue, 15 Apr 2014 20:26:42 +0200 |
parents | a507e5f1b999 |
children | 17e1c8f37d72 |
line wrap: on
line source
#include "installwrapper.h" #include <QFileInfo> #include <QProcess> #include <QTemporaryFile> #include <QApplication> #include <QDir> #include <QDebug> #include "logging.h" #define INSTALL_TIMEOUT 3600000 /* Wait up to an hour */ InstallWrapper::InstallWrapper(QObject* parent, const QString& path, const QStringList& choices): QThread(parent), mCertListFile(path), mChoices(choices) { } QFileInfo getCinstProcInfo() { QFileInfo fi(QCoreApplication::applicationFilePath()); QDir myDir = fi.absoluteDir(); QString instProcName = "cinst"; if (!fi.suffix().isEmpty()) { instProcName += "." + fi.suffix(); } return QFileInfo(myDir.absoluteFilePath(instProcName)); } bool InstallWrapper::writeChoices(QTemporaryFile* choicesFile) const { if (!choicesFile->open()) { return false; } foreach (const QString &b64data, mChoices) { if (!choicesFile->write(b64data.toLatin1())) { return false; } if (!choicesFile->write("\n")) { return false; } } choicesFile->close(); return true; } void InstallWrapper::run() { /* TODO: We need errorcodes here so that we can see if a user * cancled the UAC elevation */ QTemporaryFile choicesFile; QFileInfo cinstProcInfo = getCinstProcInfo(); QString cinstFileName = QDir::toNativeSeparators( getCinstProcInfo().absoluteFilePath()); if (!cinstProcInfo.isExecutable()) { emit error(tr("Could not find certificate installation process.")); return; } if (!writeChoices(&choicesFile)) { emit error(tr("Failed to write temporary file.")); return; } #ifdef WIN32 /* QProcess on Windows uses CreateProcess but we have to * use the runas shell command to get the UAC prompt if necessary. * So we have to handle the process ourself. Starting with * shell execute also means that we can not have stdout and stderr * redirection. This is the reason we use command line parameters * and not a pipe for communication. In debug mode the installer * also makes use of output debug string. */ DWORD retval = 0; SHELLEXECUTEINFOW shExecInfo; memset (&shExecInfo, 0, sizeof(SHELLEXECUTEINFOW)); /* Windows needs each parameter packed in " */ QString parameters = "\"list=" + mCertListFile + "\" \"choices=" + choicesFile.fileName() + "\""; shExecInfo.cbSize = sizeof(SHELLEXECUTEINFOW); shExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; shExecInfo.lpVerb = L"runas"; shExecInfo.lpFile = reinterpret_cast<LPCWSTR> (cinstFileName.utf16()); shExecInfo.lpParameters = reinterpret_cast<LPCWSTR> (parameters.utf16()); qDebug() << "Starting process " << cinstFileName <<" params: " << parameters; if (!ShellExecuteExW(&shExecInfo)) { char* errmsg = getLastErrorMsg(); QString qerrmsg = QString::fromUtf8(errmsg); free(errmsg); emit error(tr("Error executing process: %1").arg(qerrmsg)); return; } retval = WaitForSingleObject(shExecInfo.hProcess, INSTALL_TIMEOUT); if (retval != WAIT_OBJECT_0) { if (retval == WAIT_FAILED) { char* errmsg = getLastErrorMsg(); QString qerrmsg = QString::fromUtf8(errmsg); free(errmsg); emit error (tr("Error monitoring process: %1").arg(qerrmsg)); return; } else { emit error (tr("Certificate installation timed out.")); return; } } if (GetExitCodeProcess(shExecInfo.hProcess, &retval)) { if (retval == STILL_ACTIVE) { qDebug() << "Process still running, huh.."; } } else { char* errmsg = getLastErrorMsg(); QString qerrmsg = QString::fromUtf8(errmsg); free(errmsg); emit error (tr("Failed to check process status: %1").arg(qerrmsg)); CloseHandle(shExecInfo.hProcess); return; } CloseHandle(shExecInfo.hProcess); if (retval != 0) { /* TODO make this nicer */ emit error (tr("The process failed with return code. %1").arg(retval)); return; } #else /* WIN32 */ QProcess installerProcess; installerProcess.setProgram(cinstProcInfo.absoluteFilePath()); QStringList parameters; choicesFile.setAutoRemove(false); parameters << "list=" + mCertListFile << "choices=" + choicesFile.fileName(); installerProcess.setArguments(parameters); qDebug() << "Starting process " << cinstFileName <<" params: " << parameters; installerProcess.start(); if (!installerProcess.waitForStarted() || installerProcess.state() == QProcess::NotRunning) { emit error (tr("Failed to start installer process.")); return; } installerProcess.waitForFinished(); if (installerProcess.exitStatus() == QProcess::CrashExit) { /* Woops */ emit error (tr("Failed to complete installation.")); return; } else if (installerProcess.exitStatus() != QProcess::NormalExit) { /* Can not Happen. there are only those two values but maybe * qt changed.. */ emit error (tr("Failed to complete installation.")); return; } if (installerProcess.exitCode() == 0) { qDebug() << "output: " << installerProcess.readAllStandardOutput(); } else { /* TODO handle errors defined by errorcodes.h */ qDebug() << "Installer Process returned: " << installerProcess.exitCode(); qDebug() << "output: " << installerProcess.readAllStandardOutput(); return; } #endif emit installationSuccessful(); }