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:
Vladimir Golovnev (Glassez) 2015-01-08 21:58:35 +03:00
commit f851875ad1

View file

@ -1339,134 +1339,138 @@ 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; QStringList keys;
DWORD subkeys_count = 0;
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;
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) if (res == ERROR_SUCCESS)
keys.push_back(QString::fromWCharArray(key_name)); keys.push_back(QString::fromWCharArray(lpName));
} }
delete[] key_name;
delete[] lpName;
} }
return keys; return keys;
} }
QString getRegValue(const HKEY &handle, const QString &name = QString()) { QString getRegValue(HKEY handle, const QString &name = QString())
QString end_result; {
DWORD type = 0; QString result;
DWORD size = 0;
DWORD array_size = 0;
LPTSTR value_name = NULL; DWORD type = 0;
DWORD cbData = 0;
LPWSTR lpValueName = NULL;
if (!name.isEmpty()) { if (!name.isEmpty()) {
value_name = new TCHAR[name.size()+1]; lpValueName = new WCHAR[name.size() + 1];
name.toWCharArray(value_name); name.toWCharArray(lpValueName);
value_name[name.size()] = '\0'; lpValueName[name.size()] = 0;
} }
// Discover the size of the value // Discover the size of the value
::RegQueryValueEx(handle, value_name, NULL, &type, NULL, &size); ::RegQueryValueExW(handle, lpValueName, NULL, &type, NULL, &cbData);
array_size = size / sizeof(TCHAR); DWORD cBuffer = (cbData / sizeof(WCHAR)) + 1;
if (size % sizeof(TCHAR)) LPWSTR lpData = new WCHAR[cBuffer];
array_size++; LONG res = ::RegQueryValueExW(handle, lpValueName, NULL, &type, (LPBYTE)lpData, &cbData);
array_size++; //For null character if (lpValueName)
LPTSTR value = new TCHAR[array_size]; delete[] lpValueName;
long res = ::RegQueryValueEx(handle, value_name, NULL, &type, (LPBYTE)value, &size);
if (res == ERROR_SUCCESS) { if (res == ERROR_SUCCESS) {
value[array_size] = '\0'; lpData[cBuffer] = 0;
end_result = QString::fromWCharArray(value); result = QString::fromWCharArray(lpData);
} }
delete[] lpData;
if (value_name) return result;
delete[] value_name;
if (value)
delete[] value;
return end_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;
switch (type) { REGSAM samDesired = KEY_READ;
case USER: if (type == SYSTEM_32BIT)
res = ::RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Python\\PythonCore"), 0, KEY_READ, &key_handle1); samDesired |= KEY_WOW64_32KEY;
break; else if (type == SYSTEM_64BIT)
case SYSTEM_32BIT: samDesired |= KEY_WOW64_64KEY;
res = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Python\\PythonCore"), 0, KEY_READ|KEY_WOW64_32KEY, &key_handle1);
break; QString path;
case SYSTEM_64BIT: LONG res = 0;
res = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Python\\PythonCore"), 0, KEY_READ|KEY_WOW64_64KEY, &key_handle1); HKEY hkPythonCore;
break; res = ::RegOpenKeyExW(hkRoot, L"SOFTWARE\\Python\\PythonCore", 0, samDesired, &hkPythonCore);
}
if (res == ERROR_SUCCESS) { if (res == ERROR_SUCCESS) {
QStringList versions = getRegSubkeys(key_handle1); QStringList versions = getRegSubkeys(hkPythonCore);
qDebug("Python versions nb: %d", versions.size()); qDebug("Python versions nb: %d", versions.size());
versions.sort(); versions.sort();
while(!versions.empty()) { bool found = false;
const QString version = versions.takeLast()+"\\InstallPath"; while(!found && !versions.empty()) {
HKEY key_handle2; const QString version = versions.takeLast() + "\\InstallPath";
LPTSTR subkey = new TCHAR[version.size()+1]; LPWSTR lpSubkey = new WCHAR[version.size() + 1];
version.toWCharArray(subkey); version.toWCharArray(lpSubkey);
subkey[version.size()] = '\0'; lpSubkey[version.size()] = 0;
switch (type) { HKEY hkInstallPath;
case USER: res = ::RegOpenKeyExW(hkPythonCore, lpSubkey, 0, samDesired, &hkInstallPath);
res = ::RegOpenKeyEx(key_handle1, subkey, 0, KEY_READ, &key_handle2); delete[] lpSubkey;
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) { if (res == ERROR_SUCCESS) {
qDebug("Detected possible Python v%s location", qPrintable(version)); qDebug("Detected possible Python v%s location", qPrintable(version));
QString path = getRegValue(key_handle2); path = getRegValue(hkInstallPath);
::RegCloseKey(key_handle2); ::RegCloseKey(hkInstallPath);
if (!path.isEmpty() && QDir(path).exists("python.exe")) { if (!path.isEmpty() && QDir(path).exists("python.exe")) {
qDebug("Found python.exe at %s", qPrintable(path)); qDebug("Found python.exe at %s", qPrintable(path));
::RegCloseKey(key_handle1); found = true;
}
}
}
if (!found)
path = QString();
::RegCloseKey(hkPythonCore);
}
return path; return path;
}
}
else
::RegCloseKey(key_handle2);
}
}
::RegCloseKey(key_handle1);
return QString::null;
} }
} }
QString Preferences::getPythonPath() { QString Preferences::getPythonPath()
{
QString path = pythonSearchReg(USER); QString path = pythonSearchReg(USER);
if (path.isEmpty()) 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()) if (!path.isEmpty())
return path; return path;
@ -1474,10 +1478,11 @@ QString Preferences::getPythonPath() {
QStringList supported_versions; QStringList supported_versions;
supported_versions << "32" << "31" << "30" << "27" << "26" << "25"; supported_versions << "32" << "31" << "30" << "27" << "26" << "25";
foreach (const QString &v, supported_versions) { foreach (const QString &v, supported_versions) {
if (QFile::exists("C:/Python"+v+"/python.exe")) if (QFile::exists("C:/Python" + v + "/python.exe"))
return "C:/Python"+v; return "C:/Python" + v;
} }
return QString::null;
return QString();
} }
bool Preferences::neverCheckFileAssoc() const { bool Preferences::neverCheckFileAssoc() const {