#include "DeviceEnumerator.h" std::map DeviceEnumerator::getVideoDevicesMap() { return getDevicesMap(CLSID_VideoInputDeviceCategory); } std::map DeviceEnumerator::getAudioDevicesMap() { return getDevicesMap(CLSID_AudioInputDeviceCategory); } // Returns a map of id and devices that can be used std::map DeviceEnumerator::getDevicesMap(const GUID deviceClass) { std::map deviceMap; HRESULT hr = CoInitialize(nullptr); if (FAILED(hr)) { return deviceMap; // Empty deviceMap as an error } // Create the System Device Enumerator ICreateDevEnum *pDevEnum; hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum)); // If succeeded, create an enumerator for the category IEnumMoniker *pEnum = NULL; if (SUCCEEDED(hr)) { hr = pDevEnum->CreateClassEnumerator(deviceClass, &pEnum, 0); if (hr == S_FALSE) { hr = VFW_E_NOT_FOUND; } pDevEnum->Release(); } // Now we check if the enumerator creation succeeded int deviceId = -1; if (SUCCEEDED(hr)) { // Fill the map with id and friendly device name IMoniker *pMoniker = NULL; while (pEnum->Next(1, &pMoniker, NULL) == S_OK) { IPropertyBag *pPropBag; HRESULT hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag)); if (FAILED(hr)) { pMoniker->Release(); continue; } // Create variant to hold data VARIANT var; VariantInit(&var); std::string deviceName; std::string devicePath; // Read FriendlyName or Description hr = pPropBag->Read(L"Description", &var, 0); // Read description if (FAILED(hr)) { // If description fails, try with the friendly name hr = pPropBag->Read(L"FriendlyName", &var, 0); } // If still fails, continue with next device if (FAILED(hr)) { VariantClear(&var); continue; } // Convert to string else { deviceName = ConvertBSTRToMBS(var.bstrVal); } VariantClear(&var); // We clean the variable in order to read the next value // We try to read the DevicePath hr = pPropBag->Read(L"DevicePath", &var, 0); if (FAILED(hr)) { VariantClear(&var); continue; // If it fails we continue with next device } else { devicePath = ConvertBSTRToMBS(var.bstrVal); } // We populate the map deviceId++; Device currentDevice; currentDevice.id = deviceId; currentDevice.deviceName = deviceName; currentDevice.devicePath = devicePath; deviceMap[deviceId] = currentDevice; } pEnum->Release(); } CoUninitialize(); return deviceMap; } /* This two methods were taken from https://stackoverflow.com/questions/6284524/bstr-to-stdstring-stdwstring-and-vice-versa */ std::string DeviceEnumerator::ConvertBSTRToMBS(BSTR bstr) { int wslen = ::SysStringLen(bstr); return ConvertWCSToMBS((wchar_t*)bstr, wslen); } std::string DeviceEnumerator::ConvertWCSToMBS(const wchar_t* pstr, long wslen) { int len = ::WideCharToMultiByte(CP_ACP, 0, pstr, wslen, NULL, 0, NULL, NULL); std::string dblstr(len, '\0'); len = ::WideCharToMultiByte(CP_ACP, 0 /* no flags */, pstr, wslen /* not necessary NULL-terminated */, &dblstr[0], len, NULL, NULL /* no default char */); return dblstr; }