|
|
@ -9,6 +9,7 @@ |
|
|
|
|
|
|
|
|
|
|
|
#include <string> |
|
|
|
#include <string> |
|
|
|
#include <vector> |
|
|
|
#include <vector> |
|
|
|
|
|
|
|
#include <cctype> |
|
|
|
|
|
|
|
|
|
|
|
// Include the necessary headers to interface with the Windows registry and
|
|
|
|
// Include the necessary headers to interface with the Windows registry and
|
|
|
|
// environment.
|
|
|
|
// environment.
|
|
|
@ -17,156 +18,115 @@ |
|
|
|
#define NOMINMAX |
|
|
|
#define NOMINMAX |
|
|
|
#include <Windows.h> |
|
|
|
#include <Windows.h> |
|
|
|
|
|
|
|
|
|
|
|
// Has all the registry lookup related code
|
|
|
|
/// \brief Read registry string.
|
|
|
|
struct MSVCRegLookup { |
|
|
|
/// This also supports a means to look for high-versioned keys by use
|
|
|
|
HKEY hRootKey; |
|
|
|
/// of a $VERSION placeholder in the key path.
|
|
|
|
HKEY hKey; |
|
|
|
/// $VERSION in the key path is a placeholder for the version number,
|
|
|
|
const char* subKey; |
|
|
|
/// causing the highest value path to be searched for and used.
|
|
|
|
|
|
|
|
/// I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
|
|
|
|
|
|
|
|
/// There can be additional characters in the component. Only the numeric
|
|
|
|
|
|
|
|
/// characters are compared.
|
|
|
|
|
|
|
|
static bool getSystemRegistryString(const char *keyPath, const char *valueName, |
|
|
|
|
|
|
|
char *value, size_t maxLength) { |
|
|
|
|
|
|
|
HKEY hRootKey = NULL; |
|
|
|
|
|
|
|
HKEY hKey = NULL; |
|
|
|
|
|
|
|
const char* subKey = NULL; |
|
|
|
DWORD valueType; |
|
|
|
DWORD valueType; |
|
|
|
|
|
|
|
DWORD valueSize = maxLength - 1; |
|
|
|
MSVCRegLookup() |
|
|
|
long lResult; |
|
|
|
: hRootKey(NULL), hKey(NULL), subKey(NULL), valueType(0) { } |
|
|
|
bool returnValue = false; |
|
|
|
|
|
|
|
|
|
|
|
bool InitializeRootKey(const char *keyPath) { |
|
|
|
if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) { |
|
|
|
if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) { |
|
|
|
hRootKey = HKEY_CLASSES_ROOT; |
|
|
|
hRootKey = HKEY_CLASSES_ROOT; |
|
|
|
subKey = keyPath + 18; |
|
|
|
subKey = keyPath + 18; |
|
|
|
} else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) { |
|
|
|
} else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) { |
|
|
|
hRootKey = HKEY_USERS; |
|
|
|
hRootKey = HKEY_USERS; |
|
|
|
subKey = keyPath + 11; |
|
|
|
subKey = keyPath + 11; |
|
|
|
} else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) { |
|
|
|
} else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) { |
|
|
|
hRootKey = HKEY_LOCAL_MACHINE; |
|
|
|
hRootKey = HKEY_LOCAL_MACHINE; |
|
|
|
subKey = keyPath + 19; |
|
|
|
subKey = keyPath + 19; |
|
|
|
} else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) { |
|
|
|
} else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) { |
|
|
|
hRootKey = HKEY_CURRENT_USER; |
|
|
|
hRootKey = HKEY_CURRENT_USER; |
|
|
|
subKey = keyPath + 18; |
|
|
|
subKey = keyPath + 18; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool FindSimpleKeyValue(const char *valueName, char *value, DWORD valueSize) { |
|
|
|
const char *placeHolder = strstr(subKey, "$VERSION"); |
|
|
|
bool Ret = false; |
|
|
|
char bestName[256]; |
|
|
|
long Res = RegOpenKeyExA(hRootKey, subKey, 0, KEY_READ, &hKey); |
|
|
|
bestName[0] = '\0'; |
|
|
|
if (Res == ERROR_SUCCESS) { |
|
|
|
// If we have a $VERSION placeholder, do the highest-version search.
|
|
|
|
Res = RegQueryValueExA(hKey, valueName, NULL, &valueType, |
|
|
|
if (placeHolder) { |
|
|
|
(LPBYTE)value, &valueSize); |
|
|
|
const char *keyEnd = placeHolder - 1; |
|
|
|
if (Res == ERROR_SUCCESS) |
|
|
|
const char *nextKey = placeHolder; |
|
|
|
Ret = true; |
|
|
|
|
|
|
|
RegCloseKey(hKey); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return Ret; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool FindBestVersionKeyValue(const char* versionIndex, |
|
|
|
|
|
|
|
const char *valueName, char *value, DWORD valueSize) { |
|
|
|
|
|
|
|
bool Ret = false; |
|
|
|
|
|
|
|
const char *keyEnd = versionIndex - 1; |
|
|
|
|
|
|
|
const char *nextKey = versionIndex; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Find end of previous key.
|
|
|
|
// Find end of previous key.
|
|
|
|
while ((keyEnd > subKey) && (*keyEnd != '\\')) |
|
|
|
while ((keyEnd > subKey) && (*keyEnd != '\\')) |
|
|
|
keyEnd--; |
|
|
|
keyEnd--; |
|
|
|
|
|
|
|
|
|
|
|
// Find end of key containing $VERSION.
|
|
|
|
// Find end of key containing $VERSION.
|
|
|
|
while (*nextKey && (*nextKey != '\\')) |
|
|
|
while (*nextKey && (*nextKey != '\\')) |
|
|
|
nextKey++; |
|
|
|
nextKey++; |
|
|
|
|
|
|
|
|
|
|
|
size_t partialKeyLength = keyEnd - subKey; |
|
|
|
size_t partialKeyLength = keyEnd - subKey; |
|
|
|
char partialKey[256]; |
|
|
|
char partialKey[256]; |
|
|
|
if (partialKeyLength > sizeof(partialKey)) |
|
|
|
if (partialKeyLength > sizeof(partialKey)) |
|
|
|
partialKeyLength = sizeof(partialKey); |
|
|
|
partialKeyLength = sizeof(partialKey); |
|
|
|
strncpy(partialKey, subKey, partialKeyLength); |
|
|
|
strncpy(partialKey, subKey, partialKeyLength); |
|
|
|
partialKey[partialKeyLength] = '\0'; |
|
|
|
partialKey[partialKeyLength] = '\0'; |
|
|
|
|
|
|
|
|
|
|
|
HKEY hTopKey = NULL; |
|
|
|
HKEY hTopKey = NULL; |
|
|
|
long Res = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ, &hTopKey); |
|
|
|
lResult = RegOpenKeyExA(hRootKey, partialKey, 0, KEY_READ, &hTopKey); |
|
|
|
|
|
|
|
if (lResult == ERROR_SUCCESS) { |
|
|
|
if (Res != ERROR_SUCCESS) |
|
|
|
char keyName[256]; |
|
|
|
return false; |
|
|
|
int bestIndex = -1; |
|
|
|
|
|
|
|
double bestValue = 0.0; |
|
|
|
char keyName[256]; |
|
|
|
DWORD index, size = sizeof(keyName) - 1; |
|
|
|
int bestIndex = -1; |
|
|
|
for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, |
|
|
|
char bestName[256]; |
|
|
|
NULL, NULL, NULL) == ERROR_SUCCESS; index++) { |
|
|
|
bestName[0] = '\0'; |
|
|
|
const char *sp = keyName; |
|
|
|
double bestValue = 0.0; |
|
|
|
while (*sp && !isdigit(*sp)) |
|
|
|
|
|
|
|
sp++; |
|
|
|
// Find the highest versioned key.
|
|
|
|
if (!*sp) |
|
|
|
DWORD index, size = sizeof(keyName) - 1; |
|
|
|
continue; |
|
|
|
for (index = 0; RegEnumKeyExA(hTopKey, index, keyName, &size, NULL, |
|
|
|
const char *ep = sp + 1; |
|
|
|
NULL, NULL, NULL) == ERROR_SUCCESS; index++) { |
|
|
|
while (*ep && (isdigit(*ep) || (*ep == '.'))) |
|
|
|
const char *sp = keyName; |
|
|
|
ep++; |
|
|
|
while (*sp && !isdigit(*sp)) |
|
|
|
char numBuf[32]; |
|
|
|
sp++; |
|
|
|
strncpy(numBuf, sp, sizeof(numBuf) - 1); |
|
|
|
if (!*sp) |
|
|
|
numBuf[sizeof(numBuf) - 1] = '\0'; |
|
|
|
continue; |
|
|
|
double value = strtod(numBuf, NULL); |
|
|
|
const char *ep = sp + 1; |
|
|
|
if (value > bestValue) { |
|
|
|
while (*ep && (isdigit(*ep) || (*ep == '.'))) |
|
|
|
bestIndex = (int)index; |
|
|
|
ep++; |
|
|
|
bestValue = value; |
|
|
|
char numBuf[32]; |
|
|
|
strcpy(bestName, keyName); |
|
|
|
strncpy(numBuf, sp, sizeof(numBuf) - 1); |
|
|
|
} |
|
|
|
numBuf[sizeof(numBuf) - 1] = '\0'; |
|
|
|
size = sizeof(keyName) - 1; |
|
|
|
|
|
|
|
} |
|
|
|
double versionValue = strtod(numBuf, NULL); |
|
|
|
// If we found the highest versioned key, open the key and get the value.
|
|
|
|
if (versionValue > bestValue) { |
|
|
|
if (bestIndex != -1) { |
|
|
|
// Better values are only better if the desired key exists for them.
|
|
|
|
// Append rest of key.
|
|
|
|
std::string candidate = std::string(keyName) + nextKey; |
|
|
|
strncat(bestName, nextKey, sizeof(bestName) - 1); |
|
|
|
Res = RegOpenKeyExA(hTopKey, candidate.c_str(), 0, KEY_READ, &hKey); |
|
|
|
bestName[sizeof(bestName) - 1] = '\0'; |
|
|
|
if (Res == ERROR_SUCCESS) { |
|
|
|
// Open the chosen key path remainder.
|
|
|
|
Res = RegQueryValueExA(hKey, valueName, NULL, &valueType, |
|
|
|
lResult = RegOpenKeyExA(hTopKey, bestName, 0, KEY_READ, &hKey); |
|
|
|
(LPBYTE)value, &valueSize); |
|
|
|
if (lResult == ERROR_SUCCESS) { |
|
|
|
if (Res == ERROR_SUCCESS) { |
|
|
|
lResult = RegQueryValueExA(hKey, valueName, NULL, &valueType, |
|
|
|
bestIndex = (int)index; |
|
|
|
(LPBYTE)value, &valueSize); |
|
|
|
bestValue = versionValue; |
|
|
|
if (lResult == ERROR_SUCCESS) |
|
|
|
strcpy(bestName, keyName); |
|
|
|
returnValue = true; |
|
|
|
} |
|
|
|
|
|
|
|
RegCloseKey(hKey); |
|
|
|
RegCloseKey(hKey); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
RegCloseKey(hTopKey); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
// If we found the highest versioned key, open the key and get the value.
|
|
|
|
lResult = RegOpenKeyExA(hRootKey, subKey, 0, KEY_READ, &hKey); |
|
|
|
if (bestIndex != -1) { |
|
|
|
if (lResult == ERROR_SUCCESS) { |
|
|
|
// Append rest of key.
|
|
|
|
lResult = RegQueryValueExA(hKey, valueName, NULL, &valueType, |
|
|
|
strncat(bestName, nextKey, sizeof(bestName) - 1); |
|
|
|
(LPBYTE)value, &valueSize); |
|
|
|
bestName[sizeof(bestName) - 1] = '\0'; |
|
|
|
if (lResult == ERROR_SUCCESS) |
|
|
|
// Open the chosen key path remainder.
|
|
|
|
returnValue = true; |
|
|
|
Res = RegOpenKeyExA(hTopKey, bestName, 0, KEY_READ, &hKey); |
|
|
|
RegCloseKey(hKey); |
|
|
|
if (Res == ERROR_SUCCESS) { |
|
|
|
|
|
|
|
Res = RegQueryValueExA(hKey, valueName, NULL, &valueType, |
|
|
|
|
|
|
|
(LPBYTE)value, &valueSize); |
|
|
|
|
|
|
|
if (Res == ERROR_SUCCESS) |
|
|
|
|
|
|
|
Ret = true; |
|
|
|
|
|
|
|
RegCloseKey(hKey); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
RegCloseKey(hTopKey); |
|
|
|
|
|
|
|
return Ret; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
return returnValue; |
|
|
|
|
|
|
|
|
|
|
|
/// \brief Read registry string.
|
|
|
|
|
|
|
|
/// This also supports a means to look for high-versioned keys by use
|
|
|
|
|
|
|
|
/// of a $VERSION placeholder in the key path.
|
|
|
|
|
|
|
|
/// $VERSION in the key path is a placeholder for the version number,
|
|
|
|
|
|
|
|
/// causing the highest value path to be searched for and used.
|
|
|
|
|
|
|
|
/// I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
|
|
|
|
|
|
|
|
/// There can be additional characters in the component. Only the numeric
|
|
|
|
|
|
|
|
/// characters are compared.
|
|
|
|
|
|
|
|
static bool getSystemRegistryString(const char *keyPath, const char *valueName, |
|
|
|
|
|
|
|
char *value, size_t maxLength) { |
|
|
|
|
|
|
|
MSVCRegLookup Reg; |
|
|
|
|
|
|
|
if (!Reg.InitializeRootKey(keyPath)) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char* versionIndex = strstr(Reg.subKey, "$VERSION"); |
|
|
|
|
|
|
|
// If we have a $VERSION placeholder, do the highest-version search.
|
|
|
|
|
|
|
|
if (versionIndex) |
|
|
|
|
|
|
|
return Reg.FindBestVersionKeyValue(versionIndex, valueName, |
|
|
|
|
|
|
|
value, maxLength-1); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
return Reg.FindSimpleKeyValue(valueName, value, maxLength-1); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// \brief Get Windows SDK installation directory.
|
|
|
|
/// \brief Get Windows SDK installation directory.
|
|
|
|