VS2008 中的断言,但 VS2005 中没有

Posted

技术标签:

【中文标题】VS2008 中的断言,但 VS2005 中没有【英文标题】:Assertion in VS2008 but not in VS2005 【发布时间】:2009-03-31 14:56:28 【问题描述】:

从 VS2005 切换到 VS2008 SP1 后,我发现了一个我无法解释的问题。 一个程序在 VS2005 下在发布和调试模式下都能正常工作。在 VS2008 下,当进入调试器时,会引发一个断言。 如果我让程序运行(在调试或发布模式下),则根本没有断言。

我花了将近两天的时间,我不明白我做错了什么。

程序说明: 我有一个基于 MFC 对话框的程序,它创建一个用户线程 (CWinThread),该线程创建应用程序的主对话框。 工作线程无限循环并每秒向对话框发布一条消息。消息在 gui 线程中处理。

我的部分代码:

gui线程的InitInstance:

BOOL CGraphicalThread::InitInstance()

    CGUIThreadDlg* pDlg = new CGUIThreadDlg();
    pDlg->Create(CGUIThreadDlg::IDD);
    m_pMainWnd = pDlg;
    AfxGetApp()->m_pMainWnd = pDlg;
    return TRUE;

工作线程:

UINT ThreadProc(LPVOID pVoid)

    do
    
        AfxGetApp()->m_pMainWnd->PostMessage(WM_APP+1, (WPARAM)new CString("Hello"), NULL);
        Sleep(1000);
    
    while(!bStopThread);

    return 0;

对话消息处理程序是这样的:

LRESULT CGUIThreadDlg::OnMsg(WPARAM wp, LPARAM lp)

    CListBox* pList = (CListBox*)GetDlgItem(IDC_LIST1);
    CString* ps = (CString*)wp;
    pList->InsertString(-1, *ps);
    delete ps;
    return 1L;

这与 VS2005 完美配合。 但是用VS2008,但是一旦下断点并进入调试模式,我就会提出一个断言??? wincore.cpp 第 906 行

CObject* p=NULL;
if(pMap)

      ASSERT( (p = pMap->LookupPermanent(m_hWnd)) != NULL ||
              (p = pMap->LookupTemporary(m_hWnd)) != NULL);

ASSERT((CWnd*)p == this);   // must be us
// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another.  The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.

如果我删除 GUI 线程并在 CWinApp 线程中创建对话框,问题就不会再出现了。

有人知道吗? 我做错了吗?

谢谢

【问题讨论】:

【参考方案1】:
// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another.  The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.

【讨论】:

是的,我知道。我不是在另一个线程中操作窗口,只是向它发布消息。我尝试使用原始 HWND,但问题仍然存在。无论如何,它并没有解释为什么它在 VS2005 上运行良好,而在 VS2008 上运行良好。 wincore.cpp 对于 VC++ 版本 8 和 9 是不同的。版本 8 是 VS 2005,版本 9 是 VS 2008 我建议将主对话框中的 HWND 作为线程参数传递,然后在线程中调用 CWnd::FromHandle(hWnd)->PostMessage(...);【参考方案2】:

@Ismael:我已经尝试过断言仍然被触发。我发现删除断言的唯一方法是在 CWinApp 线程中创建对话框。 但这并不能解释会发生什么,因为仍然有工作线程每秒发布到对话框。 无论如何,谢谢。

@daanish.rumani:我检查了 wincore.cpp 和 CWnd::AssertValid() 完全相同(但其余文件有很多差异)。

我会接受一段代码适用于 VS2005 而不是 VS2008,但是

    我看不出我做错了什么。 如果我做错了什么,正确的处理方法是什么? 为什么只有在遇到断点并且我跳过 Sleep 调用时才会触发断言? 我可以很好地运行程序,即使它在调试模式下编译,只要我不进入调试器。 会不会是调试器中的错误?

【讨论】:

理想情况下,您应该编辑原始问题以添加这些精度。答案是给别人的:) 是的。除非您真的自己找到了答案,否则不要发布答案。只需在其他人的答案或 cmets 下方编辑您的问题和/或评论即可。 对不起,我会注意的

以上是关于VS2008 中的断言,但 VS2005 中没有的主要内容,如果未能解决你的问题,请参考以下文章

安装 vs2005, vs2008 报错

SQL Server 2008 VS 2005 Reporting Services 整合SharePoint 2007 支持比较Part1

VS2008+SQL2005,用SqlDataSource控件新建数据库连接,无法打开数据源,说没有权限。

VS 2008 相对于 VS 2005 的优势

如何把VS2008的Solution改成VS2005格式

SqlDataReader C#,SQL Server 2005,VS 2008