Skip to content

Commit f3c2dbf

Browse files
committed
fix(windows): avoid crashes when enumerating devices with buggy drivers (#26)\n\nUse SEH to protect moniker->BindToObject during enumeration and device binding, so buggy drivers (e.g., unplugged Oculus Quest 3) don't crash the process. Log and skip problematic devices.
1 parent 1d4e51f commit f3c2dbf

1 file changed

Lines changed: 33 additions & 17 deletions

File tree

src/ccap_imp_windows.cpp

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -400,13 +400,19 @@ std::vector<std::string> ProviderDirectShow::findDeviceNames() {
400400

401401
enumerateDevices([&](IMoniker* moniker, std::string_view name) {
402402
// Try to bind device, check if available
403-
IBaseFilter* filter = nullptr;
404-
HRESULT hr = moniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&filter);
405-
if (SUCCEEDED(hr) && filter) {
406-
m_allDeviceNames.emplace_back(name.data(), name.size());
407-
filter->Release();
408-
} else {
409-
CCAP_LOG_I("ccap: \"%s\" is not a valid video capture device, removed\n", name.data());
403+
// Use SEH to catch crashes from buggy drivers (e.g., unplugged devices like Oculus Quest 3)
404+
__try {
405+
IBaseFilter* filter = nullptr;
406+
HRESULT hr = moniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&filter);
407+
if (SUCCEEDED(hr) && filter) {
408+
m_allDeviceNames.emplace_back(name.data(), name.size());
409+
filter->Release();
410+
} else {
411+
CCAP_LOG_I("ccap: \"%s\" is not a valid video capture device, removed\n", name.data());
412+
}
413+
} __except (EXCEPTION_EXECUTE_HANDLER) {
414+
// Catch crashes from buggy camera drivers (e.g., when camera is physically unplugged)
415+
CCAP_LOG_W("ccap: \"%s\" caused an exception during device binding, skipping\n", name.data());
410416
}
411417
// Unavailable devices are not added to the list
412418
return false; // Continue enumeration
@@ -660,19 +666,29 @@ bool ProviderDirectShow::open(std::string_view deviceName) {
660666

661667
enumerateDevices([&](IMoniker* moniker, std::string_view name) {
662668
if (deviceName.empty() || deviceName == name) {
663-
auto hr = moniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&m_deviceFilter);
664-
if (SUCCEEDED(hr)) {
665-
CCAP_LOG_V("ccap: Using video capture device: %s\n", name.data());
666-
m_deviceName = name;
667-
found = true;
668-
return true; // stop enumeration when returning true
669-
} else {
669+
// Use SEH to catch crashes from buggy drivers (e.g., unplugged devices like Oculus Quest 3)
670+
__try {
671+
auto hr = moniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&m_deviceFilter);
672+
if (SUCCEEDED(hr)) {
673+
CCAP_LOG_V("ccap: Using video capture device: %s\n", name.data());
674+
m_deviceName = name;
675+
found = true;
676+
return true; // stop enumeration when returning true
677+
} else {
678+
if (!deviceName.empty()) {
679+
reportError(ErrorCode::InvalidDevice, "\"" + std::string(deviceName) + "\" is not a valid video capture device, bind failed");
680+
return true; // stop enumeration when returning true
681+
}
682+
683+
CCAP_LOG_I("ccap: bind \"%s\" failed(result=%x), try next device...\n", name.data(), hr);
684+
}
685+
} __except (EXCEPTION_EXECUTE_HANDLER) {
686+
// Catch crashes from buggy camera drivers (e.g., when camera is physically unplugged)
687+
CCAP_LOG_W("ccap: \"%s\" caused an exception during device binding, skipping\n", name.data());
670688
if (!deviceName.empty()) {
671-
reportError(ErrorCode::InvalidDevice, "\"" + std::string(deviceName) + "\" is not a valid video capture device, bind failed");
689+
reportError(ErrorCode::InvalidDevice, "\"" + std::string(deviceName) + "\" caused an exception during binding");
672690
return true; // stop enumeration when returning true
673691
}
674-
675-
CCAP_LOG_I("ccap: bind \"%s\" failed(result=%x), try next device...\n", name.data(), hr);
676692
}
677693
}
678694
// continue enumerating when returning false

0 commit comments

Comments
 (0)