view ui/installwrapper.cpp @ 289:9ad00a3255f4

Change cinst from stdin input to use arguments. As we have to execute this process on Windows over the shell a stdin / stdout communication is not really possible without some major hacks. So you now have to supply an instructions file and the path to the certificatelist as arguments when this process is called
author Andre Heinecke <aheinecke@intevation.de>
date Wed, 02 Apr 2014 13:52:02 +0000
parents f23e0ccd5d14
children dc4efb0a70cb
line wrap: on
line source
#include "installwrapper.h"

#include <QFileInfo>
#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& instructions):
    QThread(parent),
    mCertListFile(path),
    mInstructions(instructions)
{
}

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));
}

#ifdef WIN32
void InstallWrapper::run()
{
    /* TODO: We need errorcodes here so that we can see if a user
     * cancled the UAC elevation */
    QTemporaryFile instructionsFile;
    QFileInfo cinstProcInfo = getCinstProcInfo();
    DWORD retval = 0;
    SHELLEXECUTEINFOW shExecInfo;
    memset (&shExecInfo, 0, sizeof(SHELLEXECUTEINFOW));

    QString cinstFileName = QDir::toNativeSeparators(
            getCinstProcInfo().absoluteFilePath());

    if (!cinstProcInfo.isExecutable()) {
        emit error(tr("Could not find certificate installation process."));
        return;
    }

    instructionsFile.open();

    foreach (const QString &b64data, mInstructions) {
       instructionsFile.write(b64data.toLatin1());
       instructionsFile.write("\n");
    }

    instructionsFile.close();

    QString parameters = "\"list=" + mCertListFile + 
        "\" \"instructions=" +instructionsFile.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);

    if (retval != 0) {
        /* TODO make this nicer */
        emit error (tr("The process failed with return code. %1").arg(retval));
    }
}
#else
void InstallWrapper::run()
{
}
#endif

http://wald.intevation.org/projects/trustbridge/