Warning, file /frameworks/kinit/src/kwrapper/kwrapper_win.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2007 Ralf Habacker <ralf.habacker@freenet.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 /*
0009   kde application starter
0010   - allows starting kde application without any additional path settings [1]
0011   - supports multiple root installation which is often used by packagers
0012     (adds bin/lib directories from KDEDIRS environment to PATH environment)
0013   - designed to start kde application from windows start menu entries
0014   - support for reading KDEDIRS setting from flat file
0015     (located in <path-of-kwrapper.exe>/../../kdedirs.cache)
0016   - planned: automatic KDEDIRS detection support
0017 
0018 [1] recent kde cmake buildsystem on win32 installs shared libraries
0019     into lib instead of bin. This requires to have the lib directory
0020     in the PATH environment variable too (required for all paths in KDEDIRS)
0021 
0022  TODO: There is an prelimary concept of setting KDEDIRS environment variable
0023        from a cache file located on a well known path relative from the requested
0024        application.
0025        The recent implementation expects a file name 'kdedirs.cache' two level
0026        above this executable which will be <ProgramFiles> in case kwrapper5 lives
0027        in <Programfiles>/kde5/bin.
0028        This works not in any case especially when running application inside the
0029        build directory.
0030 
0031 */
0032 
0033 #include <stdio.h>
0034 #include <assert.h>
0035 #include <stdlib.h>
0036 #include <process.h>
0037 #include <windows.h>
0038 
0039 #include <QString>
0040 #include <QProcess>
0041 #include <QtDebug>
0042 #include <QFileInfo>
0043 #include <QCoreApplication>
0044 #include <QList>
0045 
0046 bool verbose = 0;
0047 
0048 int main(int argc, char **argv)
0049 {
0050     QCoreApplication app(argc, argv);
0051 
0052     QStringList envPath; /// paths for using in environment of started process
0053     QStringList searchPath; /// paths for using to find executable
0054     QString exeToStart;
0055     QString myAppName = QStringLiteral("kwrapper5:");
0056     QStringList exeParams;
0057     int firstParam = 1;
0058 
0059     if (QCoreApplication::arguments().size() == 1) {
0060         qDebug() << myAppName << "no application given";
0061         return 1;
0062     }
0063 
0064     if (QCoreApplication::arguments().at(1) == QStringLiteral("--verbose")) {
0065         verbose = 1;
0066         firstParam = 2;
0067     }
0068 
0069     exeToStart = QCoreApplication::arguments().at(firstParam);
0070 
0071     for (int i = firstParam + 1; i < QCoreApplication::arguments().size(); i++) {
0072         exeParams << QCoreApplication::arguments().at(i);
0073     }
0074 
0075     QString path = QString::fromLocal8Bit(qgetenv("PATH")).toLower()
0076         .replace(QLatin1Char('\\'), QLatin1Char('/'));
0077 
0078     /** add paths from PATH environment
0079         - all to client path environment
0080         - paths not ending with lib to application search path
0081     */
0082     const auto lst = path.split(QLatin1Char(';'));
0083     for (const QString &a : lst) {
0084         if (!envPath.contains(a)) {
0085             envPath << a;
0086         }
0087         if (!a.endsWith(QLatin1String("/lib")) && !a.endsWith(QLatin1String("/lib/")) && !searchPath.contains(a)) {
0088             searchPath << a;
0089         }
0090     }
0091 
0092     // add current install path
0093     path = QCoreApplication::applicationDirPath().toLower().replace(QLatin1Char('\\'), QLatin1Char('/'));
0094     if (!envPath.contains(path)) {
0095         envPath << path;
0096     }
0097 
0098     // detect directory where kdedirs.cache lives
0099     // this is not complete, KDEDIRS path should be used as base too
0100     QFileInfo fi(path + QStringLiteral("/../.."));
0101     QString rootPath = fi.canonicalPath();
0102 
0103     if (verbose) {
0104         qDebug() << "try to find kdedirs.cache in" << rootPath;
0105     }
0106 
0107     // add current lib path to client path environment
0108     path = path.replace(QStringLiteral("bin"), QStringLiteral("lib"));
0109     if (!envPath.contains(path)) {
0110         envPath << path;
0111     }
0112 
0113     /**
0114       add bin and lib paths from KDEDIRS
0115         - bin/lib to client path environment
0116         - bin to application search path
0117     */
0118     path = QString::fromLocal8Bit(qgetenv("KDEDIRS")).toLower().replace(QLatin1Char('\\'), QLatin1Char('/'));
0119     QStringList kdedirs;
0120 
0121     if (!path.isEmpty()) {
0122         kdedirs = path.split(QLatin1Char(';'));
0123     }
0124 
0125     bool changedKDEDIRS = 0;
0126     // setup kdedirs if not present
0127     if (kdedirs.size() == 0) {
0128         QStringList kdedirsCacheList;
0129 #ifdef Q_CC_MSVC
0130         kdedirsCacheList << rootPath + QStringLiteral("/kdedirs.cache.msvc");
0131 #endif
0132         kdedirsCacheList << rootPath + QStringLiteral("/kdedirs.cache");
0133 
0134         bool found = false;
0135         for (const QString &kdedirsCachePath : std::as_const(kdedirsCacheList)) {
0136             QFile f(kdedirsCachePath);
0137             if (f.exists()) {
0138                 f.open(QIODevice::ReadOnly);
0139                 QByteArray data = f.readAll();
0140                 f.close();
0141                 kdedirs = QString::fromLocal8Bit(data).split(QLatin1Char(';'));
0142                 if (verbose) {
0143                     qDebug() << "load kdedirs cache from " << kdedirsCachePath <<  "values=" << kdedirs;
0144                 }
0145                 found = true;
0146                 break;
0147             }
0148         }
0149         if (!found) {
0150             /*
0151                         f.open(QIODevice::WriteOnly);
0152                         // search all paths one level above for a directory share/apps
0153                         // write entries into a cache
0154                         f.write(kdedirs.join(";").toLatin1());
0155                         f.close();
0156             */
0157         }
0158         changedKDEDIRS = 1;
0159     }
0160     if (verbose) {
0161         qDebug() << "found KDEDIRS\n\t" << kdedirs.join(QStringLiteral("\n\t"));
0162     }
0163 
0164     for (const QString &a : std::as_const(kdedirs)) {
0165         if (!envPath.contains(a + QStringLiteral("/bin"))) {
0166             envPath << a + QStringLiteral("/bin");
0167         }
0168         if (!envPath.contains(a + QStringLiteral("/lib"))) {
0169             envPath << a + QStringLiteral("/lib");
0170         }
0171         if (!searchPath.contains(a + QStringLiteral("/bin"))) {
0172             searchPath << a + QStringLiteral("/bin");
0173         }
0174     }
0175 
0176     // find executable
0177     WCHAR _appName[MAX_PATH + 1];
0178 
0179     if (verbose) {
0180         qDebug() << "search " << exeToStart << "in";
0181     }
0182 
0183     bool found = false;
0184     for (const QString &a : std::as_const(searchPath)) {
0185         if (verbose) {
0186             qDebug() << "\t" << a;
0187         }
0188 #ifndef _WIN32_WCE
0189         if (SearchPathW((LPCWSTR)a.utf16(), (LPCWSTR)exeToStart.utf16(),
0190                         L".exe", MAX_PATH + 1, (LPWSTR)_appName, NULL)) {
0191             found = true;
0192             break;
0193         }
0194 #else
0195         if (QFile::exists(a + "/" + exeToStart + ".exe")) {
0196             found = true;
0197             break;
0198         }
0199 #endif
0200     }
0201     QString appName = QString::fromUtf16((unsigned short *)_appName);
0202 
0203     if (!found) {
0204         qWarning() << myAppName << "application not found";
0205         return 3;
0206     }
0207 
0208     if (verbose) {
0209         qDebug() << "run" << exeToStart << "with params" << exeParams
0210             << "and PATH environment\n\t" << envPath.join(QStringLiteral("\n\t"));
0211     }
0212 
0213     // setup client process environment
0214     QStringList env = QProcess::systemEnvironment();
0215     env.replaceInStrings(QRegExp(QStringLiteral("^PATH=(.*)"), Qt::CaseInsensitive),
0216         QLatin1String("PATH=") + envPath.join(QLatin1Char(';')));
0217     if (changedKDEDIRS) {
0218         env << QStringLiteral("KDEDIRS=") + kdedirs.join(QLatin1Char(';'));
0219     }
0220 
0221     QProcess *process = new QProcess;
0222     process->setEnvironment(env);
0223     process->start(appName, exeParams);
0224     if (process->state() == QProcess::NotRunning) {
0225         qWarning() << myAppName << "process not running";
0226         return 4;
0227     }
0228     process->waitForStarted();
0229 
0230     return 0;
0231 }