From 5ba2aba2e7285a51d544827461f01fb84aaf50ac Mon Sep 17 00:00:00 2001 From: Gonzalo Exequiel Pedone Date: Fri, 9 Oct 2020 12:01:40 -0300 Subject: [PATCH] Check that the CLSID is not taken when creating a device path. --- dshow/PlatformUtils/src/preferences.cpp | 101 +---------- dshow/PlatformUtils/src/preferences.h | 1 - dshow/PlatformUtils/src/utils.cpp | 215 ++++++++++++++++++++---- dshow/PlatformUtils/src/utils.h | 5 + dshow/VCamIPC/src/ipcbridge.cpp | 41 +---- dshow/VirtualCamera/src/plugin.cpp | 3 +- 6 files changed, 196 insertions(+), 170 deletions(-) diff --git a/dshow/PlatformUtils/src/preferences.cpp b/dshow/PlatformUtils/src/preferences.cpp index 332ac82..9e554ba 100644 --- a/dshow/PlatformUtils/src/preferences.cpp +++ b/dshow/PlatformUtils/src/preferences.cpp @@ -129,98 +129,6 @@ bool AkVCam::Preferences::readBool(const std::string &key, bool defaultValue) return readInt(key, defaultValue) != 0; } -std::vector AkVCam::Preferences::listRegisteredCameras(HINSTANCE hinstDLL) -{ - WCHAR *strIID = nullptr; - StringFromIID(CLSID_VideoInputDeviceCategory, &strIID); - - std::wstringstream ss; - ss << L"CLSID\\" - << strIID - << L"\\Instance"; - CoTaskMemFree(strIID); - - HKEY key = nullptr; - auto result = RegOpenKeyExW(HKEY_CLASSES_ROOT, - ss.str().c_str(), - 0, - MAXIMUM_ALLOWED, - &key); - - if (result != ERROR_SUCCESS) - return {}; - - DWORD subkeys = 0; - - result = RegQueryInfoKey(key, - nullptr, - nullptr, - nullptr, - &subkeys, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr); - - if (result != ERROR_SUCCESS) { - RegCloseKey(key); - - return {}; - } - - std::vector cameras; - FILETIME lastWrite; - - for (DWORD i = 0; i < subkeys; i++) { - WCHAR subKey[MAX_PATH]; - memset(subKey, 0, MAX_PATH * sizeof(WCHAR)); - DWORD subKeyLen = MAX_PATH; - result = RegEnumKeyExW(key, - i, - subKey, - &subKeyLen, - nullptr, - nullptr, - nullptr, - &lastWrite); - - if (result != ERROR_SUCCESS) - continue; - - std::wstringstream ss; - ss << L"CLSID\\" << subKey << L"\\InprocServer32"; - WCHAR path[MAX_PATH]; - memset(path, 0, MAX_PATH * sizeof(WCHAR)); - DWORD pathSize = MAX_PATH; - - if (RegGetValueW(HKEY_CLASSES_ROOT, - ss.str().c_str(), - nullptr, - RRF_RT_REG_SZ, - nullptr, - path, - &pathSize) == ERROR_SUCCESS) { - WCHAR modulePath[MAX_PATH]; - memset(modulePath, 0, MAX_PATH * sizeof(WCHAR)); - GetModuleFileNameW(hinstDLL, modulePath, MAX_PATH); - - if (!lstrcmpiW(path, modulePath)) { - CLSID clsid; - memset(&clsid, 0, sizeof(CLSID)); - CLSIDFromString(subKey, &clsid); - cameras.push_back(clsid); - } - } - } - - RegCloseKey(key); - - return cameras; -} - void AkVCam::Preferences::deleteKey(const std::string &key) { AkLogFunction(); @@ -390,6 +298,8 @@ std::string AkVCam::Preferences::createDevicePath() for (size_t i = 0; i < camerasCount(); i++) cameraPaths.push_back(cameraPath(i)); + // List device CLSIDs in use. + auto cameraClsids = listAllCameras(); const int maxId = 64; for (int i = 0; i < maxId; i++) { @@ -397,11 +307,12 @@ std::string AkVCam::Preferences::createDevicePath() * incremental index to a common prefix. */ auto path = DSHOW_PLUGIN_DEVICE_PREFIX + std::to_string(i); + auto clsid = createClsidFromStr(path); + auto pit = std::find(cameraPaths.begin(), cameraPaths.end(), path); + auto cit = std::find(cameraClsids.begin(), cameraClsids.end(), clsid); // Check if the path is being used, if not return it. - if (std::find(cameraPaths.begin(), - cameraPaths.end(), - path) == cameraPaths.end()) + if (pit == cameraPaths.end() && cit == cameraClsids.end()) return path; } diff --git a/dshow/PlatformUtils/src/preferences.h b/dshow/PlatformUtils/src/preferences.h index 71ed476..124c302 100644 --- a/dshow/PlatformUtils/src/preferences.h +++ b/dshow/PlatformUtils/src/preferences.h @@ -40,7 +40,6 @@ namespace AkVCam int readInt(const std::string &key, int defaultValue=0); double readDouble(const std::string &key, double defaultValue=0.0); bool readBool(const std::string &key, bool defaultValue=false); - std::vector listRegisteredCameras(HINSTANCE hinstDLL); void deleteKey(const std::string &key); void move(const std::string &keyFrom, const std::string &keyTo); std::string addDevice(const std::string &description); diff --git a/dshow/PlatformUtils/src/utils.cpp b/dshow/PlatformUtils/src/utils.cpp index 8191b65..868dfae 100644 --- a/dshow/PlatformUtils/src/utils.cpp +++ b/dshow/PlatformUtils/src/utils.cpp @@ -43,41 +43,9 @@ namespace AkVCam GUID guid; const DWORD *masks; - inline static const std::vector &formats() - { - static const DWORD bits555[] = {0x007c00, 0x0003e0, 0x00001f}; - static const DWORD bits565[] = {0x00f800, 0x0007e0, 0x00001f}; - - static const std::vector formats { - {PixelFormatRGB32, BI_RGB , MEDIASUBTYPE_RGB32 , nullptr}, - {PixelFormatRGB24, BI_RGB , MEDIASUBTYPE_RGB24 , nullptr}, - {PixelFormatRGB16, BI_BITFIELDS , MEDIASUBTYPE_RGB565, bits565}, - {PixelFormatRGB15, BI_BITFIELDS , MEDIASUBTYPE_RGB555, bits555}, - {PixelFormatUYVY , MAKEFOURCC('U', 'Y', 'V', 'Y'), MEDIASUBTYPE_UYVY , nullptr}, - {PixelFormatYUY2 , MAKEFOURCC('Y', 'U', 'Y', '2'), MEDIASUBTYPE_YUY2 , nullptr}, - {PixelFormatNV12 , MAKEFOURCC('N', 'V', '1', '2'), MEDIASUBTYPE_NV12 , nullptr} - }; - - return formats; - } - - static inline const VideoFormatSpecsPrivate *byGuid(const GUID &guid) - { - for (auto &format: formats()) - if (IsEqualGUID(format.guid, guid)) - return &format; - - return nullptr; - } - - static inline const VideoFormatSpecsPrivate *byPixelFormat(FourCC pixelFormat) - { - for (auto &format: formats()) - if (format.pixelFormat == pixelFormat) - return &format; - - return nullptr; - } + inline static const std::vector &formats(); + static inline const VideoFormatSpecsPrivate *byGuid(const GUID &guid); + static inline const VideoFormatSpecsPrivate *byPixelFormat(FourCC pixelFormat); }; } @@ -86,6 +54,26 @@ bool operator <(const CLSID &a, const CLSID &b) return AkVCam::stringFromIid(a) < AkVCam::stringFromIid(b); } +std::string AkVCam::locatePluginPath() +{ + AkLogFunction(); + char path[MAX_PATH]; + memset(path, 0, MAX_PATH); + HMODULE hmodule = nullptr; + + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + LPCTSTR(&locatePluginPath), + &hmodule)) { + GetModuleFileNameA(hmodule, path, MAX_PATH); + } + + if (strlen(path) < 1) + return {}; + + return dirname(path); +} + std::string AkVCam::tempPath() { CHAR tempPath[MAX_PATH]; @@ -104,6 +92,16 @@ std::string AkVCam::moduleFileName(HINSTANCE hinstDLL) return std::string(fileName); } +std::string AkVCam::dirname(const std::string &path) +{ + return path.substr(0, path.rfind("\\")); +} + +bool AkVCam::fileExists(const std::string &path) +{ + return GetFileAttributesA(path.c_str()) & FILE_ATTRIBUTE_ARCHIVE; +} + std::string AkVCam::errorToString(DWORD errorCode) { CHAR *errorStr = nullptr; @@ -1048,3 +1046,150 @@ AkVCam::VideoFrame AkVCam::loadPicture(const std::string &fileName) return frame; } + +std::vector AkVCam::listAllCameras() +{ + WCHAR *strIID = nullptr; + StringFromIID(CLSID_VideoInputDeviceCategory, &strIID); + + std::wstringstream ss; + ss << L"CLSID\\" << strIID << L"\\Instance"; + CoTaskMemFree(strIID); + + HKEY key = nullptr; + auto result = RegOpenKeyExW(HKEY_CLASSES_ROOT, + ss.str().c_str(), + 0, + MAXIMUM_ALLOWED, + &key); + + if (result != ERROR_SUCCESS) + return {}; + + DWORD subkeys = 0; + + result = RegQueryInfoKey(key, + nullptr, + nullptr, + nullptr, + &subkeys, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr); + + if (result != ERROR_SUCCESS) { + RegCloseKey(key); + + return {}; + } + + std::vector cameras; + FILETIME lastWrite; + + for (DWORD i = 0; i < subkeys; i++) { + WCHAR subKey[MAX_PATH]; + memset(subKey, 0, MAX_PATH * sizeof(WCHAR)); + DWORD subKeyLen = MAX_PATH; + result = RegEnumKeyExW(key, + i, + subKey, + &subKeyLen, + nullptr, + nullptr, + nullptr, + &lastWrite); + + if (result == ERROR_SUCCESS) { + CLSID clsid; + memset(&clsid, 0, sizeof(CLSID)); + CLSIDFromString(subKey, &clsid); + cameras.push_back(clsid); + } + } + + RegCloseKey(key); + + return cameras; +} + +std::vector AkVCam::listRegisteredCameras() +{ + AkLogFunction(); + auto pluginFolder = locatePluginPath(); + AkLogDebug() << "Plugin path: " << pluginFolder << std::endl; + + if (pluginFolder.empty()) + return {}; + + auto pluginPath = pluginFolder + "\\" DSHOW_PLUGIN_NAME ".dll"; + AkLogDebug() << "Plugin binary: " << pluginPath << std::endl; + + if (!fileExists(pluginPath)) { + AkLogError() << "Plugin binary not found: " << pluginPath << std::endl; + + return {}; + } + + std::vector cameras; + + for (auto &clsid: listAllCameras()) { + auto subKey = "CLSID\\" + stringFromIid(clsid) + "\\InprocServer32"; + CHAR path[MAX_PATH]; + memset(path, 0, MAX_PATH * sizeof(CHAR)); + DWORD pathSize = MAX_PATH; + + if (RegGetValueA(HKEY_CLASSES_ROOT, + subKey.c_str(), + nullptr, + RRF_RT_REG_SZ, + nullptr, + path, + &pathSize) == ERROR_SUCCESS) { + + if (path == pluginPath) + cameras.push_back(clsid); + } + } + + return cameras; +} + +const std::vector &AkVCam::VideoFormatSpecsPrivate::formats() +{ + static const DWORD bits555[] = {0x007c00, 0x0003e0, 0x00001f}; + static const DWORD bits565[] = {0x00f800, 0x0007e0, 0x00001f}; + + static const std::vector formats { + {PixelFormatRGB32, BI_RGB , MEDIASUBTYPE_RGB32 , nullptr}, + {PixelFormatRGB24, BI_RGB , MEDIASUBTYPE_RGB24 , nullptr}, + {PixelFormatRGB16, BI_BITFIELDS , MEDIASUBTYPE_RGB565, bits565}, + {PixelFormatRGB15, BI_BITFIELDS , MEDIASUBTYPE_RGB555, bits555}, + {PixelFormatUYVY , MAKEFOURCC('U', 'Y', 'V', 'Y'), MEDIASUBTYPE_UYVY , nullptr}, + {PixelFormatYUY2 , MAKEFOURCC('Y', 'U', 'Y', '2'), MEDIASUBTYPE_YUY2 , nullptr}, + {PixelFormatNV12 , MAKEFOURCC('N', 'V', '1', '2'), MEDIASUBTYPE_NV12 , nullptr} + }; + + return formats; +} + +const AkVCam::VideoFormatSpecsPrivate *AkVCam::VideoFormatSpecsPrivate::byGuid(const GUID &guid) +{ + for (auto &format: formats()) + if (IsEqualGUID(format.guid, guid)) + return &format; + + return nullptr; +} + +const AkVCam::VideoFormatSpecsPrivate *AkVCam::VideoFormatSpecsPrivate::byPixelFormat(FourCC pixelFormat) +{ + for (auto &format: formats()) + if (format.pixelFormat == pixelFormat) + return &format; + + return nullptr; +} diff --git a/dshow/PlatformUtils/src/utils.h b/dshow/PlatformUtils/src/utils.h index a5109f3..1a7381a 100644 --- a/dshow/PlatformUtils/src/utils.h +++ b/dshow/PlatformUtils/src/utils.h @@ -34,8 +34,11 @@ namespace AkVCam class VideoFormat; class VideoFrame; + std::string locatePluginPath(); std::string tempPath(); std::string moduleFileName(HINSTANCE hinstDLL); + std::string dirname(const std::string &path); + bool fileExists(const std::string &path); std::string errorToString(DWORD errorCode); CLSID createClsidFromStr(const std::string &str); std::string createClsidStrFromStr(const std::string &str); @@ -67,6 +70,8 @@ namespace AkVCam LSTATUS deleteTree(HKEY key, LPCSTR subkey, REGSAM samFlags); LSTATUS copyTree(HKEY src, LPCSTR subkey, HKEY dst, REGSAM samFlags); VideoFrame loadPicture(const std::string &fileName); + std::vector listAllCameras(); + std::vector listRegisteredCameras(); } #endif // PLATFORM_UTILS_H diff --git a/dshow/VCamIPC/src/ipcbridge.cpp b/dshow/VCamIPC/src/ipcbridge.cpp index 051fac9..001a28c 100644 --- a/dshow/VCamIPC/src/ipcbridge.cpp +++ b/dshow/VCamIPC/src/ipcbridge.cpp @@ -66,12 +66,9 @@ namespace AkVCam ~IpcBridgePrivate(); inline const std::vector &controls() const; - static std::string dirname(const std::string &path); void updateDeviceSharedProperties(); void updateDeviceSharedProperties(const std::string &deviceId, const std::string &owner); - bool fileExists(const std::string &path) const; - static std::string locatePluginPath(); static void pipeStateChanged(void *userData, MessageServer::PipeState state); @@ -422,7 +419,7 @@ std::vector AkVCam::IpcBridge::listeners(const std::string &deviceI std::vector AkVCam::IpcBridge::clientsPids() const { AkLogFunction(); - auto pluginPath = this->d->locatePluginPath(); + auto pluginPath = locatePluginPath(); AkLogDebug() << "Plugin path: " << pluginPath << std::endl; if (pluginPath.empty()) @@ -431,7 +428,7 @@ std::vector AkVCam::IpcBridge::clientsPids() const auto path = pluginPath + "\\" DSHOW_PLUGIN_NAME ".dll"; AkLogDebug() << "Plugin binary: " << path << std::endl; - if (!this->d->fileExists(path)) + if (!fileExists(path)) return {}; std::vector pids; @@ -550,7 +547,7 @@ void AkVCam::IpcBridge::removeFormat(const std::string &deviceId, int index) void AkVCam::IpcBridge::updateDevices() { AkLogFunction(); - auto pluginPath = this->d->locatePluginPath(); + auto pluginPath = locatePluginPath(); AkLogDebug() << "Plugin path: " << pluginPath << std::endl; if (pluginPath.empty()) @@ -559,7 +556,7 @@ void AkVCam::IpcBridge::updateDevices() auto path = pluginPath + "\\" DSHOW_PLUGIN_NAME ".dll"; AkLogDebug() << "Plugin binary: " << path << std::endl; - if (!this->d->fileExists(path)) { + if (!fileExists(path)) { AkLogError() << "Plugin binary not found: " << path << std::endl; return; @@ -800,11 +797,6 @@ const std::vector &AkVCam::IpcBridgePrivate::controls() c return controls; } -std::string AkVCam::IpcBridgePrivate::dirname(const std::string &path) -{ - return path.substr(0, path.rfind("\\")); -} - void AkVCam::IpcBridgePrivate::updateDeviceSharedProperties() { for (size_t i = 0; i < Preferences::camerasCount(); i++) { @@ -837,31 +829,6 @@ void AkVCam::IpcBridgePrivate::updateDeviceSharedProperties(const std::string &d } } -bool AkVCam::IpcBridgePrivate::fileExists(const std::string &path) const -{ - return GetFileAttributesA(path.c_str()) & FILE_ATTRIBUTE_ARCHIVE; -} - -std::string AkVCam::IpcBridgePrivate::locatePluginPath() -{ - AkLogFunction(); - char path[MAX_PATH]; - memset(path, 0, MAX_PATH); - HMODULE hmodule = nullptr; - - if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | - GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - LPCTSTR(&AkVCam::IpcBridgePrivate::locatePluginPath), - &hmodule)) { - GetModuleFileNameA(hmodule, path, MAX_PATH); - } - - if (strlen(path) < 1) - return {}; - - return dirname(path); -} - void AkVCam::IpcBridgePrivate::pipeStateChanged(void *userData, MessageServer::PipeState state) { diff --git a/dshow/VirtualCamera/src/plugin.cpp b/dshow/VirtualCamera/src/plugin.cpp index 5147481..574f988 100644 --- a/dshow/VirtualCamera/src/plugin.cpp +++ b/dshow/VirtualCamera/src/plugin.cpp @@ -121,8 +121,7 @@ STDAPI DllUnregisterServer() { pluginInterface()->initializeLogger(); AkLogFunction(); - auto cameras = - AkVCam::Preferences::listRegisteredCameras(pluginInterface()->pluginHinstance()); + auto cameras = AkVCam::listRegisteredCameras(); for (auto camera: cameras) { AkLogInfo() << "Deleting "