Improve reliability for finding FTDI devices on Windows
parent
ae78122cbe
commit
d042086c90
|
|
@ -3,11 +3,14 @@
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace icsneo {
|
namespace icsneo {
|
||||||
|
|
||||||
class Registry {
|
class Registry {
|
||||||
public:
|
public:
|
||||||
|
static bool EnumerateSubkeys(std::wstring path, std::vector<std::wstring>& subkeys);
|
||||||
|
|
||||||
// Get string value
|
// Get string value
|
||||||
static bool Get(std::wstring path, std::wstring key, std::wstring& value);
|
static bool Get(std::wstring path, std::wstring key, std::wstring& value);
|
||||||
static bool Get(std::string path, std::string key, std::string& value);
|
static bool Get(std::string path, std::string key, std::string& value);
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,46 @@ Registry::Key::~Key() {
|
||||||
RegCloseKey(key);
|
RegCloseKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Registry::EnumerateSubkeys(std::wstring path, std::vector<std::wstring>& subkeys) {
|
||||||
|
Key regKey(path);
|
||||||
|
if(!regKey.IsOpen())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char className[MAX_PATH];
|
||||||
|
memset(className, 0, sizeof(className));
|
||||||
|
DWORD classNameLen = MAX_PATH;
|
||||||
|
DWORD subKeyCount = 0;
|
||||||
|
DWORD maxSubKeyLen, maxClassStringLen, valueCount, maxValueNameLen, maxValueDataLen, securityDescriptorLen;
|
||||||
|
FILETIME lastWriteTime;
|
||||||
|
auto ret = RegQueryInfoKey(
|
||||||
|
regKey.GetKey(),
|
||||||
|
className,
|
||||||
|
&classNameLen,
|
||||||
|
nullptr,
|
||||||
|
&subKeyCount,
|
||||||
|
&maxSubKeyLen,
|
||||||
|
&maxClassStringLen,
|
||||||
|
&valueCount,
|
||||||
|
&maxValueNameLen,
|
||||||
|
&maxValueDataLen,
|
||||||
|
&securityDescriptorLen,
|
||||||
|
&lastWriteTime);
|
||||||
|
|
||||||
|
if(ret != ERROR_SUCCESS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
subkeys.clear();
|
||||||
|
for(DWORD i = 0; i < subKeyCount; i++) {
|
||||||
|
DWORD nameLen = MAX_PATH;
|
||||||
|
char name[MAX_PATH];
|
||||||
|
memset(name, 0, sizeof(name));
|
||||||
|
ret = RegEnumKeyEx(regKey.GetKey(), i, name, &nameLen, nullptr, nullptr, nullptr, &lastWriteTime);
|
||||||
|
if(ret == ERROR_SUCCESS)
|
||||||
|
subkeys.push_back(converter.from_bytes(name));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Registry::Get(std::wstring path, std::wstring key, std::wstring& value) {
|
bool Registry::Get(std::wstring path, std::wstring key, std::wstring& value) {
|
||||||
Key regKey(path);
|
Key regKey(path);
|
||||||
if(!regKey.IsOpen())
|
if(!regKey.IsOpen())
|
||||||
|
|
|
||||||
|
|
@ -71,17 +71,68 @@ std::vector<neodevice_t> VCP::FindByProduct(int product, std::vector<std::wstrin
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstringstream oss;
|
std::wstringstream oss;
|
||||||
if(!sn || conversionError) {
|
if(!sn || conversionError)
|
||||||
// This is a device with characters in the serial number
|
oss << entry.substr(startchar + 1, 6); // This is a device with characters in the serial number
|
||||||
oss << entry.substr(startchar + 1, 6);
|
else
|
||||||
}
|
|
||||||
else {
|
|
||||||
oss << sn;
|
oss << sn;
|
||||||
}
|
|
||||||
|
|
||||||
std::string serial = converter.to_bytes(oss.str());
|
std::string serial = converter.to_bytes(oss.str());
|
||||||
if(serial.find_first_of('\\') != std::string::npos)
|
// The serial number should not have a path slash in it. If it does, that means we don't have the real serial.
|
||||||
continue; // Not sure how this happened but a slash is not valid in the serial
|
if(serial.find_first_of('\\') != std::string::npos) {
|
||||||
|
// The serial number was not in the first serenum key where we expected it.
|
||||||
|
// We can try to match the ContainerID with the one in ALL_ENUM\USB and get a serial that way
|
||||||
|
std::wstringstream uess;
|
||||||
|
uess << ALL_ENUM_REG_KEY << L"\\USB\\" << vss.str() << L'&' << pss.str() << L'\\';
|
||||||
|
std::wstringstream ciss;
|
||||||
|
ciss << ALL_ENUM_REG_KEY << entry;
|
||||||
|
std::wstring containerIDFromEntry, containerIDFromEnum;
|
||||||
|
if(!Registry::Get(ciss.str(), L"ContainerID", containerIDFromEntry))
|
||||||
|
continue; // We did not get a container ID. This can happen on Windows XP and before.
|
||||||
|
if(containerIDFromEntry.empty())
|
||||||
|
continue; // The container ID was empty?
|
||||||
|
std::vector<std::wstring> subkeys;
|
||||||
|
if(!Registry::EnumerateSubkeys(uess.str(), subkeys))
|
||||||
|
continue; // VID/PID combo was not present at all.
|
||||||
|
if(subkeys.empty())
|
||||||
|
continue; // No devices for VID/PID.
|
||||||
|
std::wstring correctSerial;
|
||||||
|
for(auto& subkey : subkeys) {
|
||||||
|
std::wstringstream skss;
|
||||||
|
skss << uess.str() << L'\\' << subkey;
|
||||||
|
if(!Registry::Get(skss.str(), L"ContainerID", containerIDFromEnum))
|
||||||
|
continue;
|
||||||
|
if(containerIDFromEntry != containerIDFromEnum)
|
||||||
|
continue;
|
||||||
|
correctSerial = subkey;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(correctSerial.empty())
|
||||||
|
continue; // Didn't find the device within the subkeys of the enumeration
|
||||||
|
|
||||||
|
sn = 0;
|
||||||
|
conversionError = false;
|
||||||
|
try {
|
||||||
|
sn = std::stoi(correctSerial);
|
||||||
|
}
|
||||||
|
catch(...) {
|
||||||
|
conversionError = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!sn || conversionError) {
|
||||||
|
// This is a device with characters in the serial number
|
||||||
|
if(correctSerial.size() != 6)
|
||||||
|
continue;
|
||||||
|
serial = converter.to_bytes(correctSerial);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::wstringstream soss;
|
||||||
|
soss << sn;
|
||||||
|
serial = converter.to_bytes(soss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(serial.find_first_of('\\') != std::string::npos)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
strcpy_s(device.serial, sizeof(device.serial), serial.c_str());
|
strcpy_s(device.serial, sizeof(device.serial), serial.c_str());
|
||||||
|
|
||||||
// Serial number is saved, we want the COM port number now
|
// Serial number is saved, we want the COM port number now
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue