Visual C++报Debug Assertion Failed错误,获取Firefox标签页URL失败如何解决
问题复现
运行时弹出Debug Assertion Failed! Visual C++错误,错误截图如下:
核心报错点
- 尝试用
__try捕获异常时报错:Cannot use __try in functions that require object unwinding - 关闭异常抛出模式后,错误定位到代码行:
if FAILED(navigation->FindFirst(TreeScope_Descendants, c2, &editbox))
问题原因
__try是MSVC提供的结构化异常处理(SEH)语法,和C++的栈自动析构逻辑不兼容。你的函数内包含CComPtr智能指针、自定义的coinit析构结构体这类需要自动执行析构的对象,编译器会直接禁止在这类函数内使用__try语法,避免出现内存泄漏。- 你代码中所有COM调用的
FAILED判断仅打印日志,没有中断执行逻辑。如果前面root->FindFirst查找导航栏失败,navigation会是空指针,后续直接调用空指针的FindFirst方法就会触发断言错误。
修复方案
1. 替换__try异常捕获逻辑
不要使用SEH的__try,改用C++标准的try/catch即可。如果一定要用SEH,可以把需要捕获异常的逻辑抽成单独的子函数,子函数内不要定义任何需要自动析构的局部对象,再在getURL中调用该子函数。
2. 补全错误中断逻辑
每一步COM调用判断失败后直接返回错误值,不要继续执行后续逻辑,修改后的完整参考代码:
char* getURL() { char* urlstr = (char*)"None"; if (FAILED(CoInitialize(nullptr))) { cout << "CoInitialize error..." << endl; return urlstr; } struct coinit { ~coinit() { CoUninitialize(); } } cleanup; // 查找第一个可见的火狐窗口 HWND hwnd = NULL; while (true) { hwnd = FindWindowEx(0, hwnd, "MozillaWindowClass", NULL); if (!hwnd) return urlstr; if (IsWindowVisible(hwnd)) break; } // 初始化UIAutomation CComPtr<IUIAutomation> uia; if (FAILED(uia.CoCreateInstance(CLSID_CUIAutomation))) { cout << "UIAutomation实例创建失败" << endl; return urlstr; } CComPtr<IUIAutomationElement> root, navigation, editbox; CComPtr<IUIAutomationCondition> c1, c2; // 从窗口句柄获取根元素 if (FAILED(uia->ElementFromHandle(hwnd, &root))) { cout << "获取窗口根元素失败" << endl; return urlstr; } // 查找导航栏 uia->CreatePropertyCondition(UIA_AutomationIdPropertyId, CComVariant(L"nav-bar"), &c1); if (FAILED(root->FindFirst(TreeScope_Children, c1, &navigation)) || navigation == nullptr) { cout << "未找到导航栏" << endl; return urlstr; } // 查找地址栏输入框 uia->CreatePropertyCondition(UIA_AutomationIdPropertyId, CComVariant(L"urlbar-input"), &c2); if (FAILED(navigation->FindFirst(TreeScope_Descendants, c2, &editbox)) || editbox == nullptr) { cout << "未找到地址栏输入框" << endl; return urlstr; } // 读取地址栏内容 CComVariant url; if (FAILED(editbox->GetCurrentPropertyValue(UIA_ValueValuePropertyId, &url))) { cout << "读取地址栏内容失败" << endl; return urlstr; } if (url.bstrVal != NULL) { urlstr = _com_util::ConvertBSTRToString(url.bstrVal); } return urlstr; }
3. 其他注意点
- 如果你的项目是Unicode编码,
FindWindowEx的窗口类名字符串要改成宽字符版本L"MozillaWindowClass",避免类型转换错误。 _com_util::ConvertBSTRToString返回的字符串是堆分配内存,调用getURL的一方用完后需要调用free释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者aiueo
相关产品推荐
相关产品推荐

