Browse Source

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.
adaptive-webui-19844
Vladimir Golovnev (Glassez) 10 years ago
parent
commit
f851875ad1
  1. 245
      src/preferences/preferences.cpp

245
src/preferences/preferences.cpp

@ -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
{
QStringList getRegSubkeys(const HKEY &handle) { USER,
QStringList keys; SYSTEM_32BIT,
DWORD subkeys_count = 0; SYSTEM_64BIT
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++) {
res = ::RegEnumKeyEx(handle, 0, key_name, &max_subkey_len, NULL, NULL, NULL, NULL);
if (res == ERROR_SUCCESS)
keys.push_back(QString::fromWCharArray(key_name));
}
delete[] key_name;
}
return keys; QStringList getRegSubkeys(HKEY handle)
} {
QStringList keys;
DWORD cSubKeys = 0;
DWORD cMaxSubKeyLen = 0;
LONG res = ::RegQueryInfoKeyW(handle, NULL, NULL, NULL, &cSubKeys, &cMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
if (res == ERROR_SUCCESS) {
cMaxSubKeyLen++; // For null character
LPWSTR lpName = new WCHAR[cMaxSubKeyLen];
DWORD cName;
for (DWORD i = 0; i < cSubKeys; ++i) {
cName = cMaxSubKeyLen;
res = ::RegEnumKeyExW(handle, 0, lpName, &cName, NULL, NULL, NULL, NULL);
if (res == ERROR_SUCCESS)
keys.push_back(QString::fromWCharArray(lpName));
}
QString getRegValue(const HKEY &handle, const QString &name = QString()) { delete[] lpName;
QString end_result; }
DWORD type = 0;
DWORD size = 0;
DWORD array_size = 0;
LPTSTR value_name = NULL; return keys;
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 QString getRegValue(HKEY handle, const QString &name = QString())
::RegQueryValueEx(handle, value_name, NULL, &type, NULL, &size); {
array_size = size / sizeof(TCHAR); QString result;
if (size % sizeof(TCHAR))
array_size++; DWORD type = 0;
array_size++; //For null character DWORD cbData = 0;
LPTSTR value = new TCHAR[array_size]; LPWSTR lpValueName = NULL;
if (!name.isEmpty()) {
long res = ::RegQueryValueEx(handle, value_name, NULL, &type, (LPBYTE)value, &size); lpValueName = new WCHAR[name.size() + 1];
if (res == ERROR_SUCCESS) { name.toWCharArray(lpValueName);
value[array_size] = '\0'; lpValueName[name.size()] = 0;
end_result = QString::fromWCharArray(value); }
}
if (value_name) // Discover the size of the value
delete[] value_name; ::RegQueryValueExW(handle, lpValueName, NULL, &type, NULL, &cbData);
if (value) DWORD cBuffer = (cbData / sizeof(WCHAR)) + 1;
delete[] value; 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 end_result; return result;
} }
QString pythonSearchReg(const REG_SEARCH_TYPE type) { QString pythonSearchReg(const REG_SEARCH_TYPE type)
HKEY key_handle1; {
long res = 0; HKEY hkRoot;
if (type == USER)
hkRoot = HKEY_CURRENT_USER;
else
hkRoot = HKEY_LOCAL_MACHINE;
REGSAM samDesired = KEY_READ;
if (type == SYSTEM_32BIT)
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;
}
}
}
switch (type) { if (!found)
case USER: path = QString();
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) { ::RegCloseKey(hkPythonCore);
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
::RegCloseKey(key_handle2);
} }
}
::RegCloseKey(key_handle1); return path;
return QString::null;
} }
} }
QString Preferences::getPythonPath() { QString Preferences::getPythonPath()
QString path = pythonSearchReg(USER); {
if (path.isEmpty()) QString path = pythonSearchReg(USER);
if (!path.isEmpty())
return path;
path = pythonSearchReg(SYSTEM_32BIT); path = pythonSearchReg(SYSTEM_32BIT);
else return path; if (!path.isEmpty())
return path;
if (path.isEmpty())
path = pythonSearchReg(SYSTEM_64BIT); path = pythonSearchReg(SYSTEM_64BIT);
else return path; if (!path.isEmpty())
return path;
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;
}
// Fallback: Detect python from default locations return QString();
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::null;
} }
bool Preferences::neverCheckFileAssoc() const { bool Preferences::neverCheckFileAssoc() const {

Loading…
Cancel
Save