如何在应用程序退出时诊断 comptr 版本中的异常

Posted

技术标签:

【中文标题】如何在应用程序退出时诊断 comptr 版本中的异常【英文标题】:how to diagnose exception in comptr release on application exit 【发布时间】:2013-12-05 14:53:02 【问题描述】:

我的应用程序在应用程序退出时出现异常。当调用 CoUnintialize 时,Callstack 显示异常来自 CComPtr::release。

>   ieframe.dll!ATL::CComPtr<IWebBrowser2>::Release()  + 0x5b bytes 
    ieframe.dll!CConnectionPoint::UnadviseAll()  + 0x131d0 bytes    
    ieframe.dll!CConnectionPoint::~CConnectionPoint()  + 0x18 bytes 
    ieframe.dll!CShellOcx::~CShellOcx()  + 0xf7 bytes   
    ieframe.dll!CWebBrowserOC::`scalar deleting destructor'()  + 0x14 bytes 
    ieframe.dll!CAggregatedUnknown::CUnkInner::Release()  + 0x474a1 bytes   
    ole32.dll!CStdIdentity::ReleaseCtrlUnk()  Line 1149 C++
    ole32.dll!CStdMarshal::Disconnect(unsigned long dwType)  Line 3454  C++
    ole32.dll!CStdMarshal::DisconnectAndRelease(unsigned long dwType)  Line 3161 + 0x11 bytes   C++
    ole32.dll!COIDTable::ThreadCleanup()  + 0x31bed bytes   C++
    ole32.dll!FinishShutdown()  Line 1035   C++
    ole32.dll!ApartmentUninitialize(int fHostThread)  Line 1291 C++
    ole32.dll!wCoUninitialize(COleTls & Tls, int fHostThread)  Line 2709 + 0x7 bytes    C++
    ole32.dll!CoUninitialize()  Line 2632   C++
    imm32.dll!000007feff3832f2()    
    [Frames below may be incorrect and/or missing, no symbols loaded for imm32.dll] 
    msctf.dll!000007fefeea7d59()    
    ntdll.dll!RtlProcessFlsData()  + 0x84 bytes 
    ntdll.dll!LdrShutdownThread()  + 0x4b bytes 
    ntdll.dll!RtlExitUserThread()  + 0x38 bytes 
    IEShims.dll!NS_CreateThread::DesktopIE_ThreadProc()  + 0xd6 bytes   
    kernel32.dll!BaseThreadInitThunk()  + 0xd bytes 
    ntdll.dll!RtlUserThreadStart()  + 0x21 bytes    

例外是访问冲突

你们有遇到过这样的情况吗?我可以应用什么策略来确定其根本原因? 到目前为止,我已经完成了以下操作

我使用了 windbg,但是我在 windbg 中遇到的异常与我在 VS2010 中得到的不同实际上异常是相同的“访问冲突”但堆栈跟踪不同。我不是很擅长 windbg 来解决这个问题。任何指针在windbg中追踪它? 我试图删除一些代码,但也没有成功。

【问题讨论】:

CoUninitialize 调用的那一刻,您应该已经终止了所有 COM 活动。你没有它发生。 堆损坏足以解释这一点。 【参考方案1】:

这很可能是由于错误的对象释放顺序而发生的。考虑以下示例:COM 对象 A 意味着拥有 COM 对象 B,因此预期的顺序是对象 A 被显式调用 Release() 并且在它的析构函数中它将调用对象 B 上的 Release()。现在当 CoUnintialize()被称为 COM 将强制释放 some 序列中的所有 COM 对象。因此,对象 B 有可能首先被称为 Release(),现在对象 A 持有一个指向它认为是对象 B 的悬空指针,因此当对象 A Release() 被调用时,它会尝试利用悬空指针并运行到未定义的行为。

这个问题的解决方案是在调用CoUnintialize()之前以正确的顺序显式释放对象。

【讨论】:

问题是在这种情况下 CoUnintialize 不是从我的代码中调用的。我在调用 CoUnintialize 时在我的代码中设置了断点并且它永远不会被调用。我只在那之前得到异常。 正如我们从堆栈跟踪中看到的那样,一些线程正在被破坏,那么您是否使用了工作线程?如果不是,那意味着你的主线程已经结束,如果它没有调用 CoUninitialize 就结束了,它可能因为一些严重的错误而被破坏(所以运行时调用 ExitProcess)。据我所知,可以在诸如 CoUninitialize 之类的 API 函数上设置断点。如果这样做,您可能会更好地了解哪个代码调用了 CoUninitialize。【参考方案2】:

我有这个问题,红后

http://mfctips.com/2012/10/29/cfiledialogdomodal-causes-access-violation/

我怀疑问题在于将 QFileDialog 作为我的 Qmainwindow 方法的局部变量。然后我解决了它,将我的 Qfiledialog 作为 QMainwindow 的私有成员,如下所示:

//在MainWindow.h中

class MainWindow : public QMainWindow


Q_OBJECT
......      
private:
......
QFileDialog *ptDialog;
..... 

所以我在MainWindow构造函数中给ptDialog一个新的QfileDialog,并在MainWindow方法中根据我的需要调用ptDialog->exec(),如下:

//在MainWindow.cpp中

//构造函数

MainWindow::MainWindow(QWidget *parent):
QMainWindow(parent),
ui(new Ui::MainWindow)
    
.....
ptDialog=new QFileDialog(this, tr("Abrir Imagem"),QCoreApplication::applicationDirPath(), "Imagens (*.png *.jpg *.jpeg *.bmp)");
......

//我想使用QFileDialog的任何方法

void MainWindow::LoadFile()

    if(ptDialog->exec())
    
        SetFile(ptDialog->selectedFiles().first());

    


我想,这样Qmainwindow只会在应用端释放,避免了这个问题。

【讨论】:

以上是关于如何在应用程序退出时诊断 comptr 版本中的异常的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 R 处理 OLS 中的异方差性

DX11 将顶点缓冲区映射为 WRL::ComPtr

ComPtr的介绍以及使用

Spark 错误 - 退出状态:143。诊断:容器应请求终止

如何诊断由 IIS7 托管的 WCF 服务中的 W3WP.exe 错误

当操作返回元页面 html 时,如何更好地诊断 WCF 服务?