36 #include <QCoreApplication>
38 #include <QRegularExpression>
39 #include <QStringList>
55 proc.start(exeName, {
"--version"}, QIODevice::ReadOnly);
56 if (proc.waitForFinished() && (proc.exitCode() == QProcess::NormalExit))
58 QByteArray procOutput = proc.readAllStandardOutput();
59 if (procOutput.isEmpty())
60 procOutput = proc.readAllStandardError();
61 procOutput = procOutput.simplified();
67 if (outputSplit.size() <= 1)
72 const QString versionStr = outputSplit[1];
73 const int idx = versionStr.indexOf(QRegularExpression(
"[^\\.\\d]"));
77 info = {exeName, versionStr.left(idx)};
84 LogMsg(QCoreApplication::translate(
"Utils::ForeignApps",
"Python detected, executable name: '%1', version: %2")
100 QStringList getRegSubkeys(
const HKEY handle)
105 DWORD cMaxSubKeyLen = 0;
106 LONG res = ::RegQueryInfoKeyW(handle, NULL, NULL, NULL, &cSubKeys, &cMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
108 if (res == ERROR_SUCCESS)
111 LPWSTR lpName =
new WCHAR[cMaxSubKeyLen];
114 for (DWORD i = 0; i < cSubKeys; ++i)
116 cName = cMaxSubKeyLen;
117 res = ::RegEnumKeyExW(handle, i, lpName, &cName, NULL, NULL, NULL, NULL);
118 if (res == ERROR_SUCCESS)
119 keys.push_back(QString::fromWCharArray(lpName));
128 QString getRegValue(
const HKEY handle,
const QString &name = {})
134 LPWSTR lpValueName = NULL;
137 lpValueName =
new WCHAR[name.size() + 1];
138 name.toWCharArray(lpValueName);
139 lpValueName[name.size()] = 0;
143 ::RegQueryValueExW(handle, lpValueName, NULL, &type, NULL, &cbData);
144 DWORD cBuffer = (cbData /
sizeof(WCHAR)) + 1;
145 LPWSTR lpData =
new WCHAR[cBuffer];
146 LONG res = ::RegQueryValueExW(handle, lpValueName, NULL, &type, (LPBYTE)lpData, &cbData);
148 delete[] lpValueName;
150 if (res == ERROR_SUCCESS)
152 lpData[cBuffer - 1] = 0;
153 result = QString::fromWCharArray(lpData);
160 QString pythonSearchReg(
const REG_SEARCH_TYPE type)
164 hkRoot = HKEY_CURRENT_USER;
166 hkRoot = HKEY_LOCAL_MACHINE;
168 REGSAM samDesired = KEY_READ;
169 if (type == SYSTEM_32BIT)
170 samDesired |= KEY_WOW64_32KEY;
171 else if (type == SYSTEM_64BIT)
172 samDesired |= KEY_WOW64_64KEY;
177 res = ::RegOpenKeyExW(hkRoot, L
"SOFTWARE\\Python\\PythonCore", 0, samDesired, &hkPythonCore);
179 if (res == ERROR_SUCCESS)
181 QStringList versions = getRegSubkeys(hkPythonCore);
182 qDebug(
"Python versions nb: %d", versions.size());
186 while (!found && !versions.empty())
188 const QString version = versions.takeLast() +
"\\InstallPath";
189 LPWSTR lpSubkey =
new WCHAR[version.size() + 1];
190 version.toWCharArray(lpSubkey);
191 lpSubkey[version.size()] = 0;
194 res = ::RegOpenKeyExW(hkPythonCore, lpSubkey, 0, samDesired, &hkInstallPath);
197 if (res == ERROR_SUCCESS)
199 qDebug(
"Detected possible Python v%s location", qUtf8Printable(version));
200 path = getRegValue(hkInstallPath);
201 ::RegCloseKey(hkInstallPath);
205 const QDir baseDir {path};
207 if (baseDir.exists(
"python3.exe"))
210 path = baseDir.filePath(
"python3.exe");
212 else if (baseDir.exists(
"python.exe"))
215 path = baseDir.filePath(
"python.exe");
224 ::RegCloseKey(hkPythonCore);
230 QString findPythonPath()
232 QString path = pythonSearchReg(USER);
236 path = pythonSearchReg(SYSTEM_32BIT);
240 path = pythonSearchReg(SYSTEM_64BIT);
245 const QFileInfoList dirs = QDir(
"C:/").entryInfoList({
"Python*"}, QDir::Dirs, (QDir::Name | QDir::Reversed));
246 for (
const QFileInfo &info : dirs)
248 const QString py3Path {info.absolutePath() +
"/python3.exe"};
249 if (QFile::exists(py3Path))
252 const QString pyPath {info.absolutePath() +
"/python.exe"};
253 if (QFile::exists(pyPath))
264 return (!executableName.isEmpty() && version.isValid());
269 return (version >=
Version {3, 5, 0});
283 #if defined(Q_OS_WIN)
288 LogMsg(QCoreApplication::translate(
"Utils::ForeignApps",
"Python not detected"),
Log::INFO);
void LogMsg(const QString &message, const Log::MsgType &type)
QVector< QByteArray > splitToViews(const QByteArray &in, const QByteArray &sep, const Qt::SplitBehavior behavior=Qt::KeepEmptyParts)
bool testPythonInstallation(const QString &exeName, PythonInfo &info)
bool isSupportedVersion() const