mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-08-21 22:03:27 -07:00
Improve Windows Registry searching for Python.
Simplify logic of related functions. Make sure that all open handles are closed. Explicitly use Unicode versions of Windows API functions. Prevent max subkey length overwrite. Use Windows API style of variable names.
This commit is contained in:
parent
68c06c7485
commit
f851875ad1
1 changed files with 130 additions and 125 deletions
|
@ -1339,145 +1339,150 @@ void Preferences::disableRecursiveDownload(bool disable) {
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
namespace {
|
namespace {
|
||||||
enum REG_SEARCH_TYPE {USER, SYSTEM_32BIT, SYSTEM_64BIT};
|
enum REG_SEARCH_TYPE
|
||||||
|
{
|
||||||
|
USER,
|
||||||
|
SYSTEM_32BIT,
|
||||||
|
SYSTEM_64BIT
|
||||||
|
};
|
||||||
|
|
||||||
QStringList getRegSubkeys(const HKEY &handle) {
|
QStringList getRegSubkeys(HKEY handle)
|
||||||
QStringList keys;
|
{
|
||||||
DWORD subkeys_count = 0;
|
QStringList keys;
|
||||||
DWORD max_subkey_len = 0;
|
|
||||||
long res = ::RegQueryInfoKey(handle, NULL, NULL, NULL, &subkeys_count, &max_subkey_len, NULL, NULL, NULL, NULL, NULL, NULL);
|
|
||||||
if (res == ERROR_SUCCESS) {
|
|
||||||
max_subkey_len++; //For null character
|
|
||||||
LPTSTR key_name = new TCHAR[max_subkey_len];
|
|
||||||
|
|
||||||
for (uint i=0; i<subkeys_count; i++) {
|
DWORD cSubKeys = 0;
|
||||||
res = ::RegEnumKeyEx(handle, 0, key_name, &max_subkey_len, NULL, NULL, NULL, NULL);
|
DWORD cMaxSubKeyLen = 0;
|
||||||
if (res == ERROR_SUCCESS)
|
LONG res = ::RegQueryInfoKeyW(handle, NULL, NULL, NULL, &cSubKeys, &cMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||||
keys.push_back(QString::fromWCharArray(key_name));
|
|
||||||
}
|
|
||||||
delete[] key_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
return keys;
|
if (res == ERROR_SUCCESS) {
|
||||||
}
|
cMaxSubKeyLen++; // For null character
|
||||||
|
LPWSTR lpName = new WCHAR[cMaxSubKeyLen];
|
||||||
|
DWORD cName;
|
||||||
|
|
||||||
QString getRegValue(const HKEY &handle, const QString &name = QString()) {
|
for (DWORD i = 0; i < cSubKeys; ++i) {
|
||||||
QString end_result;
|
cName = cMaxSubKeyLen;
|
||||||
DWORD type = 0;
|
res = ::RegEnumKeyExW(handle, 0, lpName, &cName, NULL, NULL, NULL, NULL);
|
||||||
DWORD size = 0;
|
if (res == ERROR_SUCCESS)
|
||||||
DWORD array_size = 0;
|
keys.push_back(QString::fromWCharArray(lpName));
|
||||||
|
|
||||||
LPTSTR value_name = NULL;
|
|
||||||
if (!name.isEmpty()) {
|
|
||||||
value_name = new TCHAR[name.size()+1];
|
|
||||||
name.toWCharArray(value_name);
|
|
||||||
value_name[name.size()] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Discover the size of the value
|
|
||||||
::RegQueryValueEx(handle, value_name, NULL, &type, NULL, &size);
|
|
||||||
array_size = size / sizeof(TCHAR);
|
|
||||||
if (size % sizeof(TCHAR))
|
|
||||||
array_size++;
|
|
||||||
array_size++; //For null character
|
|
||||||
LPTSTR value = new TCHAR[array_size];
|
|
||||||
|
|
||||||
long res = ::RegQueryValueEx(handle, value_name, NULL, &type, (LPBYTE)value, &size);
|
|
||||||
if (res == ERROR_SUCCESS) {
|
|
||||||
value[array_size] = '\0';
|
|
||||||
end_result = QString::fromWCharArray(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value_name)
|
|
||||||
delete[] value_name;
|
|
||||||
if (value)
|
|
||||||
delete[] value;
|
|
||||||
|
|
||||||
return end_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString pythonSearchReg(const REG_SEARCH_TYPE type) {
|
|
||||||
HKEY key_handle1;
|
|
||||||
long res = 0;
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case USER:
|
|
||||||
res = ::RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Python\\PythonCore"), 0, KEY_READ, &key_handle1);
|
|
||||||
break;
|
|
||||||
case SYSTEM_32BIT:
|
|
||||||
res = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Python\\PythonCore"), 0, KEY_READ|KEY_WOW64_32KEY, &key_handle1);
|
|
||||||
break;
|
|
||||||
case SYSTEM_64BIT:
|
|
||||||
res = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Python\\PythonCore"), 0, KEY_READ|KEY_WOW64_64KEY, &key_handle1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res == ERROR_SUCCESS) {
|
|
||||||
QStringList versions = getRegSubkeys(key_handle1);
|
|
||||||
qDebug("Python versions nb: %d", versions.size());
|
|
||||||
versions.sort();
|
|
||||||
|
|
||||||
while(!versions.empty()) {
|
|
||||||
const QString version = versions.takeLast()+"\\InstallPath";
|
|
||||||
HKEY key_handle2;
|
|
||||||
LPTSTR subkey = new TCHAR[version.size()+1];
|
|
||||||
version.toWCharArray(subkey);
|
|
||||||
subkey[version.size()] = '\0';
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case USER:
|
|
||||||
res = ::RegOpenKeyEx(key_handle1, subkey, 0, KEY_READ, &key_handle2);
|
|
||||||
break;
|
|
||||||
case SYSTEM_32BIT:
|
|
||||||
res = ::RegOpenKeyEx(key_handle1, subkey, 0, KEY_READ|KEY_WOW64_32KEY, &key_handle2);
|
|
||||||
break;
|
|
||||||
case SYSTEM_64BIT:
|
|
||||||
res = ::RegOpenKeyEx(key_handle1, subkey, 0, KEY_READ|KEY_WOW64_64KEY, &key_handle2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] subkey;
|
|
||||||
if (res == ERROR_SUCCESS) {
|
|
||||||
qDebug("Detected possible Python v%s location", qPrintable(version));
|
|
||||||
QString path = getRegValue(key_handle2);
|
|
||||||
::RegCloseKey(key_handle2);
|
|
||||||
if (!path.isEmpty() && QDir(path).exists("python.exe")) {
|
|
||||||
qDebug("Found python.exe at %s", qPrintable(path));
|
|
||||||
::RegCloseKey(key_handle1);
|
|
||||||
return path;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
delete[] lpName;
|
||||||
::RegCloseKey(key_handle2);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
::RegCloseKey(key_handle1);
|
return keys;
|
||||||
return QString::null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString getRegValue(HKEY handle, const QString &name = QString())
|
||||||
|
{
|
||||||
|
QString result;
|
||||||
|
|
||||||
|
DWORD type = 0;
|
||||||
|
DWORD cbData = 0;
|
||||||
|
LPWSTR lpValueName = NULL;
|
||||||
|
if (!name.isEmpty()) {
|
||||||
|
lpValueName = new WCHAR[name.size() + 1];
|
||||||
|
name.toWCharArray(lpValueName);
|
||||||
|
lpValueName[name.size()] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Discover the size of the value
|
||||||
|
::RegQueryValueExW(handle, lpValueName, NULL, &type, NULL, &cbData);
|
||||||
|
DWORD cBuffer = (cbData / sizeof(WCHAR)) + 1;
|
||||||
|
LPWSTR lpData = new WCHAR[cBuffer];
|
||||||
|
LONG res = ::RegQueryValueExW(handle, lpValueName, NULL, &type, (LPBYTE)lpData, &cbData);
|
||||||
|
if (lpValueName)
|
||||||
|
delete[] lpValueName;
|
||||||
|
|
||||||
|
if (res == ERROR_SUCCESS) {
|
||||||
|
lpData[cBuffer] = 0;
|
||||||
|
result = QString::fromWCharArray(lpData);
|
||||||
|
}
|
||||||
|
delete[] lpData;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Preferences::getPythonPath() {
|
QString pythonSearchReg(const REG_SEARCH_TYPE type)
|
||||||
QString path = pythonSearchReg(USER);
|
{
|
||||||
if (path.isEmpty())
|
HKEY hkRoot;
|
||||||
path = pythonSearchReg(SYSTEM_32BIT);
|
if (type == USER)
|
||||||
else return path;
|
hkRoot = HKEY_CURRENT_USER;
|
||||||
|
else
|
||||||
|
hkRoot = HKEY_LOCAL_MACHINE;
|
||||||
|
|
||||||
if (path.isEmpty())
|
REGSAM samDesired = KEY_READ;
|
||||||
path = pythonSearchReg(SYSTEM_64BIT);
|
if (type == SYSTEM_32BIT)
|
||||||
else return path;
|
samDesired |= KEY_WOW64_32KEY;
|
||||||
|
else if (type == SYSTEM_64BIT)
|
||||||
|
samDesired |= KEY_WOW64_64KEY;
|
||||||
|
|
||||||
|
QString path;
|
||||||
|
LONG res = 0;
|
||||||
|
HKEY hkPythonCore;
|
||||||
|
res = ::RegOpenKeyExW(hkRoot, L"SOFTWARE\\Python\\PythonCore", 0, samDesired, &hkPythonCore);
|
||||||
|
|
||||||
|
if (res == ERROR_SUCCESS) {
|
||||||
|
QStringList versions = getRegSubkeys(hkPythonCore);
|
||||||
|
qDebug("Python versions nb: %d", versions.size());
|
||||||
|
versions.sort();
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
while(!found && !versions.empty()) {
|
||||||
|
const QString version = versions.takeLast() + "\\InstallPath";
|
||||||
|
LPWSTR lpSubkey = new WCHAR[version.size() + 1];
|
||||||
|
version.toWCharArray(lpSubkey);
|
||||||
|
lpSubkey[version.size()] = 0;
|
||||||
|
|
||||||
|
HKEY hkInstallPath;
|
||||||
|
res = ::RegOpenKeyExW(hkPythonCore, lpSubkey, 0, samDesired, &hkInstallPath);
|
||||||
|
delete[] lpSubkey;
|
||||||
|
|
||||||
|
if (res == ERROR_SUCCESS) {
|
||||||
|
qDebug("Detected possible Python v%s location", qPrintable(version));
|
||||||
|
path = getRegValue(hkInstallPath);
|
||||||
|
::RegCloseKey(hkInstallPath);
|
||||||
|
|
||||||
|
if (!path.isEmpty() && QDir(path).exists("python.exe")) {
|
||||||
|
qDebug("Found python.exe at %s", qPrintable(path));
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
path = QString();
|
||||||
|
|
||||||
|
::RegCloseKey(hkPythonCore);
|
||||||
|
}
|
||||||
|
|
||||||
if (!path.isEmpty())
|
|
||||||
return path;
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
// Fallback: Detect python from default locations
|
}
|
||||||
QStringList supported_versions;
|
|
||||||
supported_versions << "32" << "31" << "30" << "27" << "26" << "25";
|
QString Preferences::getPythonPath()
|
||||||
foreach (const QString &v, supported_versions) {
|
{
|
||||||
if (QFile::exists("C:/Python"+v+"/python.exe"))
|
QString path = pythonSearchReg(USER);
|
||||||
return "C:/Python"+v;
|
if (!path.isEmpty())
|
||||||
}
|
return path;
|
||||||
return QString::null;
|
|
||||||
|
path = pythonSearchReg(SYSTEM_32BIT);
|
||||||
|
if (!path.isEmpty())
|
||||||
|
return path;
|
||||||
|
|
||||||
|
path = pythonSearchReg(SYSTEM_64BIT);
|
||||||
|
if (!path.isEmpty())
|
||||||
|
return path;
|
||||||
|
|
||||||
|
// Fallback: Detect python from default locations
|
||||||
|
QStringList supported_versions;
|
||||||
|
supported_versions << "32" << "31" << "30" << "27" << "26" << "25";
|
||||||
|
foreach (const QString &v, supported_versions) {
|
||||||
|
if (QFile::exists("C:/Python" + v + "/python.exe"))
|
||||||
|
return "C:/Python" + v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Preferences::neverCheckFileAssoc() const {
|
bool Preferences::neverCheckFileAssoc() const {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue