39 #include <comutils/ComVariant.h>
40 #include <intrusive_ptr_COM.h>
42 #include <boost/intrusive_ptr.hpp>
43 #include <boost/noncopyable.hpp>
58 class ComRAII : boost::noncopyable {
61 auto result = CoInitializeEx(
nullptr, COINIT_MULTITHREADED);
70 bool failed()
const {
return m_failed; }
73 bool m_failed =
false;
80 class USBVidPidExtractor {
84 "USB.VID_([[:xdigit:]]{4})&PID_([[:xdigit:]]{4})") {}
86 boost::optional<std::pair<uint16_t, uint16_t>>
87 getVidPid(std::string
const &hardwareId) {
89 if (!std::regex_search(hardwareId, m, m_vidPidRegex)) {
95 return std::make_pair(m_hexToInt(m.str(1)),
96 m_hexToInt(m.str(2)));
102 uint16_t m_hexToInt(std::string
const &str) {
105 m_ss << std::hex << str;
111 std::regex m_vidPidRegex;
119 getPNPDeviceIdSearchString(boost::optional<uint16_t>
const &vendorID,
120 boost::optional<uint16_t>
const &productID) {
123 std::ostringstream searchTerms;
125 searchTerms <<
"VID_" << std::setfill(
'0') << std::setw(4)
126 << std::hex << *vendorID;
128 if (vendorID && productID) {
132 searchTerms <<
"PID_" << std::setfill(
'0') << std::setw(4)
133 << std::hex << *productID;
136 std::string ret{searchTerms.str()};
138 [](
char c) { return ::toupper(c); });
143 std::vector<USBSerialDevice>
144 getSerialDeviceList(boost::optional<uint16_t> vendorID,
145 boost::optional<uint16_t> productID) {
146 using boost::intrusive_ptr;
148 auto searchString = getPNPDeviceIdSearchString(vendorID, productID);
151 std::vector<USBSerialDevice> devices;
155 if (comSetup.failed()) {
164 intrusive_ptr<IWbemLocator> locator;
167 CoCreateInstance(CLSID_WbemLocator,
nullptr, CLSCTX_INPROC_SERVER,
168 IID_IWbemLocator, AttachPtr(locator));
170 if (FAILED(result)) {
176 intrusive_ptr<IWbemServices> wbemServices;
181 result = locator->ConnectServer(
182 bstr_t(L
"ROOT\\CIMV2"),
186 WBEM_FLAG_CONNECT_USE_MAX_WAIT,
190 AttachPtr(wbemServices)
193 if (FAILED(result)) {
200 CoSetProxyBlanket(wbemServices.get(), RPC_C_AUTHN_WINNT,
201 RPC_C_AUTHZ_NONE,
nullptr, RPC_C_AUTHN_LEVEL_CALL,
202 RPC_C_IMP_LEVEL_IMPERSONATE,
nullptr, EOAC_NONE);
204 if (FAILED(result)) {
211 intrusive_ptr<IEnumWbemClassObject> devEnum;
212 result = wbemServices->ExecQuery(
213 bstr_t(L
"WQL"), bstr_t(L
"SELECT * FROM Win32_SerialPort"),
214 WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
nullptr,
217 if (FAILED(result)) {
221 USBVidPidExtractor vidPidExtractor;
223 intrusive_ptr<IWbemClassObject> wbemClassObj;
226 HRESULT hr = devEnum->Next(WBEM_INFINITE, 1,
227 AttachPtr(wbemClassObj), &numObjRet);
229 if (FAILED(hr) || numObjRet == 0) {
233 using comutils::Variant;
238 hr = wbemClassObj->Get(L
"DeviceID", 0, AttachVariant(varPort),
241 util::wideToUTF8String(get<std::wstring>(varPort));
245 Variant varHardwareID;
246 hr = wbemClassObj->Get(L
"PNPDeviceID", 0,
247 AttachVariant(varHardwareID),
nullptr,
249 std::string hardwareID =
250 util::wideToUTF8String(get<std::wstring>(varHardwareID));
252 if (!searchString.empty()) {
253 if (hardwareID.find(searchString) == std::string::npos) {
260 auto vidPid = vidPidExtractor.getVidPid(hardwareID);
268 std::string path =
"\\\\.\\" + port;
270 devices.emplace_back(vidPid->first, vidPid->second, path, port);
std::stringstream m_ss
String stream used to convert the hex string to an int.
Header wrapping the C99 standard stdint header.
t_< detail::transform_< List, Fun >> transform
Configured header for internal UTF16 or Windows TCHAR to UTF8 conversion. Using this header requires ...